3
* AUTHOR: Colin Perkins
4
* MODIFIED: Orion Hodson, Piers O'Hanlon, Kristian Hasler
6
* Copyright (c) 1998-2000 University College London
9
* Redistribution and use in source and binary forms, with or without
10
* modification, is permitted provided that the following conditions
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
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 */
42
#include "config_unix.h"
43
#include "config_win32.h"
46
#include "inet_pton.h"
47
#include "inet_ntop.h"
48
#include "vsnprintf.h"
51
#ifdef NEED_ADDRINFO_H
59
const struct in6_addr in6addr_any = {IN6ADDR_ANY_INIT};
63
const struct in6_addr in6addr_any = {IN6ADDR_ANY_INIT};
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 */
71
#define IPPROTO_IPV6 IPPROTO_IP
72
struct in6_addr in6addr_any = {IN6ADDR_ANY_INIT};
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.
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 */
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))
92
struct in_addr imr_multiaddr; /* IP multicast address of group */
93
struct in_addr imr_interface; /* local IP address of interface */
98
#define INADDR_NONE 0xffffffff
102
int mode; /* IPv4 or IPv6 */
108
struct in_addr addr4;
110
struct in6_addr addr6;
111
#endif /* HAVE_IPv6 */
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.
119
#define SETSOCKOPT winsock_versions_setsockopt
121
#define SETSOCKOPT setsockopt
124
/*****************************************************************************/
125
/* Support functions... */
126
/*****************************************************************************/
129
socket_error(const char *msg, ...)
132
uint32_t blen = sizeof(buffer) / sizeof(buffer[0]);
136
#define WSERR(x) {#x,x}
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)
152
int i, e = WSAGetLastError();
154
while(ws_errs[i].my_errno && ws_errs[i].my_errno != e) {
158
_vsnprintf(buffer, blen, msg, ap);
160
printf("ERROR: %s, (%d - %s)\n", msg, e, ws_errs[i].errname);
163
vsnprintf(buffer, blen, msg, ap);
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
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 */
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.
187
winsock_versions_setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen)
191
case IP_MULTICAST_IF:
192
success = setsockopt(s, level, WS1_IP_MULTICAST_IF, optval, optlen);
194
case IP_MULTICAST_TTL:
195
success = setsockopt(s, level, WS1_IP_MULTICAST_TTL, optval, optlen);
196
success = setsockopt(s, level, optname, optval, optlen);
198
case IP_MULTICAST_LOOP:
199
success = setsockopt(s, level, WS1_IP_MULTICAST_LOOP, optval, optlen);
201
case IP_ADD_MEMBERSHIP:
202
success = setsockopt(s, level, WS1_IP_ADD_MEMBERSHIP, optval, optlen);
204
case IP_DROP_MEMBERSHIP:
205
success = setsockopt(s, level, WS1_IP_DROP_MEMBERSHIP, optval, optlen);
211
return setsockopt(s, level, optname, optval, optlen);
215
#ifdef NEED_INET_ATON
216
#ifdef NEED_INET_ATON_STATIC
219
int inet_aton(const char *name, struct in_addr *addr)
221
addr->s_addr = inet_addr(name);
222
return (addr->s_addr != (in_addr_t) INADDR_NONE);
226
#ifdef NEED_IN6_IS_ADDR_MULTICAST
227
#define IN6_IS_ADDR_MULTICAST(addr) ((addr)->s6_addr[0] == 0xffU)
230
#if defined(NEED_IN6_IS_ADDR_UNSPECIFIED) && defined(MUSICA_IPV6)
231
#define IN6_IS_ADDR_UNSPECIFIED(addr) IS_UNSPEC_IN6_ADDR(*addr)
236
/*****************************************************************************/
237
/* IPv4 specific functions... */
238
/*****************************************************************************/
240
static int udp_addr_valid4(const char *dst)
242
struct in_addr addr4;
245
if (inet_pton(AF_INET, dst, &addr4)) {
249
h = gethostbyname(dst);
253
socket_error("Can't resolve IP address for %s", dst);
258
static socket_udp *udp_init4(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
260
int reuse = 1, udpbufsize=1048576;
261
struct sockaddr_in s_in;
262
struct in_addr iface_addr;
264
int recv_buf_size = 65536;
266
socket_udp *s = (socket_udp *)malloc(sizeof(socket_udp));
269
s->rx_port = rx_port;
270
s->tx_port = tx_port;
272
if (inet_pton(AF_INET, addr, &s->addr4) != 1) {
273
struct hostent *h = gethostbyname(addr);
275
socket_error("Can't resolve IP address for %s", addr);
279
memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4));
282
if (inet_pton(AF_INET, iface, &iface_addr) != 1) {
283
debug_msg("Illegal interface specification\n");
288
iface_addr.s_addr = 0;
290
s->fd = socket(AF_INET, SOCK_DGRAM, 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");
297
if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_RCVBUF, (char *) &udpbufsize, sizeof(udpbufsize)) != 0) {
298
socket_error("setsockopt SO_RCVBUF");
303
if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
304
socket_error("setsockopt SO_REUSEADDR");
308
if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
309
socket_error("setsockopt SO_REUSEPORT");
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");
320
if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
324
imr.imr_multiaddr.s_addr = s->addr4.s_addr;
325
imr.imr_interface.s_addr = iface_addr.s_addr;
327
if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) {
328
socket_error("setsockopt IP_ADD_MEMBERSHIP");
332
if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) {
333
socket_error("setsockopt IP_MULTICAST_LOOP");
337
if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &s->ttl, sizeof(s->ttl)) != 0) {
338
socket_error("setsockopt IP_MULTICAST_TTL");
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");
348
s->addr = strdup(addr);
352
static void udp_exit4(socket_udp *s)
354
if (IN_MULTICAST(ntohl(s->addr4.s_addr))) {
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");
362
debug_msg("Dropped membership of multicast group\n");
370
udp_send4(socket_udp *s, char *buffer, int buflen)
372
struct sockaddr_in s_in;
375
assert(s->mode == IPv4);
376
assert(buffer != NULL);
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));
387
udp_sendv4(socket_udp *s, struct iovec *vector, int count)
390
struct sockaddr_in s_in;
393
assert(s->mode == IPv4);
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);
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] */
405
msg.msg_controllen = 0;
408
return sendmsg(s->fd, &msg, 0);
412
static const char *udp_host_addr4(void)
414
static char hname[MAXHOSTNAMELEN];
415
struct hostent *hent;
416
struct in_addr iaddr;
418
if (gethostname(hname, MAXHOSTNAMELEN) != 0) {
419
debug_msg("Cannot get hostname!");
422
hent = gethostbyname(hname);
424
socket_error("Can't resolve IP address for %s", hname);
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;
433
/*****************************************************************************/
434
/* IPv6 specific functions... */
435
/*****************************************************************************/
437
static int udp_addr_valid6(const char *dst)
440
struct in6_addr addr6;
441
switch (inet_pton(AF_INET6, dst, &addr6)) {
449
debug_msg("inet_pton failed\n");
452
#endif /* HAVE_IPv6 */
457
static socket_udp *udp_init6(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
461
struct sockaddr_in6 s_in;
462
socket_udp *s = (socket_udp *) malloc(sizeof(socket_udp));
465
s->rx_port = rx_port;
466
s->tx_port = tx_port;
470
debug_msg("Not yet implemented\n");
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");
481
s->fd = socket(AF_INET6, SOCK_DGRAM, 0);
483
socket_error("socket");
486
if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) {
487
socket_error("setsockopt SO_REUSEADDR");
491
if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) {
492
socket_error("setsockopt SO_REUSEPORT");
497
memset((char *)&s_in, 0, sizeof(s_in));
498
s_in.sin6_family = AF_INET6;
499
s_in.sin6_port = htons(rx_port);
501
s_in.sin6_len = sizeof(s_in);
503
s_in.sin6_addr = in6addr_any;
504
if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) {
505
socket_error("bind");
509
if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
510
unsigned int loop = 1;
511
struct ipv6_mreq imr;
513
imr.i6mr_interface = 1;
514
imr.i6mr_multiaddr = s->addr6;
516
imr.ipv6mr_multiaddr = s->addr6;
517
imr.ipv6mr_interface = 0;
520
if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr, sizeof(imr)) != 0) {
521
socket_error("setsockopt IPV6_ADD_MEMBERSHIP");
525
if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) != 0) {
526
socket_error("setsockopt IPV6_MULTICAST_LOOP");
529
if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof(ttl)) != 0) {
530
socket_error("setsockopt IPV6_MULTICAST_HOPS");
537
s->addr = strdup(addr);
549
static void udp_exit6(socket_udp *s)
552
if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) {
553
struct ipv6_mreq imr;
555
imr.i6mr_interface = 1;
556
imr.i6mr_multiaddr = s->addr6;
558
imr.ipv6mr_multiaddr = s->addr6;
559
imr.ipv6mr_interface = 0;
562
if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) {
563
socket_error("setsockopt IPV6_DROP_MEMBERSHIP");
572
#endif /* HAVE_IPv6 */
575
static int udp_send6(socket_udp *s, char *buffer, int buflen)
578
struct sockaddr_in6 s_in;
581
assert(s->mode == IPv6);
582
assert(buffer != NULL);
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);
590
s_in.sin6_len = sizeof(s_in);
592
return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));
603
udp_sendv6(socket_udp *s, struct iovec *vector, int count)
607
struct sockaddr_in6 s_in;
610
assert(s->mode == IPv6);
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);
617
s_in.sin6_len = sizeof(s_in);
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
625
msg.msg_controllen = 0;
628
return sendmsg(s->fd, &msg, 0);
638
static const char *udp_host_addr6(socket_udp *s)
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;
647
newsock=socket(AF_INET6, SOCK_DGRAM,0);
648
memset ((char *)&addr6, 0, len);
649
addr6.sin6_family = AF_INET6;
651
addr6.sin6_len = len;
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);
658
memset ((char *)&local, 0, len);
659
if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){
660
local.sin6_addr = in6addr_any;
662
debug_msg("getsockname failed\n");
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");
673
hints.ai_protocol = 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;
682
if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) {
683
debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err));
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);
692
return (const char*)hname;
694
if (inet_ntop(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) {
695
debug_msg("inet_ntop: %s: \n", hname);
698
return (const char*)hname;
699
#else /* HAVE_IPv6 */
701
return "::"; /* The unspecified address... */
702
#endif /* HAVE_IPv6 */
705
/*****************************************************************************/
706
/* Generic functions, which call the appropriate protocol specific routines. */
707
/*****************************************************************************/
711
* @addr: string representation of IPv4 or IPv6 network address.
713
* Returns TRUE if @addr is valid, FALSE otherwise.
716
int udp_addr_valid(const char *addr)
718
return udp_addr_valid4(addr) | udp_addr_valid6(addr);
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.
728
* Creates a session for sending and receiving UDP datagrams over IP
731
* Returns: a pointer to a valid socket_udp structure on success, NULL otherwise.
733
socket_udp *udp_init(const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl)
735
return udp_init_if(addr, NULL, rx_port, tx_port, ttl);
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.
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.
750
* Return value: a pointer to a socket_udp structure on success, NULL otherwise.
752
socket_udp *udp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl)
756
if (strchr(addr, ':') == NULL) {
757
res = udp_init4(addr, iface, rx_port, tx_port, ttl);
759
res = udp_init6(addr, iface, rx_port, tx_port, ttl);
766
* @s: UDP session to be terminated.
768
* Closes UDP session.
771
void udp_exit(socket_udp *s)
774
case IPv4 : udp_exit4(s); break;
775
case IPv6 : udp_exit6(s); break;
783
* @buffer: pointer to buffer to be transmitted.
784
* @buflen: length of @buffer.
786
* Transmits a UDP datagram containing data from @buffer.
788
* Return value: 0 on success, -1 on failure.
790
int udp_send(socket_udp *s, char *buffer, int buflen)
793
case IPv4 : return udp_send4(s, buffer, buflen);
794
case IPv6 : return udp_send6(s, buffer, buflen);
795
default : abort(); /* Yuk! */
803
udp_sendv(socket_udp *s, struct iovec *vector, int count)
806
case IPv4 : return udp_sendv4(s, vector, count);
807
case IPv6 : return udp_sendv6(s, vector, count);
808
default : abort(); /* Yuk! */
817
* @buffer: buffer to read data into.
818
* @buflen: length of @buffer.
820
* Reads from datagram queue associated with UDP session.
822
* Return value: number of bytes read, returns 0 if no data is available.
824
int udp_recv(socket_udp *s, char *buffer, int buflen)
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. */
832
assert(buffer != NULL);
835
len = recvfrom(s->fd, buffer, buflen, 0, 0, 0);
839
if (errno != ECONNREFUSED) {
840
socket_error("recvfrom");
851
* Clears file descriptor from set associated with UDP sessions (see select(2)).
854
void udp_fd_zero(void)
864
* Adds file descriptor associated of @s to set associated with UDP sessions.
866
void udp_fd_set(socket_udp *s)
869
if (s->fd > (fd_t)max_fd) {
878
* Checks if file descriptor associated with UDP session is ready for
879
* reading. This function should be called after udp_select().
881
* Returns: non-zero if set, zero otherwise.
883
int udp_fd_isset(socket_udp *s)
885
return FD_ISSET(s->fd, &rfd);
890
* @timeout: maximum period to wait for data to arrive.
892
* Waits for data to arrive for UDP sessions.
894
* Return value: number of UDP sessions ready for reading.
896
int udp_select(struct timeval *timeout)
898
return select(max_fd + 1, &rfd, NULL, NULL, timeout);
905
* Return value: character string containing network address
906
* associated with session @s.
908
const char *udp_host_addr(socket_udp *s)
911
case IPv4 : return udp_host_addr4();
912
case IPv6 : return udp_host_addr6(s);
922
* This function allows applications to apply their own socketopt()'s
923
* and ioctl()'s to the UDP session.
925
* Return value: file descriptor of socket used by session @s.
927
int udp_fd(socket_udp *s)
929
if (s && s->fd > 0) {