blob: fd84156b5b7b662ae81849591f58d70df8e9acef [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <ucommon-config.h>
40#include <commoncpp/config.h>
41#include <commoncpp/export.h>
42#include <commoncpp/string.h>
43#include <commoncpp/socket.h>
44#include <commoncpp/udp.h>
45
46#ifdef _MSWINDOWS_
47#include <io.h>
48#define _IOLEN64 (unsigned)
49#define _IORET64 (int)
50typedef int socklen_t;
51
52#define socket_errno WSAGetLastError()
53#else
54#include <sys/ioctl.h>
55#include <netinet/tcp.h>
56#ifdef HAVE_NET_IP6_H
57#include <netinet/ip6.h>
58#endif
59#define socket_errno errno
60# ifndef O_NONBLOCK
61# define O_NONBLOCK O_NDELAY
62# endif
63# ifdef IPPROTO_IP
64# ifndef SOL_IP
65# define SOL_IP IPPROTO_IP
66# endif // !SOL_IP
67# endif // IPPROTO_IP
68#endif // !WIN32
69
70#ifndef INADDR_LOOPBACK
71#define INADDR_LOOPBACK (unsigned long)0x7f000001
72#endif
73
74#ifdef HAVE_NETINET_IN_H
75#include <netinet/in.h>
76#endif
77
78#if defined(__hpux)
79#define _XOPEN_SOURCE_EXTENDED
80#endif
81
82#ifdef HAVE_NET_IF_H
83#include <net/if.h>
84#endif
85
86#ifndef _IOLEN64
87#define _IOLEN64
88#endif
89
90#ifndef _IORET64
91#define _IORET64
92#endif
93
94using namespace COMMONCPP_NAMESPACE;
95
96#ifdef HAVE_GETADDRINFO
97
98UDPSocket::UDPSocket(const char *name, Family fam) :
99Socket(fam, SOCK_DGRAM, IPPROTO_UDP)
100{
101 char namebuf[128], *cp;
102 struct addrinfo hint, *list = NULL, *first;
103
104 family = fam;
105
106 switch(fam) {
107#ifdef CCXX_IPV6
108 case IPV6:
109 peer.ipv6.sin6_family = family;
110 break;
111#endif
112 case IPV4:
113 peer.ipv4.sin_family = family;
114 }
115
116 snprintf(namebuf, sizeof(namebuf), "%s", name);
117 cp = strrchr(namebuf, '/');
118 if(!cp && family == IPV4)
119 cp = strrchr(namebuf, ':');
120
121 if(!cp) {
122 cp = namebuf;
123 name = NULL;
124 }
125 else {
126 name = namebuf;
127 *(cp++) = 0;
128 if(!strcmp(name, "*"))
129 name = NULL;
130 }
131
132 memset(&hint, 0, sizeof(hint));
133
134 hint.ai_family = family;
135 hint.ai_socktype = SOCK_DGRAM;
136 hint.ai_protocol = IPPROTO_UDP;
137 hint.ai_flags = AI_PASSIVE;
138
139 if(getaddrinfo(name, cp, &hint, &list) || !list) {
140 error(errBindingFailed, (char *)"Could not find service", errno);
141 endSocket();
142 return;
143 }
144
145#if defined(SO_REUSEADDR)
146 int opt = 1;
147 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
148 (socklen_t)sizeof(opt));
149#endif
150
151 first = list;
152
153 while(list) {
154 if(!bind(so, list->ai_addr, (socklen_t)list->ai_addrlen)) {
155 state = BOUND;
156 break;
157 }
158 list = list->ai_next;
159 }
160 freeaddrinfo(first);
161
162 if(state != BOUND) {
163 endSocket();
164 error(errBindingFailed, (char *)"Count not bind socket", errno);
165 return;
166 }
167}
168
169#else
170
171UDPSocket::UDPSocket(const char *name, Family fam) :
172Socket(fam, SOCK_DGRAM, IPPROTO_UDP)
173{
174 char namebuf[128], *cp;
175 tpport_t port = 0;
176 struct servent *svc = NULL;
177 socklen_t alen = 0;
178 struct sockaddr *addr = NULL;
179
180 family = fam;
181
182 snprintf(namebuf, sizeof(namebuf), "%s", name);
183 cp = strrchr(namebuf, '/');
184 if(!cp && family == IPV4)
185 cp = strrchr(namebuf, ':');
186
187 if(!cp) {
188 cp = namebuf;
189 name = "*";
190 }
191 else {
192 name = namebuf;
193 *(cp++) = 0;
194 }
195
196 if(isdigit(*cp))
197 port = atoi(cp);
198 else {
199 mutex.enter();
200 svc = getservbyname(cp, "udp");
201 if(svc)
202 port = ntohs(svc->s_port);
203 mutex.leave();
204 if(!svc) {
205 error(errBindingFailed, (char *)"Could not find service", errno);
206 endSocket();
207 return;
208 }
209 }
210
211 struct sockaddr_in addr4;
212 IPV4Address ia4(name);
213#ifdef CCXX_IPV6
214 struct sockaddr_in6 addr6;
215 IPV6Address ia6(name);
216#endif
217
218 switch(family) {
219#ifdef CCXX_IPV6
220 case IPV6:
221 peer.ipv6.sin6_family = family;
222 memset(&addr6, 0, sizeof(addr6));
223 addr6.sin6_family = family;
224 addr6.sin6_addr = ia6.getAddress();
225 addr6.sin6_port = htons(port);
226 alen = sizeof(addr6);
227 addr = (struct sockaddr *)&addr6;
228 break;
229#endif
230 case IPV4:
231 peer.ipv4.sin_family = family;
232 memset(&addr4, 0, sizeof(addr4));
233 addr4.sin_family = family;
234 addr4.sin_addr = ia4.getAddress();
235 addr4.sin_port = htons(port);
236 alen = sizeof(&addr4);
237 addr = (struct sockaddr *)&addr4;
238 }
239
240#if defined(SO_REUSEADDR)
241 int opt = 1;
242 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
243 (socklen_t)sizeof(opt));
244#endif
245
246 if(addr && !bind(so, addr, alen))
247 state = BOUND;
248
249 if(state != BOUND) {
250 endSocket();
251 error(errBindingFailed, (char *)"Count not bind socket", errno);
252 return;
253 }
254}
255
256#endif
257
258UDPSocket::UDPSocket(Family fam) :
259Socket(fam, SOCK_DGRAM, IPPROTO_UDP)
260{
261 family = fam;
262 memset(&peer, 0, sizeof(peer));
263 switch(fam) {
264#ifdef CCXX_IPV6
265 case IPV6:
266 peer.ipv6.sin6_family = family;
267 break;
268#endif
269 case IPV4:
270 peer.ipv4.sin_family = family;
271 }
272}
273
274UDPSocket::UDPSocket(const IPV4Address &ia, tpport_t port) :
275Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
276{
277 family = IPV4;
278 memset(&peer.ipv4, 0, sizeof(peer));
279 peer.ipv4.sin_family = AF_INET;
280 peer.ipv4.sin_addr = ia.getAddress();
281 peer.ipv4.sin_port = htons(port);
282#if defined(SO_REUSEADDR)
283 int opt = 1;
284 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
285#endif
286 if(bind(so, (struct sockaddr *)&peer.ipv4, sizeof(peer.ipv4))) {
287 endSocket();
288 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
289 return;
290 }
291 state = BOUND;
292}
293
294#ifdef CCXX_IPV6
295UDPSocket::UDPSocket(const IPV6Address &ia, tpport_t port) :
296Socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
297{
298 family = IPV6;
299 memset(&peer.ipv6, 0, sizeof(peer));
300 peer.ipv6.sin6_family = AF_INET6;
301 peer.ipv6.sin6_addr = ia.getAddress();
302 peer.ipv6.sin6_port = htons(port);
303#if defined(SO_REUSEADDR)
304 int opt = 1;
305 setsockopt(so, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, (socklen_t)sizeof(opt));
306#endif
307 if(bind(so, (struct sockaddr *)&peer.ipv6, sizeof(peer.ipv6))) {
308 endSocket();
309 error(errBindingFailed,(char *)"Could not bind socket",socket_errno);
310 return;
311 }
312 state = BOUND;
313}
314#endif
315
316UDPSocket::~UDPSocket()
317{
318 endSocket();
319}
320
321ssize_t UDPSocket::send(const void *buf, size_t len)
322{
323 struct sockaddr *addr = NULL;
324 socklen_t alen = 0;
325
326 switch(family) {
327#ifdef CCXX_IPV6
328 case IPV6:
329 addr = (struct sockaddr *)&peer.ipv6;
330 alen = sizeof(struct sockaddr_in6);
331 break;
332#endif
333 case IPV4:
334 addr = (struct sockaddr *)&peer.ipv4;
335 alen = sizeof(struct sockaddr_in);
336 break;
337 default:
338 return -1;
339 }
340
341 if(isConnected()) {
342 addr = NULL;
343 alen = 0;
344 }
345
346 return _IORET64 ::sendto(so, (const char *)buf, _IOLEN64 len, MSG_NOSIGNAL, addr, alen);
347}
348
349ssize_t UDPSocket::receive(void *buf, size_t len, bool reply)
350{
351 struct sockaddr *addr = NULL;
352 struct sockaddr_in senderAddress; // DMC 2/7/05 ADD for use below.
353 socklen_t alen = 0;
354
355 switch(family) {
356#ifdef CCXX_IPV6
357 case IPV6:
358 addr = (struct sockaddr *)&peer.ipv6;
359 alen = sizeof(struct sockaddr_in6);
360 break;
361#endif
362 case IPV4:
363 addr = (struct sockaddr *)&peer.ipv4;
364 alen = sizeof(struct sockaddr_in);
365 break;
366 default:
367 return -1;
368 }
369
370 if(isConnected() || !reply) {
371 // DMC 2/7/05 MOD to use senderAddress instead of NULL, to prevent 10014 error
372 // from recvfrom.
373 //addr = NULL;
374 //alen = 0;
375 addr = (struct sockaddr*)(&senderAddress);
376 alen = sizeof(struct sockaddr_in);
377 }
378
379 int bytes = ::recvfrom(so, (char *)buf, _IOLEN64 len, 0, addr, &alen);
380
381#ifdef _MSWINDOWS_
382
383 if (bytes == SOCKET_ERROR) {
384 WSAGetLastError();
385 }
386#endif
387
388 return _IORET64 bytes;
389}
390
391Socket::Error UDPSocket::join(const IPV4Multicast &ia,int InterfaceIndex)
392{
393
394#if defined(_MSWINDOWS_) && defined(IP_ADD_MEMBERSHIP)
395
396 // DMC 2/7/05: Added WIN32 block. Win32 does not define the ip_mreqn structure,
397 // so we must use ip_mreq with INADDR_ANY.
398 struct ip_mreq group;
399 struct sockaddr_in myaddr;
400 socklen_t len = sizeof(myaddr);
401
402 if(!flags.multicast)
403 return error(errMulticastDisabled);
404
405 memset(&group, 0, sizeof(group));
406 getsockname(so, (struct sockaddr *)&myaddr, &len);
407 group.imr_multiaddr.s_addr = ia.getAddress().s_addr;
408 group.imr_interface.s_addr = INADDR_ANY;
409 setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group));
410 return errSuccess;
411
412#elif defined(IP_ADD_MEMBERSHIP) && defined(SIOCGIFINDEX) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(_OSF_SOURCE) && !defined(__hpux) && !defined(__GNU__)
413
414 struct ip_mreqn group;
415 struct sockaddr_in myaddr;
416 socklen_t len = sizeof(myaddr);
417
418 if(!flags.multicast)
419 return error(errMulticastDisabled);
420
421 getsockname(so, (struct sockaddr *)&myaddr, &len);
422 memset(&group, 0, sizeof(group));
423 memcpy(&group.imr_address, &myaddr.sin_addr, sizeof(myaddr.sin_addr));
424 group.imr_multiaddr = ia.getAddress();
425 group.imr_ifindex = InterfaceIndex;
426 setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group));
427 return errSuccess;
428#elif defined(IP_ADD_MEMBERSHIP)
429 // if no by index, use INADDR_ANY
430 struct ip_mreq group;
431 struct sockaddr_in myaddr;
432 socklen_t len = sizeof(myaddr);
433
434 if(!flags.multicast)
435 return error(errMulticastDisabled);
436
437 getsockname(so, (struct sockaddr *)&myaddr, &len);
438 memset(&group, sizeof(group), 0);
439 group.imr_multiaddr.s_addr = ia.getAddress().s_addr;
440 group.imr_interface.s_addr = INADDR_ANY;
441 setsockopt(so, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group));
442 return errSuccess;
443#else
444 return error(errServiceUnavailable);
445#endif
446}
447
448Socket::Error UDPSocket::getInterfaceIndex(const char *DeviceName,int& InterfaceIndex)
449{
450#ifndef _MSWINDOWS_
451#if defined(IP_ADD_MEMBERSHIP) && defined(SIOCGIFINDEX) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(_OSF_SOURCE) && !defined(__hpux) && !defined(__GNU__)
452
453 struct ip_mreqn mreqn;
454 struct ifreq m_ifreq;
455 int i;
456 sockaddr_in* in4 = (sockaddr_in*) &peer.ipv4;
457 InterfaceIndex = -1;
458
459 memset(&mreqn, 0, sizeof(mreqn));
460 memcpy(&mreqn.imr_multiaddr.s_addr, &in4->sin_addr, sizeof(mreqn.imr_multiaddr.s_addr));
461
462 for (i = 0; i < IFNAMSIZ && DeviceName[i]; ++i)
463 m_ifreq.ifr_name[i] = DeviceName[i];
464 for (; i < IFNAMSIZ; ++i)
465 m_ifreq.ifr_name[i] = 0;
466
467 if (ioctl (so, SIOCGIFINDEX, &m_ifreq))
468 return error(errServiceUnavailable);
469
470#if defined(__FreeBSD__) || defined(__GNU__)
471 InterfaceIndex = m_ifreq.ifr_ifru.ifru_index;
472#else
473 InterfaceIndex = m_ifreq.ifr_ifindex;
474#endif
475 return errSuccess;
476#else
477 return error(errServiceUnavailable);
478#endif
479#else
480 return error(errServiceUnavailable);
481#endif // WIN32
482}
483
484#ifdef AF_UNSPEC
485Socket::Error UDPSocket::disconnect(void)
486{
487 struct sockaddr_in addr;
488 int len = sizeof(addr);
489
490 if(so == INVALID_SOCKET)
491 return errSuccess;
492
493 Socket::state = BOUND;
494
495 memset(&addr, 0, len);
496#ifndef _MSWINDOWS_
497 addr.sin_family = AF_UNSPEC;
498#else
499 addr.sin_family = AF_INET;
500 memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
501#endif
502 if(::connect(so, (sockaddr *)&addr, len))
503 return connectError();
504 return errSuccess;
505}
506#else
507Socket::Error UDPSocket::disconnect(void)
508{
509 if(so == INVALID_SOCKET)
510 return errSuccess;
511
512 Socket::state = BOUND;
513 return connect(getLocal());
514}
515#endif
516
517void UDPSocket::setPeer(const IPV4Host &ia, tpport_t port)
518{
519 memset(&peer.ipv4, 0, sizeof(peer.ipv4));
520 peer.ipv4.sin_family = AF_INET;
521 peer.ipv4.sin_addr = ia.getAddress();
522 peer.ipv4.sin_port = htons(port);
523}
524
525void UDPSocket::connect(const IPV4Host &ia, tpport_t port)
526{
527 setPeer(ia, port);
528 if(so == INVALID_SOCKET)
529 return;
530
531 if(!::connect(so, (struct sockaddr *)&peer.ipv4, sizeof(struct sockaddr_in)))
532 Socket::state = CONNECTED;
533}
534
535#ifdef CCXX_IPV6
536void UDPSocket::setPeer(const IPV6Host &ia, tpport_t port)
537{
538 memset(&peer.ipv6, 0, sizeof(peer.ipv6));
539 peer.ipv6.sin6_family = AF_INET6;
540 peer.ipv6.sin6_addr = ia.getAddress();
541 peer.ipv6.sin6_port = htons(port);
542}
543
544void UDPSocket::connect(const IPV6Host &ia, tpport_t port)
545{
546 setPeer(ia, port);
547
548 if(so == INVALID_SOCKET)
549 return;
550
551 if(!::connect(so, (struct sockaddr *)&peer.ipv6, sizeof(struct sockaddr_in6)))
552 Socket::state = CONNECTED;
553
554}
555
556#endif
557
558#ifdef HAVE_GETADDRINFO
559
560void UDPSocket::setPeer(const char *name)
561{
562 char namebuf[128], *cp;
563 struct addrinfo hint, *list;
564
565 snprintf(namebuf, sizeof(namebuf), "%s", name);
566 cp = strrchr(namebuf, '/');
567 if(!cp)
568 cp = strrchr(namebuf, ':');
569
570 if(!cp)
571 return;
572
573 memset(&hint, 0, sizeof(hint));
574 hint.ai_family = family;
575 hint.ai_socktype = SOCK_DGRAM;
576 hint.ai_protocol = IPPROTO_UDP;
577
578 if(getaddrinfo(namebuf, cp, &hint, &list) || !list)
579 return;
580
581 switch(family) {
582#ifdef CCXX_IPV6
583 case IPV6:
584 memcpy(&peer.ipv6, list->ai_addr, sizeof(peer.ipv6));
585 break;
586#endif
587 case IPV4:
588 memcpy(&peer.ipv4, list->ai_addr, sizeof(peer.ipv4));
589 break;
590 }
591
592 freeaddrinfo(list);
593}
594
595#else
596
597void UDPSocket::setPeer(const char *name)
598{
599 char namebuf[128], *cp;
600 struct servent *svc;
601 tpport_t port;
602
603 snprintf(namebuf, sizeof(namebuf), "%s", name);
604 cp = strrchr(namebuf, '/');
605 if(!cp)
606 cp = strrchr(namebuf, ':');
607
608 if(!cp)
609 return;
610
611 if(isdigit(*cp))
612 port = atoi(cp);
613 else {
614 mutex.enter();
615 svc = getservbyname(cp, "udp");
616 if(svc)
617 port = ntohs(svc->s_port);
618 mutex.leave();
619 if(!svc)
620 return;
621 }
622
623 memset(&peer, 0, sizeof(peer));
624
625 switch(family) {
626#ifdef CCXX_IPV6
627 case IPV6:
628 setPeer(IPV6Host(namebuf), port);
629 break;
630#endif
631 case IPV4:
632 setPeer(IPV4Host(namebuf), port);
633 break;
634 }
635}
636
637#endif
638
639void UDPSocket::connect(const char *service)
640{
641 int rtn = -1;
642
643 setPeer(service);
644
645 if(so == INVALID_SOCKET)
646 return;
647
648 switch(family) {
649#ifdef CCXX_IPV6
650 case IPV6:
651 rtn = ::connect(so, (struct sockaddr *)&peer.ipv6, sizeof(struct sockaddr_in6));
652 break;
653#endif
654 case IPV4:
655 rtn = ::connect(so, (struct sockaddr *)&peer.ipv4, sizeof(struct sockaddr_in));
656 break;
657 }
658 if(!rtn)
659 Socket::state = CONNECTED;
660}
661
662IPV4Host UDPSocket::getIPV4Peer(tpport_t *port) const
663{
664 // FIXME: insufficient buffer
665 // how to retrieve peer ??
666 char buf;
667 socklen_t len = sizeof(peer.ipv4);
668 int rtn = ::recvfrom(so, &buf, 1, MSG_PEEK, (struct sockaddr *)&peer.ipv4, &len);
669
670#ifdef _MSWINDOWS_
671 if(rtn < 1 && WSAGetLastError() != WSAEMSGSIZE) {
672 if(port)
673 *port = 0;
674
675 memset((void*) &peer.ipv4, 0, sizeof(peer.ipv4));
676 }
677#else
678 if(rtn < 1) {
679 if(port)
680 *port = 0;
681
682 memset((void*) &peer.ipv4, 0, sizeof(peer.ipv4));
683 }
684#endif
685 else {
686 if(port)
687 *port = ntohs(peer.ipv4.sin_port);
688 }
689 return IPV4Host(peer.ipv4.sin_addr);
690}
691
692#ifdef CCXX_IPV6
693IPV6Host UDPSocket::getIPV6Peer(tpport_t *port) const
694{
695 // FIXME: insufficient buffer
696 // how to retrieve peer ??
697 char buf;
698 socklen_t len = sizeof(peer.ipv6);
699 int rtn = ::recvfrom(so, &buf, 1, MSG_PEEK, (struct sockaddr *)&peer.ipv6, &len);
700
701#ifdef _MSWINDOWS_
702 if(rtn < 1 && WSAGetLastError() != WSAEMSGSIZE) {
703 if(port)
704 *port = 0;
705
706 memset((void*) &peer.ipv6, 0, sizeof(peer.ipv6));
707 }
708#else
709 if(rtn < 1) {
710 if(port)
711 *port = 0;
712
713 memset((void*) &peer.ipv6, 0, sizeof(peer.ipv6));
714 }
715#endif
716 else {
717 if(port)
718 *port = ntohs(peer.ipv6.sin6_port);
719 }
720 return IPV6Host(peer.ipv6.sin6_addr);
721}
722#endif
723
724UDPBroadcast::UDPBroadcast(const IPV4Address &ia, tpport_t port) :
725UDPSocket(ia, port)
726{
727 if(so != INVALID_SOCKET)
728 setBroadcast(true);
729}
730
731void UDPBroadcast::setPeer(const IPV4Broadcast &ia, tpport_t port)
732{
733 memset(&peer.ipv4, 0, sizeof(peer.ipv4));
734 peer.ipv4.sin_family = AF_INET;
735 peer.ipv4.sin_addr = ia.getAddress();
736 peer.ipv4.sin_port = htons(port);
737}
738
739UDPTransmit::UDPTransmit(const IPV4Address &ia, tpport_t port) :
740UDPSocket(ia, port)
741{
742 disconnect(); // assure not started live
743 ::shutdown(so, 0);
744 receiveBuffer(0);
745}
746
747#ifdef CCXX_IPV6
748UDPTransmit::UDPTransmit(const IPV6Address &ia, tpport_t port) :
749UDPSocket(ia, port)
750{
751 disconnect(); // assure not started live
752 ::shutdown(so, 0);
753 receiveBuffer(0);
754}
755#endif
756
757UDPTransmit::UDPTransmit(Family family) : UDPSocket(family)
758{
759 disconnect();
760 ::shutdown(so, 0);
761 receiveBuffer(0);
762}
763
764Socket::Error UDPTransmit::cConnect(const IPV4Address &ia, tpport_t port)
765{
766 int len = sizeof(peer.ipv4);
767
768 peer.ipv4.sin_family = AF_INET;
769 peer.ipv4.sin_addr = ia.getAddress();
770 peer.ipv4.sin_port = htons(port);
771 // Win32 will crash if you try to connect to INADDR_ANY.
772 if ( INADDR_ANY == peer.ipv4.sin_addr.s_addr )
773 peer.ipv4.sin_addr.s_addr = INADDR_LOOPBACK;
774 if(::connect(so, (sockaddr *)&peer.ipv4, len))
775 return connectError();
776 return errSuccess;
777}
778
779
780#ifdef CCXX_IPV6
781
782Socket::Error UDPTransmit::connect(const IPV6Address &ia, tpport_t port)
783{
784 int len = sizeof(peer.ipv6);
785
786 peer.ipv6.sin6_family = AF_INET6;
787 peer.ipv6.sin6_addr = ia.getAddress();
788 peer.ipv6.sin6_port = htons(port);
789 // Win32 will crash if you try to connect to INADDR_ANY.
790 if(!memcmp(&peer.ipv6.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
791 memcpy(&peer.ipv6.sin6_addr, &in6addr_loopback,
792 sizeof(in6addr_loopback));
793 if(::connect(so, (struct sockaddr *)&peer.ipv6, len))
794 return connectError();
795 return errSuccess;
796}
797#endif
798
799Socket::Error UDPTransmit::connect(const IPV4Host &ia, tpport_t port)
800{
801 if(isBroadcast())
802 setBroadcast(false);
803
804 return cConnect((IPV4Address)ia,port);
805}
806
807Socket::Error UDPTransmit::connect(const IPV4Broadcast &subnet, tpport_t port)
808{
809 if(!isBroadcast())
810 setBroadcast(true);
811
812 return cConnect((IPV4Address)subnet,port);
813}
814
815Socket::Error UDPTransmit::connect(const IPV4Multicast &group, tpport_t port)
816{
817 Error err;
818 if(!( err = UDPSocket::setMulticast(true) ))
819 return err;
820
821 return cConnect((IPV4Address)group,port);
822}
823
824#ifdef CCXX_IPV6
825Socket::Error UDPTransmit::connect(const IPV6Multicast &group, tpport_t port)
826{
827 Error error;
828 if(!( error = UDPSocket::setMulticast(true) ))
829 return error;
830
831 return connect((IPV6Address)group,port);
832}
833#endif
834
835UDPReceive::UDPReceive(const IPV4Address &ia, tpport_t port) :
836UDPSocket(ia, port)
837{
838 ::shutdown(so, 1);
839 sendBuffer(0);
840}
841
842#ifdef CCXX_IPV6
843UDPReceive::UDPReceive(const IPV6Address &ia, tpport_t port) :
844UDPSocket(ia, port)
845{
846 ::shutdown(so, 1);
847 sendBuffer(0);
848}
849#endif
850
851Socket::Error UDPReceive::connect(const IPV4Host &ia, tpport_t port)
852{
853 int len = sizeof(peer.ipv4);
854
855 peer.ipv4.sin_family = AF_INET;
856 peer.ipv4.sin_addr = ia.getAddress();
857 peer.ipv4.sin_port = htons(port);
858 // Win32 will crash if you try to connect to INADDR_ANY.
859 if ( INADDR_ANY == peer.ipv4.sin_addr.s_addr )
860 peer.ipv4.sin_addr.s_addr = INADDR_LOOPBACK;
861 if(::connect(so, (struct sockaddr *)&peer.ipv4, len))
862 return connectError();
863 return errSuccess;
864}
865
866#ifdef CCXX_IPV6
867Socket::Error UDPReceive::connect(const IPV6Host &ia, tpport_t port)
868{
869 int len = sizeof(peer.ipv6);
870
871 peer.ipv6.sin6_family = AF_INET6;
872 peer.ipv6.sin6_addr = ia.getAddress();
873 peer.ipv6.sin6_port = htons(port);
874 // Win32 will crash if you try to connect to INADDR_ANY.
875 if(!memcmp(&peer.ipv6.sin6_addr, &in6addr_any, sizeof(in6addr_any)))
876 memcpy(&peer.ipv6.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback));
877 if(::connect(so, (sockaddr *)&peer.ipv6, len))
878 return connectError();
879 return errSuccess;
880}
881#endif
882
883UDPDuplex::UDPDuplex(const IPV4Address &bind, tpport_t port) :
884UDPTransmit(bind, port + 1), UDPReceive(bind, port)
885{}
886
887#ifdef CCXX_IPV6
888UDPDuplex::UDPDuplex(const IPV6Address &bind, tpport_t port) :
889UDPTransmit(bind, port + 1), UDPReceive(bind, port)
890{}
891#endif
892
893Socket::Error UDPDuplex::connect(const IPV4Host &host, tpport_t port)
894{
895 Error rtn = UDPTransmit::connect(host, port);
896 if(rtn) {
897 UDPTransmit::disconnect();
898 UDPReceive::disconnect();
899 return rtn;
900 }
901 return UDPReceive::connect(host, port + 1);
902}
903
904#ifdef CCXX_IPV6
905Socket::Error UDPDuplex::connect(const IPV6Host &host, tpport_t port)
906{
907 Error rtn = UDPTransmit::connect(host, port);
908 if(rtn) {
909 UDPTransmit::disconnect();
910 UDPReceive::disconnect();
911 return rtn;
912 }
913 return UDPReceive::connect(host, port + 1);
914}
915#endif
916
917Socket::Error UDPDuplex::disconnect(void)
918{
919 Error rtn = UDPTransmit::disconnect();
920 Error rtn2 = UDPReceive::disconnect();
921 if (rtn) return rtn;
922 return rtn2;
923}
924