7 #define BUF_CAST(buf) ((char*)buf)
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #define BUF_CAST(buf) ((void*)buf)
21 using std::make_unique;
24 using std::unique_ptr;
30 #define SO_REUSEOPTION SO_REUSEADDR
31 #elif defined(__linux__)
33 #define SO_REUSEOPTION SO_REUSEADDR
36 #define SO_REUSEOPTION SO_REUSEPORT
47 auto socket = make_unique<UDPSocket>(
ipVersion);
48 socket->descriptor = ::socket(
ipVersion ==
IPV6?AF_INET6:AF_INET, SOCK_DGRAM, IPPROTO_UDP);
49 if (socket->descriptor == -1) {
54 if (setsockopt(socket->descriptor, SOL_SOCKET, SO_NOSIGPIPE, (
void*)&flag,
sizeof(flag)) == -1) {
59 return socket.release();
68 socket->setNonBlocked();
83 return socket.release();
92 socket->setNonBlocked();
98 return socket.release();
101 ssize_t
UDPSocket::read(
string& from,
unsigned int& port,
void* buf,
const size_t bytes) {
103 socklen_t sinLen = 0;
106 sockaddr_in6 sinIPV6;
111 sinLen =
sizeof(sinIPV4);
118 sinLen =
sizeof(sinIPV6);
122 ssize_t bytesRead = ::recvfrom(
descriptor,
BUF_CAST(buf), bytes, 0, (
struct sockaddr *)sin, &sinLen);
123 if (bytesRead == -1) {
125 auto wsaError = WSAGetLastError();
126 if (wsaError == WSAEWOULDBLOCK ||
127 wsaError == WSAECONNRESET) {
134 if (errno == EAGAIN) {
137 throw NetworkIOException(
"Error while reading from socket: " +
string(strerror(errno)));
146 char ipv4AddressString[INET_ADDRSTRLEN];
147 from = inet_ntop(AF_INET, &sinIPV4.sin_addr, ipv4AddressString, INET_ADDRSTRLEN) == NULL?
"127.0.0.1":ipv4AddressString;
148 port = ntohs(sinIPV4.sin_port);
153 char ipv6AddressString[INET6_ADDRSTRLEN];
154 from = inet_ntop(AF_INET6, &sinIPV6.sin6_addr, ipv6AddressString, INET6_ADDRSTRLEN) == NULL?
"::1":ipv6AddressString;
155 port = ntohs(sinIPV6.sin6_port);
163 ssize_t
UDPSocket::write(
const string& to,
const unsigned int port,
void* buf,
const size_t bytes) {
165 socklen_t sinLen = 0;
168 sockaddr_in6 sinIPV6;
172 sinLen =
sizeof(sinIPV4);
173 memset(&sinIPV4, 0, sinLen);
174 sinIPV4.sin_family = AF_INET;
175 sinIPV4.sin_port = htons(
port);
176 sinIPV4.sin_addr.s_addr = inet_addr(to.c_str());
182 sinLen =
sizeof(sinIPV6);
183 memset(&sinIPV6, 0, sinLen);
184 sinIPV6.sin6_family = AF_INET6;
185 sinIPV6.sin6_port = htons(
port);
186 inet_pton(AF_INET6, to.c_str(), &sinIPV6.sin6_addr);
193 #if defined(__APPLE__) || defined(_WIN32)
194 ssize_t bytesWritten = ::sendto(
descriptor,
BUF_CAST(buf), bytes, 0, (
const struct sockaddr*)sin, sinLen);
196 ssize_t bytesWritten = ::sendto(
descriptor,
BUF_CAST(buf), bytes, MSG_NOSIGNAL, (
const struct sockaddr*)sin, sinLen);
200 if (bytesWritten == -1) {
202 auto wsaError = WSAGetLastError();
203 if (wsaError == WSAEWOULDBLOCK) {
210 if (errno == EAGAIN) {
213 throw NetworkIOException(
"Error while writing to socket: " +
string(strerror(errno)));
Base exception class for network IO exceptions.
static IpVersion determineIpVersion(const string &ip)
Determine IP version.
Class representing a UDP socket.
ssize_t read(string &from, unsigned int &port, void *buf, const size_t bytes)
Reads a datagram from socket.
static UDPSocket * create(IpVersion ipVersion)
Creates a UDP socket.
ssize_t write(const string &to, const unsigned int port, void *buf, const size_t bytes)
Writes a datagram to socket.
virtual ~UDPSocket()
Destructor.
static UDPSocket * createClientSocket(IpVersion ipVersion)
Creates a UDP client socket.
static UDPSocket * createServerSocket(const string &ip, const unsigned int port)
Creates a UDP server socket.