Fix: add missing consumer.h to sessiond Makefile.am
[lttng-tools.git] / src / common / sessiond-comm / inet6.c
CommitLineData
6364a07a
DG
1/*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 *
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.
7 *
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
11 * more details.
12 *
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.
16 */
17
18#define _GNU_SOURCE
19#include <assert.h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
27#include <errno.h>
28
29#include <common/defaults.h>
30#include <common/error.h>
31
32#include "inet6.h"
33
34/*
35 * INET protocol operations.
36 */
37static const struct lttcomm_proto_ops inet6_ops = {
38 .bind = lttcomm_bind_inet6_sock,
39 .close = lttcomm_close_inet6_sock,
40 .connect = lttcomm_connect_inet6_sock,
41 .accept = lttcomm_accept_inet6_sock,
42 .listen = lttcomm_listen_inet6_sock,
43 .recvmsg = lttcomm_recvmsg_inet6_sock,
44 .sendmsg = lttcomm_sendmsg_inet6_sock,
45};
46
47/*
48 * Creates an PF_INET socket.
49 */
50int lttcomm_create_inet6_sock(struct lttcomm_sock *sock, int type, int proto)
51{
52 int val, ret;
53
54 /* Create server socket */
55 if ((sock->fd = socket(PF_INET, type, proto)) < 0) {
56 PERROR("socket inet6");
57 goto error;
58 }
59
60 sock->ops = &inet6_ops;
61
62 /*
63 * Set socket option to reuse the address.
64 */
65 ret = setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int));
66 if (ret < 0) {
67 PERROR("setsockopt inet6");
68 goto error;
69 }
70
71 return 0;
72
73error:
74 return -1;
75}
76
77/*
78 * Bind socket and return.
79 */
80int lttcomm_bind_inet6_sock(struct lttcomm_sock *sock)
81{
82 int ret;
83
84 ret = bind(sock->fd, &sock->sockaddr.addr.sin6,
85 sizeof(sock->sockaddr.addr.sin6));
86 if (ret < 0) {
87 PERROR("bind inet6");
88 }
89
90 return ret;
91}
92
93/*
94 * Connect PF_INET socket.
95 */
96int lttcomm_connect_inet6_sock(struct lttcomm_sock *sock)
97{
98 int ret, closeret;
99
100 ret = connect(sock->fd, (struct sockaddr *) &sock->sockaddr.addr.sin6,
101 sizeof(sock->sockaddr.addr.sin6));
102 if (ret < 0) {
103 /*
104 * Don't print message on connect error, because connect is used in
105 * normal execution to detect if sessiond is alive.
106 */
107 goto error_connect;
108 }
109
110 return ret;
111
112error_connect:
113 closeret = close(sock->fd);
114 if (closeret) {
115 PERROR("close inet6");
116 }
117
118 return ret;
119}
120
121/*
122 * Do an accept(2) on the sock and return the new lttcomm socket. The socket
123 * MUST be bind(2) before.
124 */
125struct lttcomm_sock *lttcomm_accept_inet6_sock(struct lttcomm_sock *sock)
126{
127 int new_fd;
128 socklen_t len = 0;
129 struct lttcomm_sock *new_sock;
130
131 if (sock->proto == LTTCOMM_SOCK_UDP) {
132 /*
133 * accept(2) does not exist for UDP so simply return the passed socket.
134 */
135 new_sock = sock;
136 goto end;
137 }
138
139 new_sock = lttcomm_alloc_sock(LTTCOMM_INET, sock->proto);
140 if (new_sock == NULL) {
141 goto error;
142 }
143
144 /* Blocking call */
145 new_fd = accept(sock->fd,
146 (struct sockaddr *) &new_sock->sockaddr.addr.sin6, &len);
147 if (new_fd < 0) {
148 PERROR("accept inet6");
149 goto error;
150 }
151
152 new_sock->fd = new_fd;
153
154end:
155 return new_sock;
156
157error:
158 free(new_sock);
159 return NULL;
160}
161
162/*
163 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
164 */
165int lttcomm_listen_inet6_sock(struct lttcomm_sock *sock, int backlog)
166{
167 int ret;
168
169 if (sock->proto == LTTCOMM_SOCK_UDP) {
170 /* listen(2) does not exist for UDP so simply return success. */
171 ret = 0;
172 goto end;
173 }
174
175 /* Default listen backlog */
176 if (backlog <= 0) {
177 backlog = LTTNG_SESSIOND_COMM_MAX_LISTEN;
178 }
179
180 ret = listen(sock->fd, backlog);
181 if (ret < 0) {
182 PERROR("listen inet6");
183 }
184
185end:
186 return ret;
187}
188
189/*
190 * Receive data of size len in put that data into the buf param. Using recvmsg
191 * API.
192 *
193 * Return the size of received data.
194 */
195ssize_t lttcomm_recvmsg_inet6_sock(struct lttcomm_sock *sock, void *buf,
196 size_t len, int flags)
197{
198 struct msghdr msg;
199 struct iovec iov[1];
200 ssize_t ret = -1;
201
202 memset(&msg, 0, sizeof(msg));
203
204 iov[0].iov_base = buf;
205 iov[0].iov_len = len;
206 msg.msg_iov = iov;
207 msg.msg_iovlen = 1;
208
209 msg.msg_name = (struct sockaddr *) &sock->sockaddr.addr.sin6;
210 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
211
212 if (flags == 0) {
213 flags = MSG_WAITALL;
214 }
215
216 do {
217 ret = recvmsg(sock->fd, &msg, flags);
218 } while (ret < 0 && errno == EINTR);
219 if (ret < 0) {
220 PERROR("recvmsg inet6");
221 }
222
223 return ret;
224}
225
226/*
227 * Send buf data of size len. Using sendmsg API.
228 *
229 * Return the size of sent data.
230 */
231ssize_t lttcomm_sendmsg_inet6_sock(struct lttcomm_sock *sock, void *buf,
232 size_t len, int flags)
233{
234 struct msghdr msg;
235 struct iovec iov[1];
236 ssize_t ret = -1;
237
238 memset(&msg, 0, sizeof(msg));
239
240 iov[0].iov_base = buf;
241 iov[0].iov_len = len;
242 msg.msg_iov = iov;
243 msg.msg_iovlen = 1;
244
245 switch (sock->proto) {
246 case LTTCOMM_SOCK_UDP:
247 msg.msg_name = (struct sockaddr *) &sock->sockaddr.addr.sin6;
248 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
249 break;
250 default:
251 break;
252 }
253
254 do {
255 ret = sendmsg(sock->fd, &msg, flags);
256 } while (ret < 0 && errno == EINTR);
257 if (ret < 0) {
258 /*
259 * Only warn about EPIPE when quiet mode is deactivated.
260 * We consider EPIPE as expected.
261 */
262 if (errno != EPIPE || !lttng_opt_quiet) {
263 PERROR("sendmsg inet6");
264 }
265 }
266
267 return ret;
268}
269
270/*
271 * Shutdown cleanly and close.
272 */
273int lttcomm_close_inet6_sock(struct lttcomm_sock *sock)
274{
275 int ret, closeret;
276
277 /* Don't try to close an invalid mark socket */
278 if (sock->fd == -1) {
279 return 0;
280 }
281
282 closeret = close(sock->fd);
283 if (closeret) {
284 PERROR("close inet6");
285 }
286
287 /* Mark socket */
288 sock->fd = -1;
289
290 return ret;
291}
This page took 0.032834 seconds and 4 git commands to generate.