Annotation of embedaddon/strongswan/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006-2013 Tobias Brunner
        !             3:  * Copyright (C) 2006 Daniel Roethlisberger
        !             4:  * Copyright (C) 2005-2010 Martin Willi
        !             5:  * Copyright (C) 2005 Jan Hutter
        !             6:  * HSR Hochschule fuer Technik Rapperswil
        !             7:  * Copyright (C) 2010 revosec AG
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or modify it
        !            10:  * under the terms of the GNU General Public License as published by the
        !            11:  * Free Software Foundation; either version 2 of the License, or (at your
        !            12:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful, but
        !            15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            16:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            17:  * for more details.
        !            18:  */
        !            19: 
        !            20: /* for struct in6_pktinfo */
        !            21: #define _GNU_SOURCE
        !            22: 
        !            23: #include "socket_dynamic_socket.h"
        !            24: 
        !            25: #include <sys/types.h>
        !            26: #include <sys/socket.h>
        !            27: #include <string.h>
        !            28: #include <errno.h>
        !            29: #include <unistd.h>
        !            30: #include <stdlib.h>
        !            31: #include <fcntl.h>
        !            32: #include <sys/ioctl.h>
        !            33: #include <netinet/in_systm.h>
        !            34: #include <netinet/in.h>
        !            35: #include <netinet/ip.h>
        !            36: #include <netinet/udp.h>
        !            37: #include <net/if.h>
        !            38: 
        !            39: #include <daemon.h>
        !            40: #include <threading/thread.h>
        !            41: #include <threading/rwlock.h>
        !            42: #include <collections/hashtable.h>
        !            43: 
        !            44: /* these are not defined on some platforms */
        !            45: #ifndef SOL_IP
        !            46: #define SOL_IP IPPROTO_IP
        !            47: #endif
        !            48: #ifndef SOL_IPV6
        !            49: #define SOL_IPV6 IPPROTO_IPV6
        !            50: #endif
        !            51: 
        !            52: /* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that
        !            53:  * previously defined IPV6_PKTINFO */
        !            54: #ifndef IPV6_RECVPKTINFO
        !            55: #define IPV6_RECVPKTINFO IPV6_PKTINFO
        !            56: #endif
        !            57: 
        !            58: typedef struct private_socket_dynamic_socket_t private_socket_dynamic_socket_t;
        !            59: typedef struct dynsock_t dynsock_t;
        !            60: 
        !            61: /**
        !            62:  * Private data of an socket_t object
        !            63:  */
        !            64: struct private_socket_dynamic_socket_t {
        !            65: 
        !            66:        /**
        !            67:         * public functions
        !            68:         */
        !            69:        socket_dynamic_socket_t public;
        !            70: 
        !            71:        /**
        !            72:         * Hashtable of bound sockets
        !            73:         */
        !            74:        hashtable_t *sockets;
        !            75: 
        !            76:        /**
        !            77:         * Lock for sockets hashtable
        !            78:         */
        !            79:        rwlock_t *lock;
        !            80: 
        !            81:        /**
        !            82:         * Notification pipe to signal receiver
        !            83:         */
        !            84:        int notify[2];
        !            85: 
        !            86:        /**
        !            87:         * Maximum packet size to receive
        !            88:         */
        !            89:        int max_packet;
        !            90: };
        !            91: 
        !            92: /**
        !            93:  * Struct for a dynamically allocated socket
        !            94:  */
        !            95: struct dynsock_t {
        !            96: 
        !            97:        /**
        !            98:         * File descriptor of socket
        !            99:         */
        !           100:        int fd;
        !           101: 
        !           102:        /**
        !           103:         * Address family
        !           104:         */
        !           105:        int family;
        !           106: 
        !           107:        /**
        !           108:         * Bound source port
        !           109:         */
        !           110:        uint16_t port;
        !           111: };
        !           112: 
        !           113: /**
        !           114:  * Hash function for hashtable
        !           115:  */
        !           116: static u_int hash(dynsock_t *key)
        !           117: {
        !           118:        return (key->family << 16) | key->port;
        !           119: }
        !           120: 
        !           121: /**
        !           122:  * Equals function for hashtable
        !           123:  */
        !           124: static bool equals(dynsock_t *a, dynsock_t *b)
        !           125: {
        !           126:        return a->family == b->family && a->port == b->port;
        !           127: }
        !           128: 
        !           129: /**
        !           130:  * Create a fd_set from all bound sockets
        !           131:  */
        !           132: static int build_fds(private_socket_dynamic_socket_t *this, fd_set *fds)
        !           133: {
        !           134:        enumerator_t *enumerator;
        !           135:        dynsock_t *key, *value;
        !           136:        int maxfd;
        !           137: 
        !           138:        FD_ZERO(fds);
        !           139:        FD_SET(this->notify[0], fds);
        !           140:        maxfd = this->notify[0];
        !           141: 
        !           142:        this->lock->read_lock(this->lock);
        !           143:        enumerator = this->sockets->create_enumerator(this->sockets);
        !           144:        while (enumerator->enumerate(enumerator, &key, &value))
        !           145:        {
        !           146:                FD_SET(value->fd, fds);
        !           147:                maxfd = max(maxfd, value->fd);
        !           148:        }
        !           149:        enumerator->destroy(enumerator);
        !           150:        this->lock->unlock(this->lock);
        !           151: 
        !           152:        return maxfd + 1;
        !           153: }
        !           154: 
        !           155: /**
        !           156:  * Find the socket select()ed
        !           157:  */
        !           158: static dynsock_t* scan_fds(private_socket_dynamic_socket_t *this, fd_set *fds)
        !           159: {
        !           160:        enumerator_t *enumerator;
        !           161:        dynsock_t *key, *value, *selected = NULL;
        !           162: 
        !           163:        this->lock->read_lock(this->lock);
        !           164:        enumerator = this->sockets->create_enumerator(this->sockets);
        !           165:        while (enumerator->enumerate(enumerator, &key, &value))
        !           166:        {
        !           167:                if (FD_ISSET(value->fd, fds))
        !           168:                {
        !           169:                        selected = value;
        !           170:                        break;
        !           171:                }
        !           172:        }
        !           173:        enumerator->destroy(enumerator);
        !           174:        this->lock->unlock(this->lock);
        !           175: 
        !           176:        return selected;
        !           177: }
        !           178: 
        !           179: /**
        !           180:  * Receive a packet from a given socket fd
        !           181:  */
        !           182: static packet_t *receive_packet(private_socket_dynamic_socket_t *this,
        !           183:                                                                dynsock_t *skt)
        !           184: {
        !           185:        host_t *source = NULL, *dest = NULL;
        !           186:        ssize_t len;
        !           187:        char buffer[this->max_packet];
        !           188:        chunk_t data;
        !           189:        packet_t *packet;
        !           190:        struct msghdr msg;
        !           191:        struct cmsghdr *cmsgptr;
        !           192:        struct iovec iov;
        !           193:        char ancillary[64];
        !           194:        union {
        !           195:                struct sockaddr_in in4;
        !           196:                struct sockaddr_in6 in6;
        !           197:        } src;
        !           198: 
        !           199:        msg.msg_name = &src;
        !           200:        msg.msg_namelen = sizeof(src);
        !           201:        iov.iov_base = buffer;
        !           202:        iov.iov_len = this->max_packet;
        !           203:        msg.msg_iov = &iov;
        !           204:        msg.msg_iovlen = 1;
        !           205:        msg.msg_control = ancillary;
        !           206:        msg.msg_controllen = sizeof(ancillary);
        !           207:        msg.msg_flags = 0;
        !           208:        len = recvmsg(skt->fd, &msg, 0);
        !           209:        if (len < 0)
        !           210:        {
        !           211:                DBG1(DBG_NET, "error reading socket: %s", strerror(errno));
        !           212:                return NULL;
        !           213:        }
        !           214:        if (msg.msg_flags & MSG_TRUNC)
        !           215:        {
        !           216:                DBG1(DBG_NET, "receive buffer too small, packet discarded");
        !           217:                return NULL;
        !           218:        }
        !           219:        DBG3(DBG_NET, "received packet %b", buffer, (u_int)len);
        !           220: 
        !           221:        /* read ancillary data to get destination address */
        !           222:        for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
        !           223:                 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
        !           224:        {
        !           225:                if (cmsgptr->cmsg_len == 0)
        !           226:                {
        !           227:                        DBG1(DBG_NET, "error reading ancillary data");
        !           228:                        return NULL;
        !           229:                }
        !           230: 
        !           231:                if (cmsgptr->cmsg_level == SOL_IPV6 &&
        !           232:                        cmsgptr->cmsg_type == IPV6_PKTINFO)
        !           233:                {
        !           234:                        struct in6_pktinfo *pktinfo;
        !           235:                        struct sockaddr_in6 dst;
        !           236: 
        !           237:                        pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr);
        !           238:                        memset(&dst, 0, sizeof(dst));
        !           239:                        memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr));
        !           240:                        dst.sin6_family = AF_INET6;
        !           241:                        dst.sin6_port = htons(skt->port);
        !           242:                        dest = host_create_from_sockaddr((sockaddr_t*)&dst);
        !           243:                }
        !           244:                if (cmsgptr->cmsg_level == SOL_IP &&
        !           245:                        cmsgptr->cmsg_type == IP_PKTINFO)
        !           246:                {
        !           247:                        struct in_pktinfo *pktinfo;
        !           248:                        struct sockaddr_in dst;
        !           249: 
        !           250:                        pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgptr);
        !           251:                        memset(&dst, 0, sizeof(dst));
        !           252:                        memcpy(&dst.sin_addr, &pktinfo->ipi_addr, sizeof(dst.sin_addr));
        !           253: 
        !           254:                        dst.sin_family = AF_INET;
        !           255:                        dst.sin_port = htons(skt->port);
        !           256:                        dest = host_create_from_sockaddr((sockaddr_t*)&dst);
        !           257:                }
        !           258:                if (dest)
        !           259:                {
        !           260:                        break;
        !           261:                }
        !           262:        }
        !           263:        if (dest == NULL)
        !           264:        {
        !           265:                DBG1(DBG_NET, "error reading IP header");
        !           266:                return NULL;
        !           267:        }
        !           268:        source = host_create_from_sockaddr((sockaddr_t*)&src);
        !           269:        DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest);
        !           270:        data = chunk_create(buffer, len);
        !           271: 
        !           272:        packet = packet_create();
        !           273:        packet->set_source(packet, source);
        !           274:        packet->set_destination(packet, dest);
        !           275:        packet->set_data(packet, chunk_clone(data));
        !           276:        return packet;
        !           277: }
        !           278: 
        !           279: METHOD(socket_t, receiver, status_t,
        !           280:        private_socket_dynamic_socket_t *this, packet_t **packet)
        !           281: {
        !           282:        dynsock_t *selected;
        !           283:        packet_t *pkt;
        !           284:        bool oldstate;
        !           285:        fd_set fds;
        !           286:        int maxfd;
        !           287: 
        !           288:        while (TRUE)
        !           289:        {
        !           290:                maxfd = build_fds(this, &fds);
        !           291: 
        !           292:                DBG2(DBG_NET, "waiting for data on sockets");
        !           293:                oldstate = thread_cancelability(TRUE);
        !           294:                if (select(maxfd, &fds, NULL, NULL, NULL) <= 0)
        !           295:                {
        !           296:                        thread_cancelability(oldstate);
        !           297:                        return FAILED;
        !           298:                }
        !           299:                thread_cancelability(oldstate);
        !           300: 
        !           301:                if (FD_ISSET(this->notify[0], &fds))
        !           302:                {       /* got notified, read garbage, rebuild fdset */
        !           303:                        char buf[1];
        !           304: 
        !           305:                        ignore_result(read(this->notify[0], buf, sizeof(buf)));
        !           306:                        DBG2(DBG_NET, "rebuilding fdset due to newly bound ports");
        !           307:                        continue;
        !           308:                }
        !           309:                selected = scan_fds(this, &fds);
        !           310:                if (selected)
        !           311:                {
        !           312:                        break;
        !           313:                }
        !           314:        }
        !           315:        pkt = receive_packet(this, selected);
        !           316:        if (pkt)
        !           317:        {
        !           318:                *packet = pkt;
        !           319:                return SUCCESS;
        !           320:        }
        !           321:        return FAILED;
        !           322: }
        !           323: 
        !           324: /**
        !           325:  * Get the port allocated dynamically using bind()
        !           326:  */
        !           327: static bool get_dynamic_port(int fd, int family, uint16_t *port)
        !           328: {
        !           329:        union {
        !           330:                struct sockaddr_storage ss;
        !           331:                struct sockaddr s;
        !           332:                struct sockaddr_in sin;
        !           333:                struct sockaddr_in6 sin6;
        !           334:        } addr;
        !           335:        socklen_t addrlen;
        !           336: 
        !           337:        addrlen = sizeof(addr);
        !           338:        if (getsockname(fd, &addr.s, &addrlen) != 0)
        !           339:        {
        !           340:                DBG1(DBG_NET, "unable to getsockname: %s", strerror(errno));
        !           341:                return FALSE;
        !           342:        }
        !           343:        switch (family)
        !           344:        {
        !           345:                case AF_INET:
        !           346:                        if (addrlen != sizeof(addr.sin) || addr.sin.sin_family != family)
        !           347:                        {
        !           348:                                break;
        !           349:                        }
        !           350:                        *port = ntohs(addr.sin.sin_port);
        !           351:                        return TRUE;
        !           352:                case AF_INET6:
        !           353:                        if (addrlen != sizeof(addr.sin6) || addr.sin6.sin6_family != family)
        !           354:                        {
        !           355:                                break;
        !           356:                        }
        !           357:                        *port = ntohs(addr.sin6.sin6_port);
        !           358:                        return TRUE;
        !           359:                default:
        !           360:                        return FALSE;
        !           361:        }
        !           362:        DBG1(DBG_NET, "received invalid getsockname() result");
        !           363:        return FALSE;
        !           364: }
        !           365: 
        !           366: /**
        !           367:  * open a socket to send and receive packets
        !           368:  */
        !           369: static int open_socket(private_socket_dynamic_socket_t *this,
        !           370:                                           int family, uint16_t *port)
        !           371: {
        !           372:        union {
        !           373:                struct sockaddr_storage ss;
        !           374:                struct sockaddr s;
        !           375:                struct sockaddr_in sin;
        !           376:                struct sockaddr_in6 sin6;
        !           377:        } addr;
        !           378:        int on = TRUE;
        !           379:        socklen_t addrlen;
        !           380:        u_int sol, pktinfo = 0;
        !           381:        int fd;
        !           382: 
        !           383:        memset(&addr, 0, sizeof(addr));
        !           384:        /* precalculate constants depending on address family */
        !           385:        switch (family)
        !           386:        {
        !           387:                case AF_INET:
        !           388:                        addr.sin.sin_family = AF_INET;
        !           389:                        addr.sin.sin_addr.s_addr = INADDR_ANY;
        !           390:                        addr.sin.sin_port = htons(*port);
        !           391:                        addrlen = sizeof(addr.sin);
        !           392:                        sol = SOL_IP;
        !           393:                        pktinfo = IP_PKTINFO;
        !           394:                        break;
        !           395:                case AF_INET6:
        !           396:                        addr.sin6.sin6_family = AF_INET6;
        !           397:                        memset(&addr.sin6.sin6_addr, 0, sizeof(addr.sin6.sin6_addr));
        !           398:                        addr.sin6.sin6_port = htons(*port);
        !           399:                        addrlen = sizeof(addr.sin6);
        !           400:                        sol = SOL_IPV6;
        !           401:                        pktinfo = IPV6_RECVPKTINFO;
        !           402:                        break;
        !           403:                default:
        !           404:                        return 0;
        !           405:        }
        !           406: 
        !           407:        fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
        !           408:        if (fd < 0)
        !           409:        {
        !           410:                DBG1(DBG_NET, "could not open socket: %s", strerror(errno));
        !           411:                return 0;
        !           412:        }
        !           413:        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
        !           414:        {
        !           415:                DBG1(DBG_NET, "unable to set SO_REUSEADDR on socket: %s", strerror(errno));
        !           416:                close(fd);
        !           417:                return 0;
        !           418:        }
        !           419: 
        !           420:        if (bind(fd, &addr.s, addrlen) < 0)
        !           421:        {
        !           422:                DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno));
        !           423:                close(fd);
        !           424:                return 0;
        !           425:        }
        !           426:        if (*port == 0 && !get_dynamic_port(fd, family, port))
        !           427:        {
        !           428:                close(fd);
        !           429:                return 0;
        !           430:        }
        !           431: 
        !           432:        /* get additional packet info on receive */
        !           433:        if (setsockopt(fd, sol, pktinfo, &on, sizeof(on)) < 0)
        !           434:        {
        !           435:                DBG1(DBG_NET, "unable to set IP_PKTINFO on socket: %s", strerror(errno));
        !           436:                close(fd);
        !           437:                return 0;
        !           438:        }
        !           439: 
        !           440:        if (!charon->kernel->bypass_socket(charon->kernel, fd, family))
        !           441:        {
        !           442:                DBG1(DBG_NET, "installing IKE bypass policy failed");
        !           443:        }
        !           444: 
        !           445:        /* enable UDP decapsulation on each socket */
        !           446:        if (!charon->kernel->enable_udp_decap(charon->kernel, fd, family, *port))
        !           447:        {
        !           448:                DBG1(DBG_NET, "enabling UDP decapsulation for %s on port %d failed",
        !           449:                         family == AF_INET ? "IPv4" : "IPv6", *port);
        !           450:        }
        !           451: 
        !           452:        return fd;
        !           453: }
        !           454: 
        !           455: /**
        !           456:  * Get the first usable socket for an address family
        !           457:  */
        !           458: static dynsock_t *get_any_socket(private_socket_dynamic_socket_t *this,
        !           459:                                                                 int family)
        !           460: {
        !           461:        dynsock_t *key, *value, *found = NULL;
        !           462:        enumerator_t *enumerator;
        !           463: 
        !           464:        this->lock->read_lock(this->lock);
        !           465:        enumerator = this->sockets->create_enumerator(this->sockets);
        !           466:        while (enumerator->enumerate(enumerator, &key, &value))
        !           467:        {
        !           468:                if (value->family == family)
        !           469:                {
        !           470:                        found = value;
        !           471:                        break;
        !           472:                }
        !           473:        }
        !           474:        enumerator->destroy(enumerator);
        !           475:        this->lock->unlock(this->lock);
        !           476: 
        !           477:        return found;
        !           478: }
        !           479: 
        !           480: /**
        !           481:  * Find/Create a socket to send from host
        !           482:  */
        !           483: static dynsock_t *find_socket(private_socket_dynamic_socket_t *this,
        !           484:                                                          int family, uint16_t port)
        !           485: {
        !           486:        dynsock_t *skt, lookup = {
        !           487:                .family = family,
        !           488:                .port = port,
        !           489:        };
        !           490:        char buf[] = {0x01};
        !           491:        int fd;
        !           492: 
        !           493:        this->lock->read_lock(this->lock);
        !           494:        skt = this->sockets->get(this->sockets, &lookup);
        !           495:        this->lock->unlock(this->lock);
        !           496:        if (skt)
        !           497:        {
        !           498:                return skt;
        !           499:        }
        !           500:        if (!port)
        !           501:        {
        !           502:                skt = get_any_socket(this, family);
        !           503:                if (skt)
        !           504:                {
        !           505:                        return skt;
        !           506:                }
        !           507:        }
        !           508:        fd = open_socket(this, family, &port);
        !           509:        if (!fd)
        !           510:        {
        !           511:                return NULL;
        !           512:        }
        !           513:        INIT(skt,
        !           514:                .family = family,
        !           515:                .port = port,
        !           516:                .fd = fd,
        !           517:        );
        !           518:        this->lock->write_lock(this->lock);
        !           519:        this->sockets->put(this->sockets, skt, skt);
        !           520:        this->lock->unlock(this->lock);
        !           521:        /* notify receiver thread to reread socket list */
        !           522:        ignore_result(write(this->notify[1], buf, sizeof(buf)));
        !           523: 
        !           524:        return skt;
        !           525: }
        !           526: 
        !           527: /**
        !           528:  * Generic function to send a message.
        !           529:  */
        !           530: static ssize_t send_msg_generic(int skt, struct msghdr *msg)
        !           531: {
        !           532:        return sendmsg(skt, msg, 0);
        !           533: }
        !           534: 
        !           535: /**
        !           536:  * Send a message with the IPv4 source address set.
        !           537:  */
        !           538: static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src)
        !           539: {
        !           540:        char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {};
        !           541:        struct cmsghdr *cmsg;
        !           542:        struct in_addr *addr;
        !           543:        struct in_pktinfo *pktinfo;
        !           544:        struct sockaddr_in *sin;
        !           545: 
        !           546:        msg->msg_control = buf;
        !           547:        msg->msg_controllen = sizeof(buf);
        !           548:        cmsg = CMSG_FIRSTHDR(msg);
        !           549:        cmsg->cmsg_level = SOL_IP;
        !           550:        cmsg->cmsg_type = IP_PKTINFO;
        !           551:        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
        !           552: 
        !           553:        pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
        !           554:        addr = &pktinfo->ipi_spec_dst;
        !           555: 
        !           556:        sin = (struct sockaddr_in*)src->get_sockaddr(src);
        !           557:        memcpy(addr, &sin->sin_addr, sizeof(struct in_addr));
        !           558:        return send_msg_generic(skt, msg);
        !           559: }
        !           560: 
        !           561: /**
        !           562:  * Send a message with the IPv6 source address set.
        !           563:  */
        !           564: static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src)
        !           565: {
        !           566:        char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {};
        !           567:        struct cmsghdr *cmsg;
        !           568:        struct in6_pktinfo *pktinfo;
        !           569:        struct sockaddr_in6 *sin;
        !           570: 
        !           571:        msg->msg_control = buf;
        !           572:        msg->msg_controllen = sizeof(buf);
        !           573:        cmsg = CMSG_FIRSTHDR(msg);
        !           574:        cmsg->cmsg_level = SOL_IPV6;
        !           575:        cmsg->cmsg_type = IPV6_PKTINFO;
        !           576:        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
        !           577:        pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
        !           578:        sin = (struct sockaddr_in6*)src->get_sockaddr(src);
        !           579:        memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr));
        !           580:        return send_msg_generic(skt, msg);
        !           581: }
        !           582: 
        !           583: METHOD(socket_t, sender, status_t,
        !           584:        private_socket_dynamic_socket_t *this, packet_t *packet)
        !           585: {
        !           586:        dynsock_t *skt;
        !           587:        host_t *src, *dst;
        !           588:        int family;
        !           589:        ssize_t len;
        !           590:        chunk_t data;
        !           591:        struct msghdr msg;
        !           592:        struct iovec iov;
        !           593: 
        !           594:        src = packet->get_source(packet);
        !           595:        dst = packet->get_destination(packet);
        !           596:        family = src->get_family(src);
        !           597:        skt = find_socket(this, family, src->get_port(src));
        !           598:        if (!skt)
        !           599:        {
        !           600:                return FAILED;
        !           601:        }
        !           602: 
        !           603:        data = packet->get_data(packet);
        !           604:        DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst);
        !           605: 
        !           606:        memset(&msg, 0, sizeof(struct msghdr));
        !           607:        msg.msg_name = dst->get_sockaddr(dst);;
        !           608:        msg.msg_namelen = *dst->get_sockaddr_len(dst);
        !           609:        iov.iov_base = data.ptr;
        !           610:        iov.iov_len = data.len;
        !           611:        msg.msg_iov = &iov;
        !           612:        msg.msg_iovlen = 1;
        !           613:        msg.msg_flags = 0;
        !           614: 
        !           615:        if (!src->is_anyaddr(src))
        !           616:        {
        !           617:                if (family == AF_INET)
        !           618:                {
        !           619:                        len = send_msg_v4(skt->fd, &msg, src);
        !           620:                }
        !           621:                else
        !           622:                {
        !           623:                        len = send_msg_v6(skt->fd, &msg, src);
        !           624:                }
        !           625:        }
        !           626:        else
        !           627:        {
        !           628:                len = send_msg_generic(skt->fd, &msg);
        !           629:        }
        !           630: 
        !           631:        if (len != data.len)
        !           632:        {
        !           633:                DBG1(DBG_NET, "error writing to socket: %s", strerror(errno));
        !           634:                return FAILED;
        !           635:        }
        !           636:        return SUCCESS;
        !           637: }
        !           638: 
        !           639: METHOD(socket_t, get_port, uint16_t,
        !           640:        private_socket_dynamic_socket_t *this, bool nat_t)
        !           641: {
        !           642:        /* we return 0 here for users that have no explicit port configured, the
        !           643:         * sender will default to the default port in this case */
        !           644:        return 0;
        !           645: }
        !           646: 
        !           647: METHOD(socket_t, supported_families, socket_family_t,
        !           648:        private_socket_dynamic_socket_t *this)
        !           649: {
        !           650:        /* we could return only the families of the opened sockets, but it could
        !           651:         * be that both families are supported even if no socket is yet open */
        !           652:        return SOCKET_FAMILY_BOTH;
        !           653: }
        !           654: 
        !           655: METHOD(socket_t, destroy, void,
        !           656:        private_socket_dynamic_socket_t *this)
        !           657: {
        !           658:        enumerator_t *enumerator;
        !           659:        dynsock_t *key, *value;
        !           660: 
        !           661:        enumerator = this->sockets->create_enumerator(this->sockets);
        !           662:        while (enumerator->enumerate(enumerator, &key, &value))
        !           663:        {
        !           664:                close(value->fd);
        !           665:                free(value);
        !           666:        }
        !           667:        enumerator->destroy(enumerator);
        !           668:        this->sockets->destroy(this->sockets);
        !           669:        this->lock->destroy(this->lock);
        !           670: 
        !           671:        close(this->notify[0]);
        !           672:        close(this->notify[1]);
        !           673:        free(this);
        !           674: }
        !           675: 
        !           676: /*
        !           677:  * See header for description
        !           678:  */
        !           679: socket_dynamic_socket_t *socket_dynamic_socket_create()
        !           680: {
        !           681:        private_socket_dynamic_socket_t *this;
        !           682: 
        !           683:        INIT(this,
        !           684:                .public = {
        !           685:                        .socket = {
        !           686:                                .send = _sender,
        !           687:                                .receive = _receiver,
        !           688:                                .get_port = _get_port,
        !           689:                                .supported_families = _supported_families,
        !           690:                                .destroy = _destroy,
        !           691:                        },
        !           692:                },
        !           693:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        !           694:                .max_packet = lib->settings->get_int(lib->settings,
        !           695:                                                                "%s.max_packet", PACKET_MAX_DEFAULT, lib->ns),
        !           696:        );
        !           697: 
        !           698:        if (pipe(this->notify) != 0)
        !           699:        {
        !           700:                DBG1(DBG_NET, "creating notify pipe for dynamic socket failed");
        !           701:                free(this);
        !           702:                return NULL;
        !           703:        }
        !           704: 
        !           705:        this->sockets = hashtable_create((void*)hash, (void*)equals, 8);
        !           706: 
        !           707:        return &this->public;
        !           708: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>