sot-talos-balance  1.7.0
Network.cpp
Go to the documentation of this file.
1 #define _CRT_SECURE_NO_WARNINGS
2 #define NOMINMAX
3 
5 
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <iostream>
11 #include <algorithm>
12 
13 #ifdef _WIN32
14 #include <iphlpapi.h>
15 #include <Ws2tcpip.h>
16 #else
17 #include <arpa/inet.h> // for inet_addr
18 #include <netinet/in.h> // for sockaddr_in, ntohl, in_addr, etc
19 #include <sys/socket.h> // for getsockname, send, AF_INET, etc
20 #include <unistd.h> // for close, read, fork, etc
21 #include <sys/types.h> /* Solaris 2.5.1 fix: u_short, required by sys/socket.h */
22 #include <sys/socket.h> /* sockets */
23 #include <sys/time.h> /* timeval */
24 #include <sys/ioctl.h> /* ioctl */
25 #include <string.h> /* bzero, for FD_SET */
26 #include <strings.h> /* bzero, for FD_ZERO (AIX) */
27 #include <netinet/in.h> /* INADDR_*, in_addr, sockaddr_in, htonl etc. */
28 #include <netinet/tcp.h> // for TCP_NODELAY
29 #include <netdb.h> /* getservbyname */
30 #include <arpa/inet.h> /* inet_addr */
31 #include <errno.h> /* socket error codes */
32 #include <ifaddrs.h>
33 
34 
35 #define SOCKET_ERROR (-1)
36 
37 #define TIMEVAL timeval
38 #define closesocket close
39 #define ioctlsocket ioctl
40 #define SOCKADDR sockaddr
41 #define SD_SEND SHUT_WR
42 
43 #endif
44 
46 {
47  mSocket = INVALID_SOCKET;
48  mUDPSocket = INVALID_SOCKET;
49  mUDPBroadcastSocket = INVALID_SOCKET;
50  mLastError = 0;
51  mErrorStr[0] = 0;
52 
53  InitWinsock();
54 }
55 
56 
58 {
59 #ifdef _WIN32
60  WSACleanup();
61 #endif
62 }
63 
64 
65 bool CNetwork::InitWinsock()
66 {
67 #ifdef _WIN32
68  WORD wVersionRequested = MAKEWORD(2,2);
69  WSADATA wsaData;
70 
71  // Initialize WinSock and check version
72  if (WSAStartup(wVersionRequested, &wsaData) != 0)
73  {
74  SetErrorString();
75  return false;
76  }
77  if (wsaData.wVersion != wVersionRequested)
78  {
79  SetErrorString();
80  return false;
81  }
82 #endif
83  return true;
84 } // InitWinsock
85 
86 
87 bool CNetwork::Connect(const char* serverAddr, unsigned short nPort)
88 {
89  mLastError = 0;
90  mErrorStr[0] = 0;
91 
92  // Connect to QTM RT server.
93 
94  mSocket = socket(AF_INET, SOCK_STREAM, 0);
95  if (mSocket == -1)
96  {
97  strcpy(mErrorStr, "Socket could not be created.");
98  }
99 
100  sockaddr_in sAddr;
101 
102  // First check if the address is a dotted number "A.B.C.D"
103  if (inet_pton(AF_INET, serverAddr, &(sAddr.sin_addr)) == 0)
104  {
105  // If it wasn't a dotted number lookup the server name
106 
107  struct addrinfo hints, *servinfo;
108 
109  memset(&hints, 0, sizeof hints);
110  hints.ai_family = AF_INET;
111  hints.ai_socktype = SOCK_STREAM;
112 
113  if (getaddrinfo(serverAddr, nullptr, &hints, &servinfo) != 0)
114  {
115  strcpy(mErrorStr, "Error looking up host name.");
116  closesocket(mSocket);
117  return false;
118  }
119  if (servinfo == nullptr)
120  {
121  strcpy(mErrorStr, "Error looking up host name.");
122  closesocket(mSocket);
123  return false;
124  }
125  sAddr.sin_addr = ((sockaddr_in *)servinfo[0].ai_addr)->sin_addr;
126  }
127  sAddr.sin_port = htons(nPort);
128  sAddr.sin_family = AF_INET;
129 
130 
131  if (connect(mSocket, (sockaddr*)(&sAddr), sizeof(sAddr)) == SOCKET_ERROR)
132  {
133  strcpy(mErrorStr, "Connect failed.");
134 
135  //SetErrorString();
136  closesocket(mSocket);
137  return false;
138  }
139 
140  // Disable Nagle's algorithm
141 #ifdef _WIN32
142  char bNoDelay = 1;
143 #else
144  int bNoDelay = 1;
145 #endif
146  if (setsockopt(mSocket, IPPROTO_TCP, TCP_NODELAY, &bNoDelay, sizeof(bNoDelay)) != 0)
147  {
148  SetErrorString();
149  closesocket(mSocket);
150  return false;
151  }
152 
153  return true;
154 } // Connect
155 
156 
158 {
159  // Try to shutdown gracefully
160 
161  shutdown(mSocket, SD_SEND);
162  closesocket(mSocket);
163  closesocket(mUDPSocket);
164  closesocket(mUDPBroadcastSocket);
165  mSocket = INVALID_SOCKET;
166  mUDPSocket = INVALID_SOCKET;
167  mUDPBroadcastSocket = INVALID_SOCKET;
168 } // Disconnect
169 
170 
172 {
173  return mSocket != INVALID_SOCKET;
174 }
175 
176 bool CNetwork::CreateUDPSocket(unsigned short &nUDPPort, bool bBroadcast)
177 {
178  if (nUDPPort == 0 || nUDPPort > 1023)
179  {
180  SOCKET tempSocket = INVALID_SOCKET;
181 
182  // Create UDP socket for data streaming
183  sockaddr_in recvAddr;
184  recvAddr.sin_family = AF_INET;
185  recvAddr.sin_port = htons(nUDPPort);
186  recvAddr.sin_addr.s_addr = INADDR_ANY;
187 
188  tempSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
189  if (tempSocket != INVALID_SOCKET)
190  {
191  u_long argp = 1;
192  // Make socket unblocking.
193  if (ioctlsocket(tempSocket, FIONBIO, &argp) == 0)
194  {
195  if (bind(tempSocket, (SOCKADDR *) &recvAddr, sizeof(recvAddr)) != -1)
196  {
197  nUDPPort = GetUdpServerPort(tempSocket);
198  if (bBroadcast)
199  {
200 #ifdef _WIN32
201  char broadcast = 1;
202 #else
203  int broadcast = 1;
204 #endif
205  if (setsockopt(tempSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == 0)
206  {
207  mUDPBroadcastSocket = tempSocket;
208  return true;
209  }
210  else
211  {
212  strcpy(mErrorStr, "Failed to set socket options for UDP server socket.");
213  }
214  }
215  else
216  {
217  mUDPSocket = tempSocket;
218  return true;
219  }
220  }
221  else
222  {
223  strcpy(mErrorStr, "Failed to bind UDP server socket.");
224  }
225  }
226  else
227  {
228  strcpy(mErrorStr, "Failed to make UDP server socket unblocking.");
229  }
230  }
231  else
232  {
233  strcpy(mErrorStr, "Failed to create UDP server socket.");
234  }
235  closesocket(tempSocket);
236  }
237 
238  return false;
239 }
240 
241 unsigned short CNetwork::GetUdpServerPort(SOCKET socket)
242 {
243  sockaddr_in recvAddr;
244  socklen_t addrLen = sizeof(recvAddr);
245  if (getsockname(socket, (struct sockaddr *)&recvAddr, &addrLen) == 0 &&
246  recvAddr.sin_family == AF_INET &&
247  addrLen == sizeof(recvAddr))
248  {
249  return ntohs(recvAddr.sin_port);
250  }
251  return 0;
252 }
253 
255 {
256  return GetUdpServerPort(mUDPSocket);
257 }
258 
260 {
261  return GetUdpServerPort(mUDPBroadcastSocket);
262 }
263 
264 // Receive a data packet. Data is stored in a local static buffer
265 // Returns number of bytes in received message, 0 on timeout or -1 if there is an error.
266 int CNetwork::Receive(char* rtDataBuff, int dataBufSize, bool header, int timeout, unsigned int *ipAddr)
267 {
268  int recieved = 0;
269  sockaddr_in source_addr;
270  socklen_t fromlen = sizeof(source_addr);
271 
272  fd_set readFDs, exceptFDs;
273  FD_ZERO(&readFDs);
274  FD_ZERO(&exceptFDs);
275 
276  if (mSocket != INVALID_SOCKET)
277  {
278  FD_SET(mSocket, &readFDs);
279  FD_SET(mSocket, &exceptFDs);
280  }
281  if (mUDPSocket != INVALID_SOCKET)
282  {
283  FD_SET(mUDPSocket, &readFDs);
284  FD_SET(mUDPSocket, &exceptFDs);
285  }
286  if (mUDPBroadcastSocket != INVALID_SOCKET)
287  {
288  FD_SET(mUDPBroadcastSocket, &readFDs);
289  FD_SET(mUDPBroadcastSocket, &exceptFDs);
290  }
291 
292  TIMEVAL* pTimeval;
293  TIMEVAL sTimeval;
294 
295  if (timeout < 0)
296  {
297  pTimeval = nullptr;
298  }
299  else
300  {
301  sTimeval.tv_sec = timeout / 1000000;
302  sTimeval.tv_usec = timeout % 1000000;
303  pTimeval = &sTimeval;
304  }
305 
306 #ifdef _WIN32
307  const int nfds = 0;
308 #else
309  const int nfds = std::max(mSocket, std::max(mUDPSocket, mUDPBroadcastSocket)) + 1;
310 #endif
311 
312  // Wait for activity on the TCP and UDP sockets.
313  int selectRes = select(nfds, &readFDs, nullptr, &exceptFDs, pTimeval);
314  if (selectRes == 0)
315  {
316  return 0; // Select timeout.
317  }
318  if (selectRes > 0)
319  {
320  if (FD_ISSET(mSocket, &exceptFDs))
321  {
322  // General socket error
323  FD_CLR(mSocket, &exceptFDs);
324  SetErrorString();
325  recieved = SOCKET_ERROR;
326  }
327  else if (FD_ISSET(mSocket, &readFDs))
328  {
329  recieved = recv(mSocket, rtDataBuff, header ? 8 : dataBufSize, 0);
330  FD_CLR(mSocket, &readFDs);
331  }
332  else if (FD_ISSET(mUDPSocket, &exceptFDs))
333  {
334  // General socket error
335  FD_CLR(mUDPSocket, &exceptFDs);
336  SetErrorString();
337  recieved = SOCKET_ERROR;
338  }
339  else if (FD_ISSET(mUDPSocket, &readFDs))
340  {
341  recieved = recvfrom(mUDPSocket, rtDataBuff, dataBufSize, 0, (sockaddr*)&source_addr, &fromlen);
342  FD_CLR(mUDPSocket, &readFDs);
343  }
344  else if (FD_ISSET(mUDPBroadcastSocket, &exceptFDs))
345  {
346  // General socket error
347  FD_CLR(mUDPBroadcastSocket, &exceptFDs);
348  SetErrorString();
349  recieved = SOCKET_ERROR;
350  }
351  else if (FD_ISSET(mUDPBroadcastSocket, &readFDs))
352  {
353  recieved = recvfrom(mUDPBroadcastSocket, rtDataBuff, dataBufSize, 0, (sockaddr*)&source_addr, &fromlen);
354  FD_CLR(mUDPBroadcastSocket, &readFDs);
355  if (ipAddr)
356  {
357  *ipAddr = source_addr.sin_addr.s_addr;
358  }
359  }
360  }
361  else
362  {
363  recieved = -1;
364  }
365 
366  if (recieved == -1)
367  {
368  SetErrorString();
369  }
370  return recieved;
371 }
372 
373 
374 bool CNetwork::Send(const char* sendBuf, int size)
375 {
376  int sent = 0;
377  int totalSent = 0;
378 
379  while (totalSent < size)
380  {
381  sent = send(mSocket, sendBuf + totalSent, size - totalSent, 0);
382  if (sent == SOCKET_ERROR)
383  {
384  SetErrorString();
385  return false;
386  }
387  totalSent += sent;
388  }
389  return true;
390 }
391 
392 
393 bool CNetwork::SendUDPBroadcast(const char* sendBuf, int size, short port, unsigned int filterAddr /* = 0 */)
394 {
395  bool broadCastSent = false;
396 
397  if (mUDPBroadcastSocket != INVALID_SOCKET)
398  {
399 #ifdef _WIN32
400  IP_ADAPTER_INFO* ifap = nullptr;
401  IP_ADAPTER_INFO* ifa = nullptr;
402  ULONG ulLen = 0;
403  DWORD erradapt;
404 
405  // Find all network interfaces.
406  erradapt = ::GetAdaptersInfo(ifap, &ulLen);
407  if (erradapt == ERROR_BUFFER_OVERFLOW)
408  {
409  ifap = (IP_ADAPTER_INFO*)malloc(ulLen);
410  erradapt = ::GetAdaptersInfo(ifap, &ulLen);
411  }
412 
413  if (erradapt == ERROR_SUCCESS)
414  {
415  sockaddr_in recvAddr;
416  recvAddr.sin_family = AF_INET;
417  recvAddr.sin_port = htons(port);
418  recvAddr.sin_addr.s_addr = 0xffffffff;
419 
420  // Send broadcast on all Ethernet interfaces.
421  ifa = ifap;
422  while (ifa)
423  {
424  if (ifa->Type == MIB_IF_TYPE_ETHERNET)
425  {
426  unsigned int nIPaddr;
427  unsigned int nIPmask;
428 
429  if (inet_pton(AF_INET, ifa->IpAddressList.IpAddress.String, &nIPaddr) == 0 ||
430  inet_pton(AF_INET, ifa->IpAddressList.IpMask.String, &nIPmask) == 0)
431  {
432  return false;
433  }
434  recvAddr.sin_addr.s_addr = nIPaddr | (~nIPmask);
435  if (recvAddr.sin_addr.s_addr != (filterAddr | (~nIPmask)))
436  {
437  if (sendto(mUDPBroadcastSocket, sendBuf, size, 0, (sockaddr*)&recvAddr, sizeof(recvAddr)) == size)
438  {
439  broadCastSent = true;
440  }
441  }
442  }
443  ifa = ifa->Next;
444  }
445  }
446  free(ifap);
447 #else
448  // Find all network interfaces.
449  struct ifaddrs* ifap = nullptr;
450  if (getifaddrs(&ifap) == 0)
451  {
452  sockaddr_in recvAddr;
453  recvAddr.sin_family = AF_INET;
454  recvAddr.sin_port = htons(port);
455  recvAddr.sin_addr.s_addr = 0xffffffff;
456 
457  // Send broadcast on all Ethernet interfaces.
458  auto* ifa = ifap;
459  while (ifa)
460  {
461  if (ifa->ifa_addr->sa_family == AF_INET)
462  {
463  auto* sa = (struct sockaddr_in *) ifa->ifa_addr;
464  auto ipAddr = sa->sin_addr.s_addr;
465 
466  auto* saMask = (struct sockaddr_in *) ifa->ifa_netmask;
467  auto ipMask = saMask->sin_addr.s_addr;
468 
469  recvAddr.sin_addr.s_addr = ipAddr | (~ipMask);
470  if (recvAddr.sin_addr.s_addr != (filterAddr | (~ipMask)))
471  {
472  if (sendto(mUDPBroadcastSocket, sendBuf, size, 0, (sockaddr*)&recvAddr, sizeof(recvAddr)) == size)
473  {
474  broadCastSent = true;
475  }
476  }
477  }
478  ifa = ifa->ifa_next;
479  }
480  }
481  freeifaddrs(ifap);
482 #endif
483  }
484 
485  return broadCastSent;
486 } // SendUDPBroadcast
487 
488 
489 void CNetwork::SetErrorString()
490 {
491 #ifdef _WIN32
492  char* error = nullptr;
493  mLastError = GetLastError();
494  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, mLastError, 0, reinterpret_cast<LPTSTR>(&error), 0, nullptr);
495  sprintf(mErrorStr, "%s", error);
496  LocalFree(error);
497 #else
498  mLastError = errno;
499  char* error = strerror(mLastError);
500  if (error != nullptr)
501  {
502  sprintf(mErrorStr, "%s", error);
503  }
504 #endif
505 }
506 
507 
509 {
510  return mErrorStr;
511 }
512 
513 
515 {
516  return mLastError;
517 }
518 
519 
520 bool CNetwork::IsLocalAddress(unsigned int nAddr) const
521 {
522 #ifdef _WIN32
523  IP_ADAPTER_INFO* pAdptInfo = nullptr;
524  IP_ADAPTER_INFO* pNextAd = nullptr;
525  DWORD erradapt;
526  ULONG ulLen = 0;
527 
528  // Find all network interfaces.
529  erradapt = ::GetAdaptersInfo(pAdptInfo, &ulLen);
530  if (erradapt == ERROR_BUFFER_OVERFLOW)
531  {
532  pAdptInfo = (IP_ADAPTER_INFO*)malloc(ulLen);
533  erradapt = ::GetAdaptersInfo(pAdptInfo, &ulLen);
534  }
535 
536  if (erradapt == ERROR_SUCCESS)
537  {
538  pNextAd = pAdptInfo;
539  while(pNextAd)
540  {
541  if (pNextAd->Type == MIB_IF_TYPE_ETHERNET)
542  {
543  // Check if it's a response from a local interface.
544  unsigned int addr;
545  if (inet_pton(AF_INET, pNextAd->IpAddressList.IpAddress.String, &addr) != 0)
546  {
547  return addr == nAddr;
548  }
549  }
550  pNextAd = pNextAd->Next;
551  }
552  }
553  free(pAdptInfo);
554 #else
555  struct ifaddrs* pAdptInfo = nullptr;
556  struct ifaddrs* pNextAd = nullptr;
557  if (getifaddrs(&pAdptInfo) == 0)
558  {
559  pNextAd = pAdptInfo;
560  while (pNextAd)
561  {
562  if (pNextAd->ifa_addr->sa_family == AF_INET)
563  {
564  struct sockaddr_in* pNextAd_in = (struct sockaddr_in *)pNextAd->ifa_addr;
565  if (pNextAd_in->sin_addr.s_addr == nAddr)
566  {
567  return true;
568  }
569  }
570  pNextAd = pNextAd->ifa_next;
571  }
572  }
573  freeifaddrs(pAdptInfo);
574 #endif
575  return false;
576 }
#define SD_SEND
Definition: Network.cpp:41
int Receive(char *rtDataBuff, int nDataBufSize, bool bHeader, int nTimeout, unsigned int *ipAddr=nullptr)
Definition: Network.cpp:266
unsigned short GetUdpServerPort()
Definition: Network.cpp:254
bool CreateUDPSocket(unsigned short &nUDPPort, bool bBroadcast=false)
Definition: Network.cpp:176
void Disconnect()
Definition: Network.cpp:157
#define closesocket
Definition: Network.cpp:38
~CNetwork()
Definition: Network.cpp:57
int GetError() const
Definition: Network.cpp:514
#define TIMEVAL
Definition: Network.cpp:37
unsigned short GetUdpBroadcastServerPort()
Definition: Network.cpp:259
#define SOCKET_ERROR
Definition: Network.cpp:35
bool Send(const char *pSendBuf, int nSize)
Definition: Network.cpp:374
#define INVALID_SOCKET
Definition: Network.h:8
char * GetErrorString()
Definition: Network.cpp:508
#define SOCKADDR
Definition: Network.cpp:40
bool SendUDPBroadcast(const char *pSendBuf, int nSize, short nPort, unsigned int nFilterAddr=0)
Definition: Network.cpp:393
bool Connected() const
Definition: Network.cpp:171
CNetwork()
Definition: Network.cpp:45
bool Connect(const char *pServerAddr, unsigned short nPort)
Definition: Network.cpp:87
bool IsLocalAddress(unsigned int nAddr) const
Definition: Network.cpp:520
#define SOCKET
Definition: Network.h:9
#define ioctlsocket
Definition: Network.cpp:39