Belle II Software development
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
24using namespace Belle2;
25
26unsigned 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
44UDPSocket::UDPSocket()
45{
46 m_addr.sin_family = AF_INET;
47 m_addr.sin_addr.s_addr = INADDR_ANY;
48}
49
50UDPSocket::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
60UDPSocket::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")); // TODO which throw is the right one?
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
94UDPSocket::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
115int 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")); TODO which throw is the right one?
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
145int 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
155size_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
180size_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
202const std::string UDPSocket::getHostName() const
203{
204 return inet_ntoa(m_addr.sin_addr);
205}
206
207unsigned int UDPSocket::getAddress() const
208{
209 return m_addr.sin_addr.s_addr;
210}
211
212unsigned int UDPSocket::getPort() const
213{
214 return ntohs(m_addr.sin_port);
215}
216
217const std::string UDPSocket::getRemoteHostName() const
218{
219 return inet_ntoa(m_remote_addr.sin_addr);
220}
221
222unsigned int UDPSocket::getRemoteAddress() const
223{
224 return m_remote_addr.sin_addr.s_addr;
225}
226
227unsigned int UDPSocket::getRemotePort() const
228{
229 return ntohs(m_remote_addr.sin_port);
230}
Abstract base class for different kinds of events.