root/common/trunk/src/net_udp.c @ 3932

Revision 3932, 28.7 KB (checked in by ucacsva, 8 years ago)

commit_msg_15Nov2006.txt

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:     net_udp.c
3 * AUTHOR:   Colin Perkins
4 * MODIFIED: Orion Hodson, Piers O'Hanlon, Kristian Hasler
5 *
6 * Copyright (c) 1998-2000 University College London
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the Computer Science
20 *      Department at University College London
21 * 4. Neither the name of the University nor of the Department may be used
22 *    to endorse or promote products derived from this software without
23 *    specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/* If this machine supports IPv6 the symbol HAVE_IPv6 should */
38/* be defined in either config_unix.h or config_win32.h. The */
39/* appropriate system header files should also be included   */
40/* by those files.                                           */
41
42#include "config_unix.h"
43#include "config_win32.h"
44#include "debug.h"
45#include "memory.h"
46#include "inet_pton.h"
47#include "inet_ntop.h"
48#include "vsnprintf.h"
49#include "net_udp.h"
50
51#ifdef NEED_ADDRINFO_H
52#include "addrinfo.h"
53#endif
54
55#define IPv4    4
56#define IPv6    6
57
58#ifdef WIN2K_IPV6
59const struct    in6_addr        in6addr_any = {IN6ADDR_ANY_INIT};
60#endif
61
62#ifdef WINXP_IPV6
63const struct    in6_addr        in6addr_any = {IN6ADDR_ANY_INIT};
64#endif
65
66/* This is pretty nasty but it's the simplest way to get round */
67/* the Detexis bug that means their MUSICA IPv6 stack uses     */
68/* IPPROTO_IP instead of IPPROTO_IPV6 in setsockopt calls      */
69/* We also need to define in6addr_any */
70#ifdef  MUSICA_IPV6
71#define IPPROTO_IPV6    IPPROTO_IP
72struct  in6_addr        in6addr_any = {IN6ADDR_ANY_INIT};
73
74/* These DEF's are required as MUSICA's winsock6.h causes a clash with some of the
75 * standard ws2tcpip.h definitions (eg struct in_addr6).
76 * Note: winsock6.h defines AF_INET6 as 24 NOT 23 as in winsock2.h - I have left it
77 * set to the MUSICA value as this is used in some of their function calls.
78 */
79//#define AF_INET6        23
80#define IP_MULTICAST_LOOP      11 /*set/get IP multicast loopback */
81#define IP_MULTICAST_IF         9 /* set/get IP multicast i/f  */
82#define IP_MULTICAST_TTL       10 /* set/get IP multicast ttl */
83#define IP_MULTICAST_LOOP      11 /*set/get IP multicast loopback */
84#define IP_ADD_MEMBERSHIP      12 /* add an IP group membership */
85#define IP_DROP_MEMBERSHIP     13/* drop an IP group membership */
86
87#define IN6_IS_ADDR_UNSPECIFIED(a) (((a)->s6_addr32[0] == 0) && \
88                                                                        ((a)->s6_addr32[1] == 0) && \
89                                                                        ((a)->s6_addr32[2] == 0) && \
90                                                                        ((a)->s6_addr32[3] == 0))
91struct ip_mreq {
92        struct in_addr imr_multiaddr;   /* IP multicast address of group */
93        struct in_addr imr_interface;   /* local IP address of interface */
94};
95#endif
96
97#ifndef INADDR_NONE
98#define INADDR_NONE 0xffffffff
99#endif
100
101struct _socket_udp {
102        int              mode;  /* IPv4 or IPv6 */
103        char            *addr;
104        uint16_t         rx_port;
105        uint16_t         tx_port;
106        ttl_t            ttl;
107        fd_t             fd;
108        struct in_addr   addr4;
109#ifdef HAVE_IPv6
110        struct in6_addr  addr6;
111#endif /* HAVE_IPv6 */
112    struct in_addr      iface_addr;
113};
114
115#ifdef WIN32
116
117#include <Iphlpapi.h>
118
119/* Want to use both Winsock 1 and 2 socket options, but since
120* IPv6 support requires Winsock 2 we have to add own backwards
121* compatibility for Winsock 1.
122*/
123#define SETSOCKOPT winsock_versions_setsockopt
124#else
125#define SETSOCKOPT setsockopt
126#endif /* WIN32 */
127
128/*****************************************************************************/
129/* Support functions...                                                      */
130/*****************************************************************************/
131
132static void
133socket_error(const char *msg, ...)
134{
135        char            buffer[255];
136        uint32_t        blen = sizeof(buffer) / sizeof(buffer[0]);
137        va_list         ap;
138
139#ifdef WIN32
140#define WSERR(x) {#x,x}
141        struct wse {
142                char  errname[20];
143                int my_errno;
144        };
145        struct wse ws_errs[] = {
146                WSERR(WSANOTINITIALISED), WSERR(WSAENETDOWN),     WSERR(WSAEACCES),
147                WSERR(WSAEINVAL),         WSERR(WSAEINTR),        WSERR(WSAEINPROGRESS),
148                WSERR(WSAEFAULT),         WSERR(WSAENETRESET),    WSERR(WSAENOBUFS),
149                WSERR(WSAENOTCONN),       WSERR(WSAENOTSOCK),     WSERR(WSAEOPNOTSUPP),
150                WSERR(WSAESHUTDOWN),      WSERR(WSAEWOULDBLOCK),  WSERR(WSAEMSGSIZE),
151                WSERR(WSAEHOSTUNREACH),   WSERR(WSAECONNABORTED), WSERR(WSAECONNRESET),
152                WSERR(WSAEADDRNOTAVAIL),  WSERR(WSAEAFNOSUPPORT), WSERR(WSAEDESTADDRREQ),
153                WSERR(WSAENETUNREACH),    WSERR(WSAETIMEDOUT),    WSERR(0)
154        };
155       
156        int i, e = WSAGetLastError();
157        i = 0;
158        while(ws_errs[i].my_errno && ws_errs[i].my_errno != e) {
159                i++;
160        }
161        va_start(ap, msg);
162        _vsnprintf(buffer, blen, msg, ap);
163        va_end(ap);
164        printf("ERROR: %s, (%d - %s)\n", msg, e, ws_errs[i].errname);
165#else
166        va_start(ap, msg);
167        vsnprintf(buffer, blen, msg, ap);
168        va_end(ap);
169        perror(buffer);
170#endif
171}
172
173#ifdef WIN32
174/* ws2tcpip.h defines these constants with different values from
175* winsock.h so files that use winsock 2 values but try to use
176* winsock 1 fail.  So what was the motivation in changing the
177* constants ?
178*/
179#define WS1_IP_MULTICAST_IF     2 /* set/get IP multicast interface   */
180#define WS1_IP_MULTICAST_TTL    3 /* set/get IP multicast timetolive  */
181#define WS1_IP_MULTICAST_LOOP   4 /* set/get IP multicast loopback    */
182#define WS1_IP_ADD_MEMBERSHIP   5 /* add  an IP group membership      */
183#define WS1_IP_DROP_MEMBERSHIP  6 /* drop an IP group membership      */
184
185/* winsock_versions_setsockopt tries 1 winsock version of option
186* optname and then winsock 2 version if that failed.
187* note: setting the TTL never fails, so we have to try both.
188*/
189
190static int
191winsock_versions_setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen)
192{
193        int success = -1;
194        switch (optname) {
195        case IP_MULTICAST_IF:
196                success = setsockopt(s, level, WS1_IP_MULTICAST_IF, optval, optlen);
197                break;
198        case IP_MULTICAST_TTL:
199                success = setsockopt(s, level, WS1_IP_MULTICAST_TTL, optval, optlen);
200                success = setsockopt(s, level, optname, optval, optlen);
201                break;
202        case IP_MULTICAST_LOOP:
203                success = setsockopt(s, level, WS1_IP_MULTICAST_LOOP, optval, optlen);
204                break;
205        case IP_ADD_MEMBERSHIP:
206                success = setsockopt(s, level, WS1_IP_ADD_MEMBERSHIP, optval, optlen);
207                break;
208        case IP_DROP_MEMBERSHIP:
209                success = setsockopt(s, level, WS1_IP_DROP_MEMBERSHIP, optval, optlen);
210                break;
211        }
212        if (success != -1) {
213                return success;
214        }
215        return setsockopt(s, level, optname, optval, optlen);
216}
217#endif
218
219#ifdef NEED_INET_ATON
220#ifdef NEED_INET_ATON_STATIC
221static 
222#endif
223int inet_aton(const char *name, struct in_addr *addr)
224{
225        addr->s_addr = inet_addr(name);
226        return (addr->s_addr != (in_addr_t) INADDR_NONE);
227}
228#endif
229
230#ifdef NEED_IN6_IS_ADDR_MULTICAST
231#define IN6_IS_ADDR_MULTICAST(addr) ((addr)->s6_addr[0] == 0xffU)
232#endif
233
234#if defined(NEED_IN6_IS_ADDR_UNSPECIFIED) && defined(MUSICA_IPV6)
235#define IN6_IS_ADDR_UNSPECIFIED(addr) IS_UNSPEC_IN6_ADDR(*addr)
236#endif
237
238
239
240/*****************************************************************************/
241/* IPv4 specific functions...                                                */
242/*****************************************************************************/
243
244static int udp_addr_valid4(const char *dst)
245{
246        struct in_addr addr4;
247        struct hostent *h;
248
249        if (inet_pton(AF_INET, dst, &addr4)) {
250                return TRUE;
251        }
252
253        h = gethostbyname(dst);
254        if (h != NULL) {
255                return TRUE;
256        }
257        socket_error("Can't resolve IP address for %s", dst);
258
259        return FALSE;
260}
261
262uint32_t    udp_socket_addr4(socket_udp *s)
263{
264  if (s == NULL) {
265    return 0;
266  }
267
268  if (s->mode != IPv4) {
269    return 0;
270  }
271
272  return (uint32_t)(s->addr4.s_addr); 
273}
274
275uint16_t    udp_socket_txport(socket_udp *s)
276{
277        if (s == NULL) {
278                return 0;
279        }
280
281        return s->tx_port;
282}
283
284int udp_socket_ttl(socket_udp *s)
285{
286        if (s == NULL) {
287                return -1;
288        }
289
290        return s->ttl;
291}
292
293static socket_udp *udp_init4(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
294{
295        int                      reuse = 1, udpbufsize=131072;
296        struct sockaddr_in       s_in;
297
298#ifdef WIN32
299      int recv_buf_size = 65536;
300#endif
301        socket_udp              *s = (socket_udp *)malloc(sizeof(socket_udp));
302        s->mode    = IPv4;
303        s->addr    = NULL;
304        s->rx_port = rx_port;
305        s->tx_port = tx_port;
306        s->ttl     = ttl;
307       
308        if (inet_pton(AF_INET, addr, &s->addr4) != 1) {
309                struct hostent *h = gethostbyname(addr);
310                if (h == NULL) {
311                        socket_error("Can't resolve IP address for %s", addr);
312                        free(s);
313                        return NULL;
314                }
315                memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4));
316        }
317        if (iface != NULL) {
318                if (inet_pton(AF_INET, iface, &s->iface_addr) != 1) {
319                        debug_msg("Illegal interface specification\n");
320                        free(s);
321                        return NULL;
322                }
323        } else {
324                s->iface_addr.s_addr = 0;
325        }
326        s->fd = socket(AF_INET, SOCK_DGRAM, 0);
327        if (s->fd < 0) {
328                socket_error("socket");
329                return NULL;
330        }
331        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_SNDBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
332                socket_error("setsockopt SO_SNDBUF");
333                return NULL;
334        }
335        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_RCVBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
336                socket_error("setsockopt SO_RCVBUF");
337                return NULL;
338        }
339        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
340                socket_error("setsockopt SO_REUSEADDR");
341                return NULL;
342        }
343#ifdef SO_REUSEPORT
344        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
345                socket_error("setsockopt SO_REUSEPORT");
346                return NULL;
347        }
348#endif
349        s_in.sin_family      = AF_INET;
350        s_in.sin_addr.s_addr = INADDR_ANY;
351        s_in.sin_port        = htons(rx_port);
352        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
353                socket_error("bind");
354                return NULL;
355        }
356        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
357                char            loop = 1;
358                struct ip_mreq  imr;
359               
360                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
361                imr.imr_interface.s_addr = s->iface_addr.s_addr;
362               
363                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
364                        socket_error("setsockopt IP_ADD_MEMBERSHIP");
365                        return NULL;
366                }
367#ifndef WIN32
368                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) {
369                        socket_error("setsockopt IP_MULTICAST_LOOP");
370                        return NULL;
371                }
372#endif
373                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &s->ttl, sizeof(s->ttl)) != 0) {
374                        socket_error("setsockopt IP_MULTICAST_TTL");
375                        return NULL;
376                }
377                if (s->iface_addr.s_addr != 0) {
378                        if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &s->iface_addr, sizeof(s->iface_addr)) != 0) {
379                                socket_error("setsockopt IP_MULTICAST_IF");
380                                return NULL;
381                        }
382                }
383        } else {
384                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0) {
385                        socket_error("setsockopt IP_TTL");
386                        return NULL;
387        }
388        }
389        s->addr = strdup(addr);
390        return s;
391}
392
393static void udp_exit4(socket_udp *s)
394{
395        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
396                struct ip_mreq  imr;
397                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
398                imr.imr_interface.s_addr = s->iface_addr.s_addr;
399
400                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
401                        socket_error("setsockopt IP_DROP_MEMBERSHIP");
402                        abort();
403                }
404                debug_msg("Dropped membership of multicast group\n");
405        }
406        close(s->fd);
407        free(s->addr);
408        free(s);
409}
410
411static inline int 
412udp_send4(socket_udp *s, char *buffer, int buflen)
413{
414        struct sockaddr_in      s_in;
415       
416        assert(s != NULL);
417        assert(s->mode == IPv4);
418        assert(buffer != NULL);
419        assert(buflen > 0);
420       
421        memset(&s_in, 0, sizeof(struct sockaddr_in));
422        s_in.sin_family      = AF_INET;
423        s_in.sin_addr.s_addr = s->addr4.s_addr;
424        s_in.sin_port        = htons(s->tx_port);
425        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
426}
427
428#ifndef WIN32
429static inline int 
430udp_sendv4(socket_udp *s, struct iovec *vector, int count)
431{
432        struct msghdr           msg;
433        struct sockaddr_in      s_in;
434       
435        assert(s != NULL);
436        assert(s->mode == IPv4);
437       
438        s_in.sin_family      = AF_INET;
439        s_in.sin_addr.s_addr = s->addr4.s_addr;
440        s_in.sin_port        = htons(s->tx_port);
441
442        msg.msg_name       = (caddr_t) &s_in;
443        msg.msg_namelen    = sizeof(s_in);
444        msg.msg_iov        = vector;
445        msg.msg_iovlen     = count;
446#ifdef HAVE_MSGHDR_MSGCTRL /* Solaris does something different here... can we just ignore these fields? [csp] */
447        msg.msg_control    = 0;
448        msg.msg_controllen = 0;
449        msg.msg_flags      = 0;
450#endif
451        return sendmsg(s->fd, &msg, 0);
452}
453#endif
454
455static const char *udp_host_addr4(void)
456{
457        static char              hname[MAXHOSTNAMELEN];
458        struct hostent          *hent;
459        struct in_addr           iaddr;
460       
461        if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
462                debug_msg("Cannot get hostname!");
463                abort();
464        }
465        hent = gethostbyname(hname);
466        if (hent == NULL) {
467                socket_error("Can't resolve IP address for %s", hname);
468                return NULL;
469        }
470        assert(hent->h_addrtype == AF_INET);
471        memcpy(&iaddr.s_addr, hent->h_addr, sizeof(iaddr.s_addr));
472        strncpy(hname, inet_ntoa(iaddr), MAXHOSTNAMELEN);
473        return (const char*)hname;
474}
475
476/*****************************************************************************/
477/* IPv6 specific functions...                                                */
478/*****************************************************************************/
479
480static int udp_addr_valid6(const char *dst)
481{
482#ifdef HAVE_IPv6
483        struct in6_addr addr6;
484        switch (inet_pton(AF_INET6, dst, &addr6)) {
485        case 1
486                return TRUE;
487                break;
488        case 0:
489                return FALSE;
490                break;
491        case -1:
492                debug_msg("inet_pton failed\n");
493                errno = 0;
494        }
495#endif /* HAVE_IPv6 */
496        UNUSED(dst);
497        return FALSE;
498}
499
500static socket_udp *udp_init6(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
501{
502#ifdef HAVE_IPv6
503        int                 reuse = 1;
504        struct sockaddr_in6 s_in;
505        socket_udp         *s = (socket_udp *) malloc(sizeof(socket_udp));
506        s->mode    = IPv6;
507        s->addr    = NULL;
508        s->rx_port = rx_port;
509        s->tx_port = tx_port;
510        s->ttl     = ttl;
511       
512        if (iface != NULL) {
513                debug_msg("Not yet implemented\n");
514                abort();
515        }
516
517        if (inet_pton(AF_INET6, addr, &s->addr6) != 1) {
518                /* We should probably try to do a DNS lookup on the name */
519                /* here, but I'm trying to get the basics going first... */
520                debug_msg("IPv6 address conversion failed\n");
521                free(s);
522                return NULL;   
523        }
524        s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
525        if (s->fd < 0) {
526                socket_error("socket");
527                return NULL;
528        }
529        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
530                socket_error("setsockopt SO_REUSEADDR");
531                return NULL;
532        }
533#ifdef SO_REUSEPORT
534        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
535                socket_error("setsockopt SO_REUSEPORT");
536                return NULL;
537        }
538#endif
539       
540        memset((char *)&s_in, 0, sizeof(s_in));
541        s_in.sin6_family = AF_INET6;
542        s_in.sin6_port   = htons(rx_port);
543#ifdef HAVE_SIN6_LEN
544        s_in.sin6_len    = sizeof(s_in);
545#endif
546        s_in.sin6_addr = in6addr_any;
547        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
548                socket_error("bind");
549                return NULL;
550        }
551       
552        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
553                unsigned int      loop = 1;
554                struct ipv6_mreq  imr;
555#ifdef MUSICA_IPV6
556                imr.i6mr_interface = 1;
557                imr.i6mr_multiaddr = s->addr6;
558#else
559                imr.ipv6mr_multiaddr = s->addr6;
560                imr.ipv6mr_interface = 0;
561#endif
562               
563                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
564                        socket_error("setsockopt IPV6_ADD_MEMBERSHIP");
565                        return NULL;
566                }
567               
568                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) != 0) {
569                        socket_error("setsockopt IPV6_MULTICAST_LOOP");
570                        return NULL;
571                }
572                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof(ttl)) != 0) {
573                        socket_error("setsockopt IPV6_MULTICAST_HOPS");
574                        return NULL;
575                }
576        } else {
577                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0) {
578                        socket_error("setsockopt IP_TTL");
579                        return NULL;
580                }
581        }
582
583        assert(s != NULL);
584
585        s->addr = strdup(addr);
586        return s;
587#else
588        UNUSED(addr);
589        UNUSED(iface);
590        UNUSED(rx_port);
591        UNUSED(tx_port);
592        UNUSED(ttl);
593        return NULL;
594#endif
595}
596
597static void udp_exit6(socket_udp *s)
598{
599#ifdef HAVE_IPv6
600        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
601                struct ipv6_mreq  imr;
602#ifdef MUSICA_IPV6
603                imr.i6mr_interface = 1;
604                imr.i6mr_multiaddr = s->addr6;
605#else
606                imr.ipv6mr_multiaddr = s->addr6;
607                imr.ipv6mr_interface = 0;
608#endif
609               
610                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
611                        socket_error("setsockopt IPV6_DROP_MEMBERSHIP");
612                        abort();
613                }
614        }
615        close(s->fd);
616        free(s->addr);
617        free(s);
618#else
619        UNUSED(s);
620#endif  /* HAVE_IPv6 */
621}
622
623static int udp_send6(socket_udp *s, char *buffer, int buflen)
624{
625#ifdef HAVE_IPv6
626        struct sockaddr_in6     s_in;
627       
628        assert(s != NULL);
629        assert(s->mode == IPv6);
630        assert(buffer != NULL);
631        assert(buflen > 0);
632       
633        memset((char *)&s_in, 0, sizeof(s_in));
634        s_in.sin6_family = AF_INET6;
635        s_in.sin6_addr   = s->addr6;
636        s_in.sin6_port   = htons(s->tx_port);
637#ifdef HAVE_SIN6_LEN
638        s_in.sin6_len    = sizeof(s_in);
639#endif
640        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
641#else
642        UNUSED(s);
643        UNUSED(buffer);
644        UNUSED(buflen);
645        return -1;
646#endif
647}
648
649#ifndef WIN32
650static int 
651udp_sendv6(socket_udp *s, struct iovec *vector, int count)
652{
653#ifdef HAVE_IPv6
654        struct msghdr           msg;
655        struct sockaddr_in6     s_in;
656       
657        assert(s != NULL);
658        assert(s->mode == IPv6);
659       
660        memset((char *)&s_in, 0, sizeof(s_in));
661        s_in.sin6_family = AF_INET6;
662        s_in.sin6_addr   = s->addr6;
663        s_in.sin6_port   = htons(s->tx_port);
664#ifdef HAVE_SIN6_LEN
665        s_in.sin6_len    = sizeof(s_in);
666#endif
667        msg.msg_name       = &s_in;
668        msg.msg_namelen    = sizeof(s_in);
669        msg.msg_iov        = vector;
670        msg.msg_iovlen     = count;
671#ifdef HAVE_MSGHDR_MSGCTRL 
672        msg.msg_control    = 0;
673        msg.msg_controllen = 0;
674        msg.msg_flags      = 0;
675#endif
676        return sendmsg(s->fd, &msg, 0);
677#else
678        UNUSED(s);
679        UNUSED(vector);
680        UNUSED(count);
681        return -1;
682#endif
683}
684#endif
685
686static const char *udp_host_addr6(socket_udp *s)
687{
688#ifdef HAVE_IPv6
689        static char              hname[MAXHOSTNAMELEN];
690        int                      gai_err, newsock;
691        struct addrinfo          hints, *ai;
692        struct sockaddr_in6      local, addr6;
693        uint32_t                        len = sizeof(local);
694        int                                     result = 0;
695
696        newsock=socket(AF_INET6, SOCK_DGRAM,0);
697    memset ((char *)&addr6, 0, len);
698    addr6.sin6_family = AF_INET6;
699#ifdef HAVE_SIN6_LEN
700    addr6.sin6_len    = len;
701#endif
702    bind (newsock, (struct sockaddr *) &addr6, len);
703    addr6.sin6_addr = s->addr6;
704    addr6.sin6_port = htons (s->rx_port);
705    connect (newsock, (struct sockaddr *) &addr6, len);
706
707    memset ((char *)&local, 0, len);
708        if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){
709                local.sin6_addr = in6addr_any;
710                local.sin6_port = 0;
711                debug_msg("getsockname failed\n");
712        }
713
714        close (newsock);
715
716        if (IN6_IS_ADDR_UNSPECIFIED(&local.sin6_addr) || IN6_IS_ADDR_MULTICAST(&local.sin6_addr)) {
717                if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
718                        debug_msg("gethostname failed\n");
719                        abort();
720                }
721               
722                hints.ai_protocol  = 0;
723                hints.ai_flags     = 0;
724                hints.ai_family    = AF_INET6;
725                hints.ai_socktype  = SOCK_DGRAM;
726                hints.ai_addrlen   = 0;
727                hints.ai_canonname = NULL;
728                hints.ai_addr      = NULL;
729                hints.ai_next      = NULL;
730
731                if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) {
732                        debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err));
733                        abort();
734                }
735               
736                if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr), hname, MAXHOSTNAMELEN) == NULL) {
737                        debug_msg("inet_ntop: %s: \n", hname);
738                        abort();
739                }
740                freeaddrinfo(ai);
741                return (const char*)hname;
742        }
743        if (inet_ntop(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) {
744                debug_msg("inet_ntop: %s: \n", hname);
745                abort();
746        }
747        return (const char*)hname;
748#else  /* HAVE_IPv6 */
749        UNUSED(s);
750        return "::";    /* The unspecified address... */
751#endif /* HAVE_IPv6 */
752}
753       
754/*****************************************************************************/
755/* Generic functions, which call the appropriate protocol specific routines. */
756/*****************************************************************************/
757
758/**
759 * udp_addr_valid:
760 * @addr: string representation of IPv4 or IPv6 network address.
761 *
762 * Returns TRUE if @addr is valid, FALSE otherwise.
763 **/
764
765int udp_addr_valid(const char *addr)
766{
767        return udp_addr_valid4(addr) | udp_addr_valid6(addr);
768}
769
770/*
771 * On Windows, determine the name of the interface
772 * that will be used for this group.
773 *
774 * If we don't do this, rat will break on machines
775 * with multiple network interfaces.
776 */
777#ifdef WIN32
778static char *find_win32_interface(const char *addr)
779{
780    struct in_addr inaddr;
781        char *iface = 0;
782
783    if (inet_pton(AF_INET, addr, &inaddr))
784    {
785                MIB_IPFORWARDROW route;
786                       
787                debug_msg("got addr %x\n", inaddr.s_addr);
788                if (GetBestRoute(inaddr.s_addr, 0, &route) == NO_ERROR)
789                {
790                        IP_ADAPTER_INFO oneinfo;
791                        PIP_ADAPTER_INFO allinfo = 0;
792                        int len;
793                        struct in_addr dst, mask, nexthop;
794
795                        dst.s_addr = route.dwForwardDest;
796                        mask.s_addr = route.dwForwardMask;
797                        nexthop.s_addr = route.dwForwardNextHop;
798
799                        debug_msg("found route dst=%s mask=%s nexthop=%s ifindex=%d\n",
800                                inet_ntoa(dst), inet_ntoa(mask), inet_ntoa(nexthop),
801                                route.dwForwardIfIndex);
802
803                        len = sizeof(oneinfo);
804                        if (GetAdaptersInfo(&oneinfo, &len) == ERROR_SUCCESS)
805                        {
806                                debug_msg("got allinfo in one\n");
807                                allinfo = &oneinfo;
808                        }
809                        else
810                        {
811                                allinfo = (PIP_ADAPTER_INFO) malloc(len);
812                                if (GetAdaptersInfo(allinfo, &len) != ERROR_SUCCESS)
813                                {
814                                        debug_msg("Could not get adapter info\n");
815                                        free(allinfo);
816                                        allinfo = 0;
817                                }
818                        }
819
820                        if (allinfo)
821                        {
822
823                                PIP_ADAPTER_INFO a;
824                                {
825                                        for (a = allinfo; a != 0; a = a->Next)
826                                        {
827
828                                                debug_msg("name='%s' desc='%s' index=%d\n",
829                                                        a->AdapterName, a->Description, a->Index);
830
831                                                if (a->Index == route.dwForwardIfIndex)
832                                                {
833                                                        PIP_ADDR_STRING s;
834                                                        /* Take the first address. */
835
836                                                        s = &a->IpAddressList;
837                                                        iface = _strdup(s->IpAddress.String);
838                                                        debug_msg("Found address '%s'\n", iface);
839                                                }
840                                        }
841                                }
842                        }
843#if 0 /* This is the stuff that just works on XP, sigh. */
844                        len = sizeof(addrs);
845                        if (GetAdaptersAddresses(AF_INET, 0, 0, addrs, &len) == ERROR_SUCCESS)
846                        {
847                                PIP_ADAPTER_ADDRESSES a;
848
849                                a = addrs;
850
851                                while (a && (iface == 0))
852                                {
853                                        if (a->IfIndex == route.dwForwardIfIndex)
854                                        {
855                                                struct sockaddr_in *sockaddr;
856                               
857                                                sockaddr = (struct sockaddr_in *) a->FirstUnicastAddress->Address.lpSockaddr;
858
859                                                debug_msg("name=%s addr=%s\n",
860                                                        a->AdapterName, inet_ntoa(sockaddr->sin_addr));
861                                                iface = _strdup(inet_ntoa(sockaddr->sin_addr));
862                                        }
863                                        a = a->Next;
864                                }
865                        }
866#endif
867                }
868    }
869
870        return iface;
871}
872#endif /* WIN32 */
873
874/**
875 * udp_init:
876 * @addr: character string containing an IPv4 or IPv6 network address.
877 * @rx_port: receive port.
878 * @tx_port: transmit port.
879 * @ttl: time-to-live value for transmitted packets.
880 *
881 * Creates a session for sending and receiving UDP datagrams over IP
882 * networks.
883 *
884 * Returns: a pointer to a valid socket_udp structure on success, NULL otherwise.
885 **/
886socket_udp *udp_init(const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl)
887{
888        return udp_init_if(addr, NULL, rx_port, tx_port, ttl);
889}
890
891/**
892 * udp_init_if:
893 * @addr: character string containing an IPv4 or IPv6 network address.
894 * @iface: character string containing an interface name.
895 * @rx_port: receive port.
896 * @tx_port: transmit port.
897 * @ttl: time-to-live value for transmitted packets.
898 *
899 * Creates a session for sending and receiving UDP datagrams over IP
900 * networks.  The session uses @iface as the interface to send and
901 * receive datagrams on.
902 *
903 * Return value: a pointer to a socket_udp structure on success, NULL otherwise.
904 **/
905socket_udp *udp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
906{
907        socket_udp *res;
908       
909        if (strchr(addr, ':') == NULL) {
910                char *computed_iface = 0;
911                /*
912                 * On WIN32, if user did not pass an interface,
913                 * find the default interface for that address
914                 * and pass it in .
915                 */
916
917#ifdef WIN32
918                if (iface == 0)
919                {
920                        computed_iface = find_win32_interface(addr);
921                        iface = computed_iface;
922                }
923#endif
924
925                res = udp_init4(addr, iface, rx_port, tx_port, ttl);
926
927                if (computed_iface)
928                        free(computed_iface);
929
930        } else {
931                res = udp_init6(addr, iface, rx_port, tx_port, ttl);
932        }
933        return res;
934}
935
936/**
937 * udp_exit:
938 * @s: UDP session to be terminated.
939 *
940 * Closes UDP session.
941 *
942 **/
943void udp_exit(socket_udp *s)
944{
945    switch(s->mode) {
946    case IPv4 : udp_exit4(s); break;
947    case IPv6 : udp_exit6(s); break;
948    default   : abort();
949    }
950}
951
952/**
953 * udp_send:
954 * @s: UDP session.
955 * @buffer: pointer to buffer to be transmitted.
956 * @buflen: length of @buffer.
957 *
958 * Transmits a UDP datagram containing data from @buffer.
959 *
960 * Return value: 0 on success, -1 on failure.
961 **/
962int udp_send(socket_udp *s, char *buffer, int buflen)
963{
964        switch (s->mode) {
965        case IPv4 : return udp_send4(s, buffer, buflen);
966        case IPv6 : return udp_send6(s, buffer, buflen);
967        default   : abort(); /* Yuk! */
968        }
969        return -1;
970}
971
972
973#ifndef WIN32
974int         
975udp_sendv(socket_udp *s, struct iovec *vector, int count)
976{
977        switch (s->mode) {
978        case IPv4 : return udp_sendv4(s, vector, count);
979        case IPv6 : return udp_sendv6(s, vector, count);
980        default   : abort(); /* Yuk! */
981        }
982        return -1;
983}
984#endif
985
986/**
987 * udp_recv:
988 * @s: UDP session.
989 * @buffer: buffer to read data into.
990 * @buflen: length of @buffer.
991 *
992 * Reads from datagram queue associated with UDP session.
993 *
994 * Return value: number of bytes read, returns 0 if no data is available.
995 **/
996int udp_recv(socket_udp *s, char *buffer, int buflen)
997{
998        /* Reads data into the buffer, returning the number of bytes read.   */
999        /* If no data is available, this returns the value zero immediately. */
1000        /* Note: since we don't care about the source address of the packet  */
1001        /* we receive, this function becomes protocol independent.           */
1002        int             len;
1003
1004        assert(buffer != NULL);
1005        assert(buflen > 0);
1006
1007        len = recvfrom(s->fd, buffer, buflen, 0, 0, 0);
1008        if (len > 0) {
1009                return len;
1010        }
1011        if (errno != ECONNREFUSED) {
1012                socket_error("recvfrom");
1013        }
1014        return 0;
1015}
1016
1017/**
1018 * udp_fd_zero:
1019 *
1020 * Clears file descriptor from set associated with UDP sessions (see select(2)).
1021 *
1022 **/
1023void udp_fd_zero( fd_set *readset, fd_t *max_fd )
1024{
1025        FD_ZERO(readset);
1026        *max_fd = 0;
1027}
1028
1029/**
1030 * udp_fd_set:
1031 * @s: UDP session.
1032 *
1033 * Adds file descriptor associated of @s to set associated with UDP sessions.
1034 **/
1035void udp_fd_set( fd_set *readset, fd_t *max_fd, socket_udp *s)
1036{
1037        FD_SET(s->fd, readset);
1038        if (s->fd > (fd_t)*max_fd) {
1039                *max_fd = s->fd;
1040        }
1041}
1042
1043/**
1044 * udp_fd_isset:
1045 * @s: UDP session.
1046 *
1047 * Checks if file descriptor associated with UDP session is ready for
1048 * reading.  This function should be called after udp_select().
1049 *
1050 * Returns: non-zero if set, zero otherwise.
1051 **/
1052int udp_fd_isset( fd_set *readset, fd_t *max_fd, socket_udp *s)
1053{
1054        UNUSED(max_fd);
1055
1056        return FD_ISSET(s->fd, readset);
1057}
1058
1059/**
1060 * udp_select:
1061 * @timeout: maximum period to wait for data to arrive.
1062 *
1063 * Waits for data to arrive for UDP sessions.
1064 *
1065 * Return value: number of UDP sessions ready for reading.
1066 **/
1067int udp_select( fd_set *readset, fd_t max_fd, struct timeval *timeout)
1068{
1069        return select(max_fd + 1, readset, NULL, NULL, timeout);
1070}
1071
1072/**
1073 * udp_host_addr:
1074 * @s: UDP session.
1075 *
1076 * Return value: character string containing network address
1077 * associated with session @s.
1078 **/
1079const char *udp_host_addr(socket_udp *s)
1080{
1081        switch (s->mode) {
1082        case IPv4 : return udp_host_addr4();
1083        case IPv6 : return udp_host_addr6(s);
1084        default   : abort();
1085        }
1086        return NULL;
1087}
1088
1089/**
1090 * udp_fd:
1091 * @s: UDP session.
1092 *
1093 * This function allows applications to apply their own socketopt()'s
1094 * and ioctl()'s to the UDP session.
1095 *
1096 * Return value: file descriptor of socket used by session @s.
1097 **/
1098int udp_fd(socket_udp *s)
1099{
1100        if (s && s->fd > 0) {
1101                return s->fd;
1102        }
1103        return 0;
1104}
1105
Note: See TracBrowser for help on using the browser.