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

Revision 3922, 28.2 KB (checked in by ucacsva, 8 years ago)

1. Removed some tagged comments from previous commits (//SV-XXX).
2. Added newer config.[sub/guess]
3. Various fixes to sync common library with that of ANL:

  • Replaced some "dnl" comments with "#" and stripped off some dnl's from the end of lines
  • Require autoconf v2.5 with AC_PREREQ(2.5)
  • Replaced LIBOBJS="$LIBOBJS inet_ntop.o" by AC_LIBOBJ([inet_ntop])
  • Find which network interface is in use (WinXP).
  • Forgotten NDEF replaced by HAVE_MSGHDR_MSGCTRL.
  • Sets event.data to s->last.active (used by AccessGrid?'s logging code).
  • Introduced rtp_get_ssrc_count() (AccessGrid? logging code).


  • 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
262static socket_udp *udp_init4(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
263{
264        int                      reuse = 1, udpbufsize=131072;
265        struct sockaddr_in       s_in;
266
267#ifdef WIN32
268      int recv_buf_size = 65536;
269#endif
270        socket_udp              *s = (socket_udp *)malloc(sizeof(socket_udp));
271        s->mode    = IPv4;
272        s->addr    = NULL;
273        s->rx_port = rx_port;
274        s->tx_port = tx_port;
275        s->ttl     = ttl;
276       
277        if (inet_pton(AF_INET, addr, &s->addr4) != 1) {
278                struct hostent *h = gethostbyname(addr);
279                if (h == NULL) {
280                        socket_error("Can't resolve IP address for %s", addr);
281                        free(s);
282                        return NULL;
283                }
284                memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4));
285        }
286        if (iface != NULL) {
287                if (inet_pton(AF_INET, iface, &s->iface_addr) != 1) {
288                        debug_msg("Illegal interface specification\n");
289                        free(s);
290                        return NULL;
291                }
292        } else {
293                s->iface_addr.s_addr = 0;
294        }
295        s->fd = socket(AF_INET, SOCK_DGRAM, 0);
296        if (s->fd < 0) {
297                socket_error("socket");
298                return NULL;
299        }
300        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_SNDBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
301                socket_error("setsockopt SO_SNDBUF");
302                return NULL;
303        }
304        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_RCVBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
305                socket_error("setsockopt SO_RCVBUF");
306                return NULL;
307        }
308        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
309                socket_error("setsockopt SO_REUSEADDR");
310                return NULL;
311        }
312#ifdef SO_REUSEPORT
313        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
314                socket_error("setsockopt SO_REUSEPORT");
315                return NULL;
316        }
317#endif
318        s_in.sin_family      = AF_INET;
319        s_in.sin_addr.s_addr = INADDR_ANY;
320        s_in.sin_port        = htons(rx_port);
321        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
322                socket_error("bind");
323                return NULL;
324        }
325        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
326                char            loop = 1;
327                struct ip_mreq  imr;
328               
329                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
330                imr.imr_interface.s_addr = s->iface_addr.s_addr;
331               
332                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
333                        socket_error("setsockopt IP_ADD_MEMBERSHIP");
334                        return NULL;
335                }
336#ifndef WIN32
337                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) {
338                        socket_error("setsockopt IP_MULTICAST_LOOP");
339                        return NULL;
340                }
341#endif
342                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &s->ttl, sizeof(s->ttl)) != 0) {
343                        socket_error("setsockopt IP_MULTICAST_TTL");
344                        return NULL;
345                }
346                if (s->iface_addr.s_addr != 0) {
347                        if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &s->iface_addr, sizeof(s->iface_addr)) != 0) {
348                                socket_error("setsockopt IP_MULTICAST_IF");
349                                return NULL;
350                        }
351                }
352        } else {
353                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0) {
354                        socket_error("setsockopt IP_TTL");
355                        return NULL;
356        }
357        }
358        s->addr = strdup(addr);
359        return s;
360}
361
362static void udp_exit4(socket_udp *s)
363{
364        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
365                struct ip_mreq  imr;
366                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
367                imr.imr_interface.s_addr = s->iface_addr.s_addr;
368
369                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
370                        socket_error("setsockopt IP_DROP_MEMBERSHIP");
371                        abort();
372                }
373                debug_msg("Dropped membership of multicast group\n");
374        }
375        close(s->fd);
376        free(s->addr);
377        free(s);
378}
379
380static inline int 
381udp_send4(socket_udp *s, char *buffer, int buflen)
382{
383        struct sockaddr_in      s_in;
384       
385        assert(s != NULL);
386        assert(s->mode == IPv4);
387        assert(buffer != NULL);
388        assert(buflen > 0);
389       
390        s_in.sin_family      = AF_INET;
391        s_in.sin_addr.s_addr = s->addr4.s_addr;
392        s_in.sin_port        = htons(s->tx_port);
393        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
394}
395
396#ifndef WIN32
397static inline int 
398udp_sendv4(socket_udp *s, struct iovec *vector, int count)
399{
400        struct msghdr           msg;
401        struct sockaddr_in      s_in;
402       
403        assert(s != NULL);
404        assert(s->mode == IPv4);
405       
406        s_in.sin_family      = AF_INET;
407        s_in.sin_addr.s_addr = s->addr4.s_addr;
408        s_in.sin_port        = htons(s->tx_port);
409
410        msg.msg_name       = (caddr_t) &s_in;
411        msg.msg_namelen    = sizeof(s_in);
412        msg.msg_iov        = vector;
413        msg.msg_iovlen     = count;
414#ifdef HAVE_MSGHDR_MSGCTRL /* Solaris does something different here... can we just ignore these fields? [csp] */
415        msg.msg_control    = 0;
416        msg.msg_controllen = 0;
417        msg.msg_flags      = 0;
418#endif
419        return sendmsg(s->fd, &msg, 0);
420}
421#endif
422
423static const char *udp_host_addr4(void)
424{
425        static char              hname[MAXHOSTNAMELEN];
426        struct hostent          *hent;
427        struct in_addr           iaddr;
428       
429        if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
430                debug_msg("Cannot get hostname!");
431                abort();
432        }
433        hent = gethostbyname(hname);
434        if (hent == NULL) {
435                socket_error("Can't resolve IP address for %s", hname);
436                return NULL;
437        }
438        assert(hent->h_addrtype == AF_INET);
439        memcpy(&iaddr.s_addr, hent->h_addr, sizeof(iaddr.s_addr));
440        strncpy(hname, inet_ntoa(iaddr), MAXHOSTNAMELEN);
441        return (const char*)hname;
442}
443
444/*****************************************************************************/
445/* IPv6 specific functions...                                                */
446/*****************************************************************************/
447
448static int udp_addr_valid6(const char *dst)
449{
450#ifdef HAVE_IPv6
451        struct in6_addr addr6;
452        switch (inet_pton(AF_INET6, dst, &addr6)) {
453        case 1
454                return TRUE;
455                break;
456        case 0:
457                return FALSE;
458                break;
459        case -1:
460                debug_msg("inet_pton failed\n");
461                errno = 0;
462        }
463#endif /* HAVE_IPv6 */
464        UNUSED(dst);
465        return FALSE;
466}
467
468static socket_udp *udp_init6(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
469{
470#ifdef HAVE_IPv6
471        int                 reuse = 1;
472        struct sockaddr_in6 s_in;
473        socket_udp         *s = (socket_udp *) malloc(sizeof(socket_udp));
474        s->mode    = IPv6;
475        s->addr    = NULL;
476        s->rx_port = rx_port;
477        s->tx_port = tx_port;
478        s->ttl     = ttl;
479       
480        if (iface != NULL) {
481                debug_msg("Not yet implemented\n");
482                abort();
483        }
484
485        if (inet_pton(AF_INET6, addr, &s->addr6) != 1) {
486                /* We should probably try to do a DNS lookup on the name */
487                /* here, but I'm trying to get the basics going first... */
488                debug_msg("IPv6 address conversion failed\n");
489                free(s);
490                return NULL;   
491        }
492        s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
493        if (s->fd < 0) {
494                socket_error("socket");
495                return NULL;
496        }
497        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
498                socket_error("setsockopt SO_REUSEADDR");
499                return NULL;
500        }
501#ifdef SO_REUSEPORT
502        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
503                socket_error("setsockopt SO_REUSEPORT");
504                return NULL;
505        }
506#endif
507       
508        memset((char *)&s_in, 0, sizeof(s_in));
509        s_in.sin6_family = AF_INET6;
510        s_in.sin6_port   = htons(rx_port);
511#ifdef HAVE_SIN6_LEN
512        s_in.sin6_len    = sizeof(s_in);
513#endif
514        s_in.sin6_addr = in6addr_any;
515        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
516                socket_error("bind");
517                return NULL;
518        }
519       
520        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
521                unsigned int      loop = 1;
522                struct ipv6_mreq  imr;
523#ifdef MUSICA_IPV6
524                imr.i6mr_interface = 1;
525                imr.i6mr_multiaddr = s->addr6;
526#else
527                imr.ipv6mr_multiaddr = s->addr6;
528                imr.ipv6mr_interface = 0;
529#endif
530               
531                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
532                        socket_error("setsockopt IPV6_ADD_MEMBERSHIP");
533                        return NULL;
534                }
535               
536                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) != 0) {
537                        socket_error("setsockopt IPV6_MULTICAST_LOOP");
538                        return NULL;
539                }
540                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof(ttl)) != 0) {
541                        socket_error("setsockopt IPV6_MULTICAST_HOPS");
542                        return NULL;
543                }
544        } else {
545                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_TTL, (char *) &ttl, sizeof(ttl)) != 0) {
546                        socket_error("setsockopt IP_TTL");
547                        return NULL;
548                }
549        }
550
551        assert(s != NULL);
552
553        s->addr = strdup(addr);
554        return s;
555#else
556        UNUSED(addr);
557        UNUSED(iface);
558        UNUSED(rx_port);
559        UNUSED(tx_port);
560        UNUSED(ttl);
561        return NULL;
562#endif
563}
564
565static void udp_exit6(socket_udp *s)
566{
567#ifdef HAVE_IPv6
568        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
569                struct ipv6_mreq  imr;
570#ifdef MUSICA_IPV6
571                imr.i6mr_interface = 1;
572                imr.i6mr_multiaddr = s->addr6;
573#else
574                imr.ipv6mr_multiaddr = s->addr6;
575                imr.ipv6mr_interface = 0;
576#endif
577               
578                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
579                        socket_error("setsockopt IPV6_DROP_MEMBERSHIP");
580                        abort();
581                }
582        }
583        close(s->fd);
584        free(s->addr);
585        free(s);
586#else
587        UNUSED(s);
588#endif  /* HAVE_IPv6 */
589}
590
591static int udp_send6(socket_udp *s, char *buffer, int buflen)
592{
593#ifdef HAVE_IPv6
594        struct sockaddr_in6     s_in;
595       
596        assert(s != NULL);
597        assert(s->mode == IPv6);
598        assert(buffer != NULL);
599        assert(buflen > 0);
600       
601        memset((char *)&s_in, 0, sizeof(s_in));
602        s_in.sin6_family = AF_INET6;
603        s_in.sin6_addr   = s->addr6;
604        s_in.sin6_port   = htons(s->tx_port);
605#ifdef HAVE_SIN6_LEN
606        s_in.sin6_len    = sizeof(s_in);
607#endif
608        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
609#else
610        UNUSED(s);
611        UNUSED(buffer);
612        UNUSED(buflen);
613        return -1;
614#endif
615}
616
617#ifndef WIN32
618static int 
619udp_sendv6(socket_udp *s, struct iovec *vector, int count)
620{
621#ifdef HAVE_IPv6
622        struct msghdr           msg;
623        struct sockaddr_in6     s_in;
624       
625        assert(s != NULL);
626        assert(s->mode == IPv6);
627       
628        memset((char *)&s_in, 0, sizeof(s_in));
629        s_in.sin6_family = AF_INET6;
630        s_in.sin6_addr   = s->addr6;
631        s_in.sin6_port   = htons(s->tx_port);
632#ifdef HAVE_SIN6_LEN
633        s_in.sin6_len    = sizeof(s_in);
634#endif
635        msg.msg_name       = &s_in;
636        msg.msg_namelen    = sizeof(s_in);
637        msg.msg_iov        = vector;
638        msg.msg_iovlen     = count;
639#ifdef HAVE_MSGHDR_MSGCTRL 
640        msg.msg_control    = 0;
641        msg.msg_controllen = 0;
642        msg.msg_flags      = 0;
643#endif
644        return sendmsg(s->fd, &msg, 0);
645#else
646        UNUSED(s);
647        UNUSED(vector);
648        UNUSED(count);
649        return -1;
650#endif
651}
652#endif
653
654static const char *udp_host_addr6(socket_udp *s)
655{
656#ifdef HAVE_IPv6
657        static char              hname[MAXHOSTNAMELEN];
658        int                      gai_err, newsock;
659        struct addrinfo          hints, *ai;
660        struct sockaddr_in6      local, addr6;
661        uint32_t                        len = sizeof(local);
662        int                                     result = 0;
663
664        newsock=socket(AF_INET6, SOCK_DGRAM,0);
665    memset ((char *)&addr6, 0, len);
666    addr6.sin6_family = AF_INET6;
667#ifdef HAVE_SIN6_LEN
668    addr6.sin6_len    = len;
669#endif
670    bind (newsock, (struct sockaddr *) &addr6, len);
671    addr6.sin6_addr = s->addr6;
672    addr6.sin6_port = htons (s->rx_port);
673    connect (newsock, (struct sockaddr *) &addr6, len);
674
675    memset ((char *)&local, 0, len);
676        if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){
677                local.sin6_addr = in6addr_any;
678                local.sin6_port = 0;
679                debug_msg("getsockname failed\n");
680        }
681
682        close (newsock);
683
684        if (IN6_IS_ADDR_UNSPECIFIED(&local.sin6_addr) || IN6_IS_ADDR_MULTICAST(&local.sin6_addr)) {
685                if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
686                        debug_msg("gethostname failed\n");
687                        abort();
688                }
689               
690                hints.ai_protocol  = 0;
691                hints.ai_flags     = 0;
692                hints.ai_family    = AF_INET6;
693                hints.ai_socktype  = SOCK_DGRAM;
694                hints.ai_addrlen   = 0;
695                hints.ai_canonname = NULL;
696                hints.ai_addr      = NULL;
697                hints.ai_next      = NULL;
698
699                if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) {
700                        debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err));
701                        abort();
702                }
703               
704                if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr), hname, MAXHOSTNAMELEN) == NULL) {
705                        debug_msg("inet_ntop: %s: \n", hname);
706                        abort();
707                }
708                freeaddrinfo(ai);
709                return (const char*)hname;
710        }
711        if (inet_ntop(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) {
712                debug_msg("inet_ntop: %s: \n", hname);
713                abort();
714        }
715        return (const char*)hname;
716#else  /* HAVE_IPv6 */
717        UNUSED(s);
718        return "::";    /* The unspecified address... */
719#endif /* HAVE_IPv6 */
720}
721       
722/*****************************************************************************/
723/* Generic functions, which call the appropriate protocol specific routines. */
724/*****************************************************************************/
725
726/**
727 * udp_addr_valid:
728 * @addr: string representation of IPv4 or IPv6 network address.
729 *
730 * Returns TRUE if @addr is valid, FALSE otherwise.
731 **/
732
733int udp_addr_valid(const char *addr)
734{
735        return udp_addr_valid4(addr) | udp_addr_valid6(addr);
736}
737
738/*
739 * On Windows, determine the name of the interface
740 * that will be used for this group.
741 *
742 * If we don't do this, rat will break on machines
743 * with multiple network interfaces.
744 */
745#ifdef WIN32
746static char *find_win32_interface(const char *addr)
747{
748    struct in_addr inaddr;
749        char *iface = 0;
750
751    if (inet_pton(AF_INET, addr, &inaddr))
752    {
753                MIB_IPFORWARDROW route;
754                       
755                debug_msg("got addr %x\n", inaddr.s_addr);
756                if (GetBestRoute(inaddr.s_addr, 0, &route) == NO_ERROR)
757                {
758                        IP_ADAPTER_INFO oneinfo;
759                        PIP_ADAPTER_INFO allinfo = 0;
760                        int len;
761                        struct in_addr dst, mask, nexthop;
762
763                        dst.s_addr = route.dwForwardDest;
764                        mask.s_addr = route.dwForwardMask;
765                        nexthop.s_addr = route.dwForwardNextHop;
766
767                        debug_msg("found route dst=%s mask=%s nexthop=%s ifindex=%d\n",
768                                inet_ntoa(dst), inet_ntoa(mask), inet_ntoa(nexthop),
769                                route.dwForwardIfIndex);
770
771                        len = sizeof(oneinfo);
772                        if (GetAdaptersInfo(&oneinfo, &len) == ERROR_SUCCESS)
773                        {
774                                debug_msg("got allinfo in one\n");
775                                allinfo = &oneinfo;
776                        }
777                        else
778                        {
779                                allinfo = (PIP_ADAPTER_INFO) malloc(len);
780                                if (GetAdaptersInfo(allinfo, &len) != ERROR_SUCCESS)
781                                {
782                                        debug_msg("Could not get adapter info\n");
783                                        free(allinfo);
784                                        allinfo = 0;
785                                }
786                        }
787
788                        if (allinfo)
789                        {
790
791                                PIP_ADAPTER_INFO a;
792                                {
793                                        for (a = allinfo; a != 0; a = a->Next)
794                                        {
795
796                                                debug_msg("name='%s' desc='%s' index=%d\n",
797                                                        a->AdapterName, a->Description, a->Index);
798
799                                                if (a->Index == route.dwForwardIfIndex)
800                                                {
801                                                        PIP_ADDR_STRING s;
802                                                        /* Take the first address. */
803
804                                                        s = &a->IpAddressList;
805                                                        iface = _strdup(s->IpAddress.String);
806                                                        debug_msg("Found address '%s'\n", iface);
807                                                }
808                                        }
809                                }
810                        }
811#if 0 /* This is the stuff that just works on XP, sigh. */
812                        len = sizeof(addrs);
813                        if (GetAdaptersAddresses(AF_INET, 0, 0, addrs, &len) == ERROR_SUCCESS)
814                        {
815                                PIP_ADAPTER_ADDRESSES a;
816
817                                a = addrs;
818
819                                while (a && (iface == 0))
820                                {
821                                        if (a->IfIndex == route.dwForwardIfIndex)
822                                        {
823                                                struct sockaddr_in *sockaddr;
824                               
825                                                sockaddr = (struct sockaddr_in *) a->FirstUnicastAddress->Address.lpSockaddr;
826
827                                                debug_msg("name=%s addr=%s\n",
828                                                        a->AdapterName, inet_ntoa(sockaddr->sin_addr));
829                                                iface = _strdup(inet_ntoa(sockaddr->sin_addr));
830                                        }
831                                        a = a->Next;
832                                }
833                        }
834#endif
835                }
836    }
837
838        return iface;
839}
840#endif /* WIN32 */
841
842/**
843 * udp_init:
844 * @addr: character string containing an IPv4 or IPv6 network address.
845 * @rx_port: receive port.
846 * @tx_port: transmit port.
847 * @ttl: time-to-live value for transmitted packets.
848 *
849 * Creates a session for sending and receiving UDP datagrams over IP
850 * networks.
851 *
852 * Returns: a pointer to a valid socket_udp structure on success, NULL otherwise.
853 **/
854socket_udp *udp_init(const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl)
855{
856        return udp_init_if(addr, NULL, rx_port, tx_port, ttl);
857}
858
859/**
860 * udp_init_if:
861 * @addr: character string containing an IPv4 or IPv6 network address.
862 * @iface: character string containing an interface name.
863 * @rx_port: receive port.
864 * @tx_port: transmit port.
865 * @ttl: time-to-live value for transmitted packets.
866 *
867 * Creates a session for sending and receiving UDP datagrams over IP
868 * networks.  The session uses @iface as the interface to send and
869 * receive datagrams on.
870 *
871 * Return value: a pointer to a socket_udp structure on success, NULL otherwise.
872 **/
873socket_udp *udp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
874{
875        socket_udp *res;
876       
877        if (strchr(addr, ':') == NULL) {
878                char *computed_iface = 0;
879                /*
880                 * On WIN32, if user did not pass an interface,
881                 * find the default interface for that address
882                 * and pass it in .
883                 */
884
885#ifdef WIN32
886                if (iface == 0)
887                {
888                        computed_iface = find_win32_interface(addr);
889                        iface = computed_iface;
890                }
891#endif
892
893                res = udp_init4(addr, iface, rx_port, tx_port, ttl);
894
895                if (computed_iface)
896                        free(computed_iface);
897
898        } else {
899                res = udp_init6(addr, iface, rx_port, tx_port, ttl);
900        }
901        return res;
902}
903
904/**
905 * udp_exit:
906 * @s: UDP session to be terminated.
907 *
908 * Closes UDP session.
909 *
910 **/
911void udp_exit(socket_udp *s)
912{
913    switch(s->mode) {
914    case IPv4 : udp_exit4(s); break;
915    case IPv6 : udp_exit6(s); break;
916    default   : abort();
917    }
918}
919
920/**
921 * udp_send:
922 * @s: UDP session.
923 * @buffer: pointer to buffer to be transmitted.
924 * @buflen: length of @buffer.
925 *
926 * Transmits a UDP datagram containing data from @buffer.
927 *
928 * Return value: 0 on success, -1 on failure.
929 **/
930int udp_send(socket_udp *s, char *buffer, int buflen)
931{
932        switch (s->mode) {
933        case IPv4 : return udp_send4(s, buffer, buflen);
934        case IPv6 : return udp_send6(s, buffer, buflen);
935        default   : abort(); /* Yuk! */
936        }
937        return -1;
938}
939
940
941#ifndef WIN32
942int         
943udp_sendv(socket_udp *s, struct iovec *vector, int count)
944{
945        switch (s->mode) {
946        case IPv4 : return udp_sendv4(s, vector, count);
947        case IPv6 : return udp_sendv6(s, vector, count);
948        default   : abort(); /* Yuk! */
949        }
950        return -1;
951}
952#endif
953
954/**
955 * udp_recv:
956 * @s: UDP session.
957 * @buffer: buffer to read data into.
958 * @buflen: length of @buffer.
959 *
960 * Reads from datagram queue associated with UDP session.
961 *
962 * Return value: number of bytes read, returns 0 if no data is available.
963 **/
964int udp_recv(socket_udp *s, char *buffer, int buflen)
965{
966        /* Reads data into the buffer, returning the number of bytes read.   */
967        /* If no data is available, this returns the value zero immediately. */
968        /* Note: since we don't care about the source address of the packet  */
969        /* we receive, this function becomes protocol independent.           */
970        int             len;
971
972        assert(buffer != NULL);
973        assert(buflen > 0);
974
975        len = recvfrom(s->fd, buffer, buflen, 0, 0, 0);
976        if (len > 0) {
977                return len;
978        }
979        if (errno != ECONNREFUSED) {
980                socket_error("recvfrom");
981        }
982        return 0;
983}
984
985static fd_set   rfd;
986static fd_t     max_fd;
987
988/**
989 * udp_fd_zero:
990 *
991 * Clears file descriptor from set associated with UDP sessions (see select(2)).
992 *
993 **/
994void udp_fd_zero(void)
995{
996        FD_ZERO(&rfd);
997        max_fd = 0;
998}
999
1000/**
1001 * udp_fd_set:
1002 * @s: UDP session.
1003 *
1004 * Adds file descriptor associated of @s to set associated with UDP sessions.
1005 **/
1006void udp_fd_set(socket_udp *s)
1007{
1008        FD_SET(s->fd, &rfd);
1009        if (s->fd > (fd_t)max_fd) {
1010                max_fd = s->fd;
1011        }
1012}
1013
1014/**
1015 * udp_fd_isset:
1016 * @s: UDP session.
1017 *
1018 * Checks if file descriptor associated with UDP session is ready for
1019 * reading.  This function should be called after udp_select().
1020 *
1021 * Returns: non-zero if set, zero otherwise.
1022 **/
1023int udp_fd_isset(socket_udp *s)
1024{
1025        return FD_ISSET(s->fd, &rfd);
1026}
1027
1028/**
1029 * udp_select:
1030 * @timeout: maximum period to wait for data to arrive.
1031 *
1032 * Waits for data to arrive for UDP sessions.
1033 *
1034 * Return value: number of UDP sessions ready for reading.
1035 **/
1036int udp_select(struct timeval *timeout)
1037{
1038        return select(max_fd + 1, &rfd, NULL, NULL, timeout);
1039}
1040
1041/**
1042 * udp_host_addr:
1043 * @s: UDP session.
1044 *
1045 * Return value: character string containing network address
1046 * associated with session @s.
1047 **/
1048const char *udp_host_addr(socket_udp *s)
1049{
1050        switch (s->mode) {
1051        case IPv4 : return udp_host_addr4();
1052        case IPv6 : return udp_host_addr6(s);
1053        default   : abort();
1054        }
1055        return NULL;
1056}
1057
1058/**
1059 * udp_fd:
1060 * @s: UDP session.
1061 *
1062 * This function allows applications to apply their own socketopt()'s
1063 * and ioctl()'s to the UDP session.
1064 *
1065 * Return value: file descriptor of socket used by session @s.
1066 **/
1067int udp_fd(socket_udp *s)
1068{
1069        if (s && s->fd > 0) {
1070                return s->fd;
1071        }
1072        return 0;
1073}
1074
Note: See TracBrowser for help on using the browser.