2 * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
14 #include <sys/types.h>
17 #include <common/compat/time.hpp>
20 #include <common/common.hpp>
21 #include <common/time.hpp>
22 #include <common/compat/errno.hpp>
26 #define RECONNECT_DELAY 200 /* ms */
29 * INET protocol operations.
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
,
42 * Creates an PF_INET socket.
44 int lttcomm_create_inet6_sock(struct lttcomm_sock
*sock
, int type
, int proto
)
47 unsigned long timeout
;
49 /* Create server socket */
50 if ((sock
->fd
= socket(PF_INET6
, type
, proto
)) < 0) {
51 PERROR("socket inet6");
55 sock
->ops
= &inet6_ops
;
58 * Set socket option to reuse the address.
60 ret
= setsockopt(sock
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(int));
62 PERROR("setsockopt inet6");
65 timeout
= lttcomm_get_network_timeout();
67 ret
= lttcomm_setsockopt_rcv_timeout(sock
->fd
, timeout
);
71 ret
= lttcomm_setsockopt_snd_timeout(sock
->fd
, timeout
);
84 * Bind socket and return.
86 int lttcomm_bind_inet6_sock(struct lttcomm_sock
*sock
)
88 struct sockaddr_in6 sockaddr
= sock
->sockaddr
.addr
.sin6
;
89 return bind(sock
->fd
, (struct sockaddr
*) &sockaddr
, sizeof(sockaddr
));
93 int connect_no_timeout(struct lttcomm_sock
*sock
)
95 struct sockaddr_in6 sockaddr
= sock
->sockaddr
.addr
.sin6
;
96 return connect(sock
->fd
, (struct sockaddr
*) &sockaddr
, sizeof(sockaddr
));
100 int connect_with_timeout(struct lttcomm_sock
*sock
)
102 unsigned long timeout
= lttcomm_get_network_timeout();
103 int ret
, flags
, connect_ret
;
104 struct timespec orig_time
, cur_time
;
105 unsigned long diff_ms
;
106 struct sockaddr_in6 sockaddr
;
108 ret
= fcntl(sock
->fd
, F_GETFL
, 0);
115 /* Set socket to nonblock */
116 ret
= fcntl(sock
->fd
, F_SETFL
, flags
| O_NONBLOCK
);
122 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &orig_time
);
124 PERROR("clock_gettime");
128 sockaddr
= sock
->sockaddr
.addr
.sin6
;
129 connect_ret
= connect(sock
->fd
, (struct sockaddr
*) &sockaddr
, sizeof(sockaddr
));
130 if (connect_ret
== -1 && errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
&&
131 errno
!= EINPROGRESS
) {
133 } else if (!connect_ret
) {
134 /* Connect succeeded */
138 DBG("Asynchronous connect for sock %d, performing polling with"
139 " timeout: %lums", sock
->fd
, timeout
);
142 * Perform poll loop following EINPROGRESS recommendation from
143 * connect(2) man page.
149 fds
.events
= POLLOUT
;
151 ret
= poll(&fds
, 1, RECONNECT_DELAY
);
154 } else if (ret
> 0) {
156 socklen_t optval_len
= sizeof(optval
);
158 if (!(fds
.revents
& POLLOUT
)) {
159 /* Either hup or error */
164 ret
= getsockopt(sock
->fd
, SOL_SOCKET
,
165 SO_ERROR
, &optval
, &optval_len
);
167 PERROR("getsockopt");
174 /* Get actual connect() errno from opt_val */
179 /* ret == 0: timeout */
180 ret
= lttng_clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
182 PERROR("clock_gettime");
186 if (timespec_to_ms(timespec_abs_diff(cur_time
, orig_time
), &diff_ms
) < 0) {
187 ERR("timespec_to_ms input overflows milliseconds output");
191 } while (diff_ms
< timeout
);
198 /* Restore initial flags */
199 ret
= fcntl(sock
->fd
, F_SETFL
, flags
);
202 /* Continue anyway */
209 * Connect PF_INET socket.
211 int lttcomm_connect_inet6_sock(struct lttcomm_sock
*sock
)
215 if (lttcomm_get_network_timeout()) {
216 ret
= connect_with_timeout(sock
);
218 ret
= connect_no_timeout(sock
);
221 PERROR("connect inet6");
228 closeret
= close(sock
->fd
);
230 PERROR("close inet6");
237 * Do an accept(2) on the sock and return the new lttcomm socket. The socket
238 * MUST be bind(2) before.
240 struct lttcomm_sock
*lttcomm_accept_inet6_sock(struct lttcomm_sock
*sock
)
244 struct lttcomm_sock
*new_sock
;
245 struct sockaddr_in6 new_addr
= {};
247 if (sock
->proto
== LTTCOMM_SOCK_UDP
) {
249 * accept(2) does not exist for UDP so simply return the passed socket.
255 new_sock
= lttcomm_alloc_sock(sock
->proto
);
256 if (new_sock
== NULL
) {
260 len
= sizeof(new_addr
);
263 new_fd
= accept(sock
->fd
, (struct sockaddr
*) &new_addr
, &len
);
265 PERROR("accept inet6");
268 new_sock
->sockaddr
.addr
.sin6
= new_addr
;
269 new_sock
->fd
= new_fd
;
270 new_sock
->ops
= &inet6_ops
;
281 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
283 int lttcomm_listen_inet6_sock(struct lttcomm_sock
*sock
, int backlog
)
287 if (sock
->proto
== LTTCOMM_SOCK_UDP
) {
288 /* listen(2) does not exist for UDP so simply return success. */
293 /* Default listen backlog */
295 backlog
= LTTNG_SESSIOND_COMM_MAX_LISTEN
;
298 ret
= listen(sock
->fd
, backlog
);
300 PERROR("listen inet6");
308 * Receive data of size len in put that data into the buf param. Using recvmsg
311 * Return the size of received data.
313 ssize_t
lttcomm_recvmsg_inet6_sock(struct lttcomm_sock
*sock
, void *buf
,
314 size_t len
, int flags
)
320 struct sockaddr_in6 addr
= sock
->sockaddr
.addr
.sin6
;
322 memset(&msg
, 0, sizeof(msg
));
324 iov
[0].iov_base
= buf
;
325 iov
[0].iov_len
= len
;
329 msg
.msg_name
= (struct sockaddr
*) &addr
;
330 msg
.msg_namelen
= sizeof(sock
->sockaddr
.addr
.sin6
);
333 len_last
= iov
[0].iov_len
;
334 ret
= recvmsg(sock
->fd
, &msg
, flags
);
336 if (flags
& MSG_DONTWAIT
) {
339 iov
[0].iov_base
= ((char *) iov
[0].iov_base
) + ret
;
340 iov
[0].iov_len
-= ret
;
341 LTTNG_ASSERT(ret
<= len_last
);
343 } while ((ret
> 0 && ret
< len_last
) || (ret
< 0 && errno
== EINTR
));
345 PERROR("recvmsg inet");
346 } else if (ret
> 0) {
349 /* Else ret = 0 meaning an orderly shutdown. */
355 * Send buf data of size len. Using sendmsg API.
357 * Return the size of sent data.
359 ssize_t
lttcomm_sendmsg_inet6_sock(struct lttcomm_sock
*sock
, const void *buf
,
360 size_t len
, int flags
)
366 memset(&msg
, 0, sizeof(msg
));
368 iov
[0].iov_base
= (void *) buf
;
369 iov
[0].iov_len
= len
;
373 switch (sock
->proto
) {
374 case LTTCOMM_SOCK_UDP
:
376 struct sockaddr_in6 addr
= sock
->sockaddr
.addr
.sin6
;
378 msg
.msg_name
= (struct sockaddr
*) &addr
;
379 msg
.msg_namelen
= sizeof(sock
->sockaddr
.addr
.sin6
);
387 ret
= sendmsg(sock
->fd
, &msg
, flags
);
388 } while (ret
< 0 && errno
== EINTR
);
391 * Only warn about EPIPE when quiet mode is deactivated.
392 * We consider EPIPE as expected.
394 if (errno
!= EPIPE
|| !lttng_opt_quiet
) {
395 PERROR("sendmsg inet6");
403 * Shutdown cleanly and close.
405 int lttcomm_close_inet6_sock(struct lttcomm_sock
*sock
)
409 /* Don't try to close an invalid marked socket */
410 if (sock
->fd
== -1) {
414 ret
= close(sock
->fd
);
416 PERROR("close inet6");