Ticket #1798: 0001-Implement-support-for-IPv6.patch

File 0001-Implement-support-for-IPv6.patch, 26.6 KB (added by mstapelberg, 4 years ago)
  • MANIFEST

    From 688231c304b1ee922bf1d693ad9e1fd33ebff52e Mon Sep 17 00:00:00 2001
    From: Michael Stapelberg <michael@stapelberg.de>
    Date: Wed, 22 Sep 2010 17:41:58 +0200
    Subject: [PATCH] Implement support for IPv6
    
    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 c5a941b..90f0095 100644
    a b  
    13471347src/pbc_dump.c                                              [] 
    13481348src/pbc_merge.c                                             [] 
    13491349src/pmc.c                                                   [] 
     1350src/pmc/addrinfo.pmc                                        [] 
    13501351src/pmc/addrregistry.pmc                                    [] 
    13511352src/pmc/arrayiterator.pmc                                   [] 
    13521353src/pmc/bigint.pmc                                          [] 
  • MANIFEST.generated

    diff --git a/MANIFEST.generated b/MANIFEST.generated
    index f6fadae..365d0f4 100644
    a b  
    3737include/parrot/platform.h                        [main]include 
    3838include/parrot/platform_limits.h                 [devel]include 
    3939include/parrot/vtable.h                          [main]include 
     40include/pmc/pmc_addrinfo.h                       [devel]include 
    4041include/pmc/pmc_addrregistry.h                   [devel]include 
    4142include/pmc/pmc_arrayiterator.h                  [devel]include 
    4243include/pmc/pmc_bigint.h                         [devel]include 
     
    333334src/nci.c                                        [] 
    334335src/null_config.c                                [] 
    335336src/parrot_config.c                              [] 
     337src/pmc/addrinfo.dump                            [devel]src 
    336338src/pmc/addrregistry.dump                        [devel]src 
    337339src/pmc/arrayiterator.dump                       [devel]src 
    338340src/pmc/bigint.dump                              [devel]src 
  • include/parrot/io_unix.h

    diff --git a/include/parrot/io_unix.h b/include/parrot/io_unix.h
    index 7cc8ee2..b97e288 100644
    a b  
    182182        FUNC_MODIFIES(*socket); 
    183183 
    184184INTVAL Parrot_io_bind_unix(PARROT_INTERP, 
    185     ARGMOD(PMC *socket), 
     185    ARGMOD(PMC *sock), 
    186186    ARGMOD(PMC *sockaddr)) 
    187187        __attribute__nonnull__(1) 
    188188        __attribute__nonnull__(2) 
    189189        __attribute__nonnull__(3) 
    190         FUNC_MODIFIES(*socket) 
     190        FUNC_MODIFIES(*sock) 
    191191        FUNC_MODIFIES(*sockaddr); 
    192192 
    193193INTVAL Parrot_io_connect_unix(PARROT_INTERP, 
    194     ARGMOD(PMC *socket), 
     194    ARGMOD(PMC *sock), 
    195195    ARGIN(PMC *r)) 
    196196        __attribute__nonnull__(1) 
    197197        __attribute__nonnull__(2) 
    198198        __attribute__nonnull__(3) 
    199         FUNC_MODIFIES(*socket); 
     199        FUNC_MODIFIES(*sock); 
     200 
     201PARROT_WARN_UNUSED_RESULT 
     202PARROT_CANNOT_RETURN_NULL 
     203PMC * Parrot_io_getaddrinfo(PARROT_INTERP, 
     204    ARGIN(STRING *addr), 
     205    INTVAL port, 
     206    INTVAL protocol, 
     207    INTVAL family, 
     208    INTVAL passive) 
     209        __attribute__nonnull__(1) 
     210        __attribute__nonnull__(2); 
    200211 
    201212INTVAL Parrot_io_listen_unix(SHIM_INTERP, ARGMOD(PMC *socket), INTVAL sec) 
    202213        __attribute__nonnull__(2) 
    203214        FUNC_MODIFIES(*socket); 
    204215 
     216PARROT_WARN_UNUSED_RESULT 
     217PARROT_CANNOT_RETURN_NULL 
     218PMC * Parrot_io_local_address(PARROT_INTERP, ARGIN(PMC *sock)) 
     219        __attribute__nonnull__(1) 
     220        __attribute__nonnull__(2); 
     221 
    205222INTVAL Parrot_io_poll_unix(SHIM_INTERP, 
    206223    ARGMOD(PMC *socket), 
    207224    int which, 
     
    219236        FUNC_MODIFIES(*socket) 
    220237        FUNC_MODIFIES(*s); 
    221238 
     239PARROT_WARN_UNUSED_RESULT 
     240PARROT_CANNOT_RETURN_NULL 
     241PMC * Parrot_io_remote_address(PARROT_INTERP, ARGIN(PMC *sock)) 
     242        __attribute__nonnull__(1) 
     243        __attribute__nonnull__(2); 
     244 
    222245INTVAL Parrot_io_send_unix(SHIM_INTERP, 
    223246    ARGMOD(PMC *socket), 
    224247    ARGMOD(STRING *s)) 
     
    248271    , PARROT_ASSERT_ARG(socket)) 
    249272#define ASSERT_ARGS_Parrot_io_bind_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    250273       PARROT_ASSERT_ARG(interp) \ 
    251     , PARROT_ASSERT_ARG(socket) \ 
     274    , PARROT_ASSERT_ARG(sock) \ 
    252275    , PARROT_ASSERT_ARG(sockaddr)) 
    253276#define ASSERT_ARGS_Parrot_io_connect_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    254277       PARROT_ASSERT_ARG(interp) \ 
    255     , PARROT_ASSERT_ARG(socket) \ 
     278    , PARROT_ASSERT_ARG(sock) \ 
    256279    , PARROT_ASSERT_ARG(r)) 
     280#define ASSERT_ARGS_Parrot_io_getaddrinfo __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
     281       PARROT_ASSERT_ARG(interp) \ 
     282    , PARROT_ASSERT_ARG(addr)) 
    257283#define ASSERT_ARGS_Parrot_io_listen_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    258284       PARROT_ASSERT_ARG(socket)) 
     285#define ASSERT_ARGS_Parrot_io_local_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
     286       PARROT_ASSERT_ARG(interp) \ 
     287    , PARROT_ASSERT_ARG(sock)) 
    259288#define ASSERT_ARGS_Parrot_io_poll_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    260289       PARROT_ASSERT_ARG(socket)) 
    261290#define ASSERT_ARGS_Parrot_io_recv_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    262291       PARROT_ASSERT_ARG(interp) \ 
    263292    , PARROT_ASSERT_ARG(socket) \ 
    264293    , PARROT_ASSERT_ARG(s)) 
     294#define ASSERT_ARGS_Parrot_io_remote_address __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
     295       PARROT_ASSERT_ARG(interp) \ 
     296    , PARROT_ASSERT_ARG(sock)) 
    265297#define ASSERT_ARGS_Parrot_io_send_unix __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    266298       PARROT_ASSERT_ARG(socket) \ 
    267299    , PARROT_ASSERT_ARG(s)) 
  • src/io/socket_unix.c

    diff --git a/src/io/socket_unix.c b/src/io/socket_unix.c
    index 9dcb8f9..cc70398 100644
    a b  
    3131#include "parrot/parrot.h" 
    3232#include "io_private.h" 
    3333#include "pmc/pmc_socket.h" 
     34#include "pmc/pmc_sockaddr.h" 
    3435 
    3536#ifdef PIO_OS_UNIX 
    3637 
     
    4142/* HEADERIZER BEGIN: static */ 
    4243/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */ 
    4344 
     45static void get_addrinfo(PARROT_INTERP, 
     46    ARGIN(PMC * addrinfo), 
     47    ARGIN(const char *host), 
     48    int port, 
     49    int protocol, 
     50    int family, 
     51    int passive) 
     52        __attribute__nonnull__(1) 
     53        __attribute__nonnull__(2) 
     54        __attribute__nonnull__(3); 
     55 
    4456static void get_sockaddr_in(PARROT_INTERP, 
    4557    ARGIN(PMC * sockaddr), 
    4658    ARGIN(const char* host), 
     
    4961        __attribute__nonnull__(2) 
    5062        __attribute__nonnull__(3); 
    5163 
     64#define ASSERT_ARGS_get_addrinfo __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
     65       PARROT_ASSERT_ARG(interp) \ 
     66    , PARROT_ASSERT_ARG(addrinfo) \ 
     67    , PARROT_ASSERT_ARG(host)) 
    5268#define ASSERT_ARGS_get_sockaddr_in __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ 
    5369       PARROT_ASSERT_ARG(interp) \ 
    5470    , PARROT_ASSERT_ARG(sockaddr) \ 
     
    5975/* 
    6076static void get_sockaddr_in(PARROT_INTERP, ARGIN(PMC * sockaddr), 
    6177    ARGIN(const char* host), ARGIN(int port)); 
     78static void 
     79get_addrinfo(PARROT_INTERP, ARGIN(PMC * addrinfo), ARGIN(const char *host), ARGIN(int port)); 
    6280*/ 
    6381 
    6482/* 
     
    107125    return sockaddr; 
    108126} 
    109127 
     128/* 
     129 
     130=item C<PMC * Parrot_io_getaddrinfo(PARROT_INTERP, STRING *addr, INTVAL port, 
     131INTVAL protocol, INTVAL family, INTVAL passive)> 
     132 
     133C<Parrot_io_getaddrinfo()> calls get_addrinfo() to convert hostnames or IP 
     134addresses to sockaddrs (and more) and returns an Addrinfo PMC which can be 
     135passed to C<Parrot_io_connect_unix()> or C<Parrot_io_bind_unix()>. 
     136 
     137=cut 
     138 
     139*/ 
     140 
     141/* TODO: where to move this to? originally from src/io/socket_api.c */ 
     142static int pio_pf[PIO_PF_MAX+1] = { 
     143#ifdef PF_LOCAL 
     144    PF_LOCAL,   /* PIO_PF_LOCAL */ 
     145#else 
     146    -1,         /* PIO_PF_LOCAL */ 
     147#endif 
     148#ifdef PF_UNIX 
     149    PF_UNIX,    /* PIO_PF_UNIX */ 
     150#else 
     151    -1,         /* PIO_PF_UNIX */ 
     152#endif 
     153#ifdef PF_INET 
     154    PF_INET,    /* PIO_PF_INET */ 
     155#else 
     156    -1,         /* PIO_PF_INET */ 
     157#endif 
     158#ifdef PF_INET6 
     159    PF_INET6,   /* PIO_PF_INET6 */ 
     160#else 
     161    -1,         /* PIO_PF_INET6 */ 
     162#endif 
     163}; 
     164 
     165PARROT_WARN_UNUSED_RESULT 
     166PARROT_CANNOT_RETURN_NULL 
     167PMC * 
     168Parrot_io_getaddrinfo(PARROT_INTERP, ARGIN(STRING *addr), INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive) 
     169{ 
     170    ASSERT_ARGS(Parrot_io_getaddrinfo) 
     171 
     172    char * const s        = Parrot_str_to_cstring(interp, addr); 
     173    PMC  * const addrinfo = Parrot_pmc_new(interp, enum_class_Addrinfo); 
     174 
     175    /* set family: 0 means any (AF_INET or AF_INET6) for getaddrinfo, so treat 
     176     * it specially */ 
     177    int fam = (family != 0 ? pio_pf[family] : 0); 
     178 
     179    get_addrinfo(interp, addrinfo, s, port, protocol, fam, passive); 
     180    Parrot_str_free_cstring(s); 
     181    return addrinfo; 
     182} 
     183 
     184 
     185/* 
     186 
     187=item C<PMC * Parrot_io_remote_address(PARROT_INTERP, PMC *sock)> 
     188 
     189C<Parrot_io_remote_address()> returns the remote address of the given sock 
     190PMC. It can be used to find out to which address the connection was actually 
     191established (in case of the remote server having multiple IPv4 and/or IPv6 
     192addresses. 
     193 
     194=cut 
     195 
     196*/ 
     197PARROT_WARN_UNUSED_RESULT 
     198PARROT_CANNOT_RETURN_NULL 
     199PMC * 
     200Parrot_io_remote_address(PARROT_INTERP, ARGIN(PMC *sock)) 
     201{ 
     202    ASSERT_ARGS(Parrot_io_remote_address) 
     203 
     204    PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->remote); 
     205 
     206    return addrinfo; 
     207} 
     208 
     209/* 
     210 
     211=item C<PMC * Parrot_io_local_address(PARROT_INTERP, PMC *sock)> 
     212 
     213C<Parrot_io_local_address()> returns the local address of the given sock 
     214PMC. It can be used to find out to which address the socket was actually 
     215bound (when binding to "localhost" without explicitly specifying an address 
     216family, for example). 
     217 
     218=cut 
     219 
     220*/ 
     221PARROT_WARN_UNUSED_RESULT 
     222PARROT_CANNOT_RETURN_NULL 
     223PMC * 
     224Parrot_io_local_address(PARROT_INTERP, ARGIN(PMC *sock)) 
     225{ 
     226    ASSERT_ARGS(Parrot_io_local_address) 
     227 
     228    PMC * const addrinfo = VTABLE_clone(interp, PARROT_SOCKET(sock)->local); 
     229 
     230    return addrinfo; 
     231} 
     232 
    110233 
    111234/* 
    112235 
     
    139262 
    140263/* 
    141264 
    142 =item C<INTVAL Parrot_io_connect_unix(PARROT_INTERP, PMC *socket, PMC *r)> 
     265=item C<INTVAL Parrot_io_connect_unix(PARROT_INTERP, PMC *sock, PMC *r)> 
    143266 
    144 Connects C<*io>'s socket to address C<*r>. 
     267Takes the Addrinfo PMC C<*r> and tries to establish a connection. A new socket 
     268PMC will be created because the Addrinfo may contain addresses of multiple 
     269families (IPv4 and IPv6). 
    145270 
    146271=cut 
    147272 
    148273*/ 
    149274 
    150275INTVAL 
    151 Parrot_io_connect_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGIN(PMC *r)) 
     276Parrot_io_connect_unix(PARROT_INTERP, ARGMOD(PMC *sock), ARGIN(PMC *r)) 
    152277{ 
    153278    ASSERT_ARGS(Parrot_io_connect_unix) 
    154     const Parrot_Socket_attributes * const io = PARROT_SOCKET(socket); 
     279    const Parrot_Socket_attributes * const io = PARROT_SOCKET(sock); 
     280    struct addrinfo *res = VTABLE_get_pointer(interp, r); 
     281    struct addrinfo *walk; 
     282    int fd = -1; 
     283    int i = 1; 
    155284 
    156285    if (!r) 
    157286        return -1; 
    158287 
    159     PARROT_SOCKET(socket)->remote = r; 
     288 
     289    for (walk = res; walk != NULL; walk = walk->ai_next) { 
     290        fd = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); 
     291        if (fd < 0) { 
     292            /* Cannot create socket. Not necessarily an error, for example not 
     293             * on FreeBSD, where getaddrinfo() returns IPv6 addresses even 
     294             * when the libc does not offer IPv6 support and thus fails in 
     295             * socket(). */ 
     296            continue; 
     297        } 
     298 
     299        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { 
     300            perror("Error setting SO_REUSEADDR:"); 
     301            continue; 
     302        } 
     303 
     304        /* XXX: this effectively overwrites any previously set sockets. is that alright? */ 
     305        Parrot_io_set_os_handle(interp, sock, fd); 
    160306 
    161307AGAIN: 
    162     if ((connect(io->os_handle, (struct sockaddr *)SOCKADDR_REMOTE(socket), 
    163             sizeof (struct sockaddr_in))) != 0) { 
    164         switch (errno) { 
    165           case EINTR: 
    166             goto AGAIN; 
    167           case EINPROGRESS: 
    168             goto AGAIN; 
    169           case EISCONN: 
    170             return 0; 
    171           default: 
    172             return -1; 
     308        if (connect(fd, walk->ai_addr, walk->ai_addrlen) != 0) { 
     309            switch (errno) { 
     310              case EINTR: 
     311                goto AGAIN; 
     312              case EINPROGRESS: 
     313                goto AGAIN; 
     314              case EISCONN: 
     315                break; 
     316              default: 
     317                close(fd); 
     318                fd = -1; 
     319                continue; 
     320            } 
    173321        } 
     322 
     323        PARROT_SOCKET(sock)->remote = Parrot_pmc_new(interp, enum_class_Sockaddr); 
     324 
     325        VTABLE_set_pointer(interp, PARROT_SOCKET(sock)->remote, walk); 
     326        return 0; 
    174327    } 
    175328 
    176     return 0; 
     329    if (fd == -1) 
     330        return -1; 
    177331} 
    178332 
    179333/* 
    180334 
    181 =item C<INTVAL Parrot_io_bind_unix(PARROT_INTERP, PMC *socket, PMC *sockaddr)> 
     335=item C<INTVAL Parrot_io_bind_unix(PARROT_INTERP, PMC *sock, PMC *sockaddr)> 
    182336 
    183 Binds C<*io>'s socket to the local address and port specified by C<*l>. 
     337Takes the Addrinfo PMC C<*sockaddr> and creates a listening socket. A new 
     338socket needs to be created because C<*sockaddr> may contain addresses of 
     339multiple families (IPv4 and IPv6). An example is binding to "localhost" 
     340which resolves to ::1 and 127.0.0.1. If you are on FreeBSD and have no 
     341IPv6 support, the first attempt to create a socket and bind it would fail. 
    184342 
    185343=cut 
    186344 
    187345*/ 
    188346 
    189347INTVAL 
    190 Parrot_io_bind_unix(PARROT_INTERP, ARGMOD(PMC *socket), ARGMOD(PMC *sockaddr)) 
     348Parrot_io_bind_unix(PARROT_INTERP, ARGMOD(PMC *sock), ARGMOD(PMC *sockaddr)) 
    191349{ 
    192350    ASSERT_ARGS(Parrot_io_bind_unix) 
    193     const Parrot_Socket_attributes * const io = PARROT_SOCKET(socket); 
    194     struct sockaddr_in * saddr; 
     351    const Parrot_Socket_attributes * const io = PARROT_SOCKET(sock); 
     352    struct addrinfo *res = VTABLE_get_pointer(interp, sockaddr); 
     353    struct addrinfo *walk; 
     354    int fd = -1; 
     355    int i = 1; 
    195356 
    196357    if (!sockaddr) 
    197358        return -1; 
    198359 
    199     PARROT_SOCKET(socket)->local = sockaddr; 
     360    for (walk = res; walk != NULL; walk = walk->ai_next) { 
     361        fd = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); 
     362        if (fd < 0) { 
     363            /* Cannot create socket. Not necessarily an error, for example not 
     364             * on FreeBSD, where getaddrinfo() returns IPv6 addresses even 
     365             * when the libc does not offer IPv6 support and thus fails in 
     366             * socket(). */ 
     367            continue; 
     368        } 
    200369 
    201     saddr = SOCKADDR_LOCAL(socket); 
     370        if (walk->ai_family == AF_INET6) { 
     371            if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) == -1) { 
     372                perror("Error setting IPV6_V6ONLY:"); 
     373                continue; 
     374            } 
     375        } 
    202376 
    203     if ((bind(io->os_handle, (struct sockaddr *) saddr, 
    204             sizeof (struct sockaddr_in))) == -1) { 
    205         return -1; 
     377        /* XXX: this effectively overwrites any previously set sockets. is that alright? */ 
     378        Parrot_io_set_os_handle(interp, sock, fd); 
     379 
     380        if (bind(fd, walk->ai_addr, walk->ai_addrlen) != 0) { 
     381            close(fd); 
     382            fd = -1; 
     383            continue; 
     384        } 
     385 
     386        PARROT_SOCKET(sock)->local = Parrot_pmc_new(interp, enum_class_Sockaddr); 
     387 
     388        VTABLE_set_pointer(interp, PARROT_SOCKET(sock)->local, walk); 
     389        return 0; 
    206390    } 
    207391 
    208     return 0; 
     392    if (fd == -1) 
     393        return -1; 
    209394} 
    210395 
    211396/* 
     
    249434    Parrot_Socket_attributes * io = PARROT_SOCKET(socket); 
    250435    PMC * newio   = Parrot_io_new_socket_pmc(interp, 
    251436            PIO_F_SOCKET | PIO_F_READ|PIO_F_WRITE); 
    252     Parrot_Socklen_t    addrlen = sizeof (struct sockaddr_in); 
    253     struct sockaddr_in *saddr; 
     437    Parrot_Socklen_t    addrlen = sizeof (struct sockaddr_storage); 
     438    Parrot_Sockaddr_attributes *remotedata; 
     439    struct sockaddr_storage *saddr; 
    254440    int newsock; 
    255441 
    256442    PARROT_SOCKET(newio)->local  = PARROT_SOCKET(socket)->local; 
     
    263449        return PMCNULL; 
    264450    } 
    265451 
    266     PARROT_SOCKET(newio)->os_handle = newsock; 
     452    /* Set the length for the remote sockaddr PMC so that it can distinguish 
     453     * between sockaddr_in and sockaddr_in6 */ 
     454    remotedata = PARROT_SOCKADDR(PARROT_SOCKET(newio)->remote); 
     455    remotedata->len = addrlen; 
    267456 
    268     /* XXX FIXME: Need to do a getsockname and getpeername here to 
    269      * fill in the sockaddr_in structs for local and peer */ 
     457    PARROT_SOCKET(newio)->os_handle = newsock; 
    270458 
    271     /* Optionally do a gethostyaddr() to resolve remote IP address. 
    272      * This should be based on an option set in the master socket */ 
     459    /* Optionally do a getaddrinfo() to resolve remote IP address. 
     460     * This should be based on an option set in the master socket. 
     461     * 
     462     * XXX: instead of resolving here, we should use the flags for 
     463     * getnameinfo() in the VTABLE get_string of the Sockaddr PMC. 
     464     * At the moment, it uses NI_NUMERICHOST, but when called 
     465     * differently, it will resolve the address. The advantage is 
     466     * that we only resolve when someone actually accesses the 
     467     * name. -- Michael Stapelberg */ 
    273468 
    274469    return newio; 
    275470} 
     
    480675    sa->sin_port = htons(port); 
    481676} 
    482677 
     678static void 
     679get_addrinfo(PARROT_INTERP, ARGIN(PMC * addrinfo), ARGIN(const char *host), int port, int protocol, int family, int passive) 
     680{ 
     681    ASSERT_ARGS(get_addrinfo) 
     682 
     683    struct addrinfo hints; 
     684    struct addrinfo *res; 
     685    /* We need to pass the port as a string (because you could also use a 
     686     * service specification from /etc/services). The highest port is 65535, 
     687     * so we need 5 characters + trailing null-byte. */ 
     688    char portstr[6]; 
     689    int ret; 
     690 
     691    memset(&hints, 0, sizeof(struct addrinfo)); 
     692    hints.ai_protocol = protocol; 
     693    if (passive) 
     694        hints.ai_flags = AI_PASSIVE; 
     695    hints.ai_family = family; 
     696    snprintf(portstr, sizeof(portstr), "%u", port); 
     697 
     698    if ((ret = getaddrinfo(host, portstr, &hints, &res)) != 0) { 
     699        fprintf(stderr, "getaddrinfo failure: %s\n", gai_strerror(ret)); 
     700        return; 
     701    } 
     702 
     703    VTABLE_set_pointer(interp, addrinfo, res); 
     704} 
    483705 
    484706#endif /* PIO_OS_UNIX */ 
    485707 
  • (a) /dev/null vs. (b) b/src/pmc/addrinfo.pmc

    diff --git a/src/pmc/addrinfo.pmc b/src/pmc/addrinfo.pmc
    new file mode 100644
    index 0000000..4618fc0
    a b  
     1/* 
     2Copyright (C) 2008-2009, Parrot Foundation. 
     3$Id$ 
     4 
     5=head1 NAME 
     6 
     7src/pmc/addrinfo.pmc - addrinfo holder 
     8 
     9=head1 DESCRIPTION 
     10 
     11The Addrinfo PMC holds a C pointer to a C<struct addrinfo>. 
     12 
     13 
     14=head2 Vtable Functions 
     15 
     16These are the vtable functions for the Addrinfo class. 
     17 
     18=over 4 
     19 
     20=cut 
     21 
     22*/ 
     23 
     24#ifdef __cplusplus 
     25extern "C" { 
     26#endif 
     27    struct addrinfo; 
     28#ifdef __cplusplus 
     29} 
     30#endif 
     31 
     32/* HEADERIZER HFILE: none */ 
     33/* HEADERIZER BEGIN: static */ 
     34/* HEADERIZER END: static */ 
     35 
     36pmclass Addrinfo auto_attrs { 
     37    ATTR void   *pointer; /* The stored pointer. */ 
     38 
     39/* 
     40 
     41=item C<void init()> 
     42 
     43Initializes the pointer object. 
     44 
     45=cut 
     46 
     47*/ 
     48 
     49    VTABLE void init() { 
     50        Parrot_Addrinfo_attributes * const pdata_struct = 
     51            (Parrot_Addrinfo_attributes *) PMC_data(SELF); 
     52 
     53        pdata_struct->pointer = NULL; 
     54        PObj_custom_destroy_SET(SELF); 
     55    } 
     56 
     57/* 
     58 
     59=item C<void destroy()> 
     60 
     61Destroys the PMC and frees all allocated memory. 
     62 
     63=cut 
     64 
     65*/ 
     66 
     67    VTABLE void destroy() { 
     68        Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); 
     69 
     70        if (data) { 
     71            if (data->pointer) 
     72                freeaddrinfo(data->pointer); 
     73            data->pointer = NULL; 
     74        } 
     75    } 
     76 
     77/* 
     78 
     79=item C<PMC *clone()> 
     80 
     81Creates and returns a clone of the pointer. 
     82 
     83=cut 
     84 
     85*/ 
     86 
     87    VTABLE PMC *clone() { 
     88        PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type); 
     89        memcpy(PARROT_ADDRINFO(dest)->pointer, PARROT_ADDRINFO(SELF)->pointer, 
     90                sizeof (struct sockaddr_storage)); 
     91        return dest; 
     92    } 
     93 
     94/* 
     95 
     96=item C<void *get_pointer()> 
     97 
     98Returns the pointer. 
     99 
     100=cut 
     101 
     102*/ 
     103 
     104    VTABLE void *get_pointer() { 
     105        Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); 
     106        return data->pointer; 
     107    } 
     108 
     109/* 
     110 
     111=item C<void set_pointer(void *)> 
     112 
     113Sets the pointer. 
     114 
     115=cut 
     116 
     117*/ 
     118 
     119    VTABLE void set_pointer(void *value) { 
     120        Parrot_Addrinfo_attributes * const data = PARROT_ADDRINFO(SELF); 
     121        data->pointer = value; 
     122    } 
     123 
     124} 
     125 
     126/* 
     127 
     128=back 
     129 
     130=cut 
     131 
     132*/ 
     133 
     134/* 
     135 * Local variables: 
     136 *   c-file-style: "parrot" 
     137 * End: 
     138 * vim: expandtab shiftwidth=4: 
     139 */ 
     140 
  • src/pmc/sockaddr.pmc

    diff --git a/src/pmc/sockaddr.pmc b/src/pmc/sockaddr.pmc
    index 6161557..dc1117d 100644
    a b  
    44 
    55=head1 NAME 
    66 
    7 src/pmc/sockaddr.pmc - sockaddr_in holder 
     7src/pmc/sockaddr.pmc - sockaddr_in/sockaddr_in6 holder 
    88 
    99=head1 DESCRIPTION 
    1010 
    11 The Sockaddr PMC holds raw c-pointer to sockaddr_in 
     11The Sockaddr PMC holds a C<sockaddr_in> (IPv4) or C<sockaddr_in6> (IPv6) and 
     12saves its length (to distinguish C<sockaddr_in> and C<sockaddr_in6>). 
    1213 
    1314 
    1415=head2 Vtable Functions 
     
    2425#ifdef __cplusplus 
    2526extern "C" { 
    2627#endif 
    27     struct sockaddr_in; 
     28    struct sockaddr_storage; 
    2829#ifdef __cplusplus 
    2930} 
    3031#endif 
     
    3536 
    3637pmclass Sockaddr auto_attrs { 
    3738    ATTR void   *pointer; /* The stored pointer. */ 
     39    ATTR INTVAL len; /* Length of the contents of the sockaddr_storage */ 
    3840 
    3941/* 
    4042 
    4143=item C<void init()> 
    4244 
    43 Initializes the pointer object. 
     45Initializes the PMC by allocating a C<sockaddr_storage>. 
    4446 
    4547=cut 
    4648 
     
    5153            (Parrot_Sockaddr_attributes *) PMC_data(SELF); 
    5254 
    5355        pdata_struct->pointer = mem_gc_allocate_zeroed_typed(INTERP, 
    54                 struct sockaddr_in); 
     56                struct sockaddr_storage); 
    5557        PObj_custom_destroy_SET(SELF); 
    5658    } 
    5759 
     
    7880 
    7981=item C<PMC *clone()> 
    8082 
    81 Creates and returns a clone of the pointer. 
     83Creates a new Sockaddr PMC with the same contents and length as the current 
     84one. 
    8285 
    8386=cut 
    8487 
     
    8689 
    8790    VTABLE PMC *clone() { 
    8891        PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type); 
     92 
    8993        memcpy(PARROT_SOCKADDR(dest)->pointer, PARROT_SOCKADDR(SELF)->pointer, 
    90                 sizeof (struct sockaddr_in)); 
     94                sizeof (struct sockaddr_storage)); 
     95        PARROT_SOCKADDR(dest)->len = PARROT_SOCKADDR(SELF)->len; 
    9196        return dest; 
    9297    } 
    9398 
     
    95100 
    96101=item C<void *get_pointer()> 
    97102 
    98 Returns the pointer. 
     103Returns a pointer to the C<sockaddr_in> or C<sockaddr_in6>. 
    99104 
    100105=cut 
    101106 
     
    108113 
    109114/* 
    110115 
    111 =item C<void set_pointer(void *)> 
     116=item C<STRING *get_string()> 
    112117 
    113 Sets the pointer. 
     118Returns the string representation of this sockaddr by calling C<getnameinfo(3)>. 
    114119 
    115120=cut 
    116121 
    117122*/ 
     123    VTABLE STRING *get_string() { 
     124        Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); 
     125        if (!data->pointer) 
     126            return Parrot_sprintf_c(interp, "(?)"); 
     127 
     128        struct sockaddr_storage *addr = data->pointer; 
     129        /* TODO: get hostname, not only numeric */ 
     130        char buf[INET6_ADDRSTRLEN+1]; 
     131        getnameinfo((struct sockaddr_storage*)data->pointer, data->len, buf, 
     132                sizeof(buf), NULL, 0, NI_NUMERICHOST); 
     133        return Parrot_str_new(interp, buf, 0); 
     134    } 
     135 
    118136 
    119137/* 
     138 
     139=item C<void set_pointer(void *)> 
     140 
     141Copies a C<sockaddr_in> or C<sockaddr_in6> from the given C<addrinfo> pointer 
     142(by accessing its C<ai_addr> and C<ai_addrlen> members). 
     143 
     144=cut 
     145 
     146*/ 
     147 
    120148    VTABLE void set_pointer(void *value) { 
    121149        Parrot_Sockaddr_attributes * const data = PARROT_SOCKADDR(SELF); 
    122         return data->pointer; 
     150 
     151        struct addrinfo *walk = value; 
     152        memcpy(data->pointer, walk->ai_addr, walk->ai_addrlen); 
     153        data->len = walk->ai_addrlen; 
    123154    } 
    124 */ 
    125155 
    126156} 
    127157 
  • src/pmc/socket.pmc

    diff --git a/src/pmc/socket.pmc b/src/pmc/socket.pmc
    index 1c8971a..cd3a61e 100644
    a b  
    177177 
    178178/* 
    179179 
     180=item C<getaddrinfo(STRING * address, INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive)> 
     181 
     182C<getaddrinfo> returns an object representing the result of the 
     183C<getaddrinfo(3)> function which consists of multiple socket addresses, 
     184including family and protocol. It can be passed to C<bind()> or C<connect()>. 
     185 
     186=cut 
     187 
     188*/ 
     189    METHOD getaddrinfo(STRING * address, INTVAL port, INTVAL protocol, INTVAL family, INTVAL passive) { 
     190        PMC * res = Parrot_io_getaddrinfo(INTERP, address, port, protocol, family, passive); 
     191        RETURN(PMC * res); 
     192    } 
     193 
     194/* 
     195 
     196=item C<remote_address()> 
     197 
     198C<remote_address> returns the remote address of this socket PMC. 
     199 
     200=cut 
     201 
     202*/ 
     203    METHOD remote_address() { 
     204        PMC * res = Parrot_io_remote_address(INTERP, SELF); 
     205        RETURN(PMC * res); 
     206    } 
     207 
     208/* 
     209 
     210=item C<local_address()> 
     211 
     212C<local_address> returns the local address of this socket PMC. 
     213 
     214=cut 
     215 
     216*/ 
     217    METHOD local_address() { 
     218        PMC * res = Parrot_io_local_address(INTERP, SELF); 
     219        RETURN(PMC * res); 
     220    } 
     221 
     222/* 
     223 
    180224=item C<connect(PMC * address)> 
    181225 
    182226Connects a socket object to an address. 
     
    265309=item C<bind(PMC *host)> 
    266310 
    267311C<bind> binds a socket object to the port and address specified by an 
    268 address object (the packed result of C<sockaddr>). 
     312address object (the result of C<getaddrinfo>). 
    269313 
    270314The asynchronous version takes an additional final PMC callback 
    271315argument, and only returns a status object. When the bind operation is