Subject: | UNIX sockets, plz |
$Subject. I can't say if encryption works. I don't need it, and writing SSL enabled XMPP server for just one test unit is out of my time resources.
As a side note, your server code, in XML::Stream, is FUBAR.
Subject: | unix-sockets.diff |
diff -urN backup-1.23_06/lib/XML/Stream.pm unix-sockets/lib/XML/Stream.pm
--- backup-1.23_06/lib/XML/Stream.pm 2011-07-19 19:49:32.000000000 +0300
+++ unix-sockets/lib/XML/Stream.pm 2012-03-04 22:50:48.000000000 +0200
@@ -216,6 +216,7 @@
#---------------------------------------------------------------------------
$self->{SIDS}->{default}->{hostname} = "";
$self->{SIDS}->{default}->{port} = "";
+ $self->{SIDS}->{default}->{socket} = "";
$self->{SIDS}->{default}->{sock} = 0;
$self->{SIDS}->{default}->{ssl} = 0;
$self->{SIDS}->{default}->{_tls} = 0;
@@ -489,6 +490,7 @@
Connect(hostname=>string,
port=>integer,
+ socket=>string,
to=>string,
from=>string,
myhostname=>string,
@@ -503,7 +505,10 @@
Opens a tcp connection to the
specified server and sends the proper
opening XML Stream tag. C<hostname>,
-C<port>, and C<namespace> are required.
+and C<namespace> are required.
+C<port> is required for any C<connectiontype> except C<socket> and
+C<stdinout>.
+C<socket> is required for C<connectiontype> C<socket>.
namespaces allows you to use
XML::Stream::Namespace objects.
@@ -524,11 +529,12 @@
this to the correct value, or if you
want the other side of the stream to
think that you are someone else. The
-type determines the kind of
+C<connectiontype> determines the kind of
connection that is made:
"tcpip" - TCP/IP (default)
"stdinout" - STDIN/STDOUT
+ "socket" - UNIX socket
"http" - HTTP
HTTP recognizes proxies if the ENV
@@ -538,6 +544,7 @@
C<ssl> specifies whether an SSL socket
should be used for encrypted co-
mmunications.
+It's unknown for now if encryption works with C<connectiontype> C<socket>.
C<ssl_verify> determines whether peer
certificate verification takes place.
@@ -706,6 +713,38 @@
}
#---------------------------------------------------------------------------
+ # UNIX Sockets
+ #---------------------------------------------------------------------------
+ if ($self->{SIDS}->{newconnection}->{connectiontype} eq "socket")
+ {
+ #-----------------------------------------------------------------------
+ # We still need hostnames for handshake.
+ #-----------------------------------------------------------------------
+ if ($self->{SIDS}->{newconnection}->{hostname} eq "")
+ {
+ $self->SetErrorCode("newconnection","Server hostname not specified");
+ return;
+ }
+ if ($self->{SIDS}->{newconnection}->{socket} eq "")
+ {
+ $self->SetErrorCode("newconnection","Socket filename not specified");
+ return;
+ }
+ if ($self->{SIDS}->{newconnection}->{myhostname} eq "")
+ {
+ $self->{SIDS}->{newconnection}->{myhostname} = $self->{SIDS}->{newconnection}->{derivedhostname};
+ }
+
+ $self->{SIDS}->{newconnection}->{sock} =
+ IO::Socket::UNIX->new(Peer=>$self->{SIDS}->{newconnection}->{socket},
+ Type=>SOCK_STREAM,
+ (($timeout ne "") ? ( Timeout=>$timeout ) : ()),
+ );
+ return unless $self->{SIDS}->{newconnection}->{sock};
+
+ }
+
+ #---------------------------------------------------------------------------
# STDIN/OUT
#---------------------------------------------------------------------------
if ($self->{SIDS}->{newconnection}->{connectiontype} eq "stdinout")
@@ -979,6 +1018,7 @@
my %stream_args;
if (($self->{SIDS}->{$currsid}->{connectiontype} eq "tcpip") ||
+ ($self->{SIDS}->{$currsid}->{connectiontype} eq "socket") ||
($self->{SIDS}->{$currsid}->{connectiontype} eq "http"))
{
$stream_args{to}= $self->{SIDS}->{$currsid}->{hostname}
@@ -1031,6 +1071,7 @@
IO::Select->new($self->{SIDS}->{$currsid}->{sock});
if (($self->{SIDS}->{$currsid}->{connectiontype} eq "tcpip") ||
+ ($self->{SIDS}->{$currsid}->{connectiontype} eq "socket") ||
($self->{SIDS}->{$currsid}->{connectiontype} eq "http"))
{
$self->{SELECT} = IO::Select->new($self->{SIDS}->{$currsid}->{sock});
@@ -1099,6 +1140,7 @@
$self->{SIDS}->{$sid}->{parser}->setSID($sid);
if (($self->{SIDS}->{$sid}->{connectiontype} eq "tcpip") ||
+ ($self->{SIDS}->{$sid}->{connectiontype} eq "socket") ||
($self->{SIDS}->{$sid}->{connectiontype} eq "http"))
{
$self->{SOCKETS}->{$self->{SIDS}->{$currsid}->{sock}} = $sid;
@@ -1263,6 +1305,7 @@
$self->Send($sid,"</stream:stream>");
close($self->{SIDS}->{$sid}->{sock})
if (($self->{SIDS}->{$sid}->{connectiontype} eq "tcpip") ||
+ ($self->{SIDS}->{$sid}->{connectiontype} eq "socket") ||
($self->{SIDS}->{$sid}->{connectiontype} eq "http"));
delete($self->{SOCKETS}->{$self->{SIDS}->{$sid}->{sock}});
foreach my $key (keys(%{$self->{SIDS}->{$sid}}))
@@ -1622,6 +1665,7 @@
$status = $self->{SIDS}->{$sid}->{sock}->sysread($buff,4*POSIX::BUFSIZ)
if (($self->{SIDS}->{$sid}->{connectiontype} eq "tcpip") ||
+ ($self->{SIDS}->{$sid}->{connectiontype} eq "socket") ||
($self->{SIDS}->{$sid}->{connectiontype} eq "http") ||
($self->{SIDS}->{$sid}->{connectiontype} eq "file"));
$status = sysread(STDIN,$buff,1024)
@@ -1698,6 +1742,7 @@
while ($self->{SENDLENGTH})
{
$self->{SENDWRITTEN} = $self->{SIDS}->{$sid}->{sock}->syswrite($self->{SENDSTRING},$self->{SENDLENGTH},$self->{SENDOFFSET});
+ $self->{SIDS}->{$sid}->{sock}->sync();
if (!defined($self->{SENDWRITTEN}))
{
diff -urN backup-1.23_06/t/unixsocket.t unix-sockets/t/unixsocket.t
--- backup-1.23_06/t/unixsocket.t 1970-01-01 03:00:00.000000000 +0300
+++ unix-sockets/t/unixsocket.t 2012-03-01 21:59:02.000000000 +0200
@@ -0,0 +1,110 @@
+use strict;
+use warnings;
+
+package main;
+
+use Test::More tests => 9;
+use File::Temp qw{ tempfile };
+use IO::Socket;
+use POSIX qw{ :sys_wait_h };
+
+BEGIN{ use_ok("XML::Stream","Node"); }
+
+my $sfn = ( tempfile 'socket_XXXX', DIR => 't' )[-1];
+unlink $sfn;
+
+END { unlink $sfn }
+
+my $pid = fork();
+defined $pid or die "fork: $!";
+unless( $pid )
+{
+ my $socket = IO::Socket::UNIX->new( Local=>$sfn, Listen=>5, Type =>
+ SOCK_STREAM, Timeout => 600 ) or die "# new socket: $!";
+ my $conn = $socket->accept;
+ $conn->autoflush( 1 );
+ $conn->flush;
+ #my $buf = [ $conn->getlines ];
+ my $buf;
+ $conn->sysread( $buf, 4096 ) or die "1\n";
+ $buf =~ m{^\s*<\?xml\s+version}s or die "# 2\n";
+ $buf = <<'END_OF_REPLY';
+<?xml version='1.0'?>
+<stream:stream version='1.0'
+ xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client'
+ to='client@example.org' from='example.org' xml:lang='en'
+ id='0123456789abcdef'>
+END_OF_REPLY
+ $conn->syswrite( $buf, 4096 ) or die "# 4\n";
+ sleep 2;
+ $buf = <<'END_OF_REPLY';
+<stream:features/>
+END_OF_REPLY
+ $conn->syswrite( $buf, 4096 ) or die "# 5\n";
+ $conn->sysread( $buf, 4096 ) or die "# 6\n";
+ $buf =~ m{<iq\s+} or die "# 7\n";
+ $buf = <<'END_OF_REPLY';
+<iq type='result' id='0123'/>
+END_OF_REPLY
+ $conn->syswrite( $buf, 4096 ) or die "# 8\n";
+ $conn->sysread( $buf, 4096 ) or die "# 9\n";
+ $buf =~ m{</stream:stream>} or die "# 10\n";
+ sleep 3;
+ $buf = <<'END_OF_REPLY';
+</stream:stream>
+END_OF_REPLY
+# client disconnects without proper closing in-stream, thus socket is already closed
+ $conn->syswrite( $buf, 4096 ) and die "# 11\n";
+ sleep 4;
+ exit 0;
+}
+
+my $stream = XML::Stream->new(style=>"node");
+ok( defined($stream), "new()" );
+isa_ok( $stream, "XML::Stream" );
+
+my %nodes;
+$stream->SetCallBacks( node => sub { push @{$nodes{shift @_}}, shift @_ });
+
+sleep 2;
+my $client = $stream->Connect( socket => $sfn, hostname => 'example.org',
+ from => 'client@example.org', to => 'example@org',
+ connectiontype => 'socket', namespace => 'jabber:client', timeout => 60 );
+sleep 2;
+if( waitpid $pid, WNOHANG )
+{
+ fail 'server died';
+ exit;
+}
+is_deeply $client, { version => '1.0',
+ 'xmlns:stream' => 'http://etherx.jabber.org/streams', xmlns => 'jabber:client',
+ to => 'client@example.org', from => 'example.org', 'xml:lang' => 'en',
+ id => '0123456789abcdef', }, 'connection';
+
+$stream->Send( '0123456789abcdef', '<iq type="set" id="0123"><quit/></iq>' );
+sleep 2;
+if( waitpid $pid, WNOHANG )
+{
+ fail 'server died';
+ exit;
+}
+my $status = { $stream->Process( 60 ) };
+is_deeply $status, { '0123456789abcdef' => 1 }, 'ping';
+is_deeply {
+ tag => $nodes{'0123456789abcdef'}[0]->get_tag,
+ id => $nodes{'0123456789abcdef'}[0]->get_attrib( 'id' ),
+ type => $nodes{'0123456789abcdef'}[0]->get_attrib( 'type' ) }, {
+ tag => 'iq', id => '0123', type => 'result' }, 'pong';
+
+$status = $stream->Disconnect( '0123456789abcdef' );
+sleep 2;
+if( waitpid $pid, WNOHANG )
+{
+ fail 'server died';
+ exit;
+}
+is_deeply $status, { }, 'disconnection';
+
+is waitpid( $pid, 0 ), $pid, 'server exited';
+is $?, 0, 'ok exit';
+