Here is the scenario. I need to write some code that will act like a bridge receiving data via TCP connection and sending SNMP traps on. I don't have any control of the client and at some point will loose connection to the server computer so the code needs to be robust and self repairing. Here is how it should work
The client connects to server (port 1066 so doesn't need to run as root). Every so often it will send some data of the form
chr(1) + message type + data
If message type is "0" (zero) this is a poll message and the data is 4 bytes indicating the number of messages since last poll. The server will reply back in kind with the number of messages since last poll.
If message type is anything else then the data is between 30 and 200 odd bytes terminated with <CRLF>.
Now I have the basics here already. (The specs said the poll was also <CRFL> terminated but it isn't.) There are a couple of concerns and "requirements" that I need some guidance on.
- the client shows connection is dropped should be kept up - this doesn't seem important but would be nice
- If no poll is received in 3 mins send SNMP trap - this is a modification of current situation, the trap sent on processing poll should send trap to clear a "poll missed" message
- need to ensure that if client is disconnected for whatever reason then it can reconnect again
I run the Perl script inside a shell wrapper that will restart the Perl should it terminate. This wrapper also ensures that the environment is set correctly.
<set up bits including point to database and other stuff>
my $poll = 0;
my $messages = 0;
# make the socket
my $socket = IO::Socket::INET->new(
LocalHost => '<hostname>',
LocalPort => 1066,
Proto => 'tcp',
Listen => 5,
Reuse => 1,
) or die "Socket could not be created : $!";
# accept connections
while (my $new_sock = $socket->accept()) {
while (1) {
say "Waiting!";
my $buf="";
# loop until start of message control (chr(1))
while (read($new_sock,$buf,1)) { last if $buf eq chr(1
+);}
read($new_sock,$buf,1);
if ($buf eq "0") {
# handle the POLL message
# byte 1 = ASCII start of header (1)
# byte 2 = '0' - poll message ID
# byte 3 = number of messages since last poll
+- 4 bytes
# following don't seem to be sent.
# byte 7 = ASCII CR (13)
# byte 8 = ASCII LF (10)
# already have initial bytes now get payload
read($new_sock,$poll,4);
say "POLL : $poll";
SendPollReply($new_sock);
SendSNMP("0","0","--",undef,undef);
} else {
# Other messages look like they are Cr/LF term
+inated
$buf .= <$new_sock>;
$messages++;
say "Buffer : $buf Poll : $poll Messages :
+$messages";
# only send traps for message group "A" or "C"
if ($buf =~ /([AC])(.{8})((\+\+|--))(\d{8})(.{
+10})/msx) {
my $message_group = $1;
my $station_code = $2;
my $change_type = $3;
my $date_time = $5;
my $point_name = $6;
SendSNMP($message_group,$station_code,
+$change_type,$date_time,$point_name);
}
}
}
}
close($socket);
sub SendPollReply {
my $new_sock = shift;
# send the poll reply
# byte 1 = ASCII start of header chr(1)
# byte 2 = '0' - response message ID
# byte 3 = number of messages since last poll - 4 bytes
# byte 7 = Error status '0' if OK
# byte 8 = ASCII CR (13)
# byte 9 = ASCII LF (10)
SendMessage( $new_sock,"0".sprintf("%04d",$messages)."0");
$messages=0;
}
# wrap message back to poller in required start/end characters
sub SendMessage {
my ($new_sock,$message) = @_;
$message = chr(1).$message.chr(13).chr(10);
say "REPLY : $message";
print $new_sock $message;
}