# 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