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