Belle II Software  release-08-01-10
UDPSocket.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include "daq/slc/system/UDPSocket.h"
9 
10 #include <daq/slc/base/IOException.h>
11 
12 #include <cstdio>
13 #include <cstring>
14 
15 #include <unistd.h>
16 #include <errno.h>
17 
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #include <arpa/inet.h>
22 #include <ifaddrs.h>
23 
24 using namespace Belle2;
25 
26 unsigned int UDPSocket::findSubnet(unsigned int addr)
27 {
28  struct ifaddrs* ifa_list;
29  struct ifaddrs* ifa;
30  char addrstr[256], netmaskstr[256];
31  if (getifaddrs(&ifa_list) != 0) return 0;
32  for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
33  memset(addrstr, 0, sizeof(addrstr));
34  memset(netmaskstr, 0, sizeof(netmaskstr));
35  if (ifa->ifa_addr->sa_family == AF_INET &&
36  addr == ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr) {
37  addr |= ~(((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr);
38  }
39  }
40  freeifaddrs(ifa_list);
41  return addr;
42 }
43 
44 UDPSocket::UDPSocket()
45 {
46  m_addr.sin_family = AF_INET;
47  m_addr.sin_addr.s_addr = INADDR_ANY;
48 }
49 
50 UDPSocket::UDPSocket(unsigned int port)
51 {
52  m_addr.sin_port = htons(port);
53  m_addr.sin_family = AF_INET;
54  m_addr.sin_addr.s_addr = INADDR_ANY;
55  if ((m_fd = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
56  throw (IOException("Failed to create socket"));
57  }
58 }
59 
60 UDPSocket::UDPSocket(unsigned int port,
61  const std::string& hostname,
62  bool boardcast)
63 {
64  m_addr.sin_port = htons(port);
65  m_addr.sin_family = AF_INET;
66  if (hostname.size() > 0) {
67  struct hostent* host = NULL;
68  host = gethostbyname(hostname.c_str());
69  if (host == NULL) {
70  unsigned long addr = inet_addr(hostname.c_str());
71  if ((signed long) addr < 0) {
72  throw (std::exception());
73  throw (IOException("Wrong host name or ip"));
74  } else {
75  host = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
76  }
77  }
78  m_addr.sin_addr.s_addr = (*(unsigned long*) host->h_addr_list[0]);
79  }
80  if ((m_fd = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
81  throw (IOException("Failed to create socket"));
82  }
83  if (boardcast) {
84  unsigned int addr = m_addr.sin_addr.s_addr;
85  if ((addr = findSubnet(addr)) > 0) {
86  m_addr.sin_addr.s_addr = addr;
87  }
88  int yes = 1;
89  setsockopt(m_fd, SOL_SOCKET, SO_BROADCAST,
90  (char*)&yes, sizeof(yes));
91  }
92 }
93 
94 UDPSocket::UDPSocket(unsigned int port,
95  unsigned int addr,
96  bool boardcast)
97 {
98  m_addr.sin_port = htons(port);
99  m_addr.sin_family = AF_INET;
100  m_addr.sin_addr.s_addr = addr;
101  if ((m_fd = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
102  throw (IOException("Failed to create socket"));
103  }
104  if (boardcast) {
105  addr = m_addr.sin_addr.s_addr;
106  if ((addr = findSubnet(addr)) > 0) {
107  m_addr.sin_addr.s_addr = addr;
108  }
109  int yes = 1;
110  setsockopt(m_fd, SOL_SOCKET, SO_BROADCAST,
111  (char*)&yes, sizeof(yes));
112  }
113 }
114 
115 int UDPSocket::bind(unsigned int port,
116  const std::string& hostname, bool broadcast)
117 {
118  if (m_fd <= 0 && (m_fd = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
119  throw (IOException("Failed to create socket"));
120  }
121  m_addr.sin_port = htons(port);
122  if (hostname.size() > 0) {
123  struct hostent* host = NULL;
124  host = gethostbyname(hostname.c_str());
125  if (host == NULL) {
126  unsigned long addr = inet_addr(hostname.c_str());
127  if ((signed long) addr < 0) {
128  throw (std::exception());
129  throw (IOException("Wrong host name or ip"));
130  } else {
131  host = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
132  }
133  }
134  m_addr.sin_addr.s_addr = (*(unsigned long*) host->h_addr_list[0]);
135  if (broadcast) {
136  unsigned int addr = m_addr.sin_addr.s_addr;
137  if ((addr = findSubnet(addr)) > 0) {
138  m_addr.sin_addr.s_addr = addr;
139  }
140  }
141  }
142  return bind();
143 }
144 
145 int UDPSocket::bind()
146 {
147  if (::bind(m_fd, (struct sockaddr*)&m_addr, sizeof(m_addr)) < 0) {
148  close();
149  throw (IOException("Failed to bind socket port=%d",
150  ntohs(m_addr.sin_port)));
151  }
152  return m_fd;
153 }
154 
155 size_t UDPSocket::write(const void* buf, size_t count)
156 {
157  size_t c = 0;
158  while (c < count) {
159  errno = 0;
160  int ret = sendto(m_fd, ((unsigned char*)buf + c),
161  (count - c), 0,
162  (struct sockaddr*)&m_addr, sizeof(m_addr));
163  if (ret <= 0) {
164  switch (errno) {
165  case EINTR: continue;
166  case ENETUNREACH:
167  case EHOSTUNREACH:
168  case ETIMEDOUT:
169  usleep(500);
170  continue;
171  default:
172  throw (IOException("Error while writing"));
173  }
174  }
175  c += ret;
176  }
177  return c;
178 }
179 
180 size_t UDPSocket::read(void* buf, size_t count)
181 {
182  size_t c = 0;
183  socklen_t addrlen = sizeof(m_remote_addr);
184  while (true) {
185  errno = 0;
186  int ret = recvfrom(m_fd, ((unsigned char*)buf + c), (count - c), 0,
187  (struct sockaddr*)&m_remote_addr, &addrlen);
188  if (ret <= 0) {
189  switch (errno) {
190  case EINTR: continue;
191  case EAGAIN: continue;
192  default:
193  throw (IOException("Error while reading."));
194  }
195  }
196  c += ret;
197  break;
198  }
199  return c;
200 }
201 
202 const std::string UDPSocket::getHostName() const
203 {
204  return inet_ntoa(m_addr.sin_addr);
205 }
206 
207 unsigned int UDPSocket::getAddress() const
208 {
209  return m_addr.sin_addr.s_addr;
210 }
211 
212 unsigned int UDPSocket::getPort() const
213 {
214  return ntohs(m_addr.sin_port);
215 }
216 
217 const std::string UDPSocket::getRemoteHostName() const
218 {
219  return inet_ntoa(m_remote_addr.sin_addr);
220 }
221 
222 unsigned int UDPSocket::getRemoteAddress() const
223 {
224  return m_remote_addr.sin_addr.s_addr;
225 }
226 
227 unsigned int UDPSocket::getRemotePort() const
228 {
229  return ntohs(m_remote_addr.sin_port);
230 }
Abstract base class for different kinds of events.