diff --git a/examples/io/httpd.pir b/examples/io/httpd.pir index fe6a1c1..01a596c 100644 --- a/examples/io/httpd.pir +++ b/examples/io/httpd.pir @@ -111,11 +111,13 @@ The code was heavily hacked by bernhard and leo. port = 1234 # TODO provide sys/socket constants - listener = socket 2, 1, 6 # PF_INET, SOCK_STREAM, tcp + .local pmc sock + sock = new 'Socket' + listener = sock.'socket'(2, 1, 6) # PF_INET, SOCK_STREAM, tcp unless listener goto ERR_NO_SOCKET # Pack a sockaddr_in structure with IP and port - address = sockaddr host, port + address = sock.'sockaddr'(host, port) ret = listener.'bind'(address) if ret == -1 goto ERR_bind $S0 = port diff --git a/include/parrot/io.h b/include/parrot/io.h index 88953ab..2efc85b 100644 --- a/include/parrot/io.h +++ b/include/parrot/io.h @@ -829,8 +829,13 @@ INTVAL Parrot_io_send(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(STRING *buf)) PARROT_EXPORT PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL -PMC * Parrot_io_socket(PARROT_INTERP, INTVAL fam, INTVAL type, INTVAL proto) - __attribute__nonnull__(1); +PMC * Parrot_io_socket(PARROT_INTERP, + ARGMOD_NULLOK(PMC * socket), + INTVAL fam, + INTVAL type, + INTVAL proto) + __attribute__nonnull__(1) + FUNC_MODIFIES(* socket); PARROT_EXPORT PARROT_WARN_UNUSED_RESULT diff --git a/include/parrot/io_unix.h b/include/parrot/io_unix.h index 4dd53cb..307f94c 100644 --- a/include/parrot/io_unix.h +++ b/include/parrot/io_unix.h @@ -1,7 +1,7 @@ /* io_unix.h * Copyright (C) 2001-2003, Parrot Foundation. * SVN Info - * $Id$ + * $Id: io_unix.h 36833 2009-02-17 20:09:26Z allison $ * Overview: * Parrot IO subsystem * Data Structure and Algorithms: @@ -220,8 +220,13 @@ PMC * Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port) PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL -PMC * Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto) - __attribute__nonnull__(1); +PMC * Parrot_io_socket_unix(PARROT_INTERP, + ARGIN(PMC *s), + int fam, + int type, + int proto) + __attribute__nonnull__(1) + __attribute__nonnull__(2); #define ASSERT_ARGS_Parrot_io_accept_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ @@ -249,7 +254,8 @@ PMC * Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto) PARROT_ASSERT_ARG(interp) \ || PARROT_ASSERT_ARG(addr) #define ASSERT_ARGS_Parrot_io_socket_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = \ - PARROT_ASSERT_ARG(interp) + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(s) /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ /* HEADERIZER END: src/io/socket_unix.c */ @@ -275,8 +281,8 @@ PMC * Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto) #define PIO_POLL(interp, pmc, which, sec, usec) \ Parrot_io_poll_unix((interp), (pmc), (which), (sec), (usec)) -#define PIO_NEW_SOCKET(interp, fam, type, proto) \ - Parrot_io_socket_unix((interp), (fam), (type), (proto)) +#define PIO_SOCKET(interp, socket, fam, type, proto) \ + Parrot_io_socket_unix((interp), (socket), (fam), (type), (proto)) #define PIO_RECV(interp, pmc, buf) \ Parrot_io_recv_unix((interp), (pmc), (buf)) #define PIO_SEND(interp, pmc, buf) \ diff --git a/include/parrot/io_win32.h b/include/parrot/io_win32.h index 96f943f..b39d8fd 100644 --- a/include/parrot/io_win32.h +++ b/include/parrot/io_win32.h @@ -199,8 +199,13 @@ PMC * Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port) PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL -PMC * Parrot_io_socket_win32(PARROT_INTERP, int fam, int type, int proto) - __attribute__nonnull__(1); +PMC * Parrot_io_socket_win32(PARROT_INTERP, + ARGIN(PMC * s), + int fam, + int type, + int proto) + __attribute__nonnull__(1) + __attribute__nonnull__(2); #define ASSERT_ARGS_Parrot_io_accept_win32 __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ @@ -228,7 +233,8 @@ PMC * Parrot_io_socket_win32(PARROT_INTERP, int fam, int type, int proto) PARROT_ASSERT_ARG(interp) \ || PARROT_ASSERT_ARG(addr) #define ASSERT_ARGS_Parrot_io_socket_win32 __attribute__unused__ int _ASSERT_ARGS_CHECK = \ - PARROT_ASSERT_ARG(interp) + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(s) /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ /* HEADERIZER END: src/io/socket_win32.c */ @@ -252,8 +258,8 @@ PMC * Parrot_io_socket_win32(PARROT_INTERP, int fam, int type, int proto) #define PIO_POLL(interp, pmc, which, sec, usec) \ Parrot_io_poll_win32((interp), (pmc), (which), (sec), (usec)) -#define PIO_NEW_SOCKET(interp, fam, type, proto) \ - Parrot_io_socket_win32((interp), (fam), (type), (proto)) +#define PIO_SOCKET(interp, socket, fam, type, proto) \ + Parrot_io_socket_win32((interp), (socket), (fam), (type), (proto)) #define PIO_RECV(interp, pmc, buf) \ Parrot_io_recv_win32((interp), (pmc), (buf)) #define PIO_SEND(interp, pmc, buf) \ diff --git a/src/io/socket_api.c b/src/io/socket_api.c index fe25f94..d148018 100644 --- a/src/io/socket_api.c +++ b/src/io/socket_api.c @@ -83,10 +83,19 @@ PARROT_EXPORT PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL PMC * -Parrot_io_socket(PARROT_INTERP, INTVAL fam, INTVAL type, INTVAL proto) +Parrot_io_socket(PARROT_INTERP, ARGMOD_NULLOK(PMC * socket), INTVAL fam, + INTVAL type, INTVAL proto) { ASSERT_ARGS(Parrot_io_socket) - return PIO_NEW_SOCKET(interp, fam, type, proto); + PMC *new_socket; + + if (PMC_IS_NULL(socket)) + new_socket = Parrot_io_new_socket_pmc(interp, + PIO_F_SOCKET|PIO_F_READ|PIO_F_WRITE); + else + new_socket = socket; + + return PIO_SOCKET(interp, socket, fam, type, proto); } /* diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c index db52817..1362e62 100644 --- a/src/io/socket_unix.c +++ b/src/io/socket_unix.c @@ -127,17 +127,16 @@ socket type and protocol number. PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL PMC * -Parrot_io_socket_unix(PARROT_INTERP, int fam, int type, int proto) +Parrot_io_socket_unix(PARROT_INTERP, ARGIN(PMC *s), int fam, int type, int proto) { ASSERT_ARGS(Parrot_io_socket_unix) int i; const int sock = socket(fam, type, proto); if (sock >= 0) { - PMC * io = Parrot_io_new_socket_pmc(interp, PIO_F_SOCKET|PIO_F_READ|PIO_F_WRITE); - PARROT_SOCKET(io)->os_handle = sock; - setsockopt(PARROT_SOCKET(io)->os_handle, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)); - SOCKADDR_REMOTE(io)->sin_family = fam; - return io; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)); + Parrot_io_set_os_handle(interp, s, sock); + SOCKADDR_REMOTE(s)->sin_family = fam; + return s; } return PMCNULL; } diff --git a/src/io/socket_win32.c b/src/io/socket_win32.c index 1f07d5b..b458313 100644 --- a/src/io/socket_win32.c +++ b/src/io/socket_win32.c @@ -73,15 +73,14 @@ socket type and protocol number. PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL PMC * -Parrot_io_socket_win32(PARROT_INTERP, int fam, int type, int proto) +Parrot_io_socket_win32(PARROT_INTERP, ARGIN(PMC * s), int fam, int type, int proto) { ASSERT_ARGS(Parrot_io_socket_win32) int i; const int sock = socket(fam, type, proto); if (sock >= 0) { - PMC * io = Parrot_io_new_socket_pmc(interp, PIO_F_SOCKET|PIO_F_READ|PIO_F_WRITE); - PARROT_SOCKET(io)->os_handle = (void*)sock; - setsockopt((int)PARROT_SOCKET(io)->os_handle, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)); + Parrot_io_set_os_handle(interp, s, sock); SOCKADDR_REMOTE(io)->sin_family = fam; return io; } diff --git a/src/ops/io.ops b/src/ops/io.ops index 52e3b2e..04a9d43 100644 --- a/src/ops/io.ops +++ b/src/ops/io.ops @@ -508,62 +508,12 @@ op sockaddr(out PMC, in STR, in INT) { =item B(out PMC, in INT, in INT, in INT) -Create new socket +Create new Socket PMC =cut op socket(out PMC, in INT, in INT, in INT) { - $1 = Parrot_io_socket(interp, $2, $3, $4); -} - -=item B(out INT, in PMC, in PMC) - -Bind socket to address - -=cut - -op bind(out INT, in PMC, in PMC) { - $1 = Parrot_io_bind(interp, $2, $3); -} - -=item B(out INT, in PMC, in INT) - -Start listening on previously bound socket - -=cut - -op listen(out INT, in PMC, in INT) { - $1 = Parrot_io_listen(interp, $2, $3); -} - -=item B(out PMC, in PMC) - -Accept incoming connection - -=cut - -op accept(out PMC, in PMC) { - $1 = Parrot_io_accept(interp, $2); -} - -=item B(out INT, in PMC, out STR) - -Receive data from socket - -=cut - -op recv(out INT, in PMC, out STR) { - $1 = Parrot_io_recv(interp, $2, &$3); -} - -=item B(out INT, in PMC, in STR) - -Send data to socket - -=cut - -op send(out INT, in PMC, in STR) { - $1 = Parrot_io_send(interp, $2, $3); + $1 = Parrot_io_socket(interp, PMCNULL, $2, $3, $4); } =back diff --git a/src/ops/ops.num b/src/ops/ops.num index df8be16..7748fb7 100644 --- a/src/ops/ops.num +++ b/src/ops/ops.num @@ -1280,19 +1280,3 @@ sockaddr_p_s_i 1255 sockaddr_p_sc_i 1256 sockaddr_p_s_ic 1257 sockaddr_p_sc_ic 1258 -bind_i_p_p 1259 -bind_i_pc_p 1260 -bind_i_p_pc 1261 -bind_i_pc_pc 1262 -listen_i_p_i 1263 -listen_i_pc_i 1264 -listen_i_p_ic 1265 -listen_i_pc_ic 1266 -accept_p_p 1267 -accept_p_pc 1268 -recv_i_p_s 1269 -recv_i_pc_s 1270 -send_i_p_s 1271 -send_i_pc_s 1272 -send_i_p_sc 1273 -send_i_pc_sc 1274 diff --git a/src/pmc/socket.pmc b/src/pmc/socket.pmc index 9f71c17..ae8664e 100644 --- a/src/pmc/socket.pmc +++ b/src/pmc/socket.pmc @@ -37,23 +37,12 @@ Initializes a newly created Socket object. VTABLE void init() { Parrot_Socket_attributes *data_struct = - mem_allocate_typed(Parrot_Socket_attributes); + mem_allocate_zeroed_typed(Parrot_Socket_attributes); PMC_data(SELF) = data_struct; data_struct->local = PMCNULL; data_struct->remote = PMCNULL; - /* Initialize the os_handle to the platform-specific value for closed. */ -#ifdef PIO_OS_WIN32 - data_struct->os_handle = (PIOHANDLE)INVALID_HANDLE_VALUE; -#endif -#ifdef PIO_OS_UNIX - data_struct->os_handle = (PIOHANDLE)-1; -#endif -#ifdef PIO_OS_STDIO - data_struct->os_handle = (PIOHANDLE)NULL; -#endif - PObj_custom_mark_destroy_SETALL(SELF); } @@ -68,11 +57,12 @@ Create a copy of the filehandle. */ VTABLE PMC *clone() { - Parrot_Socket_attributes * const old_struct = PARROT_SOCKET(SELF); - PMC * const copy = Parrot_io_new_socket_pmc(interp, old_struct->flags); + PMC * copy = SUPER(); + Parrot_Socket_attributes * const old_struct = PARROT_SOCKET(SELF); Parrot_Socket_attributes * const data_struct = PARROT_SOCKET(copy); - data_struct->os_handle = Parrot_dup(old_struct->os_handle); + data_struct->local = VTABLE_clone(interp, old_struct->local); + data_struct->remote = VTABLE_clone(interp, old_struct->remote); return SELF; } @@ -115,12 +105,28 @@ Free structures. } } - METHOD close() { - INTVAL status = 0; - close(PARROT_SOCKET(SELF)->os_handle); - RETURN(INTVAL status); - } +/* +=item C + +Returns whether the Socket was successfully created. + +=cut + +*/ + + VTABLE INTVAL get_bool() { + /* Initialize the os_handle to the platform-specific value for closed. */ +#ifdef PIO_OS_WIN32 + return (PARROT_SOCKET(SELF)->os_handle != (PIOHANDLE)INVALID_HANDLE_VALUE); +#endif +#ifdef PIO_OS_UNIX + return (PARROT_SOCKET(SELF)->os_handle != (PIOHANDLE)-1); +#endif +#ifdef PIO_OS_STDIO + return (PARROT_SOCKET(SELF)->os_handle != (PIOHANDLE)NULL); +#endif + } /* @@ -130,6 +136,36 @@ Free structures. =over 4 +=item C + +=cut + +*/ + + + METHOD socket(INTVAL type, INTVAL fam, INTVAL proto) { + PMC * res = Parrot_io_socket(interp, SELF, type, fam, proto); + RETURN(PMC * res); + } + +/* + +=item C + +C returns an object representing a socket address, generated +from a port number (integer) and an address (string). + +=cut + +*/ + + METHOD sockaddr(STRING * address, INTVAL port) { + PMC * res = Parrot_io_sockaddr_in(interp, address, port); + RETURN(PMC * res); + } + +/* + =item C Connects a socket object to an address. @@ -191,16 +227,68 @@ complete, it invokes the callback, passing it a status object. RETURN(INTVAL res); } +/* + +=item C + +C binds a socket object to the port and address specified by an +address object (the packed result of C). + +The asynchronous version takes an additional final PMC callback +argument, and only returns a status object. When the bind operation is +complete, it invokes the callback, passing it a status object and the +socket object it was called on. [If you want notification when a bind +operation is completed, you probably want to do something with that +bound socket object.] + +=cut + +*/ + METHOD bind(PMC *host) { INTVAL res = Parrot_io_bind(INTERP, SELF, host); RETURN(INTVAL res); } +/* + +=item C + +C specifies that a socket object is willing to accept incoming +connections. The integer argument gives the maximum size of the queue +for pending connections. + +There is no asynchronous version. C marks a set of attributes on +the socket object. + +=cut + +*/ + METHOD listen(INTVAL backlog) { INTVAL res = Parrot_io_listen(INTERP, SELF, backlog); RETURN(INTVAL res); } +/* + +=item C + +C accepts a new connection on a given socket object, and returns +a newly created socket object for the connection. + +The asynchronous version takes an additional final PMC callback +argument, and only returns a status object. When the accept operation +receives a new connection, it invokes the callback, passing it a status +object and a newly created socket object for the connection. [While the +synchronous C has to be called repeatedly in a loop (once for +each connection received), the asynchronous version is only called once, +but continues to send new connection events until the socket is closed.] + +=cut + +*/ + METHOD accept() { PMC * res = Parrot_io_accept(INTERP, SELF); RETURN(PMC * res);