~polto/elphelogm/trunk

« back to all changes in this revision

Viewing changes to common/src/net_udp.c

  • Committer: Alexandre Poltorak
  • Date: 2008-03-16 15:36:14 UTC
  • Revision ID: polto@alsenet.com-20080316153614-hh918wm42mgrvrdy
my first bazaar commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
59
const struct    in6_addr        in6addr_any = {IN6ADDR_ANY_INIT};
 
60
#endif
 
61
 
 
62
#ifdef WINXP_IPV6
 
63
const 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
 
72
struct  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))
 
91
struct 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
 
 
101
struct _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
};
 
113
 
 
114
#ifdef WIN32
 
115
/* Want to use both Winsock 1 and 2 socket options, but since
 
116
* IPv6 support requires Winsock 2 we have to add own backwards
 
117
* compatibility for Winsock 1.
 
118
*/
 
119
#define SETSOCKOPT winsock_versions_setsockopt
 
120
#else
 
121
#define SETSOCKOPT setsockopt
 
122
#endif /* WIN32 */
 
123
 
 
124
/*****************************************************************************/
 
125
/* Support functions...                                                      */
 
126
/*****************************************************************************/
 
127
 
 
128
static void
 
129
socket_error(const char *msg, ...)
 
130
{
 
131
        char            buffer[255];
 
132
        uint32_t        blen = sizeof(buffer) / sizeof(buffer[0]);
 
133
        va_list         ap;
 
134
 
 
135
#ifdef WIN32
 
136
#define WSERR(x) {#x,x}
 
137
        struct wse {
 
138
                char  errname[20];
 
139
                int my_errno;
 
140
        };
 
141
        struct wse ws_errs[] = {
 
142
                WSERR(WSANOTINITIALISED), WSERR(WSAENETDOWN),     WSERR(WSAEACCES),
 
143
                WSERR(WSAEINVAL),         WSERR(WSAEINTR),        WSERR(WSAEINPROGRESS),
 
144
                WSERR(WSAEFAULT),         WSERR(WSAENETRESET),    WSERR(WSAENOBUFS),
 
145
                WSERR(WSAENOTCONN),       WSERR(WSAENOTSOCK),     WSERR(WSAEOPNOTSUPP),
 
146
                WSERR(WSAESHUTDOWN),      WSERR(WSAEWOULDBLOCK),  WSERR(WSAEMSGSIZE),
 
147
                WSERR(WSAEHOSTUNREACH),   WSERR(WSAECONNABORTED), WSERR(WSAECONNRESET),
 
148
                WSERR(WSAEADDRNOTAVAIL),  WSERR(WSAEAFNOSUPPORT), WSERR(WSAEDESTADDRREQ),
 
149
                WSERR(WSAENETUNREACH),    WSERR(WSAETIMEDOUT),    WSERR(0)
 
150
        };
 
151
        
 
152
        int i, e = WSAGetLastError();
 
153
        i = 0;
 
154
        while(ws_errs[i].my_errno && ws_errs[i].my_errno != e) {
 
155
                i++;
 
156
        }
 
157
        va_start(ap, msg);
 
158
        _vsnprintf(buffer, blen, msg, ap);
 
159
        va_end(ap);
 
160
        printf("ERROR: %s, (%d - %s)\n", msg, e, ws_errs[i].errname);
 
161
#else
 
162
        va_start(ap, msg);
 
163
        vsnprintf(buffer, blen, msg, ap);
 
164
        va_end(ap);
 
165
        perror(buffer);
 
166
#endif
 
167
}
 
168
 
 
169
#ifdef WIN32
 
170
/* ws2tcpip.h defines these constants with different values from
 
171
* winsock.h so files that use winsock 2 values but try to use 
 
172
* winsock 1 fail.  So what was the motivation in changing the
 
173
* constants ?
 
174
*/
 
175
#define WS1_IP_MULTICAST_IF     2 /* set/get IP multicast interface   */
 
176
#define WS1_IP_MULTICAST_TTL    3 /* set/get IP multicast timetolive  */
 
177
#define WS1_IP_MULTICAST_LOOP   4 /* set/get IP multicast loopback    */
 
178
#define WS1_IP_ADD_MEMBERSHIP   5 /* add  an IP group membership      */
 
