blob: 2921e008018e99ceba05cfce588e01eafd046c2b [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
Damjan Marionf49921f2017-09-11 16:52:11 +020038#include <stdio.h>
39#include <string.h> /* strchr */
40#define __USE_GNU
Nathan Moos323418d2021-01-15 16:45:14 -080041#define _GNU_SOURCE
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#include <sys/types.h>
43#include <sys/socket.h>
Damjan Marionf49921f2017-09-11 16:52:11 +020044#include <sys/un.h>
Damjan Marionf6616382017-06-21 12:01:37 +020045#include <sys/stat.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070046#include <netinet/in.h>
47#include <arpa/inet.h>
48#include <netdb.h>
49#include <unistd.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070050#include <fcntl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070051
52#include <vppinfra/mem.h>
53#include <vppinfra/vec.h>
54#include <vppinfra/socket.h>
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +020055#include <vppinfra/linux/netns.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070056#include <vppinfra/format.h>
57#include <vppinfra/error.h>
58
Nathan Moos323418d2021-01-15 16:45:14 -080059#ifndef __GLIBC__
60/* IPPORT_USERRESERVED is not part of musl libc. */
61#define IPPORT_USERRESERVED 5000
62#endif
63
Damjan Mariondae1c7e2020-10-17 13:32:25 +020064__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -040065clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -070066{
67 va_list va;
68 va_start (va, fmt);
69 clib_socket_tx_add_va_formatted (s, fmt, &va);
70 va_end (va);
71}
72
73/* Return and bind to an unused port. */
Dave Barachc3799992016-08-15 11:12:27 -040074static word
75find_free_port (word sock)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
77 word port;
78
79 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
80 {
81 struct sockaddr_in a;
82
Dave Barachb7b92992018-10-17 10:38:51 -040083 clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
Ed Warnickecb9cada2015-12-08 15:45:58 -070084
85 a.sin_family = PF_INET;
86 a.sin_addr.s_addr = INADDR_ANY;
87 a.sin_port = htons (port);
88
89 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
90 break;
91 }
Dave Barachc3799992016-08-15 11:12:27 -040092
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 return port < 1 << 16 ? port : -1;
94}
95
96/* Convert a config string to a struct sockaddr and length for use
97 with bind or connect. */
98static clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -040099socket_config (char *config,
100 void *addr, socklen_t * addr_len, u32 ip4_default_address)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101{
Dave Barachc3799992016-08-15 11:12:27 -0400102 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
Dave Barachc3799992016-08-15 11:12:27 -0400104 if (!config)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 config = "";
106
107 /* Anything that begins with a / is a local PF_LOCAL socket. */
108 if (config[0] == '/')
109 {
Dave Barachc3799992016-08-15 11:12:27 -0400110 struct sockaddr_un *su = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111 su->sun_family = PF_LOCAL;
Damjan Marionf1213b82016-03-13 02:22:06 +0100112 clib_memcpy (&su->sun_path, config,
Dave Barachc3799992016-08-15 11:12:27 -0400113 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114 *addr_len = sizeof (su[0]);
115 }
116
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200117 /* Treat everything that starts with @ as an abstract socket. */
118 else if (config[0] == '@')
119 {
120 struct sockaddr_un *su = addr;
121 su->sun_family = PF_LOCAL;
122 clib_memcpy (&su->sun_path, config,
123 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
124
125 *addr_len = sizeof (su->sun_family) + strlen (config);
126 su->sun_path[0] = '\0';
127 }
128
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129 /* Hostname or hostname:port or port. */
130 else
131 {
Dave Barachc3799992016-08-15 11:12:27 -0400132 char *host_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133 int port = -1;
Dave Barachc3799992016-08-15 11:12:27 -0400134 struct sockaddr_in *sa = addr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
136 host_name = 0;
137 port = -1;
138 if (config[0] != 0)
139 {
140 unformat_input_t i;
141
142 unformat_init_string (&i, config, strlen (config));
143 if (unformat (&i, "%s:%d", &host_name, &port)
144 || unformat (&i, "%s:0x%x", &host_name, &port))
145 ;
146 else if (unformat (&i, "%s", &host_name))
147 ;
148 else
149 error = clib_error_return (0, "unknown input `%U'",
150 format_unformat_error, &i);
151 unformat_free (&i);
152
153 if (error)
154 goto done;
155 }
156
157 sa->sin_family = PF_INET;
158 *addr_len = sizeof (sa[0]);
159 if (port != -1)
160 sa->sin_port = htons (port);
161 else
162 sa->sin_port = 0;
163
164 if (host_name)
165 {
166 struct in_addr host_addr;
167
168 /* Recognize localhost to avoid host lookup in most common cast. */
Dave Barachc3799992016-08-15 11:12:27 -0400169 if (!strcmp (host_name, "localhost"))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
171
172 else if (inet_aton (host_name, &host_addr))
173 sa->sin_addr = host_addr;
174
175 else if (host_name && strlen (host_name) > 0)
176 {
Dave Barachc3799992016-08-15 11:12:27 -0400177 struct hostent *host = gethostbyname (host_name);
178 if (!host)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179 error = clib_error_return (0, "unknown host `%s'", config);
180 else
Dave Barachc3799992016-08-15 11:12:27 -0400181 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
182 host->h_length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 }
184
185 else
186 sa->sin_addr.s_addr = htonl (ip4_default_address);
187
188 vec_free (host_name);
189 if (error)
190 goto done;
191 }
192 }
193
Dave Barachc3799992016-08-15 11:12:27 -0400194done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 return error;
196}
197
198static clib_error_t *
199default_socket_write (clib_socket_t * s)
200{
Dave Barachc3799992016-08-15 11:12:27 -0400201 clib_error_t *err = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 word written = 0;
203 word fd = 0;
204 word tx_len;
205
206 fd = s->fd;
207
208 /* Map standard input to standard output.
209 Typically, fd is a socket for which read/write both work. */
210 if (fd == 0)
211 fd = 1;
212
213 tx_len = vec_len (s->tx_buffer);
214 written = write (fd, s->tx_buffer, tx_len);
215
216 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400217 if (written < 0 && !unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218 written = 0;
219
220 /* A "real" error occurred. */
221 if (written < 0)
222 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400223 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
224 tx_len, s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225 vec_free (s->tx_buffer);
226 goto done;
227 }
228
229 /* Reclaim the transmitted part of the tx buffer on successful writes. */
230 else if (written > 0)
231 {
232 if (written == tx_len)
233 _vec_len (s->tx_buffer) = 0;
234 else
235 vec_delete (s->tx_buffer, written, 0);
236 }
237
238 /* If a non-fatal error occurred AND
239 the buffer is full, then we must free it. */
Dave Barachc3799992016-08-15 11:12:27 -0400240 else if (written == 0 && tx_len > 64 * 1024)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 {
242 vec_free (s->tx_buffer);
243 }
244
Dave Barachc3799992016-08-15 11:12:27 -0400245done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 return err;
247}
248
249static clib_error_t *
250default_socket_read (clib_socket_t * sock, int n_bytes)
251{
252 word fd, n_read;
Dave Barachc3799992016-08-15 11:12:27 -0400253 u8 *buf;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
255 /* RX side of socket is down once end of file is reached. */
Damjan Marionf49921f2017-09-11 16:52:11 +0200256 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 return 0;
258
259 fd = sock->fd;
260
261 n_bytes = clib_max (n_bytes, 4096);
262 vec_add2 (sock->rx_buffer, buf, n_bytes);
263
264 if ((n_read = read (fd, buf, n_bytes)) < 0)
265 {
266 n_read = 0;
267
268 /* Ignore certain errors. */
Dave Barachc3799992016-08-15 11:12:27 -0400269 if (!unix_error_is_fatal (errno))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 goto non_fatal;
Dave Barachc3799992016-08-15 11:12:27 -0400271
Dave Wallace70ec09d2017-09-06 16:45:04 -0400272 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
273 n_bytes, sock->fd, sock->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 }
Dave Barachc3799992016-08-15 11:12:27 -0400275
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276 /* Other side closed the socket. */
277 if (n_read == 0)
Damjan Marionf49921f2017-09-11 16:52:11 +0200278 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
Dave Barachc3799992016-08-15 11:12:27 -0400280non_fatal:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 _vec_len (sock->rx_buffer) += n_read - n_bytes;
282
283 return 0;
284}
285
Dave Barachc3799992016-08-15 11:12:27 -0400286static clib_error_t *
287default_socket_close (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288{
289 if (close (s->fd) < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400290 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 return 0;
292}
293
Damjan Marionf49921f2017-09-11 16:52:11 +0200294static clib_error_t *
295default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
296 int fds[], int num_fds)
297{
298 struct msghdr mh = { 0 };
299 struct iovec iov[1];
Damjan Marion0215fb42018-10-30 13:04:19 +0100300 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
Damjan Marionf49921f2017-09-11 16:52:11 +0200301 int rv;
302
303 iov[0].iov_base = msg;
304 iov[0].iov_len = msglen;
305 mh.msg_iov = iov;
306 mh.msg_iovlen = 1;
307
308 if (num_fds > 0)
309 {
310 struct cmsghdr *cmsg;
Dave Barachb7b92992018-10-17 10:38:51 -0400311 clib_memset (&ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200312 mh.msg_control = ctl;
313 mh.msg_controllen = sizeof (ctl);
314 cmsg = CMSG_FIRSTHDR (&mh);
315 cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
316 cmsg->cmsg_level = SOL_SOCKET;
317 cmsg->cmsg_type = SCM_RIGHTS;
318 memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
319 }
320 rv = sendmsg (s->fd, &mh, 0);
321 if (rv < 0)
322 return clib_error_return_unix (0, "sendmsg");
323 return 0;
324}
325
326
327static clib_error_t *
328default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
329 int fds[], int num_fds)
330{
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200331#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200332 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
333 CMSG_SPACE (sizeof (struct ucred))];
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200334 struct ucred *cr = 0;
335#else
336 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
337#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200338 struct msghdr mh = { 0 };
339 struct iovec iov[1];
340 ssize_t size;
Damjan Marionf49921f2017-09-11 16:52:11 +0200341 struct cmsghdr *cmsg;
342
343 iov[0].iov_base = msg;
344 iov[0].iov_len = msglen;
345 mh.msg_iov = iov;
346 mh.msg_iovlen = 1;
347 mh.msg_control = ctl;
348 mh.msg_controllen = sizeof (ctl);
349
Dave Barachb7b92992018-10-17 10:38:51 -0400350 clib_memset (ctl, 0, sizeof (ctl));
Damjan Marionf49921f2017-09-11 16:52:11 +0200351
352 /* receive the incoming message */
353 size = recvmsg (s->fd, &mh, 0);
354 if (size != msglen)
355 {
356 return (size == 0) ? clib_error_return (0, "disconnected") :
357 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
358 s->fd, s->config);
359 }
360
361 cmsg = CMSG_FIRSTHDR (&mh);
362 while (cmsg)
363 {
364 if (cmsg->cmsg_level == SOL_SOCKET)
365 {
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200366#ifdef __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200367 if (cmsg->cmsg_type == SCM_CREDENTIALS)
368 {
369 cr = (struct ucred *) CMSG_DATA (cmsg);
370 s->uid = cr->uid;
371 s->gid = cr->gid;
372 s->pid = cr->pid;
373 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200374 else
375#endif
376 if (cmsg->cmsg_type == SCM_RIGHTS)
Damjan Marionf49921f2017-09-11 16:52:11 +0200377 {
Dave Barach178cf492018-11-13 16:34:13 -0500378 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
379 num_fds * sizeof (int));
Damjan Marionf49921f2017-09-11 16:52:11 +0200380 }
381 }
382 cmsg = CMSG_NXTHDR (&mh, cmsg);
383 }
384 return 0;
385}
386
Dave Barachc3799992016-08-15 11:12:27 -0400387static void
388socket_init_funcs (clib_socket_t * s)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389{
Dave Barachc3799992016-08-15 11:12:27 -0400390 if (!s->write_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 s->write_func = default_socket_write;
Dave Barachc3799992016-08-15 11:12:27 -0400392 if (!s->read_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 s->read_func = default_socket_read;
Dave Barachc3799992016-08-15 11:12:27 -0400394 if (!s->close_func)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395 s->close_func = default_socket_close;
Damjan Marionf49921f2017-09-11 16:52:11 +0200396 if (!s->sendmsg_func)
397 s->sendmsg_func = default_socket_sendmsg;
398 if (!s->recvmsg_func)
399 s->recvmsg_func = default_socket_recvmsg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400}
401
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200402__clib_export clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403clib_socket_init (clib_socket_t * s)
404{
Dave Barachc3799992016-08-15 11:12:27 -0400405 union
406 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407 struct sockaddr sa;
408 struct sockaddr_un su;
409 } addr;
410 socklen_t addr_len = 0;
Florin Coras42ddf692020-01-06 20:23:07 +0000411 int socket_type, rv;
Dave Barachc3799992016-08-15 11:12:27 -0400412 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413 word port;
414
415 error = socket_config (s->config, &addr.sa, &addr_len,
Damjan Marionf49921f2017-09-11 16:52:11 +0200416 (s->flags & CLIB_SOCKET_F_IS_SERVER
Dave Barachc3799992016-08-15 11:12:27 -0400417 ? INADDR_LOOPBACK : INADDR_ANY));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700418 if (error)
419 goto done;
420
421 socket_init_funcs (s);
422
Damjan Marionf49921f2017-09-11 16:52:11 +0200423 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
424 SOCK_SEQPACKET : SOCK_STREAM;
425
426 s->fd = socket (addr.sa.sa_family, socket_type, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700427 if (s->fd < 0)
428 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400429 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
430 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431 goto done;
432 }
433
434 port = 0;
435 if (addr.sa.sa_family == PF_INET)
436 port = ((struct sockaddr_in *) &addr)->sin_port;
437
Damjan Marionf49921f2017-09-11 16:52:11 +0200438 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439 {
440 uword need_bind = 1;
441
442 if (addr.sa.sa_family == PF_INET)
443 {
444 if (port == 0)
445 {
446 port = find_free_port (s->fd);
447 if (port < 0)
448 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400449 error = clib_error_return (0, "no free port (fd %d, '%s')",
450 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451 goto done;
452 }
453 need_bind = 0;
454 }
455 }
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200456 if (addr.sa.sa_family == PF_LOCAL &&
457 ((struct sockaddr_un *) &addr)->sun_path[0] != 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458 unlink (((struct sockaddr_un *) &addr)->sun_path);
459
460 /* Make address available for multiple users. */
461 {
462 int v = 1;
463 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
464 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
465 }
466
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200467#if __linux__
Damjan Marionf49921f2017-09-11 16:52:11 +0200468 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
469 {
470 int x = 1;
471 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
472 {
473 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
474 "fd %d, '%s')", s->fd,
475 s->config);
476 goto done;
477 }
478 }
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200479#endif
Damjan Marionf49921f2017-09-11 16:52:11 +0200480
Dave Barachc3799992016-08-15 11:12:27 -0400481 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700482 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400483 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
484 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 goto done;
486 }
487
488 if (listen (s->fd, 5) < 0)
489 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400490 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
491 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492 goto done;
493 }
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200494 if (addr.sa.sa_family == PF_LOCAL &&
495 s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE &&
496 ((struct sockaddr_un *) &addr)->sun_path[0] != 0)
Damjan Marionf6616382017-06-21 12:01:37 +0200497 {
498 struct stat st = { 0 };
Chris Lukeab7b8d92017-09-07 07:40:13 -0400499 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
500 {
501 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
502 s->fd, s->config);
503 goto done;
504 }
Damjan Marionf6616382017-06-21 12:01:37 +0200505 st.st_mode |= S_IWGRP;
Chris Lukeab7b8d92017-09-07 07:40:13 -0400506 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
507 0)
508 {
509 error =
510 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
511 s->fd, s->config, st.st_mode);
512 goto done;
513 }
Damjan Marionf6616382017-06-21 12:01:37 +0200514 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515 }
516 else
517 {
Damjan Marionf49921f2017-09-11 16:52:11 +0200518 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
520 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400521 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
522 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523 goto done;
524 }
525
Florin Coras42ddf692020-01-06 20:23:07 +0000526 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
527 && errno == EAGAIN)
528 ;
529 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
530 errno == EINPROGRESS))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700531 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400532 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
533 s->fd, s->config);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 goto done;
535 }
Florin Coras57e0af92021-05-26 10:21:10 -0700536 /* Connect was blocking so set fd to non-blocking now unless
537 * blocking mode explicitly requested. */
Florin Coras5fe94572021-05-24 08:58:15 -0700538 if (!(s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
Florin Coras57e0af92021-05-26 10:21:10 -0700539 !(s->flags & CLIB_SOCKET_F_BLOCKING) &&
Florin Coras5fe94572021-05-24 08:58:15 -0700540 fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
541 {
542 error = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
543 s->fd, s->config);
544 goto done;
545 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700546 }
547
548 return error;
549
Dave Barachc3799992016-08-15 11:12:27 -0400550done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 if (s->fd > 0)
552 close (s->fd);
553 return error;
554}
555
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200556__clib_export clib_error_t *
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200557clib_socket_init_netns (clib_socket_t *s, u8 *namespace)
558{
559 if (namespace == NULL || namespace[0] == 0)
560 return clib_socket_init (s);
561
562 clib_error_t *error;
Nathan Skrzypczak9218c602021-07-27 19:51:27 +0200563 int old_netns_fd, nfd = -1;
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200564
565 old_netns_fd = clib_netns_open (NULL /* self */);
566 if ((nfd = clib_netns_open (namespace)) == -1)
567 {
568 error = clib_error_return_unix (0, "clib_netns_open '%s'", namespace);
569 goto done;
570 }
571
572 if (clib_setns (nfd) == -1)
573 {
574 error = clib_error_return_unix (0, "setns '%s'", namespace);
575 goto done;
576 }
577
578 error = clib_socket_init (s);
579
580done:
581 if (clib_setns (old_netns_fd) == -1)
582 clib_warning ("Cannot set old ns");
Nathan Skrzypczak9218c602021-07-27 19:51:27 +0200583
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200584 close (old_netns_fd);
585
Nathan Skrzypczak9218c602021-07-27 19:51:27 +0200586 if (-1 != nfd)
587 close (nfd);
588
Nathan Skrzypczak4cef6de2021-07-19 18:21:43 +0200589 return error;
590}
591
592__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -0400593clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594{
Dave Barachc3799992016-08-15 11:12:27 -0400595 clib_error_t *err = 0;
596 socklen_t len = 0;
597
Dave Barachb7b92992018-10-17 10:38:51 -0400598 clib_memset (client, 0, sizeof (client[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599
600 /* Accept the new socket connection. */
601 client->fd = accept (server->fd, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400602 if (client->fd < 0)
Dave Wallace70ec09d2017-09-06 16:45:04 -0400603 return clib_error_return_unix (0, "accept (fd %d, '%s')",
604 server->fd, server->config);
Dave Barachc3799992016-08-15 11:12:27 -0400605
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606 /* Set the new socket to be non-blocking. */
607 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
608 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400609 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
610 client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700611 goto close_client;
612 }
Dave Barachc3799992016-08-15 11:12:27 -0400613
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614 /* Get peer info. */
615 len = sizeof (client->peer);
616 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
617 {
Dave Wallace70ec09d2017-09-06 16:45:04 -0400618 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619 goto close_client;
620 }
621
Damjan Marionf49921f2017-09-11 16:52:11 +0200622 client->flags = CLIB_SOCKET_F_IS_CLIENT;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
624 socket_init_funcs (client);
625 return 0;
626
Dave Barachc3799992016-08-15 11:12:27 -0400627close_client:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 close (client->fd);
629 return err;
630}
Dave Barachc3799992016-08-15 11:12:27 -0400631
632/*
633 * fd.io coding-style-patch-verification: ON
634 *
635 * Local Variables:
636 * eval: (c-set-style "gnu")
637 * End:
638 */