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