179
#define WS1_IP_DROP_MEMBERSHIP  6 /* drop an IP group membership      */
 
180
 
 
181
/* winsock_versions_setsockopt tries 1 winsock version of option 
 
182
* optname and then winsock 2 version if that failed.
 
183
* note: setting the TTL never fails, so we have to try both.
 
184
*/
 
185
 
 
186
static int
 
187
winsock_versions_setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen)
 
188
{
 
189
        int success = -1;
 
190
        switch (optname) {
 
191
        case IP_MULTICAST_IF:
 
192
                success = setsockopt(s, level, WS1_IP_MULTICAST_IF, optval, optlen);
 
193
                break;
 
194
        case IP_MULTICAST_TTL:
 
195
                success = setsockopt(s, level, WS1_IP_MULTICAST_TTL, optval, optlen);
 
196
                success = setsockopt(s, level, optname, optval, optlen);
 
197
                break;
 
198
        case IP_MULTICAST_LOOP:
 
199
                success = setsockopt(s, level, WS1_IP_MULTICAST_LOOP, optval, optlen);
 
200
                break;
 
201
        case IP_ADD_MEMBERSHIP: 
 
202
                success = setsockopt(s, level, WS1_IP_ADD_MEMBERSHIP, optval, optlen);
 
203
                break;
 
204
        case IP_DROP_MEMBERSHIP: 
 
205
                success = setsockopt(s, level, WS1_IP_DROP_MEMBERSHIP, optval, optlen);
 
206
                break;
 
207
        }
 
208
        if (success != -1) {
 
209
                return success;
 
210
        }
 
211
        return setsockopt(s, level, optname, optval, optlen);
 
212
}
 
213
#endif
 
214
 
 
215
#ifdef NEED_INET_ATON
 
216
#ifdef NEED_INET_ATON_STATIC
 
217
static 
 
218
#endif
 
219
int inet_aton(const char *name, struct in_addr *addr)
 
220
{
 
221
        addr->s_addr = inet_addr(name);
 
222
        return (addr->s_addr != (in_addr_t) INADDR_NONE);
 
223
}
 
224
#endif
 
225
 
 
226
#ifdef NEED_IN6_IS_ADDR_MULTICAST
 
227
#define IN6_IS_ADDR_MULTICAST(addr) ((addr)->s6_addr[0] == 0xffU)
 
228
#endif
 
229
 
 
230
#if defined(NEED_IN6_IS_ADDR_UNSPECIFIED) && defined(MUSICA_IPV6)
 
231
#define IN6_IS_ADDR_UNSPECIFIED(addr) IS_UNSPEC_IN6_ADDR(*addr)
 
232
#endif
 
233
 
 
234
 
 
235
 
 
236
/*****************************************************************************/
 
237
/* IPv4 specific functions...                                                */
 
238
/*****************************************************************************/
 
239
 
 
240
static int udp_addr_valid4(const char *dst)
 
241
{
 
242
        struct in_addr addr4;
 
243
        struct hostent *h;
 
244
 
 
245
        if (inet_pton(AF_INET, dst, &addr4)) {
 
246
                return TRUE;
 
247
        } 
 
248
 
 
249
        h = gethostbyname(dst);
 
250
        if (h != NULL) {
 
251
                return TRUE;
 
252
        }
 
253
        socket_error("Can't resolve IP address for %s", dst);
 
254
 
 
255
        return FALSE;
 
256
}
 
257
 
 
258
static socket_udp *udp_init4(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
 
259
{
 
260
        int                      reuse = 1, udpbufsize=1048576;
 
261
        struct sockaddr_in       s_in;
 
262
        struct in_addr           iface_addr;
 
263
#ifdef WIN32
 
264
      int recv_buf_size = 65536;
 
265
#endif
 
266
        socket_udp              *s = (socket_udp *)malloc(sizeof(socket_udp));
 
267
        s->mode    = IPv4;
 
268
        s->addr    = NULL;
 
269
        s->rx_port = rx_port;
 
270
        s->tx_port = tx_port;
 
271
        s->ttl     = ttl;
 
272
        if (inet_pton(AF_INET, addr, &s->addr4) != 1) {
 
273
                struct hostent *h = gethostbyname(addr);
 
274
                if (h == NULL) {
 
275
                        socket_error("Can't resolve IP address for %s", addr);
 
276
                        free(s);
 
277
                        return NULL;
 
278
                }
 
279
                memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4));
 
280
        }
 
