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