Belle II Software  release-05-01-25
b2_socket.cc
1 /* b2_socket.c */
2 
3 
4 #include <stdio.h>
5 #include <string.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <netinet/in.h>
9 #include <netdb.h>
10 
11 #include "daq/roisend/util.h"
12 #include "daq/roisend/b2_socket.h"
13 
14 
15 int
16 b2_timed_blocking_io(const int sd, const int timeout /* secs */)
17 {
18  int ret;
19 
20 
21  if (timeout > 0) {
22  struct timeval tv;
23 
24  tv.tv_sec = timeout;
25  tv.tv_usec = 0;
26  ret = setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
27  if (ret == -1) {
28  ERROR(setsockopt);
29  return -1;
30  }
31 
32  tv.tv_sec = timeout;
33  tv.tv_usec = 0;
34  ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
35  if (ret == -1) {
36  ERROR(setsockopt);
37  return -1;
38  }
39  } else if (timeout == 0) {
40  ret = fcntl(sd, F_SETFL, O_NDELAY);
41  if (ret == -1) {
42  ERROR(fcntl);
43  return -1;
44  }
45  } else if (timeout < 0) {
46  ret = fcntl(sd, F_GETFL, O_NDELAY);
47  if (ret == -1) {
48  ERROR(fcntl);
49  return -1;
50  }
51  ret &= ~O_NDELAY;
52  ret = fcntl(sd, F_SETFL, ret);
53  if (ret == -1) {
54  ERROR(fcntl);
55  return -1;
56  }
57  }
58 
59 
60  return 0;
61 }
62 
63 
64 int
65 b2_build_sockaddr_in(const char* hostname, const unsigned short port, struct sockaddr_in* in)
66 {
67  memset(in, 0, sizeof(struct sockaddr_in));
68 
69  in->sin_family = AF_INET;
70  {
71  struct hostent* hoste;
72  hoste = gethostbyname(hostname);
73  if (!hoste) {
74  ERROR(gethostbyname);
75  return -1;
76  }
77  in->sin_addr = *(struct in_addr*)(hoste->h_addr);
78  }
79  in->sin_port = htons(port);
80 
81 
82  return 0;
83 }
84 
85 
86 static int
87 b2_create_tcp_socket(void)
88 {
89  int sd, ret, one = 1;
90 
91 
92  sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
93  if (sd == -1) {
94  ERROR(socket);
95  return -1;
96  }
97 
98 #if 0
99  ret = b2_timed_blocking_io(sd, 0);
100  if (ret == -1) {
101  ERROR(b2_timed_blocking_io);
102  return -1;
103  }
104 #endif
105 
106  ret = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(int));
107  if (ret == -1) {
108  ERROR(setsockopt);
109  return -1;
110  }
111 
112 
113  return sd;
114 }
115 
116 
117 int /* returns socket descriptor */
118 b2_create_accept_socket(const unsigned short port) /* in reality DOES NOT accept */
119 {
120  int sd, ret;
121  struct sockaddr_in in;
122 
123 
124  sd = b2_create_tcp_socket();
125  if (sd < 0) {
126  ERROR(b2_create_tcp_socket);
127  return -1;
128  }
129 
130  ret = b2_build_sockaddr_in("0.0.0.0", port, &in);
131  if (ret == -1) {
132  ERROR(b2_build_sockaddr_in);
133  return -1;
134  }
135 
136  ret = bind(sd, (const struct sockaddr*)&in, sizeof(struct sockaddr_in));
137  if (ret == -1) {
138  ERROR(bind);
139  return -1;
140  }
141 
142  ret = listen(sd, 1);
143  if (ret == -1) {
144  ERROR(listen);
145  return -1;
146  }
147 
148 
149  return sd;
150 }
151 
152 
153 int /* returns socket descriptor */
154 b2_create_connect_socket(const char* hostname, const unsigned short port)
155 {
156  int sd, ret;
157  struct sockaddr_in in;
158 
159 
160  sd = b2_create_tcp_socket();
161  if (sd < 0) {
162  ERROR(b2_create_tcp_socket);
163  return -1;
164  }
165 
166  ret = b2_build_sockaddr_in(hostname, port, &in);
167  if (ret == -1) {
168  ERROR(b2_build_sockaddr_in);
169  return -1;
170  }
171 
172  ret = connect(sd, (const struct sockaddr*)&in, sizeof(struct sockaddr_in));
173  if (ret == -1 && errno != EINPROGRESS) {
174  ERROR(connect);
175  return -1;
176  }
177 
178 
179  return sd;
180 }
181 
182 
183 int
184 b2_send(const int sd, const void* buf, const size_t size)
185 {
186  unsigned char* ptr = (unsigned char*)buf;
187  size_t n_bytes_remained = size;
188 
189 
190  for (;;) {
191  int ret, n_bytes_send;
192 
193  ret = send(sd, ptr, n_bytes_remained, 0);
194  if (ret == -1 && errno != EINTR) {
195  ERROR(send);
196  return -1;
197  }
198  if (ret == -1 && errno == EINTR) {
199  fprintf(stderr, "%s:%d: recv(): Packet send timed out\n", __FILE__, __LINE__);
200  return -1;
201  }
202  if (ret == 0) {
203  fprintf(stderr, "%s:%d: send(): Connection closed\n", __FILE__, __LINE__);
204  return -1;
205  }
206 
207  n_bytes_send = ret;
208  ptr += n_bytes_send;
209 
210  if (n_bytes_remained < size_t(n_bytes_send))
211  /* overrun: internal error */
212  {
213  fprintf(stderr, "%s:%d: send(): Internal error\n", __FILE__, __LINE__);
214  return -1;
215  }
216  n_bytes_remained -= n_bytes_send;
217 
218  if (n_bytes_remained == 0)
219  /* fully sendout */
220  {
221  break;
222  }
223  }
224 
225 
226  return size;
227 }
228 
229 
230 int
231 b2_recv(const int sd, void* buf, const size_t size)
232 {
233  unsigned char* ptr = (unsigned char*)buf;
234  size_t n_bytes_remained = size;
235 
236 
237  for (;;) {
238  int ret, n_bytes_recv;
239 
240  ret = recv(sd, ptr, n_bytes_remained, 0);
241  if (ret == -1 && (errno != EINTR && errno != EWOULDBLOCK)) {
242  ERROR(recv);
243  return -1;
244  }
245  if (ret == -1 && (errno == EINTR || errno == EWOULDBLOCK)) {
246  fprintf(stderr, "%s:%d: recv(): Packet receive timed out\n", __FILE__, __LINE__);
247  return -1;
248  }
249  if (ret == 0) {
250  fprintf(stderr, "%s:%d: recv(): Connection closed\n", __FILE__, __LINE__);
251  return -1;
252  }
253 
254  n_bytes_recv = ret;
255  ptr += n_bytes_recv;
256  if (n_bytes_remained < size_t(n_bytes_recv))
257  /* overrun: internal error */
258  {
259  fprintf(stderr, "%s:%d: recv(): Internal error\n", __FILE__, __LINE__);
260  return -1;
261  }
262  n_bytes_remained -= n_bytes_recv;
263 
264  if (n_bytes_remained == 0)
265  /* fully readout */
266  {
267  break;
268  }
269  }
270 
271 
272  return size;
273 }
274 
275