Add and change lttcomm socket API
[lttng-tools.git] / src / common / sessiond-comm / inet6.c
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 */
37 static 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 */
50 int lttcomm_create_inet6_sock(struct lttcomm_sock *sock, int type, int proto)
51 {
52 int val = 1, 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
73 error:
74 return -1;
75 }
76
77 /*
78 * Bind socket and return.
79 */
80 int 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 */
96 int 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
112 error_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 */
125 struct 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(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 new_sock->ops = &inet6_ops;
154
155 end:
156 return new_sock;
157
158 error:
159 free(new_sock);
160 return NULL;
161 }
162
163 /*
164 * Make the socket listen using LTTNG_SESSIOND_COMM_MAX_LISTEN.
165 */
166 int lttcomm_listen_inet6_sock(struct lttcomm_sock *sock, int backlog)
167 {
168 int ret;
169
170 if (sock->proto == LTTCOMM_SOCK_UDP) {
171 /* listen(2) does not exist for UDP so simply return success. */
172 ret = 0;
173 goto end;
174 }
175
176 /* Default listen backlog */
177 if (backlog <= 0) {
178 backlog = LTTNG_SESSIOND_COMM_MAX_LISTEN;
179 }
180
181 ret = listen(sock->fd, backlog);
182 if (ret < 0) {
183 PERROR("listen inet6");
184 }
185
186 end:
187 return ret;
188 }
189
190 /*
191 * Receive data of size len in put that data into the buf param. Using recvmsg
192 * API.
193 *
194 * Return the size of received data.
195 */
196 ssize_t lttcomm_recvmsg_inet6_sock(struct lttcomm_sock *sock, void *buf,
197 size_t len, int flags)
198 {
199 struct msghdr msg;
200 struct iovec iov[1];
201 ssize_t ret = -1;
202
203 memset(&msg, 0, sizeof(msg));
204
205 iov[0].iov_base = buf;
206 iov[0].iov_len = len;
207 msg.msg_iov = iov;
208 msg.msg_iovlen = 1;
209
210 msg.msg_name = (struct sockaddr *) &sock->sockaddr.addr.sin6;
211 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
212
213 if (flags == 0) {
214 flags = MSG_WAITALL;
215 }
216
217 do {
218 ret = recvmsg(sock->fd, &msg, flags);
219 } while (ret < 0 && errno == EINTR);
220 if (ret < 0) {
221 PERROR("recvmsg inet6");
222 }
223
224 return ret;
225 }
226
227 /*
228 * Send buf data of size len. Using sendmsg API.
229 *
230 * Return the size of sent data.
231 */
232 ssize_t lttcomm_sendmsg_inet6_sock(struct lttcomm_sock *sock, void *buf,
233 size_t len, int flags)
234 {
235 struct msghdr msg;
236 struct iovec iov[1];
237 ssize_t ret = -1;
238
239 memset(&msg, 0, sizeof(msg));
240
241 iov[0].iov_base = buf;
242 iov[0].iov_len = len;
243 msg.msg_iov = iov;
244 msg.msg_iovlen = 1;
245
246 switch (sock->proto) {
247 case LTTCOMM_SOCK_UDP:
248 msg.msg_name = (struct sockaddr *) &sock->sockaddr.addr.sin6;
249 msg.msg_namelen = sizeof(sock->sockaddr.addr.sin6);
250 break;
251 default:
252 break;
253 }
254
255 do {
256 ret = sendmsg(sock->fd, &msg, flags);
257 } while (ret < 0 && errno == EINTR);
258 if (ret < 0) {
259 /*
260 * Only warn about EPIPE when quiet mode is deactivated.
261 * We consider EPIPE as expected.
262 */
263 if (errno != EPIPE || !lttng_opt_quiet) {
264 PERROR("sendmsg inet6");
265 }
266 }
267
268 return ret;
269 }
270
271 /*
272 * Shutdown cleanly and close.
273 */
274 int lttcomm_close_inet6_sock(struct lttcomm_sock *sock)
275 {
276 int ret;
277
278 /* Don't try to close an invalid marked socket */
279 if (sock->fd == -1) {
280 return 0;
281 }
282
283 ret = close(sock->fd);
284 if (ret) {
285 PERROR("close inet6");
286 }
287
288 /* Mark socket */
289 sock->fd = -1;
290
291 return ret;
292 }
This page took 0.053257 seconds and 5 git commands to generate.