2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <sys/types.h>
32 #include <common/common.h>
36 #define MSEC_PER_SEC 1000
37 #define NSEC_PER_MSEC 1000000
38 #define RECONNECT_DELAY 200 /* ms */
41 * INET protocol operations.
43 static const struct lttcomm_proto_ops inet6_ops
= {
44 .bind
= lttcomm_bind_inet6_sock
,
45 .close
= lttcomm_close_inet6_sock
,
46 .connect
= lttcomm_connect_inet6_sock
,
47 .accept
= lttcomm_accept_inet6_sock
,
48 .listen
= lttcomm_listen_inet6_sock
,
49 .recvmsg
= lttcomm_recvmsg_inet6_sock
,
50 .sendmsg
= lttcomm_sendmsg_inet6_sock
,
54 * Creates an PF_INET socket.
57 int lttcomm_create_inet6_sock(struct lttcomm_sock
*sock
, int type
, int proto
)
60 unsigned long timeout
;
62 /* Create server socket */
63 if ((sock
->fd
= socket(PF_INET6
, type
, proto
)) < 0) {
64 PERROR("socket inet6");
68 sock
->ops
= &inet6_ops
;
71 * Set socket option to reuse the address.
73 ret
= setsockopt(sock
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(int));
75 PERROR("setsockopt inet6");
78 timeout
= lttcomm_get_network_timeout();
80 ret
= lttcomm_setsockopt_rcv_timeout(sock
->fd
, timeout
);
84 ret
= lttcomm_setsockopt_snd_timeout(sock
->fd
, timeout
);
97 * Bind socket and return.
100 int lttcomm_bind_inet6_sock(struct lttcomm_sock
*sock
)
104 ret
= bind(sock
->fd
, &sock
->sockaddr
.addr
.sin6
,
105 sizeof(sock
->sockaddr
.addr
.sin6
));
107 PERROR("bind inet6");
114 int connect_no_timeout(struct lttcomm_sock
*sock
)
116 return connect(sock
->fd
, (struct sockaddr
*) &sock
->sockaddr
.addr
.sin6
,
117 sizeof(sock
->sockaddr
.addr
.sin6
));
121 * Return time_a - time_b in milliseconds.
124 unsigned long time_diff_ms(struct timespec
*time_a
,
125 struct timespec
*time_b
)
129 unsigned long result_ms
;
131 sec_diff
= time_a
->tv_sec
- time_b
->tv_sec
;
132 nsec_diff
= time_a
->tv_nsec
- time_b
->tv_nsec
;
134 result_ms
= sec_diff
* MSEC_PER_SEC
;
135 result_ms
+= nsec_diff
/ NSEC_PER_MSEC
;
140 int connect_with_timeout(struct lttcomm_sock
*sock
)
142 unsigned long timeout
= lttcomm_get_network_timeout();
143 int ret
, flags
, connect_ret
;
144 struct timespec orig_time
, cur_time
;
146 ret
= fcntl(sock
->fd
, F_GETFL
, 0);
153 /* Set socket to nonblock */
154 ret
= fcntl(sock
->fd
, F_SETFL
, flags
| O_NONBLOCK
);
160 ret
= clock_gettime(CLOCK_MONOTONIC
, &orig_time
);
162 PERROR("clock_gettime");
166 connect_ret
= connect(sock
->fd
,
167 (struct sockaddr
*) &sock
->sockaddr
.addr
.sin6
,
168 sizeof(sock
->sockaddr
.addr
.sin6
));
169 if (connect_ret
== -1 && errno
!= EAGAIN
170 && errno
!= EWOULDBLOCK
171 && errno
!= EINPROGRESS
) {
173 } else if (!connect_ret
) {
174 /* Connect succeeded */
179 * Perform poll loop following EINPROGRESS recommendation from
180 * connect(2) man page.
186 fds
.events
= POLLOUT
;
188 ret
= poll(&fds
, 1, RECONNECT_DELAY
);
191 } else if (ret
> 0) {
193 socklen_t optval_len
= sizeof(optval
);
195 if (!(fds
.revents
& POLLOUT
)) {
196 /* Either hup or error */
201 ret
= getsockopt(sock
->fd
, SOL_SOCKET
,
202 SO_ERROR
, &optval
, &optval_len
);
213 /* ret == 0: timeout */
214 ret
= clock_gettime(CLOCK_MONOTONIC
, &cur_time
);
216 PERROR("clock_gettime");
220 } while (time_diff_ms(&cur_time
, &orig_time
) < timeout
);
227 /* Restore initial flags */
228 ret
= fcntl(sock
->fd
, F_SETFL
, flags
);
231 /* Continue anyway */
238 * Connect PF_INET socket.
241 int lttcomm_connect_inet6_sock(struct lttcomm_sock
*sock
)
245 if (lttcomm_get_network_timeout()) {
246 ret
= connect_with_timeout(sock
);
248 ret
= connect_no_timeout(sock
);
251 PERROR("connect inet6");
258 closeret
= close(sock
->fd
);
260 PERROR("close inet6");
267 * Do an accept(2) on the sock and return the new lttcomm socket. The socket
268 * MUST be bind(2) before.
271 struct lttcomm_sock
*lttcomm_accept_inet6_sock(struct lttcomm_sock
*sock
)
275 struct lttcomm_sock
*new_sock
;
277 if (sock
->proto
== LTTCOMM_SOCK_UDP
) {
279 * accept(2) does not exist for UDP so simply return the passed socket.
285 new_sock
= lttcomm_alloc_sock(sock
->proto
);
286 if (new_sock
== NULL
) {
290 len
= sizeof(new_sock
->sockaddr
.addr
.sin6
);
293 new_fd
= accept(sock
->fd
,
294 (struct sockaddr
*) &new_sock
->sockaddr
.addr
.sin6
, &len
);
296 PERROR("accept inet6");
300 new_sock
->fd
= new_fd
;
301 new_sock
->ops
= &inet6_ops
;
312 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
315 int lttcomm_listen_inet6_sock(struct lttcomm_sock
*sock
, int backlog
)
319 if (sock
->proto
== LTTCOMM_SOCK_UDP
) {
320 /* listen(2) does not exist for UDP so simply return success. */
325 /* Default listen backlog */
327 backlog
= LTTNG_SESSIOND_COMM_MAX_LISTEN
;
330 ret
= listen(sock
->fd
, backlog
);
332 PERROR("listen inet6");
340 * Receive data of size len in put that data into the buf param. Using recvmsg
343 * Return the size of received data.
346 ssize_t
lttcomm_recvmsg_inet6_sock(struct lttcomm_sock
*sock
, void *buf
,
347 size_t len
, int flags
)
354 memset(&msg
, 0, sizeof(msg
));
356 iov
[0].iov_base
= buf
;
357 iov
[0].iov_len
= len
;
361 msg
.msg_name
= (struct sockaddr
*) &sock
->sockaddr
.addr
.sin6
;
362 msg
.msg_namelen
= sizeof(sock
->sockaddr
.addr
.sin6
);
365 len_last
= iov
[0].iov_len
;
366 ret
= recvmsg(sock
->fd
, &msg
, flags
);
368 iov
[0].iov_base
+= ret
;
369 iov
[0].iov_len
-= ret
;
370 assert(ret
<= len_last
);
372 } while ((ret
> 0 && ret
< len_last
) || (ret
< 0 && errno
== EINTR
));
374 PERROR("recvmsg inet");
375 } else if (ret
> 0) {
378 /* Else ret = 0 meaning an orderly shutdown. */
384 * Send buf data of size len. Using sendmsg API.
386 * Return the size of sent data.
389 ssize_t
lttcomm_sendmsg_inet6_sock(struct lttcomm_sock
*sock
, void *buf
,
390 size_t len
, int flags
)
396 memset(&msg
, 0, sizeof(msg
));
398 iov
[0].iov_base
= buf
;
399 iov
[0].iov_len
= len
;
403 switch (sock
->proto
) {
404 case LTTCOMM_SOCK_UDP
:
405 msg
.msg_name
= (struct sockaddr
*) &sock
->sockaddr
.addr
.sin6
;
406 msg
.msg_namelen
= sizeof(sock
->sockaddr
.addr
.sin6
);
413 ret
= sendmsg(sock
->fd
, &msg
, flags
);
414 } while (ret
< 0 && errno
== EINTR
);
417 * Only warn about EPIPE when quiet mode is deactivated.
418 * We consider EPIPE as expected.
420 if (errno
!= EPIPE
|| !lttng_opt_quiet
) {
421 PERROR("sendmsg inet6");
429 * Shutdown cleanly and close.
432 int lttcomm_close_inet6_sock(struct lttcomm_sock
*sock
)
436 /* Don't try to close an invalid marked socket */
437 if (sock
->fd
== -1) {
441 ret
= close(sock
->fd
);
443 PERROR("close inet6");