# New Ticket Created by  Markus Amslser 
# Please include the string:  [perl #34120]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/rt3/Ticket/Display.html?id=34120 >


This patch extends the io NET_DEVEL with the 'server' functions bind, 
listen and accept. I only tested it on win32, so no idea what happens on 
unix. I'm not sure wether i did it right with the ops numbering, but it 
worked for me (See the next patch).

Markus

Changelog:
  - implement bind, listen, accept on win32
  - some casting cleanup
Index: include/parrot/io.h
===================================================================
RCS file: /cvs/public/parrot/include/parrot/io.h,v
retrieving revision 1.61
diff -w -u -r1.61 io.h
--- include/parrot/io.h 1 Feb 2005 09:43:18 -0000       1.61
+++ include/parrot/io.h 12 Feb 2005 23:52:19 -0000
@@ -184,6 +184,9 @@
 extern INTVAL PIO_recv(theINTERP, PMC *pmc, STRING **buf);
 extern INTVAL PIO_send(theINTERP, PMC *pmc, STRING *buf);
 extern INTVAL PIO_connect(theINTERP, PMC *pmc, STRING *address);
+extern INTVAL PIO_bind(theINTERP, PMC *pmc, STRING *address);
+extern INTVAL PIO_listen(theINTERP, PMC *pmc, INTVAL backlog);
+extern PMC *PIO_accept(theINTERP, PMC *pmc);
 
 
 extern INTVAL PIO_putps(theINTERP, PMC *io, STRING *s);
