Added a EditorSocial.
[UnsignedByte.git] / src / Sockets / UdpSocket.cpp
blob6c37e9439dc44327b94894d979f1d4c31639243c
1 /** \file UdpSocket.cpp
2 ** \date 2004-02-13
3 ** \author grymse@alhem.net
4 **/
5 /*
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef _WIN32
31 #ifndef __MINGW32__
32 #pragma warning(disable:4786)
33 #endif
34 #include <stdlib.h>
35 #else
36 #include <errno.h>
37 #endif
39 #include "ISocketHandler.h"
40 #include "UdpSocket.h"
41 #include "Utility.h"
42 #include "Ipv4Address.h"
43 #include "Ipv6Address.h"
44 // include this to see strange sights
45 //#include <linux/in6.h>
48 #ifdef SOCKETS_NAMESPACE
49 namespace SOCKETS_NAMESPACE {
50 #endif
53 UdpSocket::UdpSocket(ISocketHandler& h, int ibufsz, bool ipv6) : Socket(h)
54 , m_ibuf(new char[ibufsz])
55 , m_ibufsz(ibufsz)
56 , m_bind_ok(false)
57 , m_port(0)
58 , m_last_size_written(-1)
60 #ifdef ENABLE_IPV6
61 #ifdef IPPROTO_IPV6
62 SetIpv6(ipv6);
63 #endif
64 #endif
68 UdpSocket::~UdpSocket()
70 Close();
71 delete[] m_ibuf;
75 int UdpSocket::Bind(port_t &port, int range)
77 #ifdef ENABLE_IPV6
78 #ifdef IPPROTO_IPV6
79 if (IsIpv6())
81 Ipv6Address ad(port);
82 return Bind(ad, range);
84 #endif
85 #endif
86 Ipv4Address ad(port);
87 return Bind(ad, range);
91 int UdpSocket::Bind(const std::string& intf, port_t &port, int range)
93 #ifdef ENABLE_IPV6
94 #ifdef IPPROTO_IPV6
95 if (IsIpv6())
97 Ipv6Address ad(intf, port);
98 if (ad.IsValid())
100 return Bind(ad, range);
102 SetCloseAndDelete();
103 return -1;
105 #endif
106 #endif
107 Ipv4Address ad(intf, port);
108 if (ad.IsValid())
110 return Bind(ad, range);
112 SetCloseAndDelete();
113 return -1;
117 int UdpSocket::Bind(ipaddr_t a, port_t &port, int range)
119 Ipv4Address ad(a, port);
120 return Bind(ad, range);
124 #ifdef ENABLE_IPV6
125 #ifdef IPPROTO_IPV6
126 int UdpSocket::Bind(in6_addr a, port_t &port, int range)
128 Ipv6Address ad(a, port);
129 return Bind(ad, range);
131 #endif
132 #endif
135 int UdpSocket::Bind(SocketAddress& ad, int range)
137 if (GetSocket() == INVALID_SOCKET)
139 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
141 if (GetSocket() != INVALID_SOCKET)
143 SetNonblocking(true);
144 int n = bind(GetSocket(), ad, ad);
145 int tries = range;
146 while (n == -1 && tries--)
148 ad.SetPort(ad.GetPort() + 1);
149 n = bind(GetSocket(), ad, ad);
151 if (n == -1)
153 Handler().LogError(this, "bind", Errno, StrError(Errno), LOG_LEVEL_FATAL);
154 SetCloseAndDelete();
155 return -1;
157 m_bind_ok = true;
158 m_port = ad.GetPort();
159 return 0;
161 return -1;
165 /** if you wish to use Send, first Open a connection */
166 bool UdpSocket::Open(ipaddr_t l, port_t port)
168 Ipv4Address ad(l, port);
169 return Open(ad);
173 bool UdpSocket::Open(const std::string& host, port_t port)
175 #ifdef ENABLE_IPV6
176 #ifdef IPPROTO_IPV6
177 if (IsIpv6())
179 Ipv6Address ad(host, port);
180 if (ad.IsValid())
182 return Open(ad);
184 return false;
186 #endif
187 #endif
188 Ipv4Address ad(host, port);
189 if (ad.IsValid())
191 return Open(ad);
193 return false;
197 #ifdef ENABLE_IPV6
198 #ifdef IPPROTO_IPV6
199 bool UdpSocket::Open(struct in6_addr& a, port_t port)
201 Ipv6Address ad(a, port);
202 return Open(ad);
204 #endif
205 #endif
208 bool UdpSocket::Open(SocketAddress& ad)
210 if (GetSocket() == INVALID_SOCKET)
212 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
214 if (GetSocket() != INVALID_SOCKET)
216 SetNonblocking(true);
217 if (connect(GetSocket(), ad, ad) == -1)
219 Handler().LogError(this, "connect", Errno, StrError(Errno), LOG_LEVEL_FATAL);
220 SetCloseAndDelete();
221 return false;
223 SetConnected();
224 return true;
226 return false;
230 void UdpSocket::CreateConnection()
232 #ifdef ENABLE_IPV6
233 #ifdef IPPROTO_IPV6
234 if (IsIpv6())
236 if (GetSocket() == INVALID_SOCKET)
238 SOCKET s = CreateSocket(AF_INET6, SOCK_DGRAM, "udp");
239 if (s == INVALID_SOCKET)
241 return;
243 SetNonblocking(true, s);
244 Attach(s);
246 return;
248 #endif
249 #endif
250 if (GetSocket() == INVALID_SOCKET)
252 SOCKET s = CreateSocket(AF_INET, SOCK_DGRAM, "udp");
253 if (s == INVALID_SOCKET)
255 return;
257 SetNonblocking(true, s);
258 Attach(s);
263 /** send to specified address */
264 void UdpSocket::SendToBuf(const std::string& h, port_t p, const char *data, int len, int flags)
266 #ifdef ENABLE_IPV6
267 #ifdef IPPROTO_IPV6
268 if (IsIpv6())
270 Ipv6Address ad(h, p);
271 if (ad.IsValid())
273 SendToBuf(ad, data, len, flags);
275 return;
277 #endif
278 #endif
279 Ipv4Address ad(h, p);
280 if (ad.IsValid())
282 SendToBuf(ad, data, len, flags);
287 /** send to specified address */
288 void UdpSocket::SendToBuf(ipaddr_t a, port_t p, const char *data, int len, int flags)
290 Ipv4Address ad(a, p);
291 SendToBuf(ad, data, len, flags);
295 #ifdef ENABLE_IPV6
296 #ifdef IPPROTO_IPV6
297 void UdpSocket::SendToBuf(in6_addr a, port_t p, const char *data, int len, int flags)
299 Ipv6Address ad(a, p);
300 SendToBuf(ad, data, len, flags);
302 #endif
303 #endif
306 void UdpSocket::SendToBuf(SocketAddress& ad, const char *data, int len, int flags)
308 if (GetSocket() == INVALID_SOCKET)
310 Attach(CreateSocket(ad.GetFamily(), SOCK_DGRAM, "udp"));
312 if (GetSocket() != INVALID_SOCKET)
314 SetNonblocking(true);
315 if ((m_last_size_written = sendto(GetSocket(), data, len, flags, ad, ad)) == -1)
317 Handler().LogError(this, "sendto", Errno, StrError(Errno), LOG_LEVEL_ERROR);
323 void UdpSocket::SendTo(const std::string& a, port_t p, const std::string& str, int flags)
325 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
329 void UdpSocket::SendTo(ipaddr_t a, port_t p, const std::string& str, int flags)
331 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
335 #ifdef ENABLE_IPV6
336 #ifdef IPPROTO_IPV6
337 void UdpSocket::SendTo(in6_addr a, port_t p, const std::string& str, int flags)
339 SendToBuf(a, p, str.c_str(), (int)str.size(), flags);
341 #endif
342 #endif
345 void UdpSocket::SendTo(SocketAddress& ad, const std::string& str, int flags)
347 SendToBuf(ad, str.c_str(), (int)str.size(), flags);
351 /** send to connected address */
352 void UdpSocket::SendBuf(const char *data, size_t len, int flags)
354 if (!IsConnected())
356 Handler().LogError(this, "SendBuf", 0, "not connected", LOG_LEVEL_ERROR);
357 return;
359 if ((m_last_size_written = send(GetSocket(), data, (int)len, flags)) == -1)
361 Handler().LogError(this, "send", Errno, StrError(Errno), LOG_LEVEL_ERROR);
366 void UdpSocket::Send(const std::string& str, int flags)
368 SendBuf(str.c_str(), (int)str.size(), flags);
372 void UdpSocket::OnRead()
374 #ifdef ENABLE_IPV6
375 #ifdef IPPROTO_IPV6
376 if (IsIpv6())
378 struct sockaddr_in6 sa;
379 socklen_t sa_len = sizeof(sa);
380 int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
381 int q = 10; // receive max 10 at one cycle
382 while (n > 0)
384 if (sa_len != sizeof(sa))
386 Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
388 this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
389 if (!q--)
390 break;
392 n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
394 if (n == -1)
396 #ifdef _WIN32
397 if (Errno != WSAEWOULDBLOCK)
398 #else
399 if (Errno != EWOULDBLOCK)
400 #endif
401 Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
403 return;
405 #endif
406 #endif
407 struct sockaddr_in sa;
408 socklen_t sa_len = sizeof(sa);
409 int n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
410 int q = 10;
411 while (n > 0)
413 if (sa_len != sizeof(sa))
415 Handler().LogError(this, "recvfrom", 0, "unexpected address struct size", LOG_LEVEL_WARNING);
417 this -> OnRawData(m_ibuf, n, (struct sockaddr *)&sa, sa_len);
418 if (!q--)
419 break;
421 n = recvfrom(GetSocket(), m_ibuf, m_ibufsz, 0, (struct sockaddr *)&sa, &sa_len);
423 if (n == -1)
425 #ifdef _WIN32
426 if (Errno != WSAEWOULDBLOCK)
427 #else
428 if (Errno != EWOULDBLOCK)
429 #endif
430 Handler().LogError(this, "recvfrom", Errno, StrError(Errno), LOG_LEVEL_ERROR);
435 void UdpSocket::SetBroadcast(bool b)
437 int one = 1;
438 int zero = 0;
440 if (GetSocket() == INVALID_SOCKET)
442 CreateConnection();
444 if (b)
446 if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &one, sizeof(one)) == -1)
448 Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
451 else
453 if (setsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *) &zero, sizeof(zero)) == -1)
455 Handler().LogError(this, "SetBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
461 bool UdpSocket::IsBroadcast()
463 int is_broadcast = 0;
464 socklen_t size;
466 if (GetSocket() == INVALID_SOCKET)
468 CreateConnection();
470 if (getsockopt(GetSocket(), SOL_SOCKET, SO_BROADCAST, (char *)&is_broadcast, &size) == -1)
472 Handler().LogError(this, "IsBroadcast", Errno, StrError(Errno), LOG_LEVEL_WARNING);
474 return is_broadcast != 0;
478 void UdpSocket::SetMulticastTTL(int ttl)
480 if (GetSocket() == INVALID_SOCKET)
482 CreateConnection();
484 if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(int)) == -1)
486 Handler().LogError(this, "SetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
491 int UdpSocket::GetMulticastTTL()
493 int ttl = 0;
494 socklen_t size = sizeof(int);
496 if (GetSocket() == INVALID_SOCKET)
498 CreateConnection();
500 if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_TTL, (char *)&ttl, &size) == -1)
502 Handler().LogError(this, "GetMulticastTTL", Errno, StrError(Errno), LOG_LEVEL_WARNING);
504 return ttl;
508 void UdpSocket::SetMulticastLoop(bool x)
510 if (GetSocket() == INVALID_SOCKET)
512 CreateConnection();
514 #ifdef ENABLE_IPV6
515 #ifdef IPPROTO_IPV6
516 if (IsIpv6())
518 int val = x ? 1 : 0;
519 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
521 Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
523 return;
525 #endif
526 #endif
527 int val = x ? 1 : 0;
528 if (setsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&val, sizeof(int)) == -1)
530 Handler().LogError(this, "SetMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
535 bool UdpSocket::IsMulticastLoop()
537 if (GetSocket() == INVALID_SOCKET)
539 CreateConnection();
541 #ifdef ENABLE_IPV6
542 #ifdef IPPROTO_IPV6
543 if (IsIpv6())
545 int is_loop = 0;
546 socklen_t size = sizeof(int);
547 if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
549 Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
551 return is_loop ? true : false;
553 #endif
554 #endif
555 int is_loop = 0;
556 socklen_t size = sizeof(int);
557 if (getsockopt(GetSocket(), SOL_IP, IP_MULTICAST_LOOP, (char *)&is_loop, &size) == -1)
559 Handler().LogError(this, "IsMulticastLoop", Errno, StrError(Errno), LOG_LEVEL_WARNING);
561 return is_loop ? true : false;
565 void UdpSocket::AddMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
567 if (GetSocket() == INVALID_SOCKET)
569 CreateConnection();
571 #ifdef ENABLE_IPV6
572 #ifdef IPPROTO_IPV6
573 if (IsIpv6())
575 struct ipv6_mreq x;
576 struct in6_addr addr;
577 if (Utility::u2ip( group, addr ))
579 x.ipv6mr_multiaddr = addr;
580 x.ipv6mr_interface = if_index;
581 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
583 Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
586 return;
588 #endif
589 #endif
590 struct ip_mreq x; // ip_mreqn
591 ipaddr_t addr;
592 if (Utility::u2ip( group, addr ))
594 memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
595 Utility::u2ip( local_if, addr);
596 memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
597 // x.imr_ifindex = if_index;
598 if (setsockopt(GetSocket(), SOL_IP, IP_ADD_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
600 Handler().LogError(this, "AddMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
606 void UdpSocket::DropMulticastMembership(const std::string& group, const std::string& local_if, int if_index)
608 if (GetSocket() == INVALID_SOCKET)
610 CreateConnection();
612 #ifdef ENABLE_IPV6
613 #ifdef IPPROTO_IPV6
614 if (IsIpv6())
616 struct ipv6_mreq x;
617 struct in6_addr addr;
618 if (Utility::u2ip( group, addr ))
620 x.ipv6mr_multiaddr = addr;
621 x.ipv6mr_interface = if_index;
622 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ipv6_mreq)) == -1)
624 Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
627 return;
629 #endif
630 #endif
631 struct ip_mreq x; // ip_mreqn
632 ipaddr_t addr;
633 if (Utility::u2ip( group, addr ))
635 memcpy(&x.imr_multiaddr.s_addr, &addr, sizeof(addr));
636 Utility::u2ip( local_if, addr);
637 memcpy(&x.imr_interface.s_addr, &addr, sizeof(addr));
638 // x.imr_ifindex = if_index;
639 if (setsockopt(GetSocket(), SOL_IP, IP_DROP_MEMBERSHIP, (char *)&x, sizeof(struct ip_mreq)) == -1)
641 Handler().LogError(this, "DropMulticastMembership", Errno, StrError(Errno), LOG_LEVEL_WARNING);
647 #ifdef ENABLE_IPV6
648 #ifdef IPPROTO_IPV6
649 void UdpSocket::SetMulticastHops(int hops)
651 if (GetSocket() == INVALID_SOCKET)
653 CreateConnection();
655 if (!IsIpv6())
657 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
658 return;
660 if (setsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, sizeof(int)) == -1)
662 Handler().LogError(this, "SetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
667 int UdpSocket::GetMulticastHops()
669 if (GetSocket() == INVALID_SOCKET)
671 CreateConnection();
673 if (!IsIpv6())
675 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR);
676 return -1;
678 int hops = 0;
679 socklen_t size = sizeof(int);
680 if (getsockopt(GetSocket(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hops, &size) == -1)
682 Handler().LogError(this, "GetMulticastHops", Errno, StrError(Errno), LOG_LEVEL_WARNING);
684 return hops;
686 #endif // IPPROTO_IPV6
687 #endif
690 bool UdpSocket::IsBound()
692 return m_bind_ok;
696 void UdpSocket::OnRawData(const char *buf, size_t len, struct sockaddr *sa, socklen_t sa_len)
701 port_t UdpSocket::GetPort()
703 return m_port;
707 int UdpSocket::GetLastSizeWritten()
709 return m_last_size_written;
713 #ifdef SOCKETS_NAMESPACE
715 #endif