281
        if (iface != NULL) {
 
282
                if (inet_pton(AF_INET, iface, &iface_addr) != 1) {
 
283
                        debug_msg("Illegal interface specification\n");
 
284
                        free(s);
 
285
                        return NULL;
 
286
                }
 
287
        } else {
 
288
                iface_addr.s_addr = 0;
 
289
        }
 
290
        s->fd = socket(AF_INET, SOCK_DGRAM, 0);
 
291
        if (s->fd < 0) {
 
292
                socket_error("socket");
 
293
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_SNDBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
 
294
                socket_error("setsockopt SO_SNDBUF");
 
295
                return NULL;
 
296
        }
 
297
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_RCVBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
 
298
                socket_error("setsockopt SO_RCVBUF");
 
299
                return NULL;
 
300
        }
 
301
                return NULL;
 
302
        }
 
303
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
 
304
                socket_error("setsockopt SO_REUSEADDR");
 
305
                return NULL;
 
306
        }
 
307
#ifdef SO_REUSEPORT
 
308
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
 
309
                socket_error("setsockopt SO_REUSEPORT");
 
310
                return NULL;
 
311
        }
 
312
#endif
 
313
        s_in.sin_family      = AF_INET;
 
314
        s_in.sin_addr.s_addr = INADDR_ANY;
 
315
        s_in.sin_port        = htons(rx_port);
 
316
        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
 
317
                socket_error("bind");
 
318
                return NULL;
 
319
        }
 
320
        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
 
321
                char            loop = 1;
 
322
                struct ip_mreq  imr;
 
323
                
 
324
                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
 
325
                imr.imr_interface.s_addr = iface_addr.s_addr;
 
326
                
 
327
                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
 
328
                        socket_error("setsockopt IP_ADD_MEMBERSHIP");
 
329
                        return NULL;
 
330
                }
 
331
#ifndef WIN32
 
332
                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) {
 
333
                        socket_error("setsockopt IP_MULTICAST_LOOP");
 
334
                        return NULL;
 
335
                }
 
336
#endif
 
337
                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &s->ttl, sizeof(s->ttl)) != 0) {
 
338
                        socket_error("setsockopt IP_MULTICAST_TTL");
 
339
                        return NULL;
 
340
                }
 
341
                if (iface_addr.s_addr != 0) {
 
342
                        if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &iface_addr, sizeof(iface_addr)) != 0) {
 
343
                                socket_error("setsockopt IP_MULTICAST_IF");
 
344
                                return NULL;
 
345
                        }
 
346
                }
 
347
        }
 
348
        s->addr = strdup(addr);
 
349
        return s;
 
350
}
 
351
 
 
352
static void udp_exit4(socket_udp *s)
 
353
{
 
354
        if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
 
355
                struct ip_mreq  imr;
 
356
                imr.imr_multiaddr.s_addr = s->addr4.s_addr;
 
357
                imr.imr_interface.s_addr = INADDR_ANY;
 
358
                if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
 
359
                        socket_error("setsockopt IP_DROP_MEMBERSHIP");
 
360
                        abort();
 
361
                }
 
362
                debug_msg("Dropped membership of multicast group\n");
 
363
        }
 
364
        close(s->fd);
 
365
        free(s->addr);
 
366
        free(s);
 
367
}
 
368
 
 
369
static inline int 
 
370
udp_send4(socket_udp *s, char *buffer, int buflen)
 
371
{
 
372
        struct sockaddr_in      s_in;
 
373
        
 
374
        assert(s != NULL);
 
375
        assert(s->mode == IPv4);
 
376
        assert(buffer != NULL);
 
377
        assert(buflen > 0);
 
378
        
 
379
        s_in.sin_family      = AF_INET;
 
380
        s_in.sin_addr.s_addr = s->addr4.s_addr;
 
381
        s_in.sin_port        = htons(s->tx_port);
 
382
        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
 
383
}
 
384
 
 
385
#ifndef WIN32
 
386
static inline int 
 
387
udp_sendv4(socket_udp *s, struct iovec *vector, int count)
 
