1 /** \file UdpSocket.cpp
3 ** \author grymse@alhem.net
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.
32 #pragma warning(disable:4786)
39 #include "ISocketHandler.h"
40 #include "UdpSocket.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
{
53 UdpSocket::UdpSocket(ISocketHandler
& h
, int ibufsz
, bool ipv6
) : Socket(h
)
54 , m_ibuf(new char[ibufsz
])
58 , m_last_size_written(-1)
68 UdpSocket::~UdpSocket()
75 int UdpSocket::Bind(port_t
&port
, int range
)
82 return Bind(ad
, range
);
87 return Bind(ad
, range
);
91 int UdpSocket::Bind(const std::string
& intf
, port_t
&port
, int range
)
97 Ipv6Address
ad(intf
, port
);
100 return Bind(ad
, range
);
107 Ipv4Address
ad(intf
, port
);
110 return Bind(ad
, range
);
117 int UdpSocket::Bind(ipaddr_t a
, port_t
&port
, int range
)
119 Ipv4Address
ad(a
, port
);
120 return Bind(ad
, range
);
126 int UdpSocket::Bind(in6_addr a
, port_t
&port
, int range
)
128 Ipv6Address
ad(a
, port
);
129 return Bind(ad
, range
);
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
);
146 while (n
== -1 && tries
--)
148 ad
.SetPort(ad
.GetPort() + 1);
149 n
= bind(GetSocket(), ad
, ad
);
153 Handler().LogError(this, "bind", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
158 m_port
= ad
.GetPort();
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
);
173 bool UdpSocket::Open(const std::string
& host
, port_t port
)
179 Ipv6Address
ad(host
, port
);
188 Ipv4Address
ad(host
, port
);
199 bool UdpSocket::Open(struct in6_addr
& a
, port_t port
)
201 Ipv6Address
ad(a
, port
);
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
);
230 void UdpSocket::CreateConnection()
236 if (GetSocket() == INVALID_SOCKET
)
238 SOCKET s
= CreateSocket(AF_INET6
, SOCK_DGRAM
, "udp");
239 if (s
== INVALID_SOCKET
)
243 SetNonblocking(true, s
);
250 if (GetSocket() == INVALID_SOCKET
)
252 SOCKET s
= CreateSocket(AF_INET
, SOCK_DGRAM
, "udp");
253 if (s
== INVALID_SOCKET
)
257 SetNonblocking(true, s
);
263 /** send to specified address */
264 void UdpSocket::SendToBuf(const std::string
& h
, port_t p
, const char *data
, int len
, int flags
)
270 Ipv6Address
ad(h
, p
);
273 SendToBuf(ad
, data
, len
, flags
);
279 Ipv4Address
ad(h
, p
);
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
);
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
);
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
);
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
);
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
)
356 Handler().LogError(this, "SendBuf", 0, "not connected", LOG_LEVEL_ERROR
);
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()
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
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
);
392 n
= recvfrom(GetSocket(), m_ibuf
, m_ibufsz
, 0, (struct sockaddr
*)&sa
, &sa_len
);
397 if (Errno
!= WSAEWOULDBLOCK
)
399 if (Errno
!= EWOULDBLOCK
)
401 Handler().LogError(this, "recvfrom", Errno
, StrError(Errno
), LOG_LEVEL_ERROR
);
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
);
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
);
421 n
= recvfrom(GetSocket(), m_ibuf
, m_ibufsz
, 0, (struct sockaddr
*)&sa
, &sa_len
);
426 if (Errno
!= WSAEWOULDBLOCK
)
428 if (Errno
!= EWOULDBLOCK
)
430 Handler().LogError(this, "recvfrom", Errno
, StrError(Errno
), LOG_LEVEL_ERROR
);
435 void UdpSocket::SetBroadcast(bool b
)
440 if (GetSocket() == INVALID_SOCKET
)
446 if (setsockopt(GetSocket(), SOL_SOCKET
, SO_BROADCAST
, (char *) &one
, sizeof(one
)) == -1)
448 Handler().LogError(this, "SetBroadcast", Errno
, StrError(Errno
), LOG_LEVEL_WARNING
);
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;
466 if (GetSocket() == INVALID_SOCKET
)
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
)
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()
494 socklen_t size
= sizeof(int);
496 if (GetSocket() == INVALID_SOCKET
)
500 if (getsockopt(GetSocket(), SOL_IP
, IP_MULTICAST_TTL
, (char *)&ttl
, &size
) == -1)
502 Handler().LogError(this, "GetMulticastTTL", Errno
, StrError(Errno
), LOG_LEVEL_WARNING
);
508 void UdpSocket::SetMulticastLoop(bool x
)
510 if (GetSocket() == INVALID_SOCKET
)
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
);
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
)
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;
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
)
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
);
590 struct ip_mreq x
; // ip_mreqn
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
)
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
);
631 struct ip_mreq x
; // ip_mreqn
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
);
649 void UdpSocket::SetMulticastHops(int hops
)
651 if (GetSocket() == INVALID_SOCKET
)
657 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR
);
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
)
675 Handler().LogError(this, "SetMulticastHops", 0, "Ipv6 only", LOG_LEVEL_ERROR
);
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
);
686 #endif // IPPROTO_IPV6
690 bool UdpSocket::IsBound()
696 void UdpSocket::OnRawData(const char *buf
, size_t len
, struct sockaddr
*sa
, socklen_t sa_len
)
701 port_t
UdpSocket::GetPort()
707 int UdpSocket::GetLastSizeWritten()
709 return m_last_size_written
;
713 #ifdef SOCKETS_NAMESPACE