Belle II Software development
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
22int
23b2_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
71int
72b2_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
93static int
94b2_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
124int /* returns socket descriptor */
125b2_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
160int /* returns socket descriptor */
161b2_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
190int
191b2_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
237int
238b2_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