From 0573c501f624783f1d1d005012ff60cc314dbed6 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 12:02:45 -0800 Subject: [PATCH 01/14] [TT#1798] Patch for IPv6 support by mstapelberg++ Starting a branch for this patch, because it needs more tests and documentation before being merged to master. Original commit message: connect() and bind() use an Addrinfo PMC (contains multiple socket addresses in the right order [RFC 3484]) instead of a Sockaddr PMC. It is no longer necessary to create the socket before calling bind() or connect() as both need to create sockets with the appropriate address family on their own. Also, the Sockaddr PMC internally uses a struct sockaddr_storage in combination with a length field instead of an struct sockaddr_in. This commit also implements the local_address and remote_address methods for the Socket PMC. The Sockaddr PMC can now be converted to string. --- MANIFEST | 1 + MANIFEST.generated | 2 + include/parrot/io_unix.h | 44 +++++- src/io/socket_unix.c | 292 ++++++++++++++++++++++++++++++++++----- src/pmc/addrinfo.pmc | 140 +++++++++++++++++++ src/pmc/sockaddr.pmc | 54 ++++++-- src/pmc/socket.pmc | 46 +++++- 7 files changed, 525 insertions(+), 54 deletions(-) create mode 100644 src/pmc/addrinfo.pmc diff --git a/MANIFEST b/MANIFEST index 3bc3085e26..dbe9ad0528 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1375,6 +1375,7 @@ src/pbc_disassemble.c [] src/pbc_dump.c [] src/pbc_merge.c [] src/pmc.c [] +src/pmc/addrinfo.pmc [] src/pmc/addrregistry.pmc [] src/pmc/arrayiterator.pmc [] src/pmc/bigint.pmc [] diff --git a/MANIFEST.generated b/MANIFEST.generated index f271d3ba8c..72970b419d 100644 --- a/MANIFEST.generated +++ b/MANIFEST.generated @@ -36,6 +36,7 @@ include/parrot/pbcversion.h [devel]include include/parrot/platform.h [main]include include/parrot/platform_limits.h [devel]include include/parrot/vtable.h [main]include +include/pmc/pmc_addrinfo.h [devel]include include/pmc/pmc_addrregistry.h [devel]include include/pmc/pmc_arrayiterator.h [devel]include include/pmc/pmc_bigint.h [devel]include @@ -334,6 +335,7 @@ src/jit_emit.h [] src/nci.c [] src/null_config.c [] src/parrot_config.c [] +src/pmc/addrinfo.dump [devel]src src/pmc/addrregistry.dump [devel]src src/pmc/arrayiterator.dump [devel]src src/pmc/bigint.dump [devel]src diff --git a/include/parrot/io_unix.h b/include/parrot/io_unix.h index a888f42e64..a6a302a5e9 100644 --- a/include/parrot/io_unix.h +++ b/include/parrot/io_unix.h @@ -180,26 +180,43 @@ PMC * Parrot_io_accept_unix(PARROT_INTERP, ARGMOD(PMC *socket)) FUNC_MODIFIES(*socket); INTVAL Parrot_io_bind_unix(PARROT_INTERP, - ARGMOD(PMC *socket), + ARGMOD(PMC *sock), ARGMOD(PMC *sockaddr)) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__nonnull__(3) - FUNC_MODIFIES(*socket) + FUNC_MODIFIES(*sock) FUNC_MODIFIES(*sockaddr); INTVAL Parrot_io_connect_unix(PARROT_INTERP, - ARGMOD(PMC *socket), + ARGMOD(PMC *sock), ARGIN(PMC *r)) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__nonnull__(3) - FUNC_MODIFIES(*socket); + FUNC_MODIFIES(*sock); + +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * Parrot_io_getaddrinfo(PARROT_INTERP, + ARGIN(STRING *addr), + INTVAL port, + INTVAL protocol, + INTVAL family, + INTVAL passive) + __attribute__nonnull__(1) + __attribute__nonnull__(2); INTVAL Parrot_io_listen_unix(SHIM_INTERP, ARGMOD(PMC *socket), INTVAL sec) __attribute__nonnull__(2) FUNC_MODIFIES(*socket); +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * Parrot_io_local_address(PARROT_INTERP, ARGIN(PMC *sock)) + __attribute__nonnull__(1) + __attribute__nonnull__(2); + INTVAL Parrot_io_poll_unix(SHIM_INTERP, ARGMOD(PMC *socket), int which, @@ -217,6 +234,12 @@ INTVAL Parrot_io_recv_unix(PARROT_INTERP, FUNC_MODIFIES(*socket) FUNC_MODIFIES(*s); +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * Parrot_io_remote_address(PARROT_INTERP, ARGIN(PMC *sock)) + __attribute__nonnull__(1) + __attribute__nonnull__(2); + INTVAL Parrot_io_send_unix(SHIM_INTERP, ARGMOD(PMC *socket), ARGMOD(STRING *s)) @@ -246,20 +269,29 @@ INTVAL Parrot_io_socket_unix(PARROT_INTERP, , PARROT_ASSERT_ARG(socket)) #define ASSERT_ARGS_Parrot_io_bind_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ - , PARROT_ASSERT_ARG(socket) \ + , PARROT_ASSERT_ARG(sock) \ , PARROT_ASSERT_ARG(sockaddr)) #define ASSERT_ARGS_Parrot_io_connect_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ - , PARROT_ASSERT_ARG(socket) \ + , PARROT_ASSERT_ARG(sock) \ , PARROT_ASSERT_ARG(r)) +#define ASSERT_ARGS_Parrot_io_getaddrinfo __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(addr)) #define ASSERT_ARGS_Parrot_io_listen_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(socket)) +#define ASSERT_ARGS_Parrot_io_local_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(sock)) #define ASSERT_ARGS_Parrot_io_poll_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(socket)) #define ASSERT_ARGS_Parrot_io_recv_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(socket) \ , PARROT_ASSERT_ARG(s)) +#define ASSERT_ARGS_Parrot_io_remote_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(sock)) #define ASSERT_ARGS_Parrot_io_send_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(socket) \ , PARROT_ASSERT_ARG(s)) diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c index 2569e9c6d3..276ad0d9e3 100644 --- a/src/io/socket_unix.c +++ b/src/io/socket_unix.c @@ -30,6 +30,7 @@ APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons) #include "parrot/parrot.h" #include "io_private.h" #include "pmc/pmc_socket.h" +#include "pmc/pmc_sockaddr.h" #ifdef PIO_OS_UNIX @@ -40,6 +41,17 @@ APitUE - W. Richard Stevens, AT&T SFIO, Perl 5 (Nick Ing-Simmons) /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void get_addrinfo(PARROT_INTERP, + ARGIN(PMC * addrinfo), + ARGIN(const char *host), + int port, + int protocol, + int family, + int passive) + __attribute__nonnull__(1) + __attribute__nonnull__(2) + __attribute__nonnull__(3); + static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), @@ -48,6 +60,10 @@ static void get_sockaddr_in(PARROT_INTERP, __attribute__nonnull__(2) __attribute__nonnull__(3); +#define ASSERT_ARGS_get_addrinfo __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp) \ + , PARROT_ASSERT_ARG(addrinfo) \ + , PARROT_ASSERT_ARG(host)) #define ASSERT_ARGS_get_sockaddr_in __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp) \ , PARROT_ASSERT_ARG(sockaddr) \ @@ -58,6 +74,8 @@ static void get_sockaddr_in(PARROT_INTERP, /* static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), ARGIN(int port)); +static void +get_addrinfo(PARROT_INTERP, ARGIN(PMC * addrinfo), ARGIN(const char *host), ARGIN(int port)); */ /* @@ -106,6 +124,111 @@ Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port) return sockaddr; } +/* + +=item C + +C calls get_addrinfo() to convert hostnames or IP +addresses to sockaddrs (and more) and returns an Addrinfo PMC which can be +passed to C or C. + +=cut + +*/ + +/* TODO: where to move this to? originally from src/io/socket_api.c */ +static int pio_pf[PIO_PF_MAX+1] = { +#ifdef PF_LOCAL + PF_LOCAL, /* PIO_PF_LOCAL */ +#else + -1, /* PIO_PF_LOCAL */ +#endif +#ifdef PF_UNIX + PF_UNIX, /* PIO_PF_UNIX */ +#else + -1, /* PIO_PF_UNIX */ +#endif +#ifdef PF_INET + PF_INET, /* PIO_PF_INET */ +#else + -1, /* PIO_PF_INET */ +#endif +#ifdef PF_INET6 + PF_INET6, /* PIO_PF_INET6 */ +#else + -1, /* PIO_PF_INET6 */ +#endif +}; + +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * +Parrot_io_getaddrinfo(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive) +{ + ASSERT_ARGS(Parrot_io_getaddrinfo) + + char * const s = Parrot_str_to_cstring(interp, addr); + PMC * const addrinfo = Parrot_pmc_new(interp, enum_class_Addrinfo); + + /* set family: 0 means any (AF_INET or AF_INET6) for getaddrinfo, so treat + * it specially */ + int fam = (family != 0 ? pio_pf[family] : 0); + + get_addrinfo(interp, addrinfo, s, port, protocol, fam, passive); + Parrot_str_free_cstring(s); + return addrinfo; +} + + +/* + +=item C + +C returns the remote address of the given sock +PMC. It can be used to find out to which address the connection was actually +established (in case of the remote server having multiple IPv4 and/or IPv6 +addresses. + +=cut + +*/ +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * +Parrot_io_remote_address(PARROT_INTERP, ARGIN(PMC *sock)) +{ + ASSERT_ARGS(Parrot_io_remote_address) + + PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->remote); + + return addrinfo; +} + +/* + +=item C + +C returns the local address of the given sock +PMC. It can be used to find out to which address the socket was actually +bound (when binding to "localhost" without explicitly specifying an address +family, for example). + +=cut + +*/ +PARROT_WARN_UNUSED_RESULT +PARROT_CANNOT_RETURN_NULL +PMC * +Parrot_io_local_address(PARROT_INTERP, ARGIN(PMC *sock)) +{ + ASSERT_ARGS(Parrot_io_local_address) + + PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->local); + + return addrinfo; +} + /* @@ -138,73 +261,135 @@ Parrot_io_socket_unix(PARROT_INTERP, ARGIN(PMC *s), int fam, int type, int proto /* -=item C +=item C -Connects C<*io>'s socket to address C<*r>. +Takes the Addrinfo PMC C<*r> and tries to establish a connection. A new socket +PMC will be created because the Addrinfo may contain addresses of multiple +families (IPv4 and IPv6). =cut */ INTVAL -Parrot_io_connect_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGIN(PMC *r)) +Parrot_io_connect_unix(PARROT_INTERP, ARGMOD(PMC *sock), ARGIN(PMC *r)) { ASSERT_ARGS(Parrot_io_connect_unix) - const Parrot_Socket_attributes * const io = PARROT_SOCKET(socket); + const Parrot_Socket_attributes * const io = PARROT_SOCKET(sock); + struct addrinfo *res = VTABLE_get_pointer(interp, r); + struct addrinfo *walk; + int fd = -1; + int i = 1; if (!r) return -1; - PARROT_SOCKET(socket)->remote = r; + + for (walk = res; walk != NULL; walk = walk->ai_next) { + fd = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); + if (fd < 0) { + /* Cannot create socket. Not necessarily an error, for example not + * on FreeBSD, where getaddrinfo() returns IPv6 addresses even + * when the libc does not offer IPv6 support and thus fails in + * socket(). */ + continue; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { + perror("Error setting SO_REUSEADDR:"); + continue; + } + + /* XXX: this effectively overwrites any previously set sockets. is that alright? */ + Parrot_io_set_os_handle(interp, sock, fd); AGAIN: - if ((connect(io->os_handle, (struct sockaddr *)SOCKADDR_REMOTE(socket), - sizeof (struct sockaddr_in))) != 0) { - switch (errno) { - case EINTR: - goto AGAIN; - case EINPROGRESS: - goto AGAIN; - case EISCONN: - return 0; - default: - return -1; + if (connect(fd, walk->ai_addr, walk->ai_addrlen) != 0) { + switch (errno) { + case EINTR: + goto AGAIN; + case EINPROGRESS: + goto AGAIN; + case EISCONN: + break; + default: + close(fd); + fd = -1; + continue; + } } + + PARROT_SOCKET(sock)->remote = Parrot_pmc_new(interp, enum_class_Sockaddr); + + VTABLE_set_pointer(interp, PARROT_SOCKET(sock)->remote, walk); + return 0; } - return 0; + if (fd == -1) + return -1; } /* -=item C +=item C -Binds C<*io>'s socket to the local address and port specified by C<*l>. +Takes the Addrinfo PMC C<*sockaddr> and creates a listening socket. A new +socket needs to be created because C<*sockaddr> may contain addresses of +multiple families (IPv4 and IPv6). An example is binding to "localhost" +which resolves to ::1 and 127.0.0.1. If you are on FreeBSD and have no +IPv6 support, the first attempt to create a socket and bind it would fail. =cut */ INTVAL -Parrot_io_bind_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGMOD(PMC *sockaddr)) +Parrot_io_bind_unix(PARROT_INTERP, ARGMOD(PMC *sock), ARGMOD(PMC *sockaddr)) { ASSERT_ARGS(Parrot_io_bind_unix) - const Parrot_Socket_attributes * const io = PARROT_SOCKET(socket); - struct sockaddr_in * saddr; + const Parrot_Socket_attributes * const io = PARROT_SOCKET(sock); + struct addrinfo *res = VTABLE_get_pointer(interp, sockaddr); + struct addrinfo *walk; + int fd = -1; + int i = 1; if (!sockaddr) return -1; - PARROT_SOCKET(socket)->local = sockaddr; + for (walk = res; walk != NULL; walk = walk->ai_next) { + fd = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); + if (fd < 0) { + /* Cannot create socket. Not necessarily an error, for example not + * on FreeBSD, where getaddrinfo() returns IPv6 addresses even + * when the libc does not offer IPv6 support and thus fails in + * socket(). */ + continue; + } - saddr = SOCKADDR_LOCAL(socket); + if (walk->ai_family == AF_INET6) { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) == -1) { + perror("Error setting IPV6_V6ONLY:"); + continue; + } + } - if ((bind(io->os_handle, (struct sockaddr *) saddr, - sizeof (struct sockaddr_in))) == -1) { - return -1; + /* XXX: this effectively overwrites any previously set sockets. is that alright? */ + Parrot_io_set_os_handle(interp, sock, fd); + + if (bind(fd, walk->ai_addr, walk->ai_addrlen) != 0) { + close(fd); + fd = -1; + continue; + } + + PARROT_SOCKET(sock)->local = Parrot_pmc_new(interp, enum_class_Sockaddr); + + VTABLE_set_pointer(interp, PARROT_SOCKET(sock)->local, walk); + return 0; } - return 0; + if (fd == -1) + return -1; } /* @@ -248,8 +433,9 @@ Parrot_io_accept_unix(PARROT_INTERP, ARGMOD(PMC *socket)) Parrot_Socket_attributes * io = PARROT_SOCKET(socket); PMC * newio = Parrot_io_new_socket_pmc(interp, PIO_F_SOCKET | PIO_F_READ|PIO_F_WRITE); - Parrot_Socklen_t addrlen = sizeof (struct sockaddr_in); - struct sockaddr_in *saddr; + Parrot_Socklen_t addrlen = sizeof (struct sockaddr_storage); + Parrot_Sockaddr_attributes *remotedata; + struct sockaddr_storage *saddr; int newsock; PARROT_SOCKET(newio)->local = PARROT_SOCKET(socket)->local; @@ -262,13 +448,22 @@ Parrot_io_accept_unix(PARROT_INTERP, ARGMOD(PMC *socket)) return PMCNULL; } - PARROT_SOCKET(newio)->os_handle = newsock; + /* Set the length for the remote sockaddr PMC so that it can distinguish + * between sockaddr_in and sockaddr_in6 */ + remotedata = PARROT_SOCKADDR(PARROT_SOCKET(newio)->remote); + remotedata->len = addrlen; - /* XXX FIXME: Need to do a getsockname and getpeername here to - * fill in the sockaddr_in structs for local and peer */ + PARROT_SOCKET(newio)->os_handle = newsock; - /* Optionally do a gethostyaddr() to resolve remote IP address. - * This should be based on an option set in the master socket */ + /* Optionally do a getaddrinfo() to resolve remote IP address. + * This should be based on an option set in the master socket. + * + * XXX: instead of resolving here, we should use the flags for + * getnameinfo() in the VTABLE get_string of the Sockaddr PMC. + * At the moment, it uses NI_NUMERICHOST, but when called + * differently, it will resolve the address. The advantage is + * that we only resolve when someone actually accesses the + * name. -- Michael Stapelberg */ return newio; } @@ -479,6 +674,33 @@ get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), sa->sin_port = htons(port); } +static void +get_addrinfo(PARROT_INTERP, ARGIN(PMC * addrinfo), ARGIN(const char *host), int port, int protocol, int family, int passive) +{ + ASSERT_ARGS(get_addrinfo) + + struct addrinfo hints; + struct addrinfo *res; + /* We need to pass the port as a string (because you could also use a + * service specification from /etc/services). The highest port is 65535, + * so we need 5 characters + trailing null-byte. */ + char portstr[6]; + int ret; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_protocol = protocol; + if (passive) + hints.ai_flags = AI_PASSIVE; + hints.ai_family = family; + snprintf(portstr, sizeof(portstr), "%u", port); + + if ((ret = getaddrinfo(host, portstr, &hints, &res)) != 0) { + fprintf(stderr, "getaddrinfo failure: %s\n", gai_strerror(ret)); + return; + } + + VTABLE_set_pointer(interp, addrinfo, res); +} #endif /* PIO_OS_UNIX */ diff --git a/src/pmc/addrinfo.pmc b/src/pmc/addrinfo.pmc new file mode 100644 index 0000000000..4618fc04bb --- /dev/null +++ b/src/pmc/addrinfo.pmc @@ -0,0 +1,140 @@ +/* +Copyright (C) 2008-2009, Parrot Foundation. +$Id$ + +=head1 NAME + +src/pmc/addrinfo.pmc - addrinfo holder + +=head1 DESCRIPTION + +The Addrinfo PMC holds a C pointer to a C. + + +=head2 Vtable Functions + +These are the vtable functions for the Addrinfo class. + +=over 4 + +=cut + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + struct addrinfo; +#ifdef __cplusplus +} +#endif + +/* HEADERIZER HFILE: none */ +/* HEADERIZER BEGIN: static */ +/* HEADERIZER END: static */ + +pmclass Addrinfo auto_attrs { + ATTR void *pointer; /* The stored pointer. */ + +/* + +=item C + +Initializes the pointer object. + +=cut + +*/ + + VTABLE void init() { + Parrot_Addrinfo_attributes * const pdata_struct = + (Parrot_Addrinfo_attributes *) PMC_data(SELF); + + pdata_struct->pointer = NULL; + PObj_custom_destroy_SET(SELF); + } + +/* + +=item C + +Destroys the PMC and frees all allocated memory. + +=cut + +*/ + + VTABLE void destroy() { + Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); + + if (data) { + if (data->pointer) + freeaddrinfo(data->pointer); + data->pointer = NULL; + } + } + +/* + +=item C + +Creates and returns a clone of the pointer. + +=cut + +*/ + + VTABLE PMC *clone() { + PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type); + memcpy(PARROT_ADDRINFO(dest)->pointer, PARROT_ADDRINFO(SELF)->pointer, + sizeof (struct sockaddr_storage)); + return dest; + } + +/* + +=item C + +Returns the pointer. + +=cut + +*/ + + VTABLE void *get_pointer() { + Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); + return data->pointer; + } + +/* + +=item C + +Sets the pointer. + +=cut + +*/ + + VTABLE void set_pointer(void *value) { + Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); + data->pointer = value; + } + +} + +/* + +=back + +=cut + +*/ + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ + diff --git a/src/pmc/sockaddr.pmc b/src/pmc/sockaddr.pmc index eba17d6b34..8b9a41efd9 100644 --- a/src/pmc/sockaddr.pmc +++ b/src/pmc/sockaddr.pmc @@ -3,11 +3,12 @@ Copyright (C) 2008-2009, Parrot Foundation. =head1 NAME -src/pmc/sockaddr.pmc - sockaddr_in holder +src/pmc/sockaddr.pmc - sockaddr_in/sockaddr_in6 holder =head1 DESCRIPTION -The Sockaddr PMC holds raw c-pointer to sockaddr_in +The Sockaddr PMC holds a C (IPv4) or C (IPv6) and +saves its length (to distinguish C and C). =head2 Vtable Functions @@ -23,7 +24,7 @@ These are the vtable functions for the Sockaddr class. #ifdef __cplusplus extern "C" { #endif - struct sockaddr_in; + struct sockaddr_storage; #ifdef __cplusplus } #endif @@ -34,12 +35,13 @@ extern "C" { pmclass Sockaddr auto_attrs { ATTR void *pointer; /* The stored pointer. */ + ATTR INTVAL len; /* Length of the contents of the sockaddr_storage */ /* =item C -Initializes the pointer object. +Initializes the PMC by allocating a C. =cut @@ -50,7 +52,7 @@ Initializes the pointer object. (Parrot_Sockaddr_attributes *) PMC_data(SELF); pdata_struct->pointer = mem_gc_allocate_zeroed_typed(INTERP, - struct sockaddr_in); + struct sockaddr_storage); PObj_custom_destroy_SET(SELF); } @@ -77,7 +79,8 @@ Destroys the PMC and frees all allocated memory. =item C -Creates and returns a clone of the pointer. +Creates a new Sockaddr PMC with the same contents and length as the current +one. =cut @@ -85,8 +88,10 @@ Creates and returns a clone of the pointer. VTABLE PMC *clone() { PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type); + memcpy(PARROT_SOCKADDR(dest)->pointer, PARROT_SOCKADDR(SELF)->pointer, - sizeof (struct sockaddr_in)); + sizeof (struct sockaddr_storage)); + PARROT_SOCKADDR(dest)->len = PARROT_SOCKADDR(SELF)->len; return dest; } @@ -94,7 +99,7 @@ Creates and returns a clone of the pointer. =item C -Returns the pointer. +Returns a pointer to the C or C. =cut @@ -107,20 +112,45 @@ Returns the pointer. /* -=item C +=item C -Sets the pointer. +Returns the string representation of this sockaddr by calling C. =cut */ + VTABLE STRING *get_string() { + Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); + if (!data->pointer) + return Parrot_sprintf_c(interp, "(?)"); + + struct sockaddr_storage *addr = data->pointer; + /* TODO: get hostname, not only numeric */ + char buf[INET6_ADDRSTRLEN+1]; + getnameinfo((struct sockaddr_storage*)data->pointer, data->len, buf, + sizeof(buf), NULL, 0, NI_NUMERICHOST); + return Parrot_str_new(interp, buf, 0); + } + /* + +=item C + +Copies a C or C from the given C pointer +(by accessing its C and C members). + +=cut + +*/ + VTABLE void set_pointer(void *value) { Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); - return data->pointer; + + struct addrinfo *walk = value; + memcpy(data->pointer, walk->ai_addr, walk->ai_addrlen); + data->len = walk->ai_addrlen; } -*/ } diff --git a/src/pmc/socket.pmc b/src/pmc/socket.pmc index 62ef3bea10..06da8ec4f9 100644 --- a/src/pmc/socket.pmc +++ b/src/pmc/socket.pmc @@ -176,6 +176,50 @@ from a port number (integer) and an address (string). /* +=item C + +C returns an object representing the result of the +C function which consists of multiple socket addresses, +including family and protocol. It can be passed to C or C. + +=cut + +*/ + METHOD getaddrinfo(STRING * address, INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive) { + PMC * res = Parrot_io_getaddrinfo(INTERP, address, port, protocol, family, passive); + RETURN(PMC * res); + } + +/* + +=item C + +C returns the remote address of this socket PMC. + +=cut + +*/ + METHOD remote_address() { + PMC * res = Parrot_io_remote_address(INTERP, SELF); + RETURN(PMC * res); + } + +/* + +=item C + +C returns the local address of this socket PMC. + +=cut + +*/ + METHOD local_address() { + PMC * res = Parrot_io_local_address(INTERP, SELF); + RETURN(PMC * res); + } + +/* + =item C Connects a socket object to an address. @@ -264,7 +308,7 @@ complete, it invokes the callback, passing it a status object. =item C C binds a socket object to the port and address specified by an -address object (the packed result of C). +address object (the result of C). The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the bind operation is From 6786d2d9c80d30a5657fdc5ddf72e1eb04e4d6f9 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 12:23:11 -0800 Subject: [PATCH 02/14] Make the Sockaddr PMC code valid C89 --- src/pmc/sockaddr.pmc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pmc/sockaddr.pmc b/src/pmc/sockaddr.pmc index 8b9a41efd9..8c3d0a35f2 100644 --- a/src/pmc/sockaddr.pmc +++ b/src/pmc/sockaddr.pmc @@ -121,12 +121,13 @@ Returns the string representation of this sockaddr by calling C. */ VTABLE STRING *get_string() { Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); + struct sockaddr_storage *addr = data->pointer; + /* TODO: get hostname, not only numeric */ + char buf[INET6_ADDRSTRLEN+1]; + if (!data->pointer) return Parrot_sprintf_c(interp, "(?)"); - struct sockaddr_storage *addr = data->pointer; - /* TODO: get hostname, not only numeric */ - char buf[INET6_ADDRSTRLEN+1]; getnameinfo((struct sockaddr_storage*)data->pointer, data->len, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); return Parrot_str_new(interp, buf, 0); From 2bca96e95c9d87a6eb06b3a74fe10c42e64a4c76 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 12:40:13 -0800 Subject: [PATCH 03/14] Make ipv6 detection actually work, at least on Linux --- config/auto/ipv6/test.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/auto/ipv6/test.in b/config/auto/ipv6/test.in index bcb3ce5225..73e614fb19 100644 --- a/config/auto/ipv6/test.in +++ b/config/auto/ipv6/test.in @@ -1,5 +1,5 @@ /* -Copyright (C) 2005-2009, Parrot Foundation. +Copyright (C) 2010, Parrot Foundation. */ @@ -7,9 +7,12 @@ Copyright (C) 2005-2009, Parrot Foundation. #include #include #include +#include int main(int c,char**v) { int x = socket( PF_INET6, SOCK_DGRAM, 0 ); + int errno; + if ( x < 0 ) { perror("Not OK - socket failed"); return EXIT_FAILURE; From f83d88469983f036d3da4fd2f6948e8f3a811406 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 12:54:39 -0800 Subject: [PATCH 04/14] Add a get_bool vtable for the Sockaddr PMC --- src/pmc/sockaddr.pmc | 18 ++++++++++++++++++ t/pmc/sockaddr.t | 6 ------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/pmc/sockaddr.pmc b/src/pmc/sockaddr.pmc index 8c3d0a35f2..bcfd4e267a 100644 --- a/src/pmc/sockaddr.pmc +++ b/src/pmc/sockaddr.pmc @@ -97,6 +97,24 @@ one. /* +=item C + +Returns true if the Sockaddr is defined. + +=cut + +*/ + + VTABLE INTVAL get_bool() { + Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); + + return data->pointer ? 1 : 0 ; + } + +/* + +/* + =item C Returns a pointer to the C or C. diff --git a/t/pmc/sockaddr.t b/t/pmc/sockaddr.t index 49ef56bd0c..a9bd64a6b3 100644 --- a/t/pmc/sockaddr.t +++ b/t/pmc/sockaddr.t @@ -46,13 +46,7 @@ Test the Sockaddr PMC. .sub test_bool $P0 = new 'Socket' $P1 = $P0."sockaddr"("localhost", 1234) - push_eh handler ok($P1, 'get_bool on a SockAddr') - goto done -handler: - pop_eh - todo(0,'get_bool on SockAddr does not work TT#1822') -done: .end # Local Variables: From 0f68c45926a587ab32d70847ae00d2a0ea570883 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 15:00:39 -0800 Subject: [PATCH 05/14] Add failing test for Sockaddr PMC stringification --- t/pmc/sockaddr.t | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/t/pmc/sockaddr.t b/t/pmc/sockaddr.t index a9bd64a6b3..cea62b6493 100644 --- a/t/pmc/sockaddr.t +++ b/t/pmc/sockaddr.t @@ -22,6 +22,7 @@ Test the Sockaddr PMC. test_basic() test_bool() + test_string() .end .sub test_basic @@ -49,6 +50,12 @@ Test the Sockaddr PMC. ok($P1, 'get_bool on a SockAddr') .end +.sub test_string + $P0 = new 'Socket' + $P1 = $P0."sockaddr"("localhost", 1234) + is($P1,"localhost:1234","sockaddr stringification") +.end + # Local Variables: # mode: pir # fill-column: 100 From 97058966ff6cae8c129acee804e921479939b086 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 15:21:02 -0800 Subject: [PATCH 06/14] Add some useful information to the POD of the Socket PMC tests --- t/pmc/socket.t | 3 +++ 1 file changed, 3 insertions(+) diff --git a/t/pmc/socket.t b/t/pmc/socket.t index f8756e3128..a670a06c38 100644 --- a/t/pmc/socket.t +++ b/t/pmc/socket.t @@ -13,6 +13,9 @@ t/pmc/socket.t - test the Socket PMC Tests the Socket PMC. +The IPv6-related tests in this file do not actually require an IPv6 networking +stack, so we don't need to check if this parrot is IPv6-aware. + =cut .include 'socket.pasm' From c10647eaf2e84482832e5f36616972721940920d Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Nov 2010 15:44:52 -0800 Subject: [PATCH 07/14] Create a new test file for tests that require IPv6 --- MANIFEST | 1 + t/pmc/sockaddr.t | 2 +- t/pmc/socket_ipv6.t | 95 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 t/pmc/socket_ipv6.t diff --git a/MANIFEST b/MANIFEST index dbe9ad0528..e0b79b3148 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1962,6 +1962,7 @@ t/pmc/schedulermessage.t [test] t/pmc/signal.t [test] t/pmc/sockaddr.t [test] t/pmc/socket.t [test] +t/pmc/socket_ipv6.t [test] t/pmc/string.t [test] t/pmc/stringbuilder.t [test] t/pmc/stringhandle.t [test] diff --git a/t/pmc/sockaddr.t b/t/pmc/sockaddr.t index cea62b6493..b7a8be3965 100644 --- a/t/pmc/sockaddr.t +++ b/t/pmc/sockaddr.t @@ -18,7 +18,7 @@ Test the Sockaddr PMC. .sub main :main .include 'test_more.pir' - plan(6) + plan(7) test_basic() test_bool() diff --git a/t/pmc/socket_ipv6.t b/t/pmc/socket_ipv6.t new file mode 100644 index 0000000000..5e2bff13bc --- /dev/null +++ b/t/pmc/socket_ipv6.t @@ -0,0 +1,95 @@ +#!./parrot +# Copyright (C) 2010, Parrot Foundation. + +=head1 NAME + +t/pmc/socket_ipv6.t - tests for the Socket PMC that require IPv6 + +=head1 SYNOPSIS + + % prove t/pmc/socket_ipv6.t + +=head1 DESCRIPTION + +IPv6-related tests for the Socket PMC. + +=cut + +.include 'socket.pasm' +.include 'iglobals.pasm' +.include 'errors.pasm' + + + +.sub main :main + .include 'test_more.pir' + + plan(4) + + check_for_ipv6() + + test_tcp_socket6() + test_raw_tcp_socket6() + test_udp_socket6() + test_raw_udp_socket6() +.end + +.sub check_for_ipv6 + $P0 = getinterp + $P1 = $P0[.IGLOBALS_CONFIG_HASH] + + $P2 = $P1['HAS_IPV6'] + $I1 = isnull $P2 + if $I1, no_ipv6 + say '# This Parrot is IPv6-aware' + goto done + + no_ipv6: + diag( 'No IPv6' ) + skip(4) + exit 0 + done: +.end + +.sub test_tcp_socket6 + .local pmc sock, sockaddr + sock = new 'Socket' + + sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP) + sockaddr = sock."sockaddr"("::1",80) + ok(sockaddr,"A TCP ipv6 sockaddr was set") +.end + +.sub test_raw_tcp_socket6 + .local pmc sock, sockaddr + sock = new 'Socket' + + sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_TCP) + sockaddr = sock."sockaddr"("::1",80) + ok(sockaddr,"A raw TCP ipv6 sockaddr was set") +.end + +.sub test_udp_socket6 + .local pmc sock, sockaddr + sock = new 'Socket' + + sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_UDP) + sockaddr = sock."sockaddr"("::1",80) + ok(sockaddr,"A UDP ipv6 sockaddr was set") +.end + +.sub test_raw_udp_socket6 + .local pmc sock, sockaddr + sock = new 'Socket' + + sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_UDP) + sockaddr = sock."sockaddr"("::1",80) + ok(sockaddr,"A raw UDP ipv6 sockaddr was set") +.end + + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: From ccffd274d188d9522521662ba62c922fc21e7eb0 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 09:38:46 -0800 Subject: [PATCH 08/14] [t] Add a basic test for the Addrinfo PMC --- MANIFEST | 1 + t/pmc/addrinfo.t | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 t/pmc/addrinfo.t diff --git a/MANIFEST b/MANIFEST index e0b79b3148..6deda7f0bc 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1869,6 +1869,7 @@ t/pharness/04-Usage.t [test] t/pir/macro.t [test] t/pir/registernames.t [test] t/pir/timer_exit.t [test] +t/pmc/addrinfo.t [test] t/pmc/addrregistry.t [test] t/pmc/arrayiterator.t [test] t/pmc/bigint.t [test] diff --git a/t/pmc/addrinfo.t b/t/pmc/addrinfo.t new file mode 100644 index 0000000000..6ac2790619 --- /dev/null +++ b/t/pmc/addrinfo.t @@ -0,0 +1,31 @@ +#!./parrot +# Copyright (C) 2010, Parrot Foundation. + +=head1 NAME + +t/pmc/addrinfo.t - test Addrinfo PMC + +=head1 SYNOPSIS + + % prove t/pmc/addrinfo.t + +=head1 DESCRIPTION + +Tests the Addrinfo PMC. + +=cut + +.sub main :main + .include 'test_more.pir' + + plan(1) + + $P0 = new ['Addrinfo'] + isa_ok($P0, 'Addrinfo') +.end + +# Local Variables: +# mode: pir +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4 ft=pir: From 42f16ac87a1425f26ebceedc7cbf7d0c0c463068 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 10:55:14 -0800 Subject: [PATCH 09/14] [t] Add a test for cloning an Addrinfo, which currently coredumps --- t/pmc/addrinfo.t | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/t/pmc/addrinfo.t b/t/pmc/addrinfo.t index 6ac2790619..4d84c96e5e 100644 --- a/t/pmc/addrinfo.t +++ b/t/pmc/addrinfo.t @@ -18,12 +18,23 @@ Tests the Addrinfo PMC. .sub main :main .include 'test_more.pir' - plan(1) + plan(2) + test_new() + test_clone() +.end +.sub test_new $P0 = new ['Addrinfo'] isa_ok($P0, 'Addrinfo') .end +.sub test_clone + $P0 = new ['Addrinfo'] + $P2 = clone $P0 + isa_ok($P2, 'Addrinfo') +.end + + # Local Variables: # mode: pir # fill-column: 100 From 41079088d1cb7c707b7d7b1e47373b715b6020ec Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 11:02:38 -0800 Subject: [PATCH 10/14] Fix coredump when cloning an Addrinfo PMC that hasn't had pointer set --- src/pmc/addrinfo.pmc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pmc/addrinfo.pmc b/src/pmc/addrinfo.pmc index 4618fc04bb..541f0069b0 100644 --- a/src/pmc/addrinfo.pmc +++ b/src/pmc/addrinfo.pmc @@ -86,8 +86,10 @@ Creates and returns a clone of the pointer. VTABLE PMC *clone() { PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type); - memcpy(PARROT_ADDRINFO(dest)->pointer, PARROT_ADDRINFO(SELF)->pointer, - sizeof (struct sockaddr_storage)); + if (PARROT_ADDRINFO(SELF)->pointer) + memcpy(PARROT_ADDRINFO(dest)->pointer, + PARROT_ADDRINFO(SELF)->pointer, + sizeof (struct sockaddr_storage)); return dest; } From 2f63e9f6587440d5e8946ec16a84aaa5736de5be Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 12:34:20 -0800 Subject: [PATCH 11/14] Allow creation of IPv6 sockaddr structs, whilst defaulting to IPv4 --- include/parrot/io_unix.h | 5 ++++- src/io/socket_unix.c | 18 +++++++++--------- src/pmc/socket.pmc | 13 +++++++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/include/parrot/io_unix.h b/include/parrot/io_unix.h index a6a302a5e9..2d525faaee 100644 --- a/include/parrot/io_unix.h +++ b/include/parrot/io_unix.h @@ -250,7 +250,10 @@ INTVAL Parrot_io_send_unix(SHIM_INTERP, PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL -PMC * Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port) +PMC * Parrot_io_sockaddr_in(PARROT_INTERP, + ARGIN(STRING *addr), + INTVAL port, + INTVAL family) __attribute__nonnull__(1) __attribute__nonnull__(2); diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c index 276ad0d9e3..5e1468a7fe 100644 --- a/src/io/socket_unix.c +++ b/src/io/socket_unix.c @@ -55,7 +55,8 @@ static void get_addrinfo(PARROT_INTERP, static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), - int port) + int port, + const int family) __attribute__nonnull__(1) __attribute__nonnull__(2) __attribute__nonnull__(3); @@ -91,7 +92,8 @@ Very minimal stubs for now, maybe someone will run with these. =over 4 -=item C +=item C C is not part of the layer and so must be C. @@ -112,14 +114,14 @@ C, etc.) and take this out of platform specific compilation PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL PMC * -Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port) +Parrot_io_sockaddr_in(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port, INTVAL family) { ASSERT_ARGS(Parrot_io_sockaddr_in) char * const s = Parrot_str_to_cstring(interp, addr); PMC * const sockaddr = Parrot_pmc_new(interp, enum_class_Sockaddr); - get_sockaddr_in(interp, sockaddr, s, port); + get_sockaddr_in(interp, sockaddr, s, port, family); Parrot_str_free_cstring(s); return sockaddr; } @@ -630,10 +632,10 @@ Parrot_io_poll_unix(SHIM_INTERP, ARGMOD(PMC *socket), int which, int sec, /* =item C +host, int port, const int family)> Get a new C structure for the given PMC to connect to the -specified host and port. +specified host, port and address family. =cut @@ -641,11 +643,9 @@ specified host and port. static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), - int port) + int port, const int family) { ASSERT_ARGS(get_sockaddr_in) - /* Hard coded to IPv4 for now */ - const int family = AF_INET; struct sockaddr_in * const sa = (struct sockaddr_in*)VTABLE_get_pointer(interp, sockaddr); # ifdef PARROT_DEF_INET_ATON diff --git a/src/pmc/socket.pmc b/src/pmc/socket.pmc index 06da8ec4f9..ae502af961 100644 --- a/src/pmc/socket.pmc +++ b/src/pmc/socket.pmc @@ -160,17 +160,22 @@ for readable, two for writeable, and four for exceptions. /* -=item C +=item C C returns an object representing a socket address, generated -from a port number (integer) and an address (string). +from a port number (integer) , address (string) and an optional address +family (integer). If no address family is given, it defaults to IPv4. =cut */ - METHOD sockaddr(STRING * address, INTVAL port) { - PMC * res = Parrot_io_sockaddr_in(INTERP, address, port); + METHOD sockaddr(STRING * address, INTVAL port, INTVAL family :optional) { + PMC * res; + if (!family) + family = AF_INET; + + res = Parrot_io_sockaddr_in(INTERP, address, port, family); RETURN(PMC * res); } From a34a716ed42c5d0e5b2b9bb12338056e120697a6 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 13:17:34 -0800 Subject: [PATCH 12/14] Specify the protocol family when created sockaddr's for the IPv6 tests --- t/pmc/socket_ipv6.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/pmc/socket_ipv6.t b/t/pmc/socket_ipv6.t index 5e2bff13bc..e0c0bf1369 100644 --- a/t/pmc/socket_ipv6.t +++ b/t/pmc/socket_ipv6.t @@ -56,7 +56,7 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP) - sockaddr = sock."sockaddr"("::1",80) + sockaddr = sock."sockaddr"("::1",80, .PIO_PF_INET6) ok(sockaddr,"A TCP ipv6 sockaddr was set") .end @@ -65,7 +65,7 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_TCP) - sockaddr = sock."sockaddr"("::1",80) + sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) ok(sockaddr,"A raw TCP ipv6 sockaddr was set") .end @@ -74,7 +74,7 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_UDP) - sockaddr = sock."sockaddr"("::1",80) + sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) ok(sockaddr,"A UDP ipv6 sockaddr was set") .end @@ -83,7 +83,7 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_UDP) - sockaddr = sock."sockaddr"("::1",80) + sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) ok(sockaddr,"A raw UDP ipv6 sockaddr was set") .end From e2622951dbc94ca5f013914d17822d47d734e3d3 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Fri, 26 Nov 2010 13:26:44 -0800 Subject: [PATCH 13/14] Add more IPv6 Socket tests --- src/io/socket_unix.c | 4 ++++ t/pmc/socket_ipv6.t | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c index 5e1468a7fe..431b896d9f 100644 --- a/src/io/socket_unix.c +++ b/src/io/socket_unix.c @@ -648,6 +648,10 @@ get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), ARGIN(const char* host), ASSERT_ARGS(get_sockaddr_in) struct sockaddr_in * const sa = (struct sockaddr_in*)VTABLE_get_pointer(interp, sockaddr); + + /* FIXME ::1, which is localhost in IPv6, does not seem to be + handled properly by the following code + */ # ifdef PARROT_DEF_INET_ATON if (inet_aton(host, &sa->sin_addr) != 0) { # else diff --git a/t/pmc/socket_ipv6.t b/t/pmc/socket_ipv6.t index e0c0bf1369..ca2a15fa39 100644 --- a/t/pmc/socket_ipv6.t +++ b/t/pmc/socket_ipv6.t @@ -24,7 +24,7 @@ IPv6-related tests for the Socket PMC. .sub main :main .include 'test_more.pir' - plan(4) + plan(8) check_for_ipv6() @@ -56,8 +56,11 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP) + sockaddr = sock."sockaddr"("localhost",80, .PIO_PF_INET6) + isa_ok(sockaddr,'Sockaddr',"A TCP ipv6 sockaddr to localhost was set") + sockaddr = sock."sockaddr"("::1",80, .PIO_PF_INET6) - ok(sockaddr,"A TCP ipv6 sockaddr was set") + isa_ok(sockaddr,'Sockaddr',"A TCP ipv6 sockaddr to ::1 was set") .end .sub test_raw_tcp_socket6 @@ -65,8 +68,10 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_TCP) + sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6) + isa_ok(sockaddr,'Sockaddr',"A raw TCP ipv6 sockaddr to localhost was set:") sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) - ok(sockaddr,"A raw TCP ipv6 sockaddr was set") + isa_ok(sockaddr,'Sockaddr',"A raw TCP ipv6 sockaddr to ::1 was set:") .end .sub test_udp_socket6 @@ -74,8 +79,11 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_UDP) + sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6) + isa_ok(sockaddr,'Sockaddr', "A UDP ipv6 sockaddr to localhost was set:") + sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) - ok(sockaddr,"A UDP ipv6 sockaddr was set") + isa_ok(sockaddr,'Sockaddr', "A UDP ipv6 sockaddr to ::1 was set:") .end .sub test_raw_udp_socket6 @@ -83,8 +91,10 @@ IPv6-related tests for the Socket PMC. sock = new 'Socket' sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_UDP) + sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6) + isa_ok(sockaddr,'Sockaddr', "A raw UDP ipv6 sockaddr to localhost was set: ") sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6) - ok(sockaddr,"A raw UDP ipv6 sockaddr was set") + isa_ok(sockaddr,'Sockaddr', "A raw UDP ipv6 sockaddr to ::1 was set: ") .end From 5365f8c384dba2f358cebf0ff5db94965b6085d4 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 25 Jan 2011 03:09:51 -0800 Subject: [PATCH 14/14] Remove debug statement --- src/io/socket_api.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/io/socket_api.c b/src/io/socket_api.c index d4645aeece..131cbe61be 100644 --- a/src/io/socket_api.c +++ b/src/io/socket_api.c @@ -301,7 +301,6 @@ Parrot_io_connect_handle(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address)) /* Connect to an IPv6 addrinfo if an UnManagedStruct was provided as address */ if (!PMC_IS_NULL(address) && address->vtable->base_type == enum_class_UnManagedStruct) { - fprintf(stderr, "Connecting to IPv6 addr\n"); res = VTABLE_get_pointer(interp, address); for (walk = res; walk != NULL; walk = walk->ai_next) {