JBus
JoyBus communication server
Socket.hpp
Go to the documentation of this file.
1 #ifndef JBUS_SOCKET_HPP
2 #define JBUS_SOCKET_HPP
3 
4 #ifndef _WIN32
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <netinet/tcp.h>
8 #include <arpa/inet.h>
9 #include <netdb.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #else
13 #include <winsock2.h>
14 #include <Ws2tcpip.h>
15 #endif
16 
17 #include <sys/types.h>
18 #include <fcntl.h>
19 #include <string>
20 
21 #include "Common.hpp"
22 
23 namespace jbus
24 {
25 namespace net
26 {
27 
28 /* Define the low-level send/receive flags, which depend on the OS */
29 #ifdef __linux__
30 static const int _flags = MSG_NOSIGNAL;
31 #else
32 static const int _flags = 0;
33 #endif
34 
36 class IPAddress
37 {
38  uint32_t m_address = 0;
39  bool m_valid = false;
40 
41  void resolve(const std::string& address)
42  {
43  m_address = 0;
44  m_valid = false;
45 
46  if (address == "255.255.255.255")
47  {
48  /* The broadcast address needs to be handled explicitly,
49  * because it is also the value returned by inet_addr on error */
50  m_address = INADDR_BROADCAST;
51  m_valid = true;
52  }
53  else if (address == "0.0.0.0")
54  {
55  m_address = INADDR_ANY;
56  m_valid = true;
57  }
58  else
59  {
60  /* Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") */
61  struct in_addr addr;
62  if (inet_pton(AF_INET, address.c_str(), &addr) == 1)
63  {
64  m_address = addr.s_addr;
65  m_valid = true;
66  }
67  else
68  {
69  /* Not a valid address, try to convert it as a host name */
70  addrinfo hints;
71  memset(&hints, 0, sizeof(hints));
72  hints.ai_family = AF_INET;
73  addrinfo* result = NULL;
74  if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0)
75  {
76  if (result)
77  {
78  addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;
79  freeaddrinfo(result);
80  m_address = addr.s_addr;
81  m_valid = true;
82  }
83  }
84  }
85  }
86  }
87 
88 public:
89  IPAddress(const std::string& address)
90  {
91  resolve(address);
92  }
93 
94  uint32_t toInteger() const
95  {
96  return ntohl(m_address);
97  }
98 
99  operator bool() const { return m_valid; }
100 };
101 
103 class Socket
104 {
105 #ifndef _WIN32
106  using SocketTp = int;
107 #else
108  using SocketTp = SOCKET;
109 #endif
110  SocketTp m_socket = -1;
111  bool m_isBlocking;
112 
113  static sockaddr_in createAddress(uint32_t address, unsigned short port)
114  {
115  sockaddr_in addr;
116  memset(&addr, 0, sizeof(addr));
117  addr.sin_addr.s_addr = htonl(address);
118  addr.sin_family = AF_INET;
119  addr.sin_port = htons(port);
120 
121 #ifdef __APPLE__
122  addr.sin_len = sizeof(addr);
123 #endif
124 
125  return addr;
126  }
127 
128  bool openSocket()
129  {
130  if (isOpen())
131  return false;
132 
133  m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
134  if (m_socket == -1)
135  {
136  fprintf(stderr, "Can't allocate socket\n");
137  return false;
138  }
139 
140  int one = 1;
141  setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one));
142 #ifdef __APPLE__
143  setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&one), sizeof(one));
144 #endif
145 
146  setBlocking(m_isBlocking);
147 
148  return true;
149  }
150 
151  void setRemoteSocket(int remSocket)
152  {
153  close();
154  m_socket = remSocket;
155  setBlocking(m_isBlocking);
156  }
157 
158 public:
159  enum class EResult
160  {
161  OK,
162  Error,
163  Busy
164  };
165 
166 #ifdef _WIN32
167  static EResult LastWSAError()
168  {
169  switch (WSAGetLastError())
170  {
171  case WSAEWOULDBLOCK:
172  case WSAEALREADY:
173  return EResult::Busy;
174  default:
175  return EResult::Error;
176  }
177  }
178 #endif
179 
180  Socket(bool blocking)
181  : m_isBlocking(blocking) {}
182  ~Socket() { close(); }
183 
184  Socket(const Socket& other) = delete;
185  Socket& operator=(const Socket& other) = delete;
186  Socket(Socket&& other)
187  : m_socket(other.m_socket), m_isBlocking(other.m_isBlocking)
188  {
189  other.m_socket = -1;
190  }
192  {
193  close();
194  m_socket = other.m_socket;
195  other.m_socket = -1;
196  m_isBlocking = other.m_isBlocking;
197  return *this;
198  }
199 
200  void setBlocking(bool blocking)
201  {
202  m_isBlocking = blocking;
203 #ifndef _WIN32
204  int status = fcntl(m_socket, F_GETFL);
205  if (m_isBlocking)
206  fcntl(m_socket, F_SETFL, status & ~O_NONBLOCK);
207  else
208  fcntl(m_socket, F_SETFL, status | O_NONBLOCK);
209 #else
210  u_long b = blocking ? 0 : 1;
211  ioctlsocket(m_socket, FIONBIO, &b);
212 #endif
213  }
214 
215  bool isOpen() const { return m_socket != -1; }
216  bool openAndListen(const IPAddress& address, uint32_t port)
217  {
218  if (!openSocket())
219  return false;
220 
221  sockaddr_in addr = createAddress(address.toInteger(), port);
222  if (bind(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
223  {
224  /* Not likely to happen, but... */
225  fprintf(stderr, "Failed to bind listener socket to port %d\n", port);
226  return false;
227  }
228 
229  if (::listen(m_socket, 0) == -1)
230  {
231  /* Oops, socket is deaf */
232  fprintf(stderr, "Failed to listen to port %d\n", port);
233  return false;
234  }
235 
236  return true;
237  }
238 
239  EResult accept(Socket& remoteSocketOut, sockaddr_in& fromAddress)
240  {
241  if (!isOpen())
242  return EResult::Error;
243 
244  /* Accept a new connection */
245  socklen_t length = sizeof(sockaddr_in);
246  int remoteSocket = ::accept(m_socket, reinterpret_cast<sockaddr*>(&fromAddress), &length);
247 
248  /* Check for errors */
249  if (remoteSocket == -1)
250  {
251 #ifndef _WIN32
252  EResult res = (errno == EAGAIN) ? EResult::Busy : EResult::Error;
253  if (res == EResult::Error)
254  fprintf(stderr, "Failed to accept incoming connection: %s\n", strerror(errno));
255 #else
256  EResult res = LastWSAError();
257  if (res == EResult::Error)
258  fprintf(stderr, "Failed to accept incoming connection\n");
259 #endif
260  return res;
261  }
262 
263  /* Initialize the new connected socket */
264  remoteSocketOut.setRemoteSocket(remoteSocket);
265 
266  return EResult::OK;
267  }
268 
269  EResult accept(Socket& remoteSocketOut)
270  {
271  sockaddr_in fromAddress;
272  return accept(remoteSocketOut, fromAddress);
273  }
274 
275  EResult accept(Socket& remoteSocketOut, std::string& fromHostname)
276  {
277  sockaddr_in fromAddress;
278  socklen_t len = sizeof(fromAddress);
279  char name[NI_MAXHOST];
280  EResult res = accept(remoteSocketOut, fromAddress);
281  if (res == EResult::OK)
282  if (getnameinfo((sockaddr*)&fromAddress, len, name, NI_MAXHOST, nullptr, 0, 0) == 0)
283  fromHostname.assign(name);
284  return res;
285  }
286 
287  void close()
288  {
289  if (!isOpen())
290  return;
291 #ifndef _WIN32
292  ::close(m_socket);
293 #else
294  closesocket(m_socket);
295 #endif
296  m_socket = -1;
297  }
298 
299  EResult send(const void* buf, size_t len, size_t& transferred)
300  {
301  transferred = 0;
302  if (!isOpen())
303  return EResult::Error;
304 
305  if (!buf || !len)
306  return EResult::Error;
307 
308  /* Loop until every byte has been sent */
309  int result = 0;
310  for (size_t sent = 0; sent < len; sent += result)
311  {
312  /* Send a chunk of data */
313  result = ::send(m_socket, static_cast<const char*>(buf) + sent, len - sent, _flags);
314 
315  /* Check for errors */
316  if (result < 0)
317 #ifndef _WIN32
318  return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
319 #else
320  return LastWSAError();
321 #endif
322  }
323 
324  transferred = len;
325  return EResult::OK;
326  }
327 
328  EResult send(const void* buf, size_t len)
329  {
330  size_t transferred;
331  return send(buf, len, transferred);
332  }
333 
334  EResult recv(void* buf, size_t len, size_t& transferred)
335  {
336  transferred = 0;
337  if (!isOpen())
338  return EResult::Error;
339 
340  if (!buf)
341  return EResult::Error;
342 
343  if (!len)
344  return EResult::OK;
345 
346  /* Receive a chunk of bytes */
347  int result = ::recv(m_socket, static_cast<char*>(buf), static_cast<int>(len), _flags);
348 
349  if (result < 0)
350 #ifndef _WIN32
351  return (errno == EAGAIN) ? EResult::Busy : EResult::Error;
352 #else
353  return LastWSAError();
354 #endif
355  else if (result == 0)
356  return EResult::Error;
357 
358  transferred = result;
359  return EResult::OK;
360  }
361 
362  EResult recv(void* buf, size_t len)
363  {
364  size_t transferred;
365  return recv(buf, len, transferred);
366  }
367 
368  operator bool() const { return isOpen(); }
369 
370  SocketTp GetInternalSocket() const { return m_socket; }
371 };
372 
373 }
374 }
375 
376 #endif // JBUS_SOCKET_HPP
SocketTp GetInternalSocket() const
Definition: Socket.hpp:370
EResult send(const void *buf, size_t len, size_t &transferred)
Definition: Socket.hpp:299
bool openAndListen(const IPAddress &address, uint32_t port)
Definition: Socket.hpp:216
EResult recv(void *buf, size_t len)
Definition: Socket.hpp:362
Definition: Common.hpp:8
Definition: Socket.hpp:103
bool isOpen() const
Definition: Socket.hpp:215
EResult recv(void *buf, size_t len, size_t &transferred)
Definition: Socket.hpp:334
void close()
Definition: Socket.hpp:287
~Socket()
Definition: Socket.hpp:182
Definition: Socket.hpp:36
Socket & operator=(Socket &&other)
Definition: Socket.hpp:191
EResult accept(Socket &remoteSocketOut)
Definition: Socket.hpp:269
uint32_t toInteger() const
Definition: Socket.hpp:94
Socket(Socket &&other)
Definition: Socket.hpp:186
EResult send(const void *buf, size_t len)
Definition: Socket.hpp:328
EResult accept(Socket &remoteSocketOut, sockaddr_in &fromAddress)
Definition: Socket.hpp:239
EResult
Definition: Socket.hpp:159
Socket(bool blocking)
Definition: Socket.hpp:180
void setBlocking(bool blocking)
Definition: Socket.hpp:200
EResult accept(Socket &remoteSocketOut, std::string &fromHostname)
Definition: Socket.hpp:275
IPAddress(const std::string &address)
Definition: Socket.hpp:89