388
{
 
389
        struct msghdr           msg;
 
390
        struct sockaddr_in      s_in;
 
391
        
 
392
        assert(s != NULL);
 
393
        assert(s->mode == IPv4);
 
394
        
 
395
        s_in.sin_family      = AF_INET;
 
396
        s_in.sin_addr.s_addr = s->addr4.s_addr;
 
397
        s_in.sin_port        = htons(s->tx_port);
 
398
 
 
399
        msg.msg_name       = (caddr_t) &s_in;
 
400
        msg.msg_namelen    = sizeof(s_in);
 
401
        msg.msg_iov        = vector;
 
402
        msg.msg_iovlen     = count;
 
403
#ifdef NDEF     /* Solaris does something different here... can we just ignore these fields? [csp] */
 
404
        msg.msg_control    = 0;
 
405
        msg.msg_controllen = 0;
 
406
        msg.msg_flags      = 0;
 
407
#endif
 
408
        return sendmsg(s->fd, &msg, 0);
 
409
}
 
410
#endif
 
411
 
 
412
static const char *udp_host_addr4(void)
 
413
{
 
414
        static char              hname[MAXHOSTNAMELEN];
 
415
        struct hostent          *hent;
 
416
        struct in_addr           iaddr;
 
417
        
 
418
        if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
 
419
                debug_msg("Cannot get hostname!");
 
420
                abort();
 
421
        }
 
422
        hent = gethostbyname(hname);
 
423
        if (hent == NULL) {
 
424
                socket_error("Can't resolve IP address for %s", hname);
 
425
                return NULL;
 
426
        }
 
427
        assert(hent->h_addrtype == AF_INET);
 
428
        memcpy(&iaddr.s_addr, hent->h_addr, sizeof(iaddr.s_addr));
 
429
        strncpy(hname, inet_ntoa(iaddr), MAXHOSTNAMELEN);
 
430
        return (const char*)hname;
 
431
}
 
432
 
 
433
/*****************************************************************************/
 
434
/* IPv6 specific functions...                                                */
 
435
/*****************************************************************************/
 
436
 
 
437
static int udp_addr_valid6(const char *dst)
 
438
{
 
439
#ifdef HAVE_IPv6
 
440
        struct in6_addr addr6;
 
441
        switch (inet_pton(AF_INET6, dst, &addr6)) {
 
442
        case 1:  
 
443
                return TRUE;
 
444
                break;
 
445
        case 0: 
 
446
                return FALSE;
 
447
                break;
 
448
        case -1: 
 
449
                debug_msg("inet_pton failed\n");
 
450
                errno = 0;
 
451
        }
 
452
#endif /* HAVE_IPv6 */
 
453
        UNUSED(dst);
 
454
        return FALSE;
 
455
}
 
456
 
 
457
static socket_udp *udp_init6(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
 
458
{
 
459
#ifdef HAVE_IPv6
 
460
        int                 reuse = 1;
 
461
        struct sockaddr_in6 s_in;
 
462
        socket_udp         *s = (socket_udp *) malloc(sizeof(socket_udp));
 
463
        s->mode    = IPv6;
 
464
        s->addr    = NULL;
 
465
        s->rx_port = rx_port;
 
466
        s->tx_port = tx_port;
 
467
        s->ttl     = ttl;
 
468
        
 
469
        if (iface != NULL) {
 
470
                debug_msg("Not yet implemented\n");
 
471
                abort();
 
472
        }
 
473
 
 
474
        if (inet_pton(AF_INET6, addr, &s->addr6) != 1) {
 
475
                /* We should probably try to do a DNS lookup on the name */
 
476
                /* here, but I'm trying to get the basics going first... */
 
477
                debug_msg("IPv6 address conversion failed\n");
 
478
                free(s);
 
479
                return NULL;    
 
480
        }
 
481
        s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
 
482
        if (s->fd < 0) {
 
483
                socket_error("socket");
 
484
                return NULL;
 
485
        }
 
486
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
 
487
                socket_error("setsockopt SO_REUSEADDR");
 
488
                return NULL;
 
489
        }
 
490
#ifdef SO_REUSEPORT
 
491
        if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
 
492
                socket_error("setsockopt SO_REUSEPORT");
 
493
                return NULL;
 
494
        }
 
