Force usage of assert() condition when NDEBUG is defined
[lttng-tools.git] / src / common / sessiond-comm / inet6.c
1 /*
2 * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <limits.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <common/compat/time.h>
18 #include <poll.h>
19
20 #include <common/common.h>
21 #include <common/time.h>
22 #include <common/compat/errno.h>
23
24 #include "inet6.h"
25
26 #define RECONNECT_DELAY 200 /* ms */
27
28 /*
29 * INET protocol operations.
30 */
31 static const struct lttcomm_proto_ops inet6_ops = {
32 .bind = lttcomm_bind_inet6_sock,
33 .close = lttcomm_close_inet6_sock,
34 .connect = lttcomm_connect_inet6_sock,
35 .accept = lttcomm_accept_inet6_sock,
36 .listen = lttcomm_listen_inet6_sock,
37 .recvmsg = lttcomm_recvmsg_inet6_sock,
38 .sendmsg = lttcomm_sendmsg_inet6_sock,
39 };
40
41 /*
42 * Creates an PF_INET socket.
43 */
44 LTTNG_HIDDEN
45 int lttcomm_create_inet6_sock(struct lttcomm_sock *sock, int type, int proto)
46 {
47 int val = 1, ret;
48 unsigned long timeout;
49
50 /* Create server socket */
51 if ((sock->fd = socket(PF_INET6, type, proto)) < 0) {
52 PERROR("socket inet6");
53 goto error;
54 }
55
56 sock->ops = &inet6_ops;
57
58 /*
59 * Set socket option to reuse the address.
60 */
61 ret = setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int));
62 if (ret < 0) {
63 PERROR("setsockopt inet6");
64 goto error;
65 }
66 timeout = lttcomm_get_network_timeout();
67 if (timeout) {
68 ret = lttcomm_setsockopt_rcv_timeout(sock->fd, timeout);
69 if (ret) {
70 goto error;
71 }
72 ret = lttcomm_setsockopt_snd_timeout(sock->fd, timeout);
73 if (ret) {
74 goto error;
75 }
76 }
77
78 return 0;
79
80 error:
81 return -1;
82 }
83
84 /*
85 * Bind socket and return.
86 */
87 LTTNG_HIDDEN
88 int lttcomm_bind_inet6_sock(struct lttcomm_sock *sock)
89 {
90 return bind(sock->fd,
91 (const struct sockaddr *) ALIGNED_CONST_PTR(
92 sock->sockaddr.addr.sin6),
93 sizeof(sock->sockaddr.addr.sin6));
94 }
95
96 static
97 int connect_no_timeout(struct lttcomm_sock *sock)
98 {
99 return connect(sock->fd,
100 (const struct sockaddr *) ALIGNED_CONST_PTR(
101 sock->sockaddr.addr.sin6),
102 sizeof(sock->sockaddr.addr.sin6));
103 }
104
105 static
106 int connect_with_timeout(struct lttcomm_sock *sock)
107 {
108 unsigned long timeout = lttcomm_get_network_timeout();
109 int ret, flags, connect_ret;
110 struct timespec orig_time, cur_time;
111 unsigned long diff_ms;
112
113 ret = fcntl(sock->fd, F_GETFL, 0);
114 if (ret == -1) {
115 PERROR("fcntl");
116 return -1;
117 }
118 flags = ret;
119
120 /* Set socket to nonblock */
121 ret = fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK);
122 if (ret == -1) {
123 PERROR("fcntl");
124 return -1;
125 }
126
127 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &orig_time);
128 if (ret == -1) {
129 PERROR("clock_gettime");
130 return -1;
131 }
132
133 connect_ret = connect(sock->fd,
134 (const struct sockaddr *) ALIGNED_CONST_PTR(
135 sock->sockaddr.addr.sin6),
136 sizeof(sock->sockaddr.addr.sin6));
137 if (connect_ret == -1 && errno != EAGAIN && errno != EWOULDBLOCK &&
138 errno != EINPROGRESS) {
139 goto error;
140 } else if (!connect_ret) {
141 /* Connect succeeded */
142 goto success;
143 }
144
145 DBG("Asynchronous connect for sock %d, performing polling with"
146 " timeout: %lums", sock->fd, timeout);
147
148 /*
149 * Perform poll loop following EINPROGRESS recommendation from
150 * connect(2) man page.
151 */
152 do {
153 struct pollfd fds;
154
155 fds.fd = sock->fd;
156 fds.events = POLLOUT;
157 fds.revents = 0;
158 ret = poll(&fds, 1, RECONNECT_DELAY);
159 if (ret < 0) {
160 goto error;
161 } else if (ret > 0) {
162 int optval;
163 socklen_t optval_len = sizeof(optval);
164
165 if (!(fds.revents & POLLOUT)) {
166 /* Either hup or error */
167 errno = EPIPE;
168 goto error;
169 }
170 /* got something */
171 ret = getsockopt(sock->fd, SOL_SOCKET,
172 SO_ERROR, &optval, &optval_len);
173 if (ret) {
174 PERROR("getsockopt");
175 goto error;
176 }
177 if (!optval) {
178 connect_ret = 0;
179 goto success;
180 } else {
181 /* Get actual connect() errno from opt_val */
182 errno = optval;
183 goto error;
184 }
185 }
186 /* ret == 0: timeout */
187 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &cur_time);
188 if (ret == -1) {
189 PERROR("clock_gettime");
190 connect_ret = ret;
191 goto error;
192 }
193 if (timespec_to_ms(timespec_abs_diff(cur_time, orig_time), &diff_ms) < 0) {
194 ERR("timespec_to_ms input overflows milliseconds output");
195 connect_ret = -1;
196 goto error;
197 }
198 } while (diff_ms < timeout);
199
200 /* Timeout */
201 errno = ETIMEDOUT;
202 connect_ret = -1;
203
204 success:
205 /* Restore initial flags */
206 ret = fcntl(sock->fd, F_SETFL, flags);
207 if (ret == -1) {
208 PERROR("fcntl");
209 /* Continue anyway */
210 }
211 error:
212 return connect_ret;
213 }
214
215 /*
216 * Connect PF_INET socket.
217 */
218 LTTNG_HIDDEN
219 int lttcomm_connect_inet6_sock(struct lttcomm_sock *sock)
220 {
221 int ret, closeret;
222
223 if (lttcomm_get_network_timeout()) {
224 ret = connect_with_timeout(sock);
225 } else {
226 ret = connect_no_timeout(sock);
227 }
228 if (ret < 0) {
229 PERROR("connect inet6");
230 goto error_connect;
231 }
232
233 return ret;
234
235 error_connect:
236 closeret = close(sock->fd);
237 if (closeret) {
238 PERROR("close inet6");
239 }
240
241 return ret;
242 }
243
244 /*
245 * Do an accept(2) on the sock and return the new lttcomm socket. The socket
246 * MUST be bind(2) before.
247 */
248 LTTNG_HIDDEN
249 struct lttcomm_sock *lttcomm_accept_inet6_sock(struct lttcomm_sock *sock)
250 {
251 int new_fd;
252 socklen_t len;
253 struct lttcomm_sock *new_sock;
254 struct sockaddr_in6 new_addr = {};
255
256 if (sock->proto == LTTCOMM_SOCK_UDP) {
257 /*
258 * accept(2) does not exist for UDP so simply return the passed socket.
259 */
260 new_sock = sock;
261 goto end;
262 }
263
264 new_sock = lttcomm_alloc_sock(sock->proto);
265 if (new_sock == NULL) {
266 goto error;
267 }
268
269 len = sizeof(new_addr);
270
271 /* Blocking call */
272 new_fd = accept(sock->fd, (struct sockaddr *) &new_addr, &len);
273 if (new_fd < 0) {
274 PERROR("accept inet6");
275 goto error;
276 }
277 new_sock->sockaddr.addr.sin6 = new_addr;
278 new_sock->fd = new_fd;
279 new_sock->ops = &inet6_ops;
280
281 end:
282 return new_sock;
283
284 error:
285 free(new_sock);
286 return NULL;
287 }
288
289 /*
290 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
291 */
292 LTTNG_HIDDEN
293 int lttcomm_listen_inet6_sock(struct lttcomm_sock *sock, int backlog)
294 {
295 int ret;
296
297 if (sock->proto == LTTCOMM_SOCK_UDP) {
298 /* listen(2) does not exist for UDP so simply return success. */
299 ret = 0;
300 goto end;
301 }
302
303 /* Default listen backlog */
304 if (backlog <= 0) {
305 backlog = LTTNG_SESSIOND_COMM_MAX_LISTEN;
306 }
307
308 ret = listen(sock->fd, backlog);
309 if (ret < 0) {
310 PERROR("listen inet6");
311 }
312
313 end:
314 return ret;
315 }
316
317 /*
318 * Receive data of size len in put that data into the buf param. Using recvmsg
319 * API.
320 *
321 * Return the size of received data.
322 */
323 LTTNG_HIDDEN
324 ssize_t lttcomm_recvmsg_inet6_sock(struct lttcomm_sock *sock, void *buf,
325 size_t len, int flags)
326 {
327 struct msghdr msg;
328 struct iovec iov[1];
329 ssize_t ret = -1;
330 size_t len_last;
331 struct sockaddr_in6 addr = sock->sockaddr.addr.sin6;
332
333 memset(&msg, 0, sizeof(msg));
334
335 iov[0].iov_base = buf;
336 iov[0].iov_len = len;
337 msg.msg_iov = iov;
338 msg.msg_iovlen = 1;
339
340 msg.msg_name = (struct sockaddr *) &addr;
341 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
342
343 do {
344 len_last = iov[0].iov_len;
345 ret = recvmsg(sock->fd, &msg, flags);
346 if (ret > 0) {
347 if (flags & MSG_DONTWAIT) {
348 goto end;
349 }
350 iov[0].iov_base += ret;
351 iov[0].iov_len -= ret;
352 LTTNG_ASSERT(ret <= len_last);
353 }
354 } while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
355 if (ret < 0) {
356 PERROR("recvmsg inet");
357 } else if (ret > 0) {
358 ret = len;
359 }
360 /* Else ret = 0 meaning an orderly shutdown. */
361 end:
362 return ret;
363 }
364
365 /*
366 * Send buf data of size len. Using sendmsg API.
367 *
368 * Return the size of sent data.
369 */
370 LTTNG_HIDDEN
371 ssize_t lttcomm_sendmsg_inet6_sock(struct lttcomm_sock *sock, const void *buf,
372 size_t len, int flags)
373 {
374 struct msghdr msg;
375 struct iovec iov[1];
376 ssize_t ret = -1;
377
378 memset(&msg, 0, sizeof(msg));
379
380 iov[0].iov_base = (void *) buf;
381 iov[0].iov_len = len;
382 msg.msg_iov = iov;
383 msg.msg_iovlen = 1;
384
385 switch (sock->proto) {
386 case LTTCOMM_SOCK_UDP:
387 {
388 struct sockaddr_in6 addr = sock->sockaddr.addr.sin6;
389
390 msg.msg_name = (struct sockaddr *) &addr;
391 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
392 break;
393 }
394 default:
395 break;
396 }
397
398 do {
399 ret = sendmsg(sock->fd, &msg, flags);
400 } while (ret < 0 && errno == EINTR);
401 if (ret < 0) {
402 /*
403 * Only warn about EPIPE when quiet mode is deactivated.
404 * We consider EPIPE as expected.
405 */
406 if (errno != EPIPE || !lttng_opt_quiet) {
407 PERROR("sendmsg inet6");
408 }
409 }
410
411 return ret;
412 }
413
414 /*
415 * Shutdown cleanly and close.
416 */
417 LTTNG_HIDDEN
418 int lttcomm_close_inet6_sock(struct lttcomm_sock *sock)
419 {
420 int ret;
421
422 /* Don't try to close an invalid marked socket */
423 if (sock->fd == -1) {
424 return 0;
425 }
426
427 ret = close(sock->fd);
428 if (ret) {
429 PERROR("close inet6");
430 }
431
432 /* Mark socket */
433 sock->fd = -1;
434
435 return ret;
436 }
This page took 0.037761 seconds and 4 git commands to generate.