Force usage of assert() condition when NDEBUG is defined
[lttng-tools.git] / src / common / sessiond-comm / inet6.c
CommitLineData
6364a07a 1/*
ab5be9fa 2 * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
6364a07a 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
6364a07a 5 *
6364a07a
DG
6 */
7
6c1c0768 8#define _LGPL_SOURCE
6364a07a
DG
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>
a655f4cf 16#include <fcntl.h>
389fbf04 17#include <common/compat/time.h>
a655f4cf 18#include <poll.h>
6364a07a 19
90e535ef 20#include <common/common.h>
395d6b02 21#include <common/time.h>
edf4b93e 22#include <common/compat/errno.h>
6364a07a
DG
23
24#include "inet6.h"
25
a655f4cf
MD
26#define RECONNECT_DELAY 200 /* ms */
27
6364a07a
DG
28/*
29 * INET protocol operations.
30 */
31static 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 */
90e535ef 44LTTNG_HIDDEN
6364a07a
DG
45int lttcomm_create_inet6_sock(struct lttcomm_sock *sock, int type, int proto)
46{
de5e9086 47 int val = 1, ret;
783a3b9a 48 unsigned long timeout;
6364a07a
DG
49
50 /* Create server socket */
7b43086d 51 if ((sock->fd = socket(PF_INET6, type, proto)) < 0) {
6364a07a
DG
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 }
783a3b9a
MD
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 }
6364a07a
DG
77
78 return 0;
79
80error:
81 return -1;
82}
83
84/*
85 * Bind socket and return.
86 */
90e535ef 87LTTNG_HIDDEN
6364a07a
DG
88int lttcomm_bind_inet6_sock(struct lttcomm_sock *sock)
89{
2288467f 90 return bind(sock->fd,
1a65bbb8
JG
91 (const struct sockaddr *) ALIGNED_CONST_PTR(
92 sock->sockaddr.addr.sin6),
6364a07a 93 sizeof(sock->sockaddr.addr.sin6));
6364a07a
DG
94}
95
a655f4cf
MD
96static
97int connect_no_timeout(struct lttcomm_sock *sock)
98{
1a65bbb8
JG
99 return connect(sock->fd,
100 (const struct sockaddr *) ALIGNED_CONST_PTR(
101 sock->sockaddr.addr.sin6),
a655f4cf
MD
102 sizeof(sock->sockaddr.addr.sin6));
103}
104
a655f4cf
MD
105static
106int 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;
2daf6502 111 unsigned long diff_ms;
a655f4cf
MD
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
389fbf04 127 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &orig_time);
a655f4cf
MD
128 if (ret == -1) {
129 PERROR("clock_gettime");
130 return -1;
131 }
132
133 connect_ret = connect(sock->fd,
1a65bbb8
JG
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) {
a655f4cf
MD
139 goto error;
140 } else if (!connect_ret) {
141 /* Connect succeeded */
142 goto success;
143 }
144
48ac9596
JR
145 DBG("Asynchronous connect for sock %d, performing polling with"
146 " timeout: %lums", sock->fd, timeout);
147
a655f4cf
MD
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) {
48ac9596 174 PERROR("getsockopt");
a655f4cf
MD
175 goto error;
176 }
177 if (!optval) {
178 connect_ret = 0;
179 goto success;
180 } else {
48ac9596
JR
181 /* Get actual connect() errno from opt_val */
182 errno = optval;
a655f4cf
MD
183 goto error;
184 }
185 }
186 /* ret == 0: timeout */
389fbf04 187 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &cur_time);
a655f4cf
MD
188 if (ret == -1) {
189 PERROR("clock_gettime");
190 connect_ret = ret;
191 goto error;
192 }
2daf6502
MD
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);
a655f4cf
MD
199
200 /* Timeout */
201 errno = ETIMEDOUT;
202 connect_ret = -1;
203
204success:
205 /* Restore initial flags */
206 ret = fcntl(sock->fd, F_SETFL, flags);
207 if (ret == -1) {
208 PERROR("fcntl");
209 /* Continue anyway */
210 }
211error:
212 return connect_ret;
213}
214
6364a07a
DG
215/*
216 * Connect PF_INET socket.
217 */
90e535ef 218LTTNG_HIDDEN
6364a07a
DG
219int lttcomm_connect_inet6_sock(struct lttcomm_sock *sock)
220{
221 int ret, closeret;
222
a655f4cf
MD
223 if (lttcomm_get_network_timeout()) {
224 ret = connect_with_timeout(sock);
225 } else {
226 ret = connect_no_timeout(sock);
227 }
6364a07a 228 if (ret < 0) {
82c05d47 229 PERROR("connect inet6");
6364a07a
DG
230 goto error_connect;
231 }
232
233 return ret;
234
235error_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 */
90e535ef 248LTTNG_HIDDEN
6364a07a
DG
249struct lttcomm_sock *lttcomm_accept_inet6_sock(struct lttcomm_sock *sock)
250{
251 int new_fd;
88a5db70 252 socklen_t len;
6364a07a 253 struct lttcomm_sock *new_sock;
1a65bbb8 254 struct sockaddr_in6 new_addr = {};
6364a07a
DG
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
de5e9086 264 new_sock = lttcomm_alloc_sock(sock->proto);
6364a07a
DG
265 if (new_sock == NULL) {
266 goto error;
267 }
268
1a65bbb8 269 len = sizeof(new_addr);
88a5db70 270
6364a07a 271 /* Blocking call */
1a65bbb8 272 new_fd = accept(sock->fd, (struct sockaddr *) &new_addr, &len);
6364a07a
DG
273 if (new_fd < 0) {
274 PERROR("accept inet6");
275 goto error;
276 }
1a65bbb8 277 new_sock->sockaddr.addr.sin6 = new_addr;
6364a07a 278 new_sock->fd = new_fd;
de5e9086 279 new_sock->ops = &inet6_ops;
6364a07a
DG
280
281end:
282 return new_sock;
283
284error:
285 free(new_sock);
286 return NULL;
287}
288
289/*
290 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
291 */
90e535ef 292LTTNG_HIDDEN
6364a07a
DG
293int 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
313end:
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 */
90e535ef 323LTTNG_HIDDEN
6364a07a
DG
324ssize_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;
7c5aef62 330 size_t len_last;
1a65bbb8 331 struct sockaddr_in6 addr = sock->sockaddr.addr.sin6;
6364a07a
DG
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
1a65bbb8 340 msg.msg_name = (struct sockaddr *) &addr;
6364a07a
DG
341 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
342
6364a07a 343 do {
7c5aef62 344 len_last = iov[0].iov_len;
6364a07a 345 ret = recvmsg(sock->fd, &msg, flags);
7c5aef62 346 if (ret > 0) {
5312a3ed
JG
347 if (flags & MSG_DONTWAIT) {
348 goto end;
349 }
7c5aef62
DG
350 iov[0].iov_base += ret;
351 iov[0].iov_len -= ret;
a0377dfe 352 LTTNG_ASSERT(ret <= len_last);
7c5aef62
DG
353 }
354 } while ((ret > 0 && ret < len_last) || (ret < 0 && errno == EINTR));
6364a07a 355 if (ret < 0) {
7c5aef62
DG
356 PERROR("recvmsg inet");
357 } else if (ret > 0) {
358 ret = len;
6364a07a 359 }
7c5aef62 360 /* Else ret = 0 meaning an orderly shutdown. */
5312a3ed 361end:
6364a07a
DG
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 */
90e535ef 370LTTNG_HIDDEN
c2d69327 371ssize_t lttcomm_sendmsg_inet6_sock(struct lttcomm_sock *sock, const void *buf,
6364a07a
DG
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
c2d69327 380 iov[0].iov_base = (void *) buf;
6364a07a
DG
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:
1a65bbb8
JG
387 {
388 struct sockaddr_in6 addr = sock->sockaddr.addr.sin6;
389
390 msg.msg_name = (struct sockaddr *) &addr;
6364a07a
DG
391 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
392 break;
1a65bbb8 393 }
6364a07a
DG
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 */
90e535ef 417LTTNG_HIDDEN
6364a07a
DG
418int lttcomm_close_inet6_sock(struct lttcomm_sock *sock)
419{
6e742359 420 int ret;
6364a07a 421
de5e9086 422 /* Don't try to close an invalid marked socket */
6364a07a
DG
423 if (sock->fd == -1) {
424 return 0;
425 }
426
6e742359
DG
427 ret = close(sock->fd);
428 if (ret) {
6364a07a
DG
429 PERROR("close inet6");
430 }
431
432 /* Mark socket */
433 sock->fd = -1;
434
435 return ret;
436}
This page took 0.0732350000000001 seconds and 4 git commands to generate.