495
#endif
 
496
        
 
497
        memset((char *)&s_in, 0, sizeof(s_in));
 
498
        s_in.sin6_family = AF_INET6;
 
499
        s_in.sin6_port   = htons(rx_port);
 
500
#ifdef HAVE_SIN6_LEN
 
501
        s_in.sin6_len    = sizeof(s_in);
 
502
#endif
 
503
        s_in.sin6_addr = in6addr_any;
 
504
        if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
 
505
                socket_error("bind");
 
506
                return NULL;
 
507
        }
 
508
        
 
509
        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
 
510
                unsigned int      loop = 1;
 
511
                struct ipv6_mreq  imr;
 
512
#ifdef MUSICA_IPV6
 
513
                imr.i6mr_interface = 1;
 
514
                imr.i6mr_multiaddr = s->addr6;
 
515
#else
 
516
                imr.ipv6mr_multiaddr = s->addr6;
 
517
                imr.ipv6mr_interface = 0;
 
518
#endif
 
519
                
 
520
                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr, sizeof(imr)) != 0) {
 
521
                        socket_error("setsockopt IPV6_ADD_MEMBERSHIP");
 
522
                        return NULL;
 
523
                }
 
524
                
 
525
                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) != 0) {
 
526
                        socket_error("setsockopt IPV6_MULTICAST_LOOP");
 
527
                        return NULL;
 
528
                }
 
529
                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof(ttl)) != 0) {
 
530
                        socket_error("setsockopt IPV6_MULTICAST_HOPS");
 
531
                        return NULL;
 
532
                }
 
533
        }
 
534
 
 
535
        assert(s != NULL);
 
536
 
 
537
        s->addr = strdup(addr);
 
538
        return s;
 
539
#else
 
540
        UNUSED(addr);
 
541
        UNUSED(iface);
 
542
        UNUSED(rx_port);
 
543
        UNUSED(tx_port);
 
544
        UNUSED(ttl);
 
545
        return NULL;
 
546
#endif
 
547
}
 
548
 
 
549
static void udp_exit6(socket_udp *s)
 
550
{
 
551
#ifdef HAVE_IPv6
 
552
        if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
 
553
                struct ipv6_mreq  imr;
 
554
#ifdef MUSICA_IPV6
 
555
                imr.i6mr_interface = 1;
 
556
                imr.i6mr_multiaddr = s->addr6;
 
557
#else
 
558
                imr.ipv6mr_multiaddr = s->addr6;
 
559
                imr.ipv6mr_interface = 0;
 
560
#endif
 
561
                
 
562
                if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
 
563
                        socket_error("setsockopt IPV6_DROP_MEMBERSHIP");
 
564
                        abort();
 
565
                }
 
566
        }
 
567
        close(s->fd);
 
568
        free(s->addr);
 
569
        free(s);
 
570
#else
 
571
        UNUSED(s);
 
572
#endif  /* HAVE_IPv6 */
 
573
}
 
574
 
 
575
static int udp_send6(socket_udp *s, char *buffer, int buflen)
 
576
{
 
577
#ifdef HAVE_IPv6
 
578
        struct sockaddr_in6     s_in;
 
579
        
 
580
        assert(s != NULL);
 
581
        assert(s->mode == IPv6);
 
582
        assert(buffer != NULL);
 
583
        assert(buflen > 0);
 
584
        
 
585
        memset((char *)&s_in, 0, sizeof(s_in));
 
586
        s_in.sin6_family = AF_INET6;
 
587
        s_in.sin6_addr   = s->addr6;
 
588
        s_in.sin6_port   = htons(s->tx_port);
 
589
#ifdef HAVE_SIN6_LEN
 
590
        s_in.sin6_len    = sizeof(s_in);
 
591
#endif
 
592
        return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
 
593
#else
 
594
        UNUSED(s);
 
595
        UNUSED(buffer);
 
596
        UNUSED(buflen);
 
597
        return -1;
 
598
#endif
 
599
}
 
600
 
 
601
#ifndef WIN32
 
602
static int 
 
603
udp_sendv6(socket_udp *s, struct iovec *vector, int count)
 
