TDME2  1.9.200
NetworkSocket.cpp
Go to the documentation of this file.
1 #include <string.h>
2 
3 #include <string>
4 
5 #include <tdme/tdme.h>
6 
7 #if defined(_WIN32)
8  #include <winsock2.h>
9  #include <ws2tcpip.h>
10  #define SHUT_RDWR SD_BOTH
11 #else
12  #include <errno.h>
13  #include <fcntl.h>
14  #include <unistd.h>
15  #include <netinet/in.h>
16  #include <sys/socket.h>
17  #include <arpa/inet.h>
18 #endif
19 
21 
22 using std::string;
23 using std::to_string;
24 
26 
27 NetworkSocket::IpVersion NetworkSocket::determineIpVersion(const string& ip) {
28  return ip.find(':') != std::string::npos?IpVersion::IPV6:IpVersion::IPV4;
29 }
30 
31 NetworkSocket::NetworkSocket() : descriptor(-1), ip("0.0.0.0"), port(0) {
32 }
33 
35 }
36 
37 const std::string& NetworkSocket::getAddress() {
38  return ip;
39 }
40 
41 const unsigned int NetworkSocket::getPort() {
42  return port;
43 }
44 
45 void NetworkSocket::bind(const string& ip, const unsigned int port) {
46  // determine IP version
47  auto ipVersion = determineIpVersion(ip);
48 
49  // socket address in setup
50  socklen_t sinLen = 0;
51  void* sin;
52  sockaddr_in sinIPV4;
53  sockaddr_in6 sinIPV6;
54  switch(ipVersion) {
55  case IPV4:
56  {
57  sinLen = sizeof(sinIPV4);
58  memset(&sinIPV4, 0, sinLen);
59  sinIPV4.sin_family = AF_INET;
60  sinIPV4.sin_port = htons(port);
61  sinIPV4.sin_addr.s_addr = inet_addr(ip.c_str());
62  sin = &sinIPV4;
63  }
64  break;
65  case IPV6:
66  {
67  sinLen = sizeof(sinIPV6);
68  memset(&sinIPV6, 0, sinLen);
69  sinIPV6.sin6_family = AF_INET6;
70  sinIPV6.sin6_port = htons(port);
71  inet_pton(AF_INET6, ip.c_str(), &sinIPV6.sin6_addr);
72  sin = &sinIPV6;
73  }
74  break;
75  }
76 
77  // bind
78  if (::bind(descriptor, (const struct sockaddr*)sin, sinLen) == -1) {
79  std::string msg = "Could not bind socket: ";
80  #if defined(_WIN32)
81  msg+= to_string(WSAGetLastError());
82  #else
83  msg+= strerror(errno);
84  #endif
85  throw NetworkSocketException(msg);
86  }
87 
88  // set address
89  this->ip = ip;
90  this->port = port;
91 }
92 
94  #if defined(_WIN32)
95  long unsigned int mode = 1;
96  if (ioctlsocket(descriptor, FIONBIO, &mode) != 0) {
97  std::string msg = "Could not set socket non blocked: ";
98  msg+= to_string(WSAGetLastError());
99  throw NetworkSocketException(msg);
100  }
101  #else
102  // get the server socket file descriptor control settings
103  int fdc = fcntl(descriptor, F_GETFL, 0);
104  if (fdc == -1) {
105  std::string msg = "Could not get socket file descriptor settings: ";
106  msg+= strerror(errno);
107  throw NetworkSocketException(msg);
108  }
109 
110  // make the socket non blocked
111  if (fcntl(descriptor, F_SETFL, fdc | O_NONBLOCK) == -1) {
112  std::string msg = "Could not set socket non blocked: ";
113  msg+= strerror(errno);
114  throw NetworkSocketException(msg);
115  }
116  #endif
117 }
118 
120  if (descriptor != -1) ::shutdown(descriptor, SHUT_RDWR);
121 }
122 
124  #if defined(_WIN32)
125  ::closesocket(descriptor);
126  #else
128  #endif
129  descriptor = -1;
130 }
131 
132 #if defined(__MINGW32__) && !defined(__MINGW64__)
133  // see: https://stackoverflow.com/questions/15370033/how-to-use-inet-pton-with-the-mingw-compiler
134  #define NS_INADDRSZ 4
135  #define NS_IN6ADDRSZ 16
136  #define NS_INT16SZ 2
137 
138  // author: Paul Vixie, 1996.
139  int inet_pton4(const char* src, void* dst) {
140  uint8_t tmp[NS_INADDRSZ], *tp;
141 
142  int saw_digit = 0;
143  int octets = 0;
144  *(tp = tmp) = 0;
145 
146  int ch;
147  while ((ch = *src++) != '\0') {
148  if (ch >= '0' && ch <= '9') {
149  uint32_t n = *tp * 10 + (ch - '0');
150 
151  if (saw_digit && *tp == 0)
152  return 0;
153 
154  if (n > 255)
155  return 0;
156 
157  *tp = n;
158  if (!saw_digit) {
159  if (++octets > 4)
160  return 0;
161  saw_digit = 1;
162  }
163  } else if (ch == '.' && saw_digit) {
164  if (octets == 4)
165  return 0;
166  *++tp = 0;
167  saw_digit = 0;
168  } else
169  return 0;
170  }
171  if (octets < 4)
172  return 0;
173 
174  memcpy(dst, tmp, NS_INADDRSZ);
175 
176  return 1;
177  }
178 
179  // author: Paul Vixie, 1996.
180  int inet_pton6(int af, const char* src, void* dst) {
181  static const char xdigits[] = "0123456789abcdef";
182  uint8_t tmp[NS_IN6ADDRSZ];
183 
184  uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ);
185  uint8_t *endp = tp + NS_IN6ADDRSZ;
186  uint8_t *colonp = NULL;
187 
188  /* Leading :: requires some special handling. */
189  if (*src == ':') {
190  if (*++src != ':')
191  return 0;
192  }
193 
194  const char *curtok = src;
195  int saw_xdigit = 0;
196  uint32_t val = 0;
197  int ch;
198  while ((ch = tolower(*src++)) != '\0') {
199  const char *pch = strchr(xdigits, ch);
200  if (pch != NULL) {
201  val <<= 4;
202  val |= (pch - xdigits);
203  if (val > 0xffff)
204  return 0;
205  saw_xdigit = 1;
206  continue;
207  }
208  if (ch == ':') {
209  curtok = src;
210  if (!saw_xdigit) {
211  if (colonp)
212  return 0;
213  colonp = tp;
214  continue;
215  } else if (*src == '\0') {
216  return 0;
217  }
218  if (tp + NS_INT16SZ > endp)
219  return 0;
220  *tp++ = (uint8_t) (val >> 8) & 0xff;
221  *tp++ = (uint8_t) val & 0xff;
222  saw_xdigit = 0;
223  val = 0;
224  continue;
225  }
226  if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)
227  && inet_pton4(curtok, (char*) tp) > 0) {
228  tp += NS_INADDRSZ;
229  saw_xdigit = 0;
230  break; /* '\0' was seen by inet_pton4(). */
231  }
232  return 0;
233  }
234  if (saw_xdigit) {
235  if (tp + NS_INT16SZ > endp)
236  return 0;
237  *tp++ = (uint8_t) (val >> 8) & 0xff;
238  *tp++ = (uint8_t) val & 0xff;
239  }
240  if (colonp != NULL) {
241  /*
242  * Since some memmove()'s erroneously fail to handle
243  * overlapping regions, we'll do the shift by hand.
244  */
245  const int n = tp - colonp;
246 
247  if (tp == endp)
248  return 0;
249 
250  for (int i = 1; i <= n; i++) {
251  endp[-i] = colonp[n - i];
252  colonp[n - i] = 0;
253  }
254  tp = endp;
255  }
256  if (tp != endp)
257  return 0;
258 
259  memcpy(dst, tmp, NS_IN6ADDRSZ);
260 
261  return 1;
262  }
263 
264  /*
265  * $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $
266  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
267  *
268  * Permission to use, copy, modify, and distribute this software for any
269  * purpose with or without fee is hereby granted, provided that the above
270  * copyright notice and this permission notice appear in all copies.
271  *
272  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
273  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
274  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
275  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
276  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
277  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
278  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
279  */
280  size_t strlcpy(char* __restrict dst, const char* __restrict src, size_t siz)
281  {
282  char *d = dst;
283  const char *s = src;
284  size_t n = siz;
285 
286  /* Copy as many bytes as will fit */
287  if (n != 0) {
288  while (--n != 0) {
289  if ((*d++ = *s++) == '\0')
290  break;
291  }
292  }
293 
294  /* Not enough room in dst, add NUL and traverse rest of src */
295  if (n == 0) {
296  if (siz != 0)
297  *d = '\0'; /* NUL-terminate dst */
298  while (*s++)
299  ;
300  }
301 
302  //
303  return (s - src - 1); /* count does not include NUL */
304  }
305 
306  // author: Paul Vixie, 1996.
307  char* inet_ntop4(const void* src, char* dst, size_t size) {
308  static const char fmt[128] = "%u.%u.%u.%u";
309  char tmp[sizeof "255.255.255.255"];
310  int l;
311 
312  // l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); // ****
313  std::sprintf(tmp, fmt, ((uint8_t*)src)[0], ((uint8_t*)src)[1], ((uint8_t*)src)[2], ((uint8_t*)src)[3]); // **** vc++ does not have snprintf
314  if (l <= 0 || (socklen_t) l >= size) {
315  return (NULL);
316  }
317  strlcpy(dst, tmp, size);
318  return (dst);
319  }
320 
321  // author: Paul Vixie, 1996.
322  char* inet_ntop6(int af, const void* src, char* dst, size_t size)
323  {
324  /*
325  * Note that int32_t and int16_t need only be "at least" large enough
326  * to contain a value of the specified size. On some systems, like
327  * Crays, there is no such thing as an integer variable with 16 bits.
328  * Keep this in mind if you think this function should have been coded
329  * to use pointer overlays. All the world's not a VAX.
330  */
331  char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
332  struct {
333  int base, len;
334  } best, cur;
335  u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
336  int i;
337 
338  /*
339  * Preprocess:
340  * Copy the input (bytewise) array into a wordwise array.
341  * Find the longest run of 0x00's in src[] for :: shorthanding.
342  */
343  memset(words, '\0', sizeof words);
344  for (i = 0; i < NS_IN6ADDRSZ; i++)
345  words[i / 2] |= (((uint8_t*)src)[i] << ((1 - (i % 2)) << 3));
346  best.base = -1;
347  best.len = 0;
348  cur.base = -1;
349  cur.len = 0;
350  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
351  if (words[i] == 0) {
352  if (cur.base == -1)
353  cur.base = i, cur.len = 1;
354  else
355  cur.len++;
356  } else {
357  if (cur.base != -1) {
358  if (best.base == -1 || cur.len > best.len)
359  best = cur;
360  cur.base = -1;
361  }
362  }
363  }
364  if (cur.base != -1) {
365  if (best.base == -1 || cur.len > best.len)
366  best = cur;
367  }
368  if (best.base != -1 && best.len < 2)
369  best.base = -1;
370 
371  /*
372  * Format the result.
373  */
374  tp = tmp;
375  for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
376  /* Are we inside the best run of 0x00's? */
377  if (best.base != -1 && i >= best.base && i < (best.base + best.len)) {
378  if (i == best.base)
379  *tp++ = ':';
380  continue;
381  }
382  /* Are we following an initial run of 0x00s or any real hex? */
383  if (i != 0)
384  *tp++ = ':';
385  /* Is this address an encapsulated IPv4? */
386  if (i == 6 && best.base == 0
387  && (best.len == 6 || (best.len == 7 && words[7] != 0x0001)
388  || (best.len == 5 && words[5] == 0xffff))) {
389  if (!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
390  return (NULL);
391  tp += strlen(tp);
392  break;
393  }
394  tp += std::sprintf(tp, "%x", words[i]); // ****
395  }
396  /* Was it a trailing run of 0x00's? */
397  if (best.base != -1
398  && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ))
399  *tp++ = ':';
400  *tp++ = '\0';
401 
402  /*
403  * Check for overflow, copy, and we're done.
404  */
405  if ((socklen_t) (tp - tmp) > size) {
406  return (NULL);
407  }
408  strcpy(dst, tmp);
409  return (dst);
410  }
411 
412 #endif
Base class of network sockets.
Definition: NetworkSocket.h:17
void bind(const string &ip, const unsigned int port)
Binds a socket to local ip and port.
virtual void close()
Closes the socket.
virtual void shutdown()
shuts socket down for reading and writing
static IpVersion determineIpVersion(const string &ip)
Determine IP version.
const string & getAddress()
returns the end points ip address
void setNonBlocked()
sets the socket non blocked
const unsigned int getPort()
returns the end points port
virtual ~NetworkSocket()
public destructor
NetworkSocket()
Protected constructor.