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