604
{
 
605
#ifdef HAVE_IPv6
 
606
        struct msghdr           msg;
 
607
        struct sockaddr_in6     s_in;
 
608
        
 
609
        assert(s != NULL);
 
610
        assert(s->mode == IPv6);
 
611
        
 
612
        memset((char *)&s_in, 0, sizeof(s_in));
 
613
        s_in.sin6_family = AF_INET6;
 
614
        s_in.sin6_addr   = s->addr6;
 
615
        s_in.sin6_port   = htons(s->tx_port);
 
616
#ifdef HAVE_SIN6_LEN
 
617
        s_in.sin6_len    = sizeof(s_in);
 
618
#endif
 
619
        msg.msg_name       = &s_in;
 
620
        msg.msg_namelen    = sizeof(s_in);
 
621
        msg.msg_iov        = vector;
 
622
        msg.msg_iovlen     = count;
 
623
#ifdef HAVE_MSGHDR_MSGCTRL  
 
624
        msg.msg_control    = 0;
 
625
        msg.msg_controllen = 0;
 
626
        msg.msg_flags      = 0;
 
627
#endif
 
628
        return sendmsg(s->fd, &msg, 0);
 
629
#else
 
630
        UNUSED(s);
 
631
        UNUSED(vector);
 
632
        UNUSED(count);
 
633
        return -1;
 
634
#endif
 
635
}
 
636
#endif
 
637
 
 
638
static const char *udp_host_addr6(socket_udp *s)
 
639
{
 
640
#ifdef HAVE_IPv6
 
641
        static char              hname[MAXHOSTNAMELEN];
 
642
        int                      gai_err, newsock;
 
643
        struct addrinfo          hints, *ai;
 
644
        struct sockaddr_in6      local, addr6;
 
645
        int len = sizeof(local), result = 0;
 
646
 
 
647
        newsock=socket(AF_INET6, SOCK_DGRAM,0);
 
648
    memset ((char *)&addr6, 0, len);
 
649
    addr6.sin6_family = AF_INET6;
 
650
#ifdef HAVE_SIN6_LEN
 
651
    addr6.sin6_len    = len;
 
652
#endif
 
653
    bind (newsock, (struct sockaddr *) &addr6, len);
 
654
    addr6.sin6_addr = s->addr6;
 
655
    addr6.sin6_port = htons (s->rx_port);
 
656
    connect (newsock, (struct sockaddr *) &addr6, len);
 
657
 
 
658
    memset ((char *)&local, 0, len);
 
659
        if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){
 
660
                local.sin6_addr = in6addr_any;
 
661
                local.sin6_port = 0;
 
662
                debug_msg("getsockname failed\n");
 
663
        }
 
664
 
 
665
        close (newsock);
 
666
 
 
667
        if (IN6_IS_ADDR_UNSPECIFIED(&local.sin6_addr) || IN6_IS_ADDR_MULTICAST(&local.sin6_addr)) {
 
668
                if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
 
669
                        debug_msg("gethostname failed\n");
 
670
                        abort();
 
671
                }
 
672
                
 
673
                hints.ai_protocol  = 0;
 
674
                hints.ai_flags     = 0;
 
675
                hints.ai_family    = AF_INET6;
 
676
                hints.ai_socktype  = SOCK_DGRAM;
 
677
                hints.ai_addrlen   = 0;
 
678
                hints.ai_canonname = NULL;
 
679
                hints.ai_addr      = NULL;
 
680
                hints.ai_next      = NULL;
 
681
 
 
682
                if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) {
 
683
                        debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err));
 
684
                        abort();
 
685
                }
 
686
                
 
687
                if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr), hname, MAXHOSTNAMELEN) == NULL) {
 
688
                        debug_msg("inet_ntop: %s: \n", hname);
 
689
                        abort();
 
690
                }
 
691
                freeaddrinfo(ai);
 
692
                return (const char*)hname;
 
693
        }
 
694
        if (inet_ntop(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) {
 
695
                debug_msg("inet_ntop: %s: \n", hname);
 
696
                abort();
 
697
        }
 
698
        return (const char*)hname;
 
699
#else  /* HAVE_IPv6 */
 
700
        UNUSED(s);
 
701
        return "::";    /* The unspecified address... */
 
702
#endif /* HAVE_IPv6 */
 
703
}
 
