tdaq-develop-2025-02-12
NetworkDevice.cc
1 #include "otsdaq/NetworkUtilities/NetworkDevice.h"
2 #include "otsdaq/Macros/CoutMacros.h"
3 #include "otsdaq/MessageFacility/MessageFacility.h"
4 
5 #include <iostream>
6 #include <sstream>
7 
8 #include <assert.h>
9 
10 #include <arpa/inet.h>
11 #include <unistd.h>
12 // #include <sys/socket.h>
13 #include <ifaddrs.h>
14 #include <netdb.h>
15 #include <sys/ioctl.h>
16 #if defined(SIOCGIFHWADDR)
17 #include <net/if.h>
18 #else
19 #include <net/if_dl.h>
20 #endif
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 
25 using namespace ots;
26 
27 //==============================================================================
28 NetworkDevice::NetworkDevice(std::string IPAddress, unsigned int IPPort)
29  : communicationInterface_(NULL)
30 {
31  // network stuff
32  deviceAddress_.sin_family = AF_INET; // use IPv4 host byte order
33  deviceAddress_.sin_port = htons(IPPort); // short, network byte order
34 
35  if(inet_aton(IPAddress.c_str(), &deviceAddress_.sin_addr) == 0)
36  {
37  __COUT__ << "FATAL: Invalid IP address " << IPAddress << std::endl;
38  // FIXME substitute with try catch solution !!
39  __SS__ << "Error!" << __E__;
40  __SS_THROW__;
41  }
42 
43  memset(&(deviceAddress_.sin_zero), '\0', 8); // zero the rest of the struct
44 }
45 
46 //==============================================================================
47 NetworkDevice::~NetworkDevice(void)
48 {
49  for(std::map<int, int>::iterator it = openSockets_.begin(); it != openSockets_.end();
50  it++)
51  {
52  __COUT__ << "Closing socket for port " << it->second << std::endl;
53  close(it->first);
54  }
55  openSockets_.clear();
56 }
57 
58 //==============================================================================
59 int NetworkDevice::initSocket(std::string socketPort)
60 {
61  struct addrinfo hints;
62 
63  struct addrinfo* res;
64  int status = 0;
65  int socketOut = -1;
66 
67  // first, load up address structs with getaddrinfo():
68  memset(&hints, 0, sizeof hints);
69  hints.ai_family = AF_INET; // use IPv4 for OtsUDPHardware
70  hints.ai_socktype = SOCK_DGRAM; // SOCK_DGRAM
71  hints.ai_flags = AI_PASSIVE; // fill in my IP for me
72 
73  bool socketInitialized = false;
74  int fromPort = FirstSocketPort;
75  int toPort = LastSocketPort;
76 
77  if(socketPort != "")
78  fromPort = toPort = strtol(socketPort.c_str(), 0, 10);
79 
80  std::stringstream port;
81 
82  for(int p = fromPort; p <= toPort && !socketInitialized; p++)
83  {
84  port.str("");
85  port << p;
86  __COUT__ << "Binding port: " << port.str() << std::endl;
87 
88  if((status = getaddrinfo(NULL, port.str().c_str(), &hints, &res)) != 0)
89  {
90  __COUT__ << "Getaddrinfo error status: " << status << std::endl;
91  continue;
92  }
93 
94  // make a socket:
95  socketOut = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
96 
97  // bind it to the port we passed in to getaddrinfo():
98  if(bind(socketOut, res->ai_addr, res->ai_addrlen) == -1)
99  {
100  __COUT_ERR__ << "Failed bind for port: " << port.str();
101  socketOut = -1;
102  exit(0);
103  }
104  else
105  {
106  char yes = '1';
107  setsockopt(socketOut, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
108  socketInitialized = true;
109  openSockets_[socketOut] = p;
110  __COUT__ << "Socket Number: " << socketOut << " for port: " << p
111  << " initialized." << std::endl;
112  }
113 
114  freeaddrinfo(res); // free the linked-list
115  }
116 
117  return socketOut;
118 }
119 
120 //==============================================================================
121 int NetworkDevice::initSocket(unsigned int socketPort)
122 {
123  std::stringstream socket("");
124  if(socketPort != 0)
125  socket << socketPort;
126  return initSocket(socket.str());
127 }
128 
129 //==============================================================================
130 int NetworkDevice::send(int socketDescriptor, const std::string& buffer)
131 {
132  if(sendto(socketDescriptor,
133  buffer.c_str(),
134  buffer.size(),
135  0,
136  (struct sockaddr*)&(deviceAddress_),
137  sizeof(deviceAddress_)) < (int)(buffer.size()))
138  {
139  __COUT__ << "Error writing buffer" << std::endl;
140  return -1;
141  }
142  return 0;
143 }
144 
145 //==============================================================================
146 int NetworkDevice::receive(int socketDescriptor, std::string& buffer)
147 {
148  struct timeval tv;
149  tv.tv_sec = 2;
150  tv.tv_usec = 0; // set timeout period for select()
151  fd_set fileDescriptor; // setup set for select()
152  FD_ZERO(&fileDescriptor);
153  FD_SET(socketDescriptor, &fileDescriptor);
154  select(socketDescriptor + 1, &fileDescriptor, 0, 0, &tv);
155 
156  if(FD_ISSET(socketDescriptor, &fileDescriptor))
157  {
158  std::string bufferS;
159  struct sockaddr_in tmpAddress;
160  socklen_t addressLength = sizeof(tmpAddress);
161  int nOfBytes;
162  char readBuffer[maxSocketSize];
163  if((nOfBytes = recvfrom(socketDescriptor,
164  readBuffer,
165  maxSocketSize,
166  0,
167  (struct sockaddr*)&tmpAddress,
168  &addressLength)) == -1)
169  {
170  __COUT__ << "Error reading buffer" << std::endl;
171  return -1;
172  }
173  buffer.resize(nOfBytes);
174  for(int i = 0; i < nOfBytes; i++)
175  buffer[i] = readBuffer[i];
176  }
177  else
178  {
179  __COUT__ << "Network device unresponsive. Read request timed out." << std::endl;
180  return -1;
181  }
182 
183  return 0;
184 }
185 
186 //==============================================================================
187 int NetworkDevice::listen(int socketDescriptor, std::string& buffer)
188 {
189  __COUT__ << "LISTENING!!!!!" << std::endl;
190  struct timeval tv;
191  tv.tv_sec = 5;
192  tv.tv_usec = 0; // set timeout period for select()
193  fd_set fileDescriptor; // setup set for select()
194  FD_ZERO(&fileDescriptor);
195  FD_SET(socketDescriptor, &fileDescriptor);
196  select(socketDescriptor + 1, &fileDescriptor, 0, 0, &tv);
197 
198  if(FD_ISSET(socketDescriptor, &fileDescriptor))
199  {
200  std::string bufferS;
201  struct sockaddr_in tmpAddress;
202  socklen_t addressLength = sizeof(tmpAddress);
203  int nOfBytes;
204  char readBuffer[maxSocketSize];
205  if((nOfBytes = recvfrom(socketDescriptor,
206  readBuffer,
207  maxSocketSize,
208  0,
209  (struct sockaddr*)&tmpAddress,
210  &addressLength)) == -1)
211  {
212  __COUT__ << "Error reading buffer" << std::endl;
213  return -1;
214  }
215  buffer.resize(nOfBytes);
216  for(int i = 0; i < nOfBytes; i++)
217  buffer[i] = readBuffer[i];
218  }
219  else
220  {
221  __COUT__ << "Timed out" << std::endl;
222  return -1;
223  }
224 
225  return 0;
226 }
227 
228 //==============================================================================
229 int NetworkDevice::ping(int socketDescriptor)
230 {
231  std::string pingMsg(1, 0);
232  if(send(socketDescriptor, pingMsg) == -1)
233  {
234  __COUT__ << "Can't send ping Message!" << std::endl;
235  return -1;
236  }
237 
238  std::string bufferS;
239  if(receive(socketDescriptor, bufferS) == -1)
240  {
241  __COUT__ << "Failed to ping device" << std::endl;
242  return -1;
243  }
244  /*
245  struct timeval tv;
246  tv.tv_sec = 0;
247  tv.tv_usec = 100000; //set timeout period for select()
248  fd_set fileDescriptor; //setup set for select()
249  FD_ZERO(&fileDescriptor);
250  FD_SET(socketDescriptor,&fileDescriptor);
251  select(socketDescriptor+1, &fileDescriptor, 0, 0, &tv);
252 
253  if(FD_ISSET(socketDescriptor,&fileDescriptor))
254  {
255  std::string bufferS;
256  if(receive(socketDescriptor,bufferS) == -1)
257  {
258  __COUT__ << "Failed to ping device"<< std::endl;
259  return -1;
260  }
261  }
262  else
263  {
264  __COUT__ << "Network device unresponsive. Ping request timed out." <<
265  std::endl; return -1;
266  }
267  */
268  return 0;
269 }
270 
271 //==============================================================================
272 std::string NetworkDevice::getFullIPAddress(std::string partialIpAddress)
273 {
274  __COUT__ << "partial IP: " << partialIpAddress << std::endl;
275  if(getInterface(partialIpAddress))
276  {
277  char *p, addr[32];
278  p = inet_ntoa(
279  ((struct sockaddr_in*)(communicationInterface_->ifa_addr))->sin_addr);
280  strncpy(addr, p, sizeof(addr) - 1);
281  addr[sizeof(addr) - 1] = '\0';
282 
283  return addr;
284  }
285  else
286  {
287  __COUT__ << "FIXME substitute with try catch solution !!\n\nFailed to locate "
288  "network interface matching partial IP address"
289  << std::endl;
290  // FIXME substitute with try catch solution !!
291  __SS__ << "Error!" << __E__;
292  __SS_THROW__;
293 
294  //__COUT__ << "Failed to locate network interface matching partial IP address" <<
295  // std::endl;
296  return "";
297  }
298 }
299 
300 //==============================================================================
301 std::string NetworkDevice::getInterfaceName(std::string ipAddress)
302 {
303  __COUT__ << "IP: " << ipAddress << std::endl;
304  if(getInterface(ipAddress))
305  return communicationInterface_->ifa_name;
306  else
307  {
308  // FIXME substitute with try catch solution !!
309  __COUT__ << "FIXME substitute with try catch solution !!\n\nFailed to get "
310  "interface name!"
311  << std::endl;
312  __SS__ << "Error!" << __E__;
313  __SS_THROW__;
314 
315  __COUT__ << "Failed to get interface name for IP address" << std::endl;
316  return "";
317  }
318 }
319 
320 //==============================================================================
321 int NetworkDevice::getInterface(std::string ipAddress)
322 {
323  int family, s;
324  char host[NI_MAXHOST];
325 
326  __COUT__ << "IP2: " << ipAddress << std::endl;
327  if(communicationInterface_ != 0)
328  {
329  s = getnameinfo(communicationInterface_->ifa_addr,
330 
331  (communicationInterface_->ifa_addr->sa_family == AF_INET)
332  ? sizeof(struct sockaddr_in)
333  :
334 
335  sizeof(struct sockaddr_in6),
336  host,
337  NI_MAXHOST,
338  NULL,
339  0,
340  NI_NUMERICHOST);
341 
342  if(s != 0)
343  {
344  __COUT__ << "getnameinfo() failed: " << gai_strerror(s) << std::endl;
345  // FIXME substitute with try catch solution !!
346  __COUT__ << "FIXME substitute with try catch solution !!\n\nFailed to get "
347  "name info!"
348  << std::endl;
349  __SS__ << "Error!" << __E__;
350  __SS_THROW__;
351  }
352 
353  if(std::string(host).find(ipAddress) != std::string::npos)
354  return true;
355  else
356  {
357  delete communicationInterface_;
358  communicationInterface_ = NULL;
359  }
360  }
361 
362  struct ifaddrs* ifaddr;
363 
364  struct ifaddrs* ifa;
365 
366  if(getifaddrs(&ifaddr) == -1)
367  {
368  perror("getifaddrs");
369  // FIXME substitute with try catch solution !!
370  __COUT__
371  << "FIXME substitute with try catch solution !!\n\nFailed to get ifaddress!"
372  << std::endl;
373  __SS__ << "Error!" << __E__;
374  __SS_THROW__;
375  }
376 
377  /* Walk through linked list, maintaining head pointer so we
378  can free list later */
379 
380  bool found = false;
381 
382  for(ifa = ifaddr; ifa != NULL && !found; ifa = ifa->ifa_next)
383  {
384  if(ifa->ifa_addr == NULL)
385  continue;
386 
387  family = ifa->ifa_addr->sa_family;
388 
389  /* For an AF_INET* interface address, display the address */
390 
391  if(family == AF_INET || family == AF_INET6)
392  {
393  s = getnameinfo(ifa->ifa_addr,
394 
395  (family == AF_INET) ? sizeof(struct sockaddr_in) :
396 
397  sizeof(struct sockaddr_in6),
398  host,
399  NI_MAXHOST,
400  NULL,
401  0,
402  NI_NUMERICHOST);
403 
404  if(s != 0)
405  {
406  __COUT__ << "getnameinfo() failed: " << gai_strerror(s) << std::endl;
407  // FIXME substitute with try catch solution !!
408  __COUT__ << "FIXME substitute with try catch solution !!\n\nFailed to "
409  "get getnameinfo!"
410  << std::endl;
411  __SS__ << "Error!" << __E__;
412  __SS_THROW__;
413  }
414 
415  if(std::string(host).find(ipAddress) != std::string::npos)
416  {
417  communicationInterface_ = new struct ifaddrs(*ifa);
418  found = true;
419  }
420  }
421  }
422 
423  freeifaddrs(ifaddr);
424 
425  return found;
426 }
427 
428 //==============================================================================
429 std::string NetworkDevice::getMacAddress(std::string interfaceName)
430 {
431  std::string macAddress(6, '0');
432 #if defined(SIOCGIFHWADDR)
433 
434  struct ifreq ifr;
435  int sock;
436 
437  sock = socket(PF_INET, SOCK_STREAM, 0);
438 
439  if(-1 == sock)
440  {
441  perror("socket() ");
442  return "";
443  }
444 
445  strncpy(ifr.ifr_name, interfaceName.c_str(), sizeof(ifr.ifr_name) - 1);
446  ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
447 
448  if(-1 == ioctl(sock, SIOCGIFHWADDR, &ifr))
449  {
450  perror("ioctl(SIOCGIFHWADDR) ");
451  return "";
452  }
453  for(int j = 0; j < 6; j++)
454  macAddress[j] = ifr.ifr_hwaddr.sa_data[j];
455 #else
456 
457  char mac[6];
458  ifaddrs* iflist;
459  bool found = false;
460  if(getifaddrs(&iflist) == 0)
461  {
462  for(ifaddrs* cur = iflist; cur; cur = cur->ifa_next)
463  {
464  if((cur->ifa_addr->sa_family == AF_LINK) &&
465  (strcmp(cur->ifa_name, interfaceName.c_str()) == 0) && cur->ifa_addr)
466  {
467  sockaddr_dl* sdl = (sockaddr_dl*)cur->ifa_addr;
468  memcpy(mac, LLADDR(sdl), sdl->sdl_alen);
469  found = true;
470  break;
471  }
472  }
473 
474  freeifaddrs(iflist);
475  }
476  for(int j = 0; j < 6; j++)
477  macAddress[j] = mac[j];
478 #endif
479 
480  return macAddress;
481 }
std::map< int, int > openSockets_
socket,socket port
Definition: NetworkDevice.h:37