http://qs1969.pair.com?node_id=968036

tweetiepooh has asked for the wisdom of the Perl Monks concerning the following question:

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.

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; }