-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathUDPSocket.cpp
More file actions
125 lines (99 loc) · 3.54 KB
/
Copy pathUDPSocket.cpp
File metadata and controls
125 lines (99 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "UDPSocket.h"
#include "TempFailure.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
using namespace NET;
namespace {
void setBroadcast( int socket)
{
// If this fails, we'll hear about it when we try to send. This will allow
// systems that cannot broadcast to continue if they don't plan to broadcast
int broadcastPermission = 1;
setsockopt( socket,
SOL_SOCKET,
SO_BROADCAST,
(raw_type*)&broadcastPermission,
sizeof(broadcastPermission));
}
int groupAction( int socket, const std::string& multicastGroup, int action)
{
struct ip_mreq multicastRequest;
multicastRequest.imr_multiaddr.s_addr = inet_addr( multicastGroup.c_str());
multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
return( setsockopt( socket,
IPPROTO_IP,
action,
(raw_type*)&multicastRequest,
sizeof(multicastRequest)));
}
} // namespace
UDPSocket::UDPSocket()
: InternetSocket( DATAGRAM, IPPROTO_UDP)
{
setBroadcast(m_socket);
}
void UDPSocket::sendTo( const void* buffer, size_t len, std::string_view foreignAddress, unsigned short foreignPort)
{
sockaddr_in destAddr;
fillAddress( foreignAddress, foreignPort, destAddr);
int sent = TEMP_FAILURE_RETRY (::sendto( m_socket, (const raw_type*)buffer, len, 0, (sockaddr*)&destAddr, sizeof(destAddr)));
// Write out the whole buffer as a single message
if( sent != (int)len)
throw SocketException("Send failed (sendto)");
}
int UDPSocket::receiveFrom( void* buffer, size_t len, std::string& sourceAddress, unsigned short& sourcePort)
{
sockaddr_in clientAddr;
socklen_t addrLen = sizeof(clientAddr);
int ret = TEMP_FAILURE_RETRY (::recvfrom( m_socket, (raw_type*)buffer, len, 0, (sockaddr*)&clientAddr, &addrLen));
if( ret < 0)
throw SocketException("Receive failed (recvfrom)");
sourceAddress = inet_ntoa( clientAddr.sin_addr);
sourcePort = ntohs( clientAddr.sin_port);
return ret;
}
int UDPSocket::timedReceiveFrom( void* buffer, size_t len, std::string& sourceAddress, unsigned short& sourcePort, int timeout)
{
struct pollfd poll;
poll.fd = m_socket;
poll.events = POLLIN | POLLPRI | POLLRDHUP;
int ret = TEMP_FAILURE_RETRY (::poll( &poll, 1, timeout));
if( ret == 0) return 0;
if( ret < 0) throw SocketException("Receive failed (poll)");
if( poll.revents & POLLRDHUP)
m_peerDisconnected = true;
if( poll.revents & POLLIN || poll.revents & POLLPRI)
return receiveFrom( buffer, len, sourceAddress, sourcePort);
return 0;
}
void UDPSocket::setMulticastTTL( unsigned char multicastTTL)
{
if( setsockopt( m_socket,
IPPROTO_IP,
IP_MULTICAST_TTL,
(raw_type*)&multicastTTL,
sizeof(multicastTTL)) < 0)
throw SocketException("Multicast set TTL failed (setsockopt)");
}
void UDPSocket::setMulticastInterfaceAddr( const std::string& address)
{
struct in_addr interfaceAddr;
inet_aton( address.c_str(), &interfaceAddr);
if( setsockopt( m_socket,
IPPROTO_IP,
IP_MULTICAST_IF,
(raw_type*)&interfaceAddr,
sizeof(interfaceAddr)) < 0)
throw SocketException("Multicast set Interface Address failed (setsockopt)");
}
void UDPSocket::joinGroup( const std::string& multicastGroup)
{
if( groupAction( m_socket, multicastGroup, IP_ADD_MEMBERSHIP) < 0)
throw SocketException("Multicast group join failed (setsockopt)");
}
void UDPSocket::leaveGroup( const std::string& multicastGroup)
{
if( groupAction( m_socket, multicastGroup, IP_DROP_MEMBERSHIP) < 0)
throw SocketException("Multicast group leave failed (setsockopt)");
}