1/*
2 * IXUdpSocket.cpp
3 * Author: Benjamin Sergeant
4 * Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
5 */
6
7#include "IXUdpSocket.h"
8
9#include "IXNetSystem.h"
10#include <cstring>
11#include <sstream>
12
13namespace ix
14{
15 UdpSocket::UdpSocket(int fd)
16 : _sockfd(fd)
17 {
18 ;
19 }
20
21 UdpSocket::~UdpSocket()
22 {
23 close();
24 }
25
26 void UdpSocket::close()
27 {
28 if (_sockfd == -1) return;
29
30 closeSocket(_sockfd);
31 _sockfd = -1;
32 }
33
34 int UdpSocket::getErrno()
35 {
36 int err;
37
38#ifdef _WIN32
39 err = WSAGetLastError();
40#else
41 err = errno;
42#endif
43
44 return err;
45 }
46
47 bool UdpSocket::isWaitNeeded()
48 {
49 int err = getErrno();
50
51 if (err == EWOULDBLOCK || err == EAGAIN || err == EINPROGRESS)
52 {
53 return true;
54 }
55
56 return false;
57 }
58
59 void UdpSocket::closeSocket(int fd)
60 {
61#ifdef _WIN32
62 closesocket(fd);
63#else
64 ::close(fd);
65#endif
66 }
67
68 bool UdpSocket::init(const std::string& host, int port, std::string& errMsg)
69 {
70 _sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
71 if (_sockfd < 0)
72 {
73 errMsg = "Could not create socket";
74 return false;
75 }
76
77#ifdef _WIN32
78 unsigned long nonblocking = 1;
79 ioctlsocket(_sockfd, FIONBIO, &nonblocking);
80#else
81 fcntl(_sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking
82#endif
83
84 memset(&_server, 0, sizeof(_server));
85 _server.sin_family = AF_INET;
86 _server.sin_port = htons(port);
87
88 // DNS resolution.
89 struct addrinfo hints, *result = nullptr;
90 memset(&hints, 0, sizeof(hints));
91 hints.ai_family = AF_INET;
92 hints.ai_socktype = SOCK_DGRAM;
93
94 int ret = getaddrinfo(host.c_str(), nullptr, &hints, &result);
95 if (ret != 0)
96 {
97 errMsg = strerror(UdpSocket::getErrno());
98 freeaddrinfo(result);
99 close();
100 return false;
101 }
102
103 struct sockaddr_in* host_addr = (struct sockaddr_in*) result->ai_addr;
104 memcpy(&_server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr));
105 freeaddrinfo(result);
106
107 return true;
108 }
109
110 ssize_t UdpSocket::sendto(const std::string& buffer)
111 {
112 return (ssize_t)::sendto(
113 _sockfd, buffer.data(), buffer.size(), 0, (struct sockaddr*) &_server, sizeof(_server));
114 }
115
116 ssize_t UdpSocket::recvfrom(char* buffer, size_t length)
117 {
118#ifdef _WIN32
119 int addressLen = (int) sizeof(_server);
120#else
121 socklen_t addressLen = (socklen_t) sizeof(_server);
122#endif
123 return (ssize_t)::recvfrom(
124 _sockfd, buffer, length, 0, (struct sockaddr*) &_server, &addressLen);
125 }
126} // namespace ix
127