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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
39 #include <string.h> /* strchr */
42 #include <sys/types.h>
43 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
52 #include <vppinfra/mem.h>
53 #include <vppinfra/vec.h>
54 #include <vppinfra/socket.h>
55 #include <vppinfra/linux/netns.h>
56 #include <vppinfra/format.h>
57 #include <vppinfra/error.h>
60 /* IPPORT_USERRESERVED is not part of musl libc. */
61 #define IPPORT_USERRESERVED 5000
65 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
69 clib_socket_tx_add_va_formatted (s, fmt, &va);
73 /* Return and bind to an unused port. */
75 find_free_port (word sock)
79 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
83 clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
85 a.sin_family = PF_INET;
86 a.sin_addr.s_addr = INADDR_ANY;
87 a.sin_port = htons (port);
89 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
93 return port < 1 << 16 ? port : -1;
96 /* Convert a config string to a struct sockaddr and length for use
97 with bind or connect. */
99 socket_config (char *config,
100 void *addr, socklen_t * addr_len, u32 ip4_default_address)
102 clib_error_t *error = 0;
107 /* Anything that begins with a / is a local PF_LOCAL socket. */
108 if (config[0] == '/')
110 struct sockaddr_un *su = addr;
111 su->sun_family = PF_LOCAL;
112 clib_memcpy (&su->sun_path, config,
113 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
114 *addr_len = sizeof (su[0]);
117 /* Treat everything that starts with @ as an abstract socket. */
118 else if (config[0] == '@')
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)));
125 *addr_len = sizeof (su->sun_family) + strlen (config);
126 su->sun_path[0] = '\0';
129 /* Hostname or hostname:port or port. */
134 struct sockaddr_in *sa = addr;
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))
146 else if (unformat (&i, "%s", &host_name))
149 error = clib_error_return (0, "unknown input `%U'",
150 format_unformat_error, &i);
157 sa->sin_family = PF_INET;
158 *addr_len = sizeof (sa[0]);
160 sa->sin_port = htons (port);
166 struct in_addr host_addr;
168 /* Recognize localhost to avoid host lookup in most common cast. */
169 if (!strcmp (host_name, "localhost"))
170 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
172 else if (inet_aton (host_name, &host_addr))
173 sa->sin_addr = host_addr;
175 else if (host_name && strlen (host_name) > 0)
177 struct hostent *host = gethostbyname (host_name);
179 error = clib_error_return (0, "unknown host `%s'", config);
181 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
186 sa->sin_addr.s_addr = htonl (ip4_default_address);
188 vec_free (host_name);
198 static clib_error_t *
199 default_socket_write (clib_socket_t * s)
201 clib_error_t *err = 0;
208 /* Map standard input to standard output.
209 Typically, fd is a socket for which read/write both work. */
213 tx_len = vec_len (s->tx_buffer);
214 written = write (fd, s->tx_buffer, tx_len);
216 /* Ignore certain errors. */
217 if (written < 0 && !unix_error_is_fatal (errno))
220 /* A "real" error occurred. */
223 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
224 tx_len, s->fd, s->config);
225 vec_free (s->tx_buffer);
229 /* Reclaim the transmitted part of the tx buffer on successful writes. */
230 else if (written > 0)
232 if (written == tx_len)
233 _vec_len (s->tx_buffer) = 0;
235 vec_delete (s->tx_buffer, written, 0);
238 /* If a non-fatal error occurred AND
239 the buffer is full, then we must free it. */
240 else if (written == 0 && tx_len > 64 * 1024)
242 vec_free (s->tx_buffer);
249 static clib_error_t *
250 default_socket_read (clib_socket_t * sock, int n_bytes)
255 /* RX side of socket is down once end of file is reached. */
256 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
261 n_bytes = clib_max (n_bytes, 4096);
262 vec_add2 (sock->rx_buffer, buf, n_bytes);
264 if ((n_read = read (fd, buf, n_bytes)) < 0)
268 /* Ignore certain errors. */
269 if (!unix_error_is_fatal (errno))
272 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
273 n_bytes, sock->fd, sock->config);
276 /* Other side closed the socket. */
278 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
281 _vec_len (sock->rx_buffer) += n_read - n_bytes;
286 static clib_error_t *
287 default_socket_close (clib_socket_t * s)
289 if (close (s->fd) < 0)
290 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
294 static clib_error_t *
295 default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
296 int fds[], int num_fds)
298 struct msghdr mh = { 0 };
300 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
303 iov[0].iov_base = msg;
304 iov[0].iov_len = msglen;
310 struct cmsghdr *cmsg;
311 clib_memset (&ctl, 0, sizeof (ctl));
312 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);
320 rv = sendmsg (s->fd, &mh, 0);
322 return clib_error_return_unix (0, "sendmsg");
327 static clib_error_t *
328 default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
329 int fds[], int num_fds)
332 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
333 CMSG_SPACE (sizeof (struct ucred))];
334 struct ucred *cr = 0;
336 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
338 struct msghdr mh = { 0 };
341 struct cmsghdr *cmsg;
343 iov[0].iov_base = msg;
344 iov[0].iov_len = msglen;
347 mh.msg_control = ctl;
348 mh.msg_controllen = sizeof (ctl);
350 clib_memset (ctl, 0, sizeof (ctl));
352 /* receive the incoming message */
353 size = recvmsg (s->fd, &mh, 0);
356 return (size == 0) ? clib_error_return (0, "disconnected") :
357 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
361 cmsg = CMSG_FIRSTHDR (&mh);
364 if (cmsg->cmsg_level == SOL_SOCKET)
367 if (cmsg->cmsg_type == SCM_CREDENTIALS)
369 cr = (struct ucred *) CMSG_DATA (cmsg);
376 if (cmsg->cmsg_type == SCM_RIGHTS)
378 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
379 num_fds * sizeof (int));
382 cmsg = CMSG_NXTHDR (&mh, cmsg);
388 socket_init_funcs (clib_socket_t * s)
391 s->write_func = default_socket_write;
393 s->read_func = default_socket_read;
395 s->close_func = default_socket_close;
396 if (!s->sendmsg_func)
397 s->sendmsg_func = default_socket_sendmsg;
398 if (!s->recvmsg_func)
399 s->recvmsg_func = default_socket_recvmsg;
402 __clib_export clib_error_t *
403 clib_socket_init (clib_socket_t * s)
408 struct sockaddr_un su;
410 socklen_t addr_len = 0;
412 clib_error_t *error = 0;
415 error = socket_config (s->config, &addr.sa, &addr_len,
416 (s->flags & CLIB_SOCKET_F_IS_SERVER
417 ? INADDR_LOOPBACK : INADDR_ANY));
421 socket_init_funcs (s);
423 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
424 SOCK_SEQPACKET : SOCK_STREAM;
426 s->fd = socket (addr.sa.sa_family, socket_type, 0);
429 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
435 if (addr.sa.sa_family == PF_INET)
436 port = ((struct sockaddr_in *) &addr)->sin_port;
438 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
442 if (addr.sa.sa_family == PF_INET)
446 port = find_free_port (s->fd);
449 error = clib_error_return (0, "no free port (fd %d, '%s')",
456 if (addr.sa.sa_family == PF_LOCAL &&
457 ((struct sockaddr_un *) &addr)->sun_path[0] != 0)
458 unlink (((struct sockaddr_un *) &addr)->sun_path);
460 /* Make address available for multiple users. */
463 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
464 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
468 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
471 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
473 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
474 "fd %d, '%s')", s->fd,
481 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
483 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
488 if (listen (s->fd, 5) < 0)
490 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
494 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)
498 struct stat st = { 0 };
499 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
501 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
505 st.st_mode |= S_IWGRP;
506 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
510 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
511 s->fd, s->config, st.st_mode);
518 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
519 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
521 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
526 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
529 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
530 errno == EINPROGRESS))
532 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
536 /* Connect was blocking so set fd to non-blocking now unless
537 * blocking mode explicitly requested. */
538 if (!(s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
539 !(s->flags & CLIB_SOCKET_F_BLOCKING) &&
540 fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
542 error = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
556 __clib_export clib_error_t *
557 clib_socket_init_netns (clib_socket_t *s, u8 *namespace)
559 if (namespace == NULL || namespace[0] == 0)
560 return clib_socket_init (s);
563 int old_netns_fd, nfd = -1;
565 old_netns_fd = clib_netns_open (NULL /* self */);
566 if (old_netns_fd < 0)
567 return clib_error_return_unix (0, "get current netns failed");
569 if ((nfd = clib_netns_open (namespace)) == -1)
571 error = clib_error_return_unix (0, "clib_netns_open '%s'", namespace);
575 if (clib_setns (nfd) == -1)
577 error = clib_error_return_unix (0, "setns '%s'", namespace);
581 error = clib_socket_init (s);
584 if (clib_setns (old_netns_fd) == -1)
585 clib_warning ("Cannot set old ns");
587 close (old_netns_fd);
595 __clib_export clib_error_t *
596 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
598 clib_error_t *err = 0;
601 clib_memset (client, 0, sizeof (client[0]));
603 /* Accept the new socket connection. */
604 client->fd = accept (server->fd, 0, 0);
606 return clib_error_return_unix (0, "accept (fd %d, '%s')",
607 server->fd, server->config);
609 /* Set the new socket to be non-blocking. */
610 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
612 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
618 len = sizeof (client->peer);
619 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
621 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
625 client->flags = CLIB_SOCKET_F_IS_CLIENT;
627 socket_init_funcs (client);
636 * fd.io coding-style-patch-verification: ON
639 * eval: (c-set-style "gnu")