Socket programming blunders....

G

Gavin Hamill

Hullo - I'm trying to communicate with our office PBX, and whilst I have the
full protocol documentation, I'm failing on basic socket programming...
I've ripped most of an example from the Perl Cookbook and modified it so I
have a basic interactive client that works fine:

#!/usr/bin/perl

# Message format is 32-bit little-endian length followed by
# the message, terminated with 0x0d0a incoming and 0x0d outgoing.

use IO::Socket;
$sock = new IO::Socket::INET (PeerAddr => '10.0.0.246',
PeerPort => 4000,
Proto => 'tcp',
);
die "Socket could not be created. Reason: $!\n" unless $sock;

$sock->autoflush(1);
print STDERR "[Connected]\n";
# split the program into two processes, identical twins
die "can't fork: $!" unless defined($kidpid = fork());

if ($kidpid) {
while (sysread($sock, $header,4) == 4) {
# We got a 4-byte header!
$paylen= unpack("V",$header);
print "Got message length of $paylen payload bytes\n";

if(sysread($sock, $payload, $paylen) == $paylen) {
print $payload;
}
else {
print "ERR! Bytes read didn't match value in header - received this:
-=$payload=-\n";
}
}
kill("TERM" => $kidpid); # send SIGTERM to child
}
else {
# Magic login sequence
print $sock "\x02\x00\x00\x00\x87\x00";
while (defined ($line = <STDIN>)) {
chop $line; # Remove the 0x0a LF
print $sock pack("V",length($line)+1);
print $sock $line . "\x0d"; # Suffix a CR
}
}
exit;


My problem is this:

The PBX will be sending me events, and I will need to send responses to the
PBX, parse the responses and perhaps send different replies...

If this script has fork()ed ... how on earth do I get the two halves to talk
to each other? named pipes? UNIX domain sockets?

After much reading I've drawn a blank - does anyone have suggestions or some
short code fragments I could work from?

Cheers,
Gavin,.
 
N

nobull

Gavin said:
I'm trying to communicate with our office PBX
I've ripped most of an example from the Perl
Cookbook and modified it so I have a basic interactive
client that works fine:
if ($kidpid) {
while (sysread($sock, $header,4) == 4) {
}
} else {
while (defined ($line = <STDIN>)) {
print $sock $line . "\x0d"; # Suffix a CR
}
}
The PBX will be sending me events, and I will need to send
responses to the PBX, parse the responses and perhaps send
different replies...

If this script has fork()ed ... how on earth do I get the two halves to talk
to each other? named pipes? UNIX domain sockets?

Why did you fork? It make be a quick way to handle an interactive
client where the two directions don't interact but as soon as you need
interaction you run right back into the problems that you forked to
avoid - and then some.

Sounds to me like you may be better off not forking so. If you always
wait for a message from the PBX and then respond and yo can assume that
the PBX will read that response before you need to process the next
requestthen life is simple. If not you probably need to go for an
event driven approach like IO::Select or POE.
 
X

xhoster

Gavin Hamill said:
Hullo - I'm trying to communicate with our office PBX, and whilst I have
the full protocol documentation, I'm failing on basic socket
programming... I've ripped most of an example from the Perl Cookbook and
modified it so I have a basic interactive client that works fine:

Why did Perl Cookbook tell you to fork? Are there non-forking examples
in the Cookbook?

Xho
 
A

Anno Siegel

Gavin Hamill said:
Hullo - I'm trying to communicate with our office PBX, and whilst I have the
full protocol documentation, I'm failing on basic socket programming...
I've ripped most of an example from the Perl Cookbook and modified it so I
have a basic interactive client that works fine:

#!/usr/bin/perl

# Message format is 32-bit little-endian length followed by
# the message, terminated with 0x0d0a incoming and 0x0d outgoing.

use IO::Socket;
$sock = new IO::Socket::INET (PeerAddr => '10.0.0.246',
PeerPort => 4000,
Proto => 'tcp',
);
die "Socket could not be created. Reason: $!\n" unless $sock;

$sock->autoflush(1);
print STDERR "[Connected]\n";
# split the program into two processes, identical twins
die "can't fork: $!" unless defined($kidpid = fork());

if ($kidpid) {
while (sysread($sock, $header,4) == 4) {
# We got a 4-byte header!
$paylen= unpack("V",$header);
print "Got message length of $paylen payload bytes\n";

if(sysread($sock, $payload, $paylen) == $paylen) {
print $payload;
}
else {

This check could go wrong. sysread() can come back with a short (partial)
read before all data has been transmitted. You may have to call sysread()
in a loop when messages get longer.
print "ERR! Bytes read didn't match value in header - received this:
-=$payload=-\n";
}
}
kill("TERM" => $kidpid); # send SIGTERM to child
}
else {
# Magic login sequence
print $sock "\x02\x00\x00\x00\x87\x00";
while (defined ($line = <STDIN>)) {
chop $line; # Remove the 0x0a LF
print $sock pack("V",length($line)+1);
print $sock $line . "\x0d"; # Suffix a CR
}
}
exit;


My problem is this:

The PBX will be sending me events, and I will need to send responses to the
PBX, parse the responses and perhaps send different replies...

If this script has fork()ed ... how on earth do I get the two halves to talk
to each other? named pipes? UNIX domain sockets?

Why, yes. You can use either, or an anonymous pipe, or ip sockets
(the overhead isn't so bad). In fact, it seems you only have to communicate
from the parent to the kid, so a forking open() may do.

Here's a sketch:

my $kidpid = open my( $to_kid), '|-';
if ( $kidpid ) {
my $message;
print $to_kid $message while $message = read_from_socket( $sock);
kill 'TERM', $kidpid;
} else {
print $sock "\x02\x00\x00\x00\x87\x00";
while ( my $message = <> ) {
my $reply = determine_reply( $message);
send_to_socket( $sock, $reply);
}
}

read_from_socket() and send_to_socket() may block. determine_reply()
should know an appropriate answer to all possible messages.

Anno
 
G

gdh

Thanks for the responses :)

I think I decided on using the fork() examples from the Cookbook
because at every moment, the client may need to send, OR the PBX may
have something to say to me, so I don't want to block at any time. I
also could understand the forking better than I could select() :)

The app is ultimately to listen for CallerID information from the PBX,
but I also need to do things like 'if no data received in 60 seconds,
send a NOOP packet' to keep the connection alive, and I expect the app
will need to grow in future to send more command back to the PBX...

I'll look into all the suggestions given here :)

Cheers,
Gavin.
 
X

xhoster

gdh said:
Thanks for the responses :)

I think I decided on using the fork() examples from the Cookbook
because at every moment, the client may need to send, OR the PBX may
have something to say to me, so I don't want to block at any time.

Yeah, if both ends of the connection can iniate reqeusts (as opposed to
one end just responding to requests made by the other), that makes
things a lot more difficult.
I
also could understand the forking better than I could select() :)

Alas, by the time you add the IPC to the forking, that will no longer
be the case. :)

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top