rby1-sdk
Loading...
Searching...
No Matches
udp_client.h
1#pragma once
2
3#include <string>
4#include <stdexcept>
5#include <utility>
6#if defined(_WIN32)
7#include <winsock2.h>
8#include <ws2tcpip.h>
9#else
10#include <arpa/inet.h>
11#include <fcntl.h>
12#include <sys/socket.h>
13#include <unistd.h>
14#endif
15
16namespace rb {
17
18class UdpClient {
19 public:
20 virtual int RecvFrom(unsigned char* buffer, size_t max_buf_size) const = 0;
21
22 virtual void SendTo(unsigned char* buffer, size_t buf_size) const = 0;
23};
24
25class UdpIPv4Client : public UdpClient {
26 public:
27 UdpIPv4Client(std::string ip, int port) : ip_(std::move(ip)), port_(port) {
28#if defined(_WIN32)
29 int startup_result = WSAStartup(MAKEWORD(2, 2), &wsa_data_);
30 if (startup_result) {
31 std::stringstream ss;
32 ss << "Cannot start WinSock (error: " << startup_result << ")";
33 throw std::runtime_error(ss.str());
34 }
35#endif
36
37 fd_ = socket(AF_INET, SOCK_DGRAM, 0);
38#if defined(_WIN32)
39 if (fd_ == INVALID_SOCKET) {
40 WSACleanup();
41#else
42 if (fd_ < 0) {
43#endif
44 throw std::runtime_error("Create udp socket failed");
45 }
46
47 memset(&server_addr_, 0, sizeof(server_addr_));
48 server_addr_.sin_family = AF_INET;
49 server_addr_.sin_port = htons(port_);
50 if (inet_pton(AF_INET, ip_.c_str(), &server_addr_.sin_addr) <= 0) {
51#if defined(_WIN32)
52 closesocket(fd_);
53 WSACleanup();
54#else
55 close(fd_);
56#endif
57 throw std::runtime_error("Invalid IPv4 address / Address not supported");
58 }
59
60 // Non-blocking
61#if defined(_WIN32)
62 u_long mode = 1;
63 if (ioctlsocket(fd_, FIONBIO, &mode) != NO_ERROR) {
64 shutdown(fd_, SD_BOTH);
65 closesocket(fd_);
66 WSACleanup();
67#else
68 if (fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | O_NONBLOCK) < 0) {
69 shutdown(fd_, SHUT_RDWR);
70 close(fd_);
71#endif
72 throw std::runtime_error("failed to pu the socket in non-blocking mode");
73 }
74 }
75
77#if defined(_WIN32)
78 shutdown(fd_, SD_BOTH);
79 closesocket(fd_);
80 WSACleanup();
81#else
82 shutdown(fd_, SHUT_RDWR);
83 close(fd_);
84#endif
85 }
86
87 int RecvFrom(unsigned char* buffer, size_t max_buf_size) const override {
88 struct sockaddr_in server_addr {};
89
90 socklen_t addr_len = sizeof(server_addr);
91 return (int)recvfrom(fd_, buffer, max_buf_size, 0, (struct sockaddr*)&server_addr, &addr_len);
92 }
93
94 void SendTo(unsigned char* buffer, size_t buf_size) const override {
95 sendto(fd_, buffer, buf_size, 0, (struct sockaddr*)&server_addr_, sizeof(server_addr_));
96 }
97
98 protected:
99 std::string ip_;
100 int port_;
101
102#if defined(_WIN32)
103 WSADATA wsa_data_{};
104 SOCKET fd_{};
105#else
106 int fd_{};
107#endif
108
109 struct sockaddr_in server_addr_ {};
110};
111
112class UdpIPv6Client : public UdpClient {
113 public:
114 UdpIPv6Client(std::string ip, int port) : ip_(std::move(ip)), port_(port) {
115#if defined(_WIN32)
116 int startup_result = WSAStartup(MAKEWORD(2, 2), &wsa_data_);
117 if (startup_result) {
118 std::stringstream ss;
119 ss << "Cannot start WinSock (error: " << startup_result << ")";
120 throw std::runtime_error(ss.str());
121 }
122#endif
123
124 fd_ = socket(AF_INET6, SOCK_DGRAM, 0);
125#if defined(_WIN32)
126 if (fd_ == INVALID_SOCKET) {
127 WSACleanup();
128#else
129 if (fd_ < 0) {
130#endif
131 throw std::runtime_error("Create udp socket failed");
132 }
133
134 memset(&server_addr_, 0, sizeof(server_addr_));
135 server_addr_.sin6_family = AF_INET6;
136 server_addr_.sin6_port = htons(port_);
137 if (inet_pton(AF_INET6, ip_.c_str(), &server_addr_.sin6_addr) <= 0) {
138#if defined(_WIN32)
139 closesocket(fd_);
140 WSACleanup();
141#else
142 close(fd_);
143#endif
144 throw std::runtime_error("Invalid IPv6 address / Address not supported");
145 }
146
147 // Non-blocking
148#if defined(_WIN32)
149 u_long mode = 1;
150 if (ioctlsocket(fd_, FIONBIO, &mode) != NO_ERROR) {
151 shutdown(fd_, SD_BOTH);
152 closesocket(fd_);
153 WSACleanup();
154#else
155 if (fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL) | O_NONBLOCK) < 0) {
156 shutdown(fd_, SHUT_RDWR);
157 close(fd_);
158#endif
159 throw std::runtime_error("failed to pu the socket in non-blocking mode");
160 }
161 }
162
164#if defined(_WIN32)
165 shutdown(fd_, SD_BOTH);
166 closesocket(fd_);
167 WSACleanup();
168#else
169 shutdown(fd_, SHUT_RDWR);
170 close(fd_);
171#endif
172 }
173
174 int RecvFrom(unsigned char* buffer, size_t max_buf_size) const override {
175 struct sockaddr_in6 server_addr {};
176
177 socklen_t addr_len = sizeof(server_addr);
178 return (int)recvfrom(fd_, buffer, max_buf_size, 0, (struct sockaddr*)&server_addr, &addr_len);
179 }
180
181 void SendTo(unsigned char* buffer, size_t buf_size) const override {
182 sendto(fd_, buffer, buf_size, 0, (struct sockaddr*)&server_addr_, sizeof(server_addr_));
183 }
184
185 protected:
186 std::string ip_;
187 int port_;
188
189#if defined(_WIN32)
190 WSADATA wsa_data_{};
191 SOCKET fd_{};
192#else
193 int fd_{};
194#endif
195
196 struct sockaddr_in6 server_addr_ {};
197};
198
199} // namespace rb
Definition udp_client.h:18
Definition udp_client.h:25
Definition udp_client.h:112
Definition udp_client.h:109
Definition udp_client.h:196