Index: io/io.c
===================================================================
RCS file: /cvs/public/parrot/io/io.c,v
retrieving revision 1.108
diff -w -u -r1.108 io.c
--- io/io.c     27 Jan 2005 14:11:37 -0000      1.108
+++ io/io.c     12 Feb 2005 23:52:21 -0000
@@ -1391,6 +1391,73 @@
 /*
 
 =item C<INTVAL
+PIO_bind(theINTERP, PMC *pmc, STRING *address)>
+
+Binds C<*pmc>'s socket to the local address and port specified by C<*address>.
+
+=cut
+
+*/
+
+INTVAL
+PIO_bind(theINTERP, PMC *pmc, STRING *address)
+{
+    ParrotIOLayer *l = PMC_struct_val(pmc);
+    ParrotIO *io = PMC_data(pmc);
+    if(!io)
+        return -1;
+
+    return PIO_bind_down(interpreter, l, io, address);
+}
+
+/*
+
+=item C<INTVAL
+PIO_listen(theINTERP, PMC *pmc, INTVAL backlog)>
+
+Listen for new connections on socket C<*pmc>.
+
+=cut
+
+*/
+
+INTVAL
+PIO_listen(theINTERP, PMC *pmc, INTVAL backlog)
+{
+    ParrotIOLayer *l = PMC_struct_val(pmc);
+    ParrotIO *io = PMC_data(pmc);
+    if(!io)
+        return -1;
+
+    return PIO_listen_down(interpreter, l, io, backlog);
+}
+
+/*
+
+=item C<INTVAL
+PIO_accept(theINTERP, PMC *pmc)>
+
+Accept a new connection and return a newly created C<ParrotIO> socket.
+=cut
+
+*/
+
+PMC *
+PIO_accept(theINTERP, PMC *pmc)
+{
+    ParrotIO *io2;
+    ParrotIOLayer *l = PMC_struct_val(pmc);
+    ParrotIO *io = PMC_data(pmc);
+    if(!io)
+        return NULL;
+
+    io2 = PIO_accept_down(interpreter, l, io);
+    return new_io_pmc(interpreter, io2);
+}
+
+/*
+
+=item C<INTVAL
 PIO_isatty(theINTERP, PMC *pmc)>
 
 Returns a boolean value indicating whether C<*pmc> is a console/tty.
Index: io/io_passdown.c
===================================================================
RCS file: /cvs/public/parrot/io/io_passdown.c,v
retrieving revision 1.9
diff -w -u -r1.9 io_passdown.c
--- io/io_passdown.c    1 Oct 2004 08:46:50 -0000       1.9
+++ io/io_passdown.c    12 Feb 2005 23:52:21 -0000
@@ -568,6 +568,88 @@
 
 /*
 
+=item C<INTVAL
+PIO_bind_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING *address)>
+
+Looks for the implementation of C<Bind> and calls it if found,
+returning its return value.
+
+Returns C<-1> if no implementation is found.
+
+
+=cut
+
+*/
+
+INTVAL
+PIO_bind_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING *address)
+{
+    while (layer) {
+        if (layer->api->Bind) {
+            return layer->api->Bind(interpreter, layer, io, address);
+        }
+        layer = PIO_DOWNLAYER(layer);
+    }
+    return -1;
+}
+
+/*
+
+=item C<INTVAL
+PIO_listen_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, INTVAL backlog)>
+
+Looks for the implementation of C<listen> and calls it if found,
+returning its return value.
+
+Returns C<-1> if no implementation is found.
+
+
+=cut
+
+*/
+
+INTVAL
+PIO_listen_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, INTVAL backlog)
+{
+    while (layer) {
+        if (layer->api->Listen) {
+            return layer->api->Listen(interpreter, layer, io, backlog);
+        }
+        layer = PIO_DOWNLAYER(layer);
+    }
+    return -1;
+}
+
+/*
+
+=item C<ParrotIO *
+PIO_accept_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING 
*address)Y
+
+
+Looks for the implementation of C<Accept> and calls it if found,
+returning its return value.
+
+Returns C<-1> if no implementation is found.
+
+
+=cut
+
+*/
+
+ParrotIO *
+PIO_accept_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
+{
+    while (layer) {
+        if (layer->api->Accept) {
+            return layer->api->Accept(interpreter, layer, io);
+        }
+        layer = PIO_DOWNLAYER(layer);
+    }
+    return -1;
+}
+
+/*
+
 =back
 
 =head1 SEE ALSO
Index: io/io_private.h
===================================================================
RCS file: /cvs/public/parrot/io/io_private.h,v
retrieving revision 1.18
diff -w -u -r1.18 io_private.h
--- io/io_private.h     4 Oct 2004 11:39:51 -0000       1.18
+++ io/io_private.h     12 Feb 2005 23:52:22 -0000
@@ -170,6 +170,9 @@
 INTVAL    PIO_recv_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING 
**buf);
 INTVAL    PIO_send_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING 
*buf);
 INTVAL    PIO_connect_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, 
STRING *address);
+INTVAL    PIO_bind_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING 
*address);
+INTVAL    PIO_listen_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io, 
INTVAL backlog);
+ParrotIO *PIO_accept_down(theINTERP, ParrotIOLayer *layer, ParrotIO *io);
 
 /*
  * By default, any layer not implementing an interface (ie. leaving
@@ -227,6 +230,9 @@
                             STRING *);
     INTVAL          (*Send)(theINTERP, ParrotIOLayer *, ParrotIO *, STRING *);
     INTVAL          (*Recv)(theINTERP, ParrotIOLayer *, ParrotIO *, STRING **);
+    INTVAL          (*Bind)(theINTERP, ParrotIOLayer *, ParrotIO *, STRING *);
+    INTVAL          (*Listen)(theINTERP, ParrotIOLayer *, ParrotIO *, INTVAL);
+    ParrotIO *      (*Accept)(theINTERP, ParrotIOLayer *, ParrotIO *);
 };
 
 /* these are defined rather than using NULL because strictly-speaking, ANSI C
Index: io/io_win32.c
===================================================================
RCS file: /cvs/public/parrot/io/io_win32.c,v
retrieving revision 1.49
diff -w -u -r1.49 io_win32.c
--- io/io_win32.c       1 Feb 2005 09:43:20 -0000       1.49
+++ io/io_win32.c       12 Feb 2005 23:52:23 -0000
@@ -576,7 +576,7 @@
     ParrotIO * io;
     if((sock = socket(fam, type, proto)) >= 0) {
         io = PIO_new(interpreter, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
-        io->fd = (void *) sock;
+        io->fd = (PIOHANDLE) sock;
         io->remote.sin_family = fam;
         return io;
     }
@@ -606,7 +606,7 @@
     }
 
 /*    PIO_eprintf(interpreter, "connect: fd = %d port = %d\n", io->fd, 
ntohs(io->remote.sin_port));*/
-    if((connect((int)io->fd, (struct sockaddr*)&io->remote,
+    if((connect((SOCKET)io->fd, (struct sockaddr*)&io->remote,
                    sizeof(struct sockaddr))) != 0) {
         PIO_eprintf(interpreter, "PIO_win32_connect: errno = %d\n", 
WSAGetLastError());
         return -1;
@@ -637,7 +637,7 @@
     /*
      * Ignore encoding issues for now.
      */
-    if((error = send((int)io->fd, (char *)PObj_bufstart(s) + byteswrote,
+    if((error = send((SOCKET)io->fd, (char *)PObj_bufstart(s) + byteswrote,
                             PObj_buflen(s), 0)) >= 0) {
         byteswrote += error;
         if(byteswrote >= bytes) {
@@ -656,7 +656,7 @@
 #else
             case EAGAIN:       goto AGAIN;
 #endif
-            case EPIPE:        close((int)io->fd);
+            case EPIPE:        close((SOCKET)io->fd);
                                return -1;
             default:           return -1;
         }
@@ -683,13 +683,13 @@
     char buf[2048+1];
 
 AGAIN:
-               error = recv((int)io->fd, buf, 2048, 0);
+       error = recv((SOCKET)io->fd, buf, 2048, 0);
                err = WSAGetLastError();
     if(error > 0) {
         if(error > 0)
             bytesread += error;
         else {
-            close((int)io->fd);
+            close((SOCKET)io->fd);
         }
         *s = string_make(interpreter, buf, bytesread, "iso-8859-1", 0);
         if(!*s) {
@@ -703,12 +703,12 @@
         switch(err) {
             case WSAEINTR:        goto AGAIN;
             case WSAEWOULDBLOCK:  goto AGAIN;
-            case WSAECONNRESET:   close((int)io->fd);
+            case WSAECONNRESET:   close((SOCKET)io->fd);
 #if PIO_TRACE
             PIO_eprintf(interpreter, "recv: Connection reset by peer\n");
 #endif
                                return -1;
-            default:           close((int)io->fd);
+            default:           close((SOCKET)io->fd);
 #if PIO_TRACE
                        PIO_eprintf(interpreter, "recv: errno = %d\n", err);
 #endif
@@ -717,7 +717,104 @@
     }
 }
 
+/*
+
+=item C<static INTVAL
+PIO_win32_bind(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING *l)>
+
+Binds C<*io>'s socket to the local address and port specified by C<*l>.
+
+=cut
+
+*/
+
+static INTVAL
+PIO_win32_bind(theINTERP, ParrotIOLayer *layer, ParrotIO *io, STRING *l)
+{
+    struct sockaddr_in sa;
+    if(!l) return -1;
+
+    memcpy(&sa, PObj_bufstart(l), sizeof(struct sockaddr));
+    io->local.sin_addr.s_addr = sa.sin_addr.s_addr;
+    io->local.sin_port = sa.sin_port;
+    io->local.sin_family = AF_INET;
+
+    if((bind((SOCKET)io->fd, (struct sockaddr *)&io->local, sizeof(struct 
sockaddr))) == -1)
+    {
+        PIO_eprintf(interpreter, "PIO_win32_bind: errno = %d\n", 
WSAGetLastError());
+        return -1;
+    }
+
+    return 0;
+}
+
+/*
+
+=item C<static INTVAL
+PIO_win32_listen(theINTERP, ParrotIOLayer *layer, ParrotIO *io, INTVAL sec)>
+
+Listen for new connections. This is only applicable to C<STREAM> or
+C<SEQ> sockets.
+
+=cut
+
+*/
+
+static INTVAL
+PIO_win32_listen(theINTERP, ParrotIOLayer *layer, ParrotIO *io, INTVAL backlog)
+{
+    if((listen((SOCKET)io->fd, backlog)) == -1) {
+        fprintf(stderr, "listen: errno= ret=%d fd = %d port = %d\n",
+             errno, io->fd, ntohs(io->local.sin_port));
+        return -1;
+    }
+    return 0;
+}
+
+/*
+
+=item C<static ParrotIO *
+PIO_win32_accept(theINTERP, ParrotIOLayer *layer, ParrotIO *io)>
+
+Accept a new connection and return a newly created C<ParrotIO> socket.
+
+=cut
 
+*/
+
+static ParrotIO *
+PIO_win32_accept(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
+{
+    int newsock;
+    int newsize;
+    int err_code;
+    ParrotIO *newio;
+    newio = PIO_new(interpreter, PIO_F_SOCKET, 0, PIO_F_READ|PIO_F_WRITE);
+    newsize = sizeof (struct sockaddr);
+
+    newsock = accept((SOCKET)io->fd, (struct sockaddr *)&(newio->remote), 
&newsize);
+    err_code = WSAGetLastError();
+
+    if(err_code != 0)
+    {
+        fprintf(stderr, "accept: errno=%d", err_code);
+        /* Didn't get far enough, free the io */
+        mem_sys_free(newio);
+        return NULL;
+    }
+
+    newio->fd = (PIOHANDLE) newsock;
+
+    /* XXX FIXME: Need to do a getsockname and getpeername here to
+     * fill in the sockaddr_in structs for local and peer
+     */
+
+    /* Optionally do a gethostyaddr() to resolve remote IP address.
+     * This should be based on an option set in the master socket
+     */
+
+    return newio;
+}
 
 #endif
 
@@ -756,12 +853,18 @@
     PIO_win32_connect,
     PIO_win32_send,
     PIO_win32_recv,
+    PIO_win32_bind,
+    PIO_win32_listen,
+    PIO_win32_accept
 #else
     0, /* no poll */
     0, /* no socket */
     0, /* no connect */
     0, /* no send */
     0, /* no recv */
+    0, /* no bind */
+    0, /* no listen */
+    0, /* no accept */
 #endif
 };
 
Index: ops/io.ops
===================================================================
RCS file: /cvs/public/parrot/ops/io.ops,v
retrieving revision 1.53
diff -w -u -r1.53 io.ops
--- ops/io.ops  1 Feb 2005 10:23:18 -0000       1.53
+++ ops/io.ops  12 Feb 2005 23:52:29 -0000
@@ -521,6 +521,12 @@
 
 =item B<poll>(out INT, in PMC, in INT, in INT, in INT)
 
+=item B<bind>(out INT, in PMC, in STR)
+
+=item B<listen>(out INT, in PMC, in INT)
+
+=item B<accept>(out PMC, in PMC)
+
 =cut
 
 op socket(out PMC, in INT, in INT, in INT) :base_network {
@@ -556,6 +562,21 @@
     goto NEXT();
 }
 
+op bind(out INT, in PMC, in STR) :base_network {
+    $1 = (INTVAL)PIO_bind(interpreter, $2, $3);
+    goto NEXT();
+}
+
+op listen(out INT, in PMC, in INT) :base_network {
+    $1 = (INTVAL)PIO_listen(interpreter, $2, $3);
+    goto NEXT();
+}
+
+op accept(out PMC, in PMC) :base_network {
+    $1 = PIO_accept(interpreter, $2);
+    goto NEXT();
+}
+
 ########################################
 
 =back
Index: ops/ops.num
===================================================================
RCS file: /cvs/public/parrot/ops/ops.num,v
retrieving revision 1.55
diff -w -u -r1.55 ops.num
--- ops/ops.num 17 Jan 2005 14:56:45 -0000      1.55
+++ ops/ops.num 12 Feb 2005 23:52:31 -0000
@@ -1367,3 +1367,8 @@
 pop_pad_p                      1337
 interpinfo_s_i                 1338
 interpinfo_s_ic                1339
+bind_i_p_s                     1340
+bind_i_p_sc                    1341
+listen_i_p_i                   1342
+listen_i_p_ic                  1343
+accept_p_p                     1344

Reply via email to