704
        
 
705
/*****************************************************************************/
 
706
/* Generic functions, which call the appropriate protocol specific routines. */
 
707
/*****************************************************************************/
 
708
 
 
709
/**
 
710
 * udp_addr_valid:
 
711
 * @addr: string representation of IPv4 or IPv6 network address.
 
712
 *
 
713
 * Returns TRUE if @addr is valid, FALSE otherwise.
 
714
 **/
 
715
 
 
716
int udp_addr_valid(const char *addr)
 
717
{
 
718
        return udp_addr_valid4(addr) | udp_addr_valid6(addr);
 
719
}
 
720
 
 
721
/**
 
722
 * udp_init:
 
723
 * @addr: character string containing an IPv4 or IPv6 network address.
 
724
 * @rx_port: receive port.
 
725
 * @tx_port: transmit port.
 
726
 * @ttl: time-to-live value for transmitted packets.
 
727
 *
 
728
 * Creates a session for sending and receiving UDP datagrams over IP
 
729
 * networks. 
 
730
 *
 
731
 * Returns: a pointer to a valid socket_udp structure on success, NULL otherwise.
 
732
 **/
 
733
socket_udp *udp_init(const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl)
 
734
{
 
735
        return udp_init_if(addr, NULL, rx_port, tx_port, ttl);
 
736
}
 
737
 
 
738
/**
 
739
 * udp_init_if:
 
740
 * @addr: character string containing an IPv4 or IPv6 network address.
 
741
 * @iface: character string containing an interface name.
 
742
 * @rx_port: receive port.
 
743
 * @tx_port: transmit port.
 
744
 * @ttl: time-to-live value for transmitted packets.
 
745
 *
 
746
 * Creates a session for sending and receiving UDP datagrams over IP
 
747
 * networks.  The session uses @iface as the interface to send and
 
748
 * receive datagrams on.
 
749
 * 
 
750
 * Return value: a pointer to a socket_udp structure on success, NULL otherwise.
 
751
 **/
 
752
socket_udp *udp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
 
753
{
 
754
        socket_udp *res;
 
755
        
 
756
        if (strchr(addr, ':') == NULL) {
 
757
                res = udp_init4(addr, iface, rx_port, tx_port, ttl);
 
758
        } else {
 
759
                res = udp_init6(addr, iface, rx_port, tx_port, ttl);
 
760
        }
 
761
        return res;
 
762
}
 
763
 
 
764
/**
 
765
 * udp_exit:
 
766
 * @s: UDP session to be terminated.
 
767
 *
 
768
 * Closes UDP session.
 
769
 * 
 
770
 **/
 
771
void udp_exit(socket_udp *s)
 
772
{
 
773
    switch(s->mode) {
 
774
    case IPv4 : udp_exit4(s); break;
 
775
    case IPv6 : udp_exit6(s); break;
 
776
    default   : abort();
 
777
    }
 
778
}
 
779
 
 
780
/**
 
781
 * udp_send:
 
782
 * @s: UDP session.
 
783
 * @buffer: pointer to buffer to be transmitted.
 
784
 * @buflen: length of @buffer.
 
785
 * 
 
786
 * Transmits a UDP datagram containing data from @buffer.
 
787
 * 
 
788
 * Return value: 0 on success, -1 on failure.
 
789
 **/
 
790
int udp_send(socket_udp *s, char *buffer, int buflen)
 
791
{
 
792
        switch (s->mode) {
 
793
        case IPv4 : return udp_send4(s, buffer, buflen);
 
794
        case IPv6 : return udp_send6(s, buffer, buflen);
 
795
        default   : abort(); /* Yuk! */
 
796
        }
 
797
        return -1;
 
798
}
 
799
 
 
800
 
 
801
#ifndef WIN32
 
802
int         
 
803
udp_sendv(socket_udp *s, struct iovec *vector, int count)
 
804
{
 
805
        switch (s->mode) {
 
806
        case IPv4 : return udp_sendv4(s, vector, count);
 
807
        case IPv6 : return udp_sendv6(s, vector, count);
 
808
        default   : abort(); /* Yuk! */
 
809
        }
 
810
        return -1;
 
811
}
 
812
#endif
 
