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