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/format.h>
56 #include <vppinfra/error.h>
59 /* IPPORT_USERRESERVED is not part of musl libc. */
60 #define IPPORT_USERRESERVED 5000
64 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
68 clib_socket_tx_add_va_formatted (s, fmt, &va);
72 /* Return and bind to an unused port. */
74 find_free_port (word sock)
78 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
82 clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
84 a.sin_family = PF_INET;
85 a.sin_addr.s_addr = INADDR_ANY;
86 a.sin_port = htons (port);
88 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
92 return port < 1 << 16 ? port : -1;
95 /* Convert a config string to a struct sockaddr and length for use
96 with bind or connect. */
98 socket_config (char *config,
99 void *addr, socklen_t * addr_len, u32 ip4_default_address)
101 clib_error_t *error = 0;
106 /* Anything that begins with a / is a local PF_LOCAL socket. */
107 if (config[0] == '/')
109 struct sockaddr_un *su = addr;
110 su->sun_family = PF_LOCAL;
111 clib_memcpy (&su->sun_path, config,
112 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
113 *addr_len = sizeof (su[0]);
116 /* Hostname or hostname:port or port. */
121 struct sockaddr_in *sa = addr;
129 unformat_init_string (&i, config, strlen (config));
130 if (unformat (&i, "%s:%d", &host_name, &port)
131 || unformat (&i, "%s:0x%x", &host_name, &port))
133 else if (unformat (&i, "%s", &host_name))
136 error = clib_error_return (0, "unknown input `%U'",
137 format_unformat_error, &i);
144 sa->sin_family = PF_INET;
145 *addr_len = sizeof (sa[0]);
147 sa->sin_port = htons (port);
153 struct in_addr host_addr;
155 /* Recognize localhost to avoid host lookup in most common cast. */
156 if (!strcmp (host_name, "localhost"))
157 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
159 else if (inet_aton (host_name, &host_addr))
160 sa->sin_addr = host_addr;
162 else if (host_name && strlen (host_name) > 0)
164 struct hostent *host = gethostbyname (host_name);
166 error = clib_error_return (0, "unknown host `%s'", config);
168 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
173 sa->sin_addr.s_addr = htonl (ip4_default_address);
175 vec_free (host_name);
185 static clib_error_t *
186 default_socket_write (clib_socket_t * s)
188 clib_error_t *err = 0;
195 /* Map standard input to standard output.
196 Typically, fd is a socket for which read/write both work. */
200 tx_len = vec_len (s->tx_buffer);
201 written = write (fd, s->tx_buffer, tx_len);
203 /* Ignore certain errors. */
204 if (written < 0 && !unix_error_is_fatal (errno))
207 /* A "real" error occurred. */
210 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
211 tx_len, s->fd, s->config);
212 vec_free (s->tx_buffer);
216 /* Reclaim the transmitted part of the tx buffer on successful writes. */
217 else if (written > 0)
219 if (written == tx_len)
220 _vec_len (s->tx_buffer) = 0;
222 vec_delete (s->tx_buffer, written, 0);
225 /* If a non-fatal error occurred AND
226 the buffer is full, then we must free it. */
227 else if (written == 0 && tx_len > 64 * 1024)
229 vec_free (s->tx_buffer);
236 static clib_error_t *
237 default_socket_read (clib_socket_t * sock, int n_bytes)
242 /* RX side of socket is down once end of file is reached. */
243 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
248 n_bytes = clib_max (n_bytes, 4096);
249 vec_add2 (sock->rx_buffer, buf, n_bytes);
251 if ((n_read = read (fd, buf, n_bytes)) < 0)
255 /* Ignore certain errors. */
256 if (!unix_error_is_fatal (errno))
259 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
260 n_bytes, sock->fd, sock->config);
263 /* Other side closed the socket. */
265 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
268 _vec_len (sock->rx_buffer) += n_read - n_bytes;
273 static clib_error_t *
274 default_socket_close (clib_socket_t * s)
276 if (close (s->fd) < 0)
277 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
281 static clib_error_t *
282 default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
283 int fds[], int num_fds)
285 struct msghdr mh = { 0 };
287 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
290 iov[0].iov_base = msg;
291 iov[0].iov_len = msglen;
297 struct cmsghdr *cmsg;
298 clib_memset (&ctl, 0, sizeof (ctl));
299 mh.msg_control = ctl;
300 mh.msg_controllen = sizeof (ctl);
301 cmsg = CMSG_FIRSTHDR (&mh);
302 cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
303 cmsg->cmsg_level = SOL_SOCKET;
304 cmsg->cmsg_type = SCM_RIGHTS;
305 memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
307 rv = sendmsg (s->fd, &mh, 0);
309 return clib_error_return_unix (0, "sendmsg");
314 static clib_error_t *
315 default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
316 int fds[], int num_fds)
319 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
320 CMSG_SPACE (sizeof (struct ucred))];
321 struct ucred *cr = 0;
323 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
325 struct msghdr mh = { 0 };
328 struct cmsghdr *cmsg;
330 iov[0].iov_base = msg;
331 iov[0].iov_len = msglen;
334 mh.msg_control = ctl;
335 mh.msg_controllen = sizeof (ctl);
337 clib_memset (ctl, 0, sizeof (ctl));
339 /* receive the incoming message */
340 size = recvmsg (s->fd, &mh, 0);
343 return (size == 0) ? clib_error_return (0, "disconnected") :
344 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
348 cmsg = CMSG_FIRSTHDR (&mh);
351 if (cmsg->cmsg_level == SOL_SOCKET)
354 if (cmsg->cmsg_type == SCM_CREDENTIALS)
356 cr = (struct ucred *) CMSG_DATA (cmsg);
363 if (cmsg->cmsg_type == SCM_RIGHTS)
365 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
366 num_fds * sizeof (int));
369 cmsg = CMSG_NXTHDR (&mh, cmsg);
375 socket_init_funcs (clib_socket_t * s)
378 s->write_func = default_socket_write;
380 s->read_func = default_socket_read;
382 s->close_func = default_socket_close;
383 if (!s->sendmsg_func)
384 s->sendmsg_func = default_socket_sendmsg;
385 if (!s->recvmsg_func)
386 s->recvmsg_func = default_socket_recvmsg;
389 __clib_export clib_error_t *
390 clib_socket_init (clib_socket_t * s)
395 struct sockaddr_un su;
397 socklen_t addr_len = 0;
399 clib_error_t *error = 0;
402 error = socket_config (s->config, &addr.sa, &addr_len,
403 (s->flags & CLIB_SOCKET_F_IS_SERVER
404 ? INADDR_LOOPBACK : INADDR_ANY));
408 socket_init_funcs (s);
410 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
411 SOCK_SEQPACKET : SOCK_STREAM;
413 s->fd = socket (addr.sa.sa_family, socket_type, 0);
416 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
422 if (addr.sa.sa_family == PF_INET)
423 port = ((struct sockaddr_in *) &addr)->sin_port;
425 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
429 if (addr.sa.sa_family == PF_INET)
433 port = find_free_port (s->fd);
436 error = clib_error_return (0, "no free port (fd %d, '%s')",
443 if (addr.sa.sa_family == PF_LOCAL)
444 unlink (((struct sockaddr_un *) &addr)->sun_path);
446 /* Make address available for multiple users. */
449 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
450 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
454 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
457 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
459 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
460 "fd %d, '%s')", s->fd,
467 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
469 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
474 if (listen (s->fd, 5) < 0)
476 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
480 if (addr.sa.sa_family == PF_LOCAL
481 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
483 struct stat st = { 0 };
484 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
486 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
490 st.st_mode |= S_IWGRP;
491 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
495 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
496 s->fd, s->config, st.st_mode);
503 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
504 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
506 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
511 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
514 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
515 errno == EINPROGRESS))
517 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
531 __clib_export clib_error_t *
532 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
534 clib_error_t *err = 0;
537 clib_memset (client, 0, sizeof (client[0]));
539 /* Accept the new socket connection. */
540 client->fd = accept (server->fd, 0, 0);
542 return clib_error_return_unix (0, "accept (fd %d, '%s')",
543 server->fd, server->config);
545 /* Set the new socket to be non-blocking. */
546 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
548 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
554 len = sizeof (client->peer);
555 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
557 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
561 client->flags = CLIB_SOCKET_F_IS_CLIENT;
563 socket_init_funcs (client);
572 * fd.io coding-style-patch-verification: ON
575 * eval: (c-set-style "gnu")