813
 
 
814
/**
 
815
 * udp_recv:
 
816
 * @s: UDP session.
 
817
 * @buffer: buffer to read data into.
 
818
 * @buflen: length of @buffer.
 
819
 * 
 
820
 * Reads from datagram queue associated with UDP session.
 
821
 *
 
822
 * Return value: number of bytes read, returns 0 if no data is available.
 
823
 **/
 
824
int udp_recv(socket_udp *s, char *buffer, int buflen)
 
825
{
 
826
        /* Reads data into the buffer, returning the number of bytes read.   */
 
827
        /* If no data is available, this returns the value zero immediately. */
 
828
        /* Note: since we don't care about the source address of the packet  */
 
829
        /* we receive, this function becomes protocol independent.           */
 
830
        int             len;
 
831
 
 
832
        assert(buffer != NULL);
 
833
        assert(buflen > 0);
 
834
 
 
835
        len = recvfrom(s->fd, buffer, buflen, 0, 0, 0);
 
836
        if (len > 0) {
 
837
                return len;
 
838
        }
 
839
        if (errno != ECONNREFUSED) {
 
840
                socket_error("recvfrom");
 
841
        }
 
842
        return 0;
 
843
}
 
844
 
 
845
static fd_set   rfd;
 
846
static fd_t     max_fd;
 
847
 
 
848
/**
 
849
 * udp_fd_zero:
 
850
 * 
 
851
 * Clears file descriptor from set associated with UDP sessions (see select(2)).
 
852
 * 
 
853
 **/
 
854
void udp_fd_zero(void)
 
855
{
 
856
        FD_ZERO(&rfd);
 
857
        max_fd = 0;
 
858
}
 
859
 
 
860
/**
 
861
 * udp_fd_set:
 
862
 * @s: UDP session.
 
863
 * 
 
864
 * Adds file descriptor associated of @s to set associated with UDP sessions.
 
865
 **/
 
866
void udp_fd_set(socket_udp *s)
 
867
{
 
868
        FD_SET(s->fd, &rfd);
 
869
        if (s->fd > (fd_t)max_fd) {
 
870
                max_fd = s->fd;
 
871
        }
 
872
}
 
873
 
 
874
/**
 
875
 * udp_fd_isset:
 
876
 * @s: UDP session.
 
877
 * 
 
878
 * Checks if file descriptor associated with UDP session is ready for
 
879
 * reading.  This function should be called after udp_select().
 
880
 *
 
881
 * Returns: non-zero if set, zero otherwise.
 
882
 **/
 
883
int udp_fd_isset(socket_udp *s)
 
884
{
 
885
        return FD_ISSET(s->fd, &rfd);
 
886
}
 
887
 
 
888
/**
 
889
 * udp_select:
 
890
 * @timeout: maximum period to wait for data to arrive.
 
891
 * 
 
892
 * Waits for data to arrive for UDP sessions.
 
893
 * 
 
894
 * Return value: number of UDP sessions ready for reading.
 
895
 **/
 
896
int udp_select(struct timeval *timeout)
 
897
{
 
898
        return select(max_fd + 1, &rfd, NULL, NULL, timeout);
 
899
}
 
900
 
 
901
/**
 
902
 * udp_host_addr:
 
903
 * @s: UDP session.
 
904
 * 
 
905
 * Return value: character string containing network address
 
906
 * associated with session @s.
 
907
 **/
 
908
const char *udp_host_addr(socket_udp *s)
 
909
{
 
910
        switch (s->mode) {
 
911
        case IPv4 : return udp_host_addr4();
 
912
        case IPv6 : return udp_host_addr6(s);
 
913
        default   : abort();
 
914
        }
 
915
        return NULL;
 
916
}
 
917
 
 
918
/**
 
919
 * udp_fd:
 
920
 * @s: UDP session.
 
921
 * 
 
922
 * This function allows applications to apply their own socketopt()'s
 
923
 * and ioctl()'s to the UDP session.
 
924
 * 
 
925
 * Return value: file descriptor of socket used by session @s.
 
926
 **/
 
927
int udp_fd(socket_udp *s)
 
928
{
 
929
        if (s && s->fd > 0) {
 
930
                return s->fd;
 
931
        } 
 
932
        return 0;
 
933
}
 
934
 
 
935