Browse files

Merge branch 'nwellnhof/ipv6'

  • Loading branch information...
2 parents b0e86cd + 3caaa85 commit 958c51a3700b64645884f2bfa227477dc5545d98 @nwellnhof nwellnhof committed Jan 26, 2011
View
9 config/gen/makefiles/root.in
@@ -962,8 +962,13 @@ src/scheduler$(O) : \
src/io/core$(O) : $(PARROT_H_HEADERS) src/io/io_private.h src/io/core.c
-src/io/socket_api$(O) : $(PARROT_H_HEADERS) src/io/io_private.h \
- src/io/api.str include/pmc/pmc_socket.h src/io/socket_api.c
+src/io/socket_api$(O) : \
+ $(PARROT_H_HEADERS) \
+ src/io/io_private.h \
+ src/io/api.str \
+ include/pmc/pmc_socket.h \
+ include/pmc/pmc_sockaddr.h \
+ src/io/socket_api.c
O_FILES = \
$(INTERP_O_FILES) \
View
11 include/parrot/platform_interface.h
@@ -79,20 +79,17 @@ INTVAL Parrot_io_pipe(PARROT_INTERP, ARGMOD(PIOHANDLE *reader), ARGMOD(PIOHANDLE
* Socket
*/
-PMC *
-Parrot_io_getaddrinfo(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive);
-void Parrot_io_sockaddr_in(PARROT_INTERP, ARGOUT(void *addr), ARGIN(STRING *host), int port, int family);
+PMC *Parrot_io_getaddrinfo(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive);
+STRING *Parrot_io_getnameinfo(PARROT_INTERP, ARGIN(const void *addr), INTVAL addr_len);
PIOHANDLE Parrot_io_socket(PARROT_INTERP, int fam, int type, int proto);
-INTVAL Parrot_io_connect(PARROT_INTERP, PIOHANDLE handle, ARGIN(void *addr));
-INTVAL Parrot_io_bind(PARROT_INTERP, PIOHANDLE handle, ARGIN(void *addr));
+INTVAL Parrot_io_connect(PARROT_INTERP, PIOHANDLE handle, ARGIN(void *addr), INTVAL addr_len);
+INTVAL Parrot_io_bind(PARROT_INTERP, PIOHANDLE handle, ARGIN(void *addr), INTVAL addr_len);
INTVAL Parrot_io_listen(PARROT_INTERP, PIOHANDLE handle, INTVAL sec);
PIOHANDLE Parrot_io_accept(PARROT_INTERP, PIOHANDLE handle, ARGOUT(PMC * remote_addr));
INTVAL Parrot_io_send(PARROT_INTERP, PIOHANDLE handle, ARGIN(const char *buf), size_t len);
INTVAL Parrot_io_recv(PARROT_INTERP, PIOHANDLE handle, ARGOUT(char *buf), size_t len);
INTVAL Parrot_io_poll(PARROT_INTERP, PIOHANDLE handle, int which, int sec, int usec);
INTVAL Parrot_io_close_socket(PARROT_INTERP, PIOHANDLE handle);
-PMC *Parrot_io_remote_address(PARROT_INTERP, ARGIN(PMC *sock));
-PMC *Parrot_io_local_address(PARROT_INTERP, ARGIN(PMC *sock));
/*
** Math:
View
18 src/io/io_private.h
@@ -29,17 +29,6 @@ Some ideas from AT&T SFIO.
#include <parrot/io.h>
-/* XXX: Parrot config is currently not probing for all headers so
- * I'm sticking here rather than parrot.h
- */
-#ifdef UNIX
-# include <sys/socket.h>
-#endif
-
-#ifdef WIN32
-# include <ws2tcpip.h>
-#endif
-
/* Buffer flags */
#define PIO_BF_MALLOC 00000001 /* Buffer malloced */
#define PIO_BF_READBUF 00000002 /* Buffer is read-buffer */
@@ -60,13 +49,6 @@ struct _ParrotIOData {
#define _PIO_STDOUT(i) (((ParrotIOData*)(i)->piodata)->table[PIO_STDOUT_FILENO])
#define _PIO_STDERR(i) (((ParrotIOData*)(i)->piodata)->table[PIO_STDERR_FILENO])
-/* Parrot_Socklen_t is used in POSIX accept call */
-#if PARROT_HAS_SOCKLEN_T
-typedef socklen_t Parrot_Socklen_t;
-#else
-typedef int Parrot_Socklen_t;
-#endif
-
#endif /* PARROT_IO_PRIVATE_H_GUARD */
/*
View
148 src/io/socket_api.c
@@ -21,6 +21,7 @@ These are the primary interface functions for working with socket objects.
#include "io_private.h"
#include "api.str"
#include "pmc/pmc_socket.h"
+#include "pmc/pmc_sockaddr.h"
#include <stdarg.h>
@@ -211,6 +212,9 @@ Parrot_io_socket_handle(PARROT_INTERP, ARGMOD_NULLOK(PMC *socket), INTVAL fam,
return -1;
SETATTR_Socket_os_handle(interp, new_socket, os_handle);
+ SETATTR_Socket_family(interp, new_socket, fam);
+ SETATTR_Socket_type(interp, new_socket, type);
+ SETATTR_Socket_protocol(interp, new_socket, proto);
return 0;
}
@@ -294,69 +298,47 @@ INTVAL
Parrot_io_connect_handle(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
{
ASSERT_ARGS(Parrot_io_connect_handle)
- struct addrinfo *res, *walk;
- int fd = -1;
- int i = 1;
Parrot_Socket_attributes * const io = PARROT_SOCKET(pmc);
+ int i;
- /* Connect to an IPv6 addrinfo if an UnManagedStruct was provided as address */
- if (!PMC_IS_NULL(address) && address->vtable->base_type == enum_class_UnManagedStruct) {
- res = (struct addrinfo *)VTABLE_get_pointer(interp, address);
-
- 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 (Parrot_io_socket_is_closed(interp, pmc))
+ return -1;
+ if (PMC_IS_NULL(address))
+ return -1;
+
+ /* Iterate over all addresses if an array is passed */
+ if (address->vtable->base_type != enum_class_Sockaddr) {
+ INTVAL len = VTABLE_elements(interp, address);
+
+ for (i = 0; i < len; ++i) {
+ PMC *sa = VTABLE_get_pmc_keyed_int(interp, address, i);
+ Parrot_Sockaddr_attributes * const sa_data = PARROT_SOCKADDR(sa);
+ struct sockaddr_storage *ss =
+ (struct sockaddr_storage *)sa_data->pointer;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)) == -1) {
- perror("Error setting SO_REUSEADDR:");
+ if (ss->ss_family != io->family
+ || (sa_data->type != io->type
+ && sa_data->type != 0)
+ || sa_data->protocol != io->protocol)
continue;
- }
-
- /* XXX: this effectively overwrites any previously set sockets. is that alright? */
- SETATTR_Socket_os_handle(interp, pmc, fd);
-
-AGAIN:
- 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(pmc)->remote = Parrot_pmc_new(interp, enum_class_Sockaddr);
-
- VTABLE_set_pointer(interp, PARROT_SOCKET(pmc)->remote, walk);
+
+ io->remote = sa;
+
+ Parrot_io_connect(interp, io->os_handle, ss, sa_data->len);
+
return 0;
}
- if (fd == -1)
- return -1;
- fprintf(stderr, "huh?!\n");
+ Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
+ "No address found for family %d, type %d, proto %d",
+ io->family, io->type, io->protocol);
}
- if (Parrot_io_socket_is_closed(interp, pmc))
- return -1;
- if (PMC_IS_NULL(address))
- return -1;
-
io->remote = address;
return Parrot_io_connect(interp, io->os_handle,
- VTABLE_get_pointer(interp, address));
+ VTABLE_get_pointer(interp, address),
+ VTABLE_get_integer(interp, address));
}
/*
@@ -375,61 +357,47 @@ INTVAL
Parrot_io_bind_handle(PARROT_INTERP, ARGMOD(PMC *pmc), ARGMOD(PMC *address))
{
ASSERT_ARGS(Parrot_io_bind_handle)
- struct addrinfo *res, *walk;
- int fd = -1;
- int i = 1;
Parrot_Socket_attributes * const io = PARROT_SOCKET(pmc);
+ int i;
- /* Bind to an IPv6 address (UnManagedStruct with an struct addrinfo inside */
- if (!PMC_IS_NULL(address) && address->vtable->base_type == enum_class_UnManagedStruct) {
- res = (struct addrinfo *)VTABLE_get_pointer(interp, address);
-
- 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 (Parrot_io_socket_is_closed(interp, pmc))
+ return -1;
+ if (PMC_IS_NULL(address))
+ return -1;
- if (walk->ai_family == AF_INET6) {
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof (i)) == -1) {
- perror("Error setting IPV6_V6ONLY:");
- continue;
- }
- }
+ /* Iterate over all addresses if an array is passed */
+ if (address->vtable->base_type != enum_class_Sockaddr) {
+ INTVAL len = VTABLE_elements(interp, address);
- /* XXX: this effectively overwrites any previously set sockets. is that alright? */
- SETATTR_Socket_os_handle(interp, pmc, fd);
+ for (i = 0; i < len; ++i) {
+ PMC *sa = VTABLE_get_pmc_keyed_int(interp, address, i);
+ Parrot_Sockaddr_attributes * const sa_data = PARROT_SOCKADDR(sa);
+ struct sockaddr_storage *ss =
+ (struct sockaddr_storage *)sa_data->pointer;
- if (bind(fd, walk->ai_addr, walk->ai_addrlen) != 0) {
- close(fd);
- fd = -1;
+ if (ss->ss_family != io->family
+ || (sa_data->type != io->type
+ && sa_data->type != 0)
+ || sa_data->protocol != io->protocol)
continue;
- }
- PARROT_SOCKET(pmc)->local = Parrot_pmc_new(interp, enum_class_Sockaddr);
+ io->local = sa;
+
+ Parrot_io_bind(interp, io->os_handle, ss, sa_data->len);
- VTABLE_set_pointer(interp, PARROT_SOCKET(pmc)->local, walk);
return 0;
}
- if (fd == -1)
- return -1;
-
+ Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
+ "No address found for family %d, type %d, proto %d",
+ io->family, io->type, io->protocol);
}
- if (Parrot_io_socket_is_closed(interp, pmc))
- return -1;
- if (PMC_IS_NULL(address))
- return -1;
-
io->local = address;
return Parrot_io_bind(interp, io->os_handle,
- VTABLE_get_pointer(interp, address));
+ VTABLE_get_pointer(interp, address),
+ VTABLE_get_integer(interp, address));
}
/*
View
280 src/platform/generic/socket.c
@@ -15,6 +15,13 @@ src/platform/generic/socket.c - UNIX socket functions
*/
+#ifdef _WIN32
+# include <ws2tcpip.h>
+# undef CONST
+#else
+# include <sys/socket.h>
+#endif
+
#include "parrot/parrot.h"
#include "../../io/io_private.h"
#include "pmc/pmc_socket.h"
@@ -60,27 +67,15 @@ typedef int PIOSOCKET;
#endif
+#if PARROT_HAS_SOCKLEN_T
+typedef socklen_t Parrot_Socklen_t;
+#else
+typedef int Parrot_Socklen_t;
+#endif
+
/* HEADERIZER HFILE: none */
/* 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);
-
-#define ASSERT_ARGS_get_addrinfo __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
- PARROT_ASSERT_ARG(interp) \
- , PARROT_ASSERT_ARG(addrinfo) \
- , PARROT_ASSERT_ARG(host))
-/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
@@ -141,20 +136,82 @@ static int pio_pf[PIO_PF_MAX+1] = {
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)
+Parrot_io_getaddrinfo(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port,
+ INTVAL protocol, INTVAL family, INTVAL passive)
{
- char * const s = Parrot_str_to_cstring(interp, addr);
- PMC * const addrinfo = Parrot_pmc_new(interp, enum_class_UnManagedStruct);
+ char *s;
+ PMC *array;
/* 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);
+ struct addrinfo hints;
+ struct addrinfo *ai, *walk;
+ /* 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;
+
+ if (STRING_IS_NULL(addr))
+ s = NULL;
+ else
+ s = Parrot_str_to_cstring(interp, addr);
+
+ memset(&hints, 0, sizeof (struct addrinfo));
+ if (passive)
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = fam;
+ hints.ai_protocol = protocol;
+ snprintf(portstr, sizeof (portstr), "%ld", port);
+
+ if ((ret = getaddrinfo(s, portstr, &hints, &ai)) != 0)
+ Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_PIO_ERROR,
+ "getaddrinfo failed: %s", s ? s : "(null)");
+
Parrot_str_free_cstring(s);
- return addrinfo;
+
+ array = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
+
+ for (walk = ai; walk; walk = ai->ai_next) {
+ PMC *sockaddr = Parrot_pmc_new(interp, enum_class_Sockaddr);
+
+ VTABLE_set_pointer(interp, sockaddr, walk);
+ VTABLE_push_pmc(interp, array, sockaddr);
+ }
+
+ freeaddrinfo(ai);
+
+ return array;
+}
+
+/*
+
+=item C<STRING * Parrot_io_getnameinfo(PARROT_INTERP, const void *sa, INTVAL
+len)>
+
+Uses C<socket()> to create a socket with the specified address family,
+socket type and protocol number.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CANNOT_RETURN_NULL
+STRING *
+Parrot_io_getnameinfo(PARROT_INTERP, ARGIN(const void *sa), INTVAL len)
+{
+ /* TODO: get hostname, not only numeric */
+ char buf[INET6_ADDRSTRLEN+1];
+ /* numeric port maximum is 65535, so 5 chars */
+ char portbuf[6];
+
+ getnameinfo((const struct sockaddr *)sa, len, buf, sizeof (buf),
+ portbuf, sizeof (portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ return Parrot_str_format_data(interp, "%s:%s", buf, portbuf);
}
/*
@@ -169,25 +226,29 @@ socket type and protocol number.
*/
PARROT_WARN_UNUSED_RESULT
-PARROT_CAN_RETURN_NULL
PIOHANDLE
Parrot_io_socket(PARROT_INTERP, int fam, int type, int proto)
{
const PIOSOCKET sock = socket(fam, type, proto);
- int i = 1;
+ const int value = 1;
if (sock == PIO_INVALID_SOCKET)
return PIO_INVALID_HANDLE;
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i));
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof (value));
+
+#ifdef IPV6_V6ONLY
+ if (fam == AF_INET6)
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof (value));
+#endif
return (PIOHANDLE)sock;
}
/*
-=item C<INTVAL Parrot_io_connect(PARROT_INTERP, PIOHANDLE os_handle, void
-*addr)>
+=item C<INTVAL Parrot_io_connect(PARROT_INTERP, PIOHANDLE os_handle, void *addr,
+INTVAL addr_len)>
Connects C<*io>'s socket to address C<*r>.
@@ -196,11 +257,11 @@ Connects C<*io>'s socket to address C<*r>.
*/
INTVAL
-Parrot_io_connect(PARROT_INTERP, PIOHANDLE os_handle, ARGIN(void *addr))
+Parrot_io_connect(PARROT_INTERP, PIOHANDLE os_handle, ARGIN(void *addr),
+ INTVAL addr_len)
{
AGAIN:
- if ((connect((PIOSOCKET)os_handle, (struct sockaddr *)addr,
- sizeof (struct sockaddr_in))) != 0) {
+ if (connect((PIOSOCKET)os_handle, (struct sockaddr *)addr, addr_len) != 0) {
switch (PIO_SOCK_ERRNO) {
case PIO_SOCK_EINTR:
goto AGAIN;
@@ -218,7 +279,8 @@ Parrot_io_connect(PARROT_INTERP, PIOHANDLE os_handle, ARGIN(void *addr))
/*
-=item C<INTVAL Parrot_io_bind(PARROT_INTERP, PIOHANDLE os_handle, void *addr)>
+=item C<INTVAL Parrot_io_bind(PARROT_INTERP, PIOHANDLE os_handle, void *addr,
+INTVAL addr_len)>
Binds C<*io>'s socket to the local address and port specified by C<*l>.
@@ -227,12 +289,10 @@ Binds C<*io>'s socket to the local address and port specified by C<*l>.
*/
INTVAL
-Parrot_io_bind(PARROT_INTERP, PIOHANDLE os_handle, ARGMOD(void *addr))
+Parrot_io_bind(PARROT_INTERP, PIOHANDLE os_handle, ARGMOD(void *addr),
+ INTVAL addr_len)
{
- struct sockaddr_in * saddr;
-
- if ((bind((PIOSOCKET)os_handle, (struct sockaddr *)addr,
- sizeof (struct sockaddr_in))) == -1) {
+ if (bind((PIOSOCKET)os_handle, (struct sockaddr *)addr, addr_len) != 0) {
return -1;
}
@@ -424,61 +484,6 @@ Parrot_io_poll(SHIM_INTERP, PIOHANDLE os_handle, int which, int sec,
/*
-=item C<void Parrot_io_sockaddr_in(PARROT_INTERP, void *addr, STRING *host_str,
-int port, int family)>
-
-Fill in a C<sockaddr_in> structure to connect to the specified host and port.
-
-=cut
-
-*/
-
-void
-Parrot_io_sockaddr_in(PARROT_INTERP, ARGOUT(void *addr),
- ARGIN(STRING *host_str), int port, int family)
-{
- char * const host = Parrot_str_to_cstring(interp, host_str);
- int success;
-
- struct sockaddr_in * const sa = (struct sockaddr_in*)addr;
-
- /* Hard coded to IPv4 for now */
- family = AF_INET;
-
-#ifdef _WIN32
- sa->sin_addr.S_un.S_addr = inet_addr(host);
- success = sa->sin_addr.S_un.S_addr != -1;
-#else
-# ifdef PARROT_DEF_INET_ATON
- success = inet_aton(host, &sa->sin_addr) != 0;
-# else
- /* positive retval is success */
- success = inet_pton(family, host, &sa->sin_addr) > 0;
-# endif
-#endif
-
- if (!success) {
- /* Maybe it is a hostname, try to lookup */
- /* XXX Check PIO option before doing a name lookup,
- * it may have been toggled off.
- */
- struct hostent *he = gethostbyname(host);
- /* XXX FIXME - Handle error condition better */
- if (!he) {
- fprintf(stderr, "gethostbyname failure [%s]\n", host);
- return;
- }
- memcpy((char*)&sa->sin_addr, he->h_addr, sizeof (sa->sin_addr));
- }
-
- Parrot_str_free_cstring(host);
-
- sa->sin_family = family;
- sa->sin_port = htons(port);
-}
-
-/*
-
=item C<INTVAL Parrot_io_close_socket(PARROT_INTERP, PIOHANDLE handle)>
Closes the given file descriptor. Returns 0 on success, -1 on error.
@@ -499,93 +504,6 @@ Parrot_io_close_socket(SHIM_INTERP, PIOHANDLE handle)
/*
-=item C<PMC * Parrot_io_remote_address(PARROT_INTERP, PMC *sock)>
-
-C<Parrot_io_remote_address()> 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))
-{
- PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->remote);
-
- return addrinfo;
-}
-
-/*
-
-=item C<PMC * Parrot_io_local_address(PARROT_INTERP, PMC *sock)>
-
-C<Parrot_io_local_address()> 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))
-{
- PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->local);
-
- return addrinfo;
-}
-
-/*
-
-=item C<static void get_addrinfo(PARROT_INTERP, PMC * addrinfo, const char
-*host, int port, int protocol, int family, int passive)>
-
-Internal helper function to call getaddrinfo and store the result pointer in
-the given PMC (of type UnManagedStruct).
-
-=cut
-
-*/
-
-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);
-}
-
-
-/*
-
=back
=head1 SEE ALSO
View
72 src/pmc/sockaddr.pmc
@@ -34,8 +34,10 @@ extern "C" {
/* HEADERIZER END: static */
pmclass Sockaddr auto_attrs {
- ATTR void *pointer; /* The stored pointer. */
- ATTR INTVAL len; /* Length of the contents of the sockaddr_storage */
+ ATTR INTVAL type;
+ ATTR INTVAL protocol;
+ ATTR INTVAL len; /* Length of the sockaddr struct */
+ ATTR void *pointer; /* Pointer to a sockaddr struct */
/*
@@ -48,11 +50,14 @@ Initializes the PMC by allocating a C<sockaddr_storage>.
*/
VTABLE void init() {
- Parrot_Sockaddr_attributes * const pdata_struct =
+ Parrot_Sockaddr_attributes * const attrs =
(Parrot_Sockaddr_attributes *) PMC_data(SELF);
- pdata_struct->pointer = mem_gc_allocate_zeroed_typed(INTERP,
- struct sockaddr_storage);
+ attrs->type = 0;
+ attrs->protocol = 0;
+ attrs->pointer = NULL;
+ attrs->len = 0;
+
PObj_custom_destroy_SET(SELF);
}
@@ -70,7 +75,8 @@ Destroys the PMC and frees all allocated memory.
Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
if (data) {
- mem_gc_free(INTERP, data->pointer);
+ if (data->pointer)
+ mem_gc_free(INTERP, data->pointer);
data->pointer = NULL;
}
}
@@ -88,10 +94,19 @@ one.
VTABLE PMC *clone() {
PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
+ Parrot_Sockaddr_attributes * const old_attrs = PARROT_SOCKADDR(SELF);
+ Parrot_Sockaddr_attributes * const new_attrs = PARROT_SOCKADDR(dest);
+
+ new_attrs->type = old_attrs->type;
+ new_attrs->protocol = old_attrs->protocol;
+ new_attrs->len = old_attrs->len;
+
+ if (old_attrs->len) {
+ new_attrs->pointer = Parrot_gc_allocate_memory_chunk(INTERP,
+ old_attrs->len);
+ memcpy(new_attrs->pointer, old_attrs->pointer, old_attrs->len);
+ }
- memcpy(PARROT_SOCKADDR(dest)->pointer, PARROT_SOCKADDR(SELF)->pointer,
- sizeof (struct sockaddr_storage));
- PARROT_SOCKADDR(dest)->len = PARROT_SOCKADDR(SELF)->len;
return dest;
}
@@ -108,7 +123,25 @@ Returns true if the Sockaddr is defined.
VTABLE INTVAL get_bool() {
Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
- return data->pointer ? 1 : 0 ;
+ return data->pointer ? 1 : 0;
+ }
+
+/*
+
+=item C<INTVAL get_integer()>
+
+Returns the length of the sockaddr struct.
+
+=cut
+
+*/
+
+ VTABLE INTVAL get_integer() {
+ INTVAL len;
+
+ GET_ATTR_len(INTERP, SELF, len);
+
+ return len;
}
/*
@@ -137,17 +170,11 @@ Returns the string representation of this sockaddr by calling C<getnameinfo(3)>.
*/
VTABLE STRING *get_string() {
Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
- /* TODO: get hostname, not only numeric */
- char buf[INET6_ADDRSTRLEN+1];
- /* numeric port maximum is 65535, so 5 chars */
- char portbuf[6];
if (!data->pointer)
return Parrot_sprintf_c(interp, "(?)");
- getnameinfo((struct sockaddr *)data->pointer, data->len, buf,
- sizeof (buf), portbuf, sizeof (portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
- return Parrot_str_format_data(interp, "%s:%s", buf, portbuf);
+ return Parrot_io_getnameinfo(INTERP, data->pointer, data->len);
}
@@ -164,10 +191,15 @@ Copies a C<sockaddr_in> or C<sockaddr_in6> from the given C<addrinfo> pointer
VTABLE void set_pointer(void *value) {
Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF);
+ struct addrinfo *ai = (struct addrinfo *)value;
+
+ data->type = ai->ai_socktype;
+ data->protocol = ai->ai_protocol;
+ data->len = ai->ai_addrlen;
+ data->pointer = Parrot_gc_allocate_memory_chunk(INTERP,
+ ai->ai_addrlen);
- struct addrinfo *walk = (struct addrinfo *)value;
- memcpy(data->pointer, walk->ai_addr, walk->ai_addrlen);
- data->len = walk->ai_addrlen;
+ memcpy(data->pointer, ai->ai_addr, ai->ai_addrlen);
}
}
View
29 src/pmc/socket.pmc
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2011, Parrot Foundation.
+Copyright (C) 2008-2011, Parrot Foundation.
=head1 NAME
@@ -29,6 +29,9 @@ The Socket PMC performs network I/O operations.
pmclass Socket extends Handle provides socket auto_attrs {
ATTR PMC *local; /* Local addr */
ATTR PMC *remote; /* Remote addr */
+ ATTR INTVAL family;
+ ATTR INTVAL type;
+ ATTR INTVAL protocol;
ATTR STRING *buf;
/*
@@ -181,23 +184,27 @@ family (integer). If no address family is given, it defaults to IPv4.
*/
METHOD sockaddr(STRING * address, INTVAL port, INTVAL family :optional) {
- PMC * sockaddr;
+ PMC *array;
+ PMC *res;
if (!family)
- family = AF_INET;
+ family = PF_INET;
- sockaddr = Parrot_pmc_new(interp, enum_class_Sockaddr);
- Parrot_io_sockaddr_in(INTERP,
- VTABLE_get_pointer(INTERP, sockaddr), address, port, family);
- PARROT_SOCKADDR(sockaddr)->len = sizeof (struct sockaddr_in);
- RETURN(PMC * sockaddr);
+ array = Parrot_io_getaddrinfo(INTERP, address, port, IPPROTO_TCP, family, 0);
+
+ if (VTABLE_elements(interp, array))
+ res = VTABLE_get_pmc_keyed_int(interp, array, 0);
+ else
+ res = PMCNULL;
+
+ RETURN(PMC * res);
}
/*
=item C<getaddrinfo(STRING * address, INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive)>
-C<getaddrinfo> returns an object representing the result of the
+C<getaddrinfo> returns an array of Sockaddr PMCs representing the result of the
C<getaddrinfo(3)> function which consists of multiple socket addresses,
including family and protocol. It can be passed to C<bind()> or C<connect()>.
@@ -220,7 +227,7 @@ C<remote_address> returns the remote address of this socket PMC.
*/
METHOD remote_address() {
- PMC * res = Parrot_io_remote_address(INTERP, SELF);
+ PMC * res = PARROT_SOCKET(SELF)->remote;
RETURN(PMC * res);
}
@@ -234,7 +241,7 @@ C<local_address> returns the local address of this socket PMC.
*/
METHOD local_address() {
- PMC * res = Parrot_io_local_address(INTERP, SELF);
+ PMC * res = PARROT_SOCKET(SELF)->local;
RETURN(PMC * res);
}
View
47 t/pmc/socket_ipv6.t
@@ -40,11 +40,12 @@ IPv6-related tests for the Socket PMC.
.sub test_bind
.local pmc sock, addrinfo
- .local string str
+ .local string str, null_string
.local int result
sock = new 'Socket'
- addrinfo = sock.'getaddrinfo'('localhost', 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 1)
+ sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP)
+ addrinfo = sock.'getaddrinfo'(null_string, 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 0)
result = sock.'bind'(addrinfo)
is(result, 0, 'bind ok (IPv6 localhost)')
@@ -53,7 +54,8 @@ IPv6-related tests for the Socket PMC.
sock.'close'()
- addrinfo = sock.'getaddrinfo'('localhost', 1234, .PIO_PROTO_TCP, .PIO_PF_INET, 1)
+ sock.'socket'(.PIO_PF_INET, .PIO_SOCK_STREAM, .PIO_PROTO_TCP)
+ addrinfo = sock.'getaddrinfo'(null_string, 1234, .PIO_PROTO_TCP, .PIO_PF_INET, 0)
result = sock.'bind'(addrinfo)
is(result, 0, 'bind ok (IPv4 localhost)')
@@ -64,7 +66,7 @@ IPv6-related tests for the Socket PMC.
.sub test_server
.local pmc interp, conf, server, sock, address, result
- .local string command, str
+ .local string command, str, null_string
.local int status
interp = getinterp
@@ -87,7 +89,8 @@ IPv6-related tests for the Socket PMC.
is(str, "Server started\n", 'Server process started')
sock = new 'Socket'
- address = sock.'getaddrinfo'('localhost', 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 0)
+ sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP)
+ address = sock.'getaddrinfo'(null_string, 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 0)
status = sock.'connect'(address)
nok(status, 'connect')
@@ -124,47 +127,57 @@ IPv6-related tests for the Socket PMC.
.sub test_tcp_socket6
.local pmc sock, sockaddr
- sock = new 'Socket'
+ .local string null_string
+ sock = new 'Socket'
sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP)
- sockaddr = sock."sockaddr"("localhost",80, .PIO_PF_INET6)
+
+ sockaddr = sock."sockaddr"(null_string, 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr',"A TCP ipv6 sockaddr to localhost was set")
- sockaddr = sock."sockaddr"("::1",80, .PIO_PF_INET6)
+ sockaddr = sock."sockaddr"("::1", 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr',"A TCP ipv6 sockaddr to ::1 was set")
.end
.sub test_raw_tcp_socket6
.local pmc sock, sockaddr
- sock = new 'Socket'
+ .local string null_string
+ sock = new 'Socket'
sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_TCP)
- sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6)
+
+ sockaddr = sock."sockaddr"(null_string, 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)
+
+ sockaddr = sock."sockaddr"("::1", 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr',"A raw TCP ipv6 sockaddr to ::1 was set:")
.end
.sub test_udp_socket6
.local pmc sock, sockaddr
- sock = new 'Socket'
+ .local string null_string
+ sock = new 'Socket'
sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_UDP)
- sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6)
+
+ sockaddr = sock."sockaddr"(null_string, 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr', "A UDP ipv6 sockaddr to localhost was set:")
- sockaddr = sock."sockaddr"("::1",80,.PIO_PF_INET6)
+ sockaddr = sock."sockaddr"("::1", 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr', "A UDP ipv6 sockaddr to ::1 was set:")
.end
.sub test_raw_udp_socket6
.local pmc sock, sockaddr
- sock = new 'Socket'
+ .local string null_string
+ sock = new 'Socket'
sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_RAW, .PIO_PROTO_UDP)
- sockaddr = sock."sockaddr"("localhost",80,.PIO_PF_INET6)
+
+ sockaddr = sock."sockaddr"(null_string, 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)
+
+ sockaddr = sock."sockaddr"("::1", 80, .PIO_PF_INET6)
isa_ok(sockaddr,'Sockaddr', "A raw UDP ipv6 sockaddr to ::1 was set: ")
.end
View
5 t/pmc/testlib/test_server_ipv6.pir
@@ -23,11 +23,12 @@ in case of test failures.
.sub main :main
.local pmc sock, address, conn
- .local string str
+ .local string str, null_string
.local int len, status
sock = new 'Socket'
- address = sock.'getaddrinfo'('localhost', 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 1)
+ sock.'socket'(.PIO_PF_INET6, .PIO_SOCK_STREAM, .PIO_PROTO_TCP)
+ address = sock.'getaddrinfo'(null_string, 1234, .PIO_PROTO_TCP, .PIO_PF_INET6, 0)
status = sock.'bind'(address)
sock.'listen'(5)

0 comments on commit 958c51a

Please sign in to comment.