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 */
41 #include <sys/types.h>
42 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
51 #include <vppinfra/mem.h>
52 #include <vppinfra/vec.h>
53 #include <vppinfra/socket.h>
54 #include <vppinfra/format.h>
55 #include <vppinfra/error.h>
58 clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
62 clib_socket_tx_add_va_formatted (s, fmt, &va);
66 /* Return and bind to an unused port. */
68 find_free_port (word sock)
72 for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
76 clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
78 a.sin_family = PF_INET;
79 a.sin_addr.s_addr = INADDR_ANY;
80 a.sin_port = htons (port);
82 if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
86 return port < 1 << 16 ? port : -1;
89 /* Convert a config string to a struct sockaddr and length for use
90 with bind or connect. */
92 socket_config (char *config,
93 void *addr, socklen_t * addr_len, u32 ip4_default_address)
95 clib_error_t *error = 0;
100 /* Anything that begins with a / is a local PF_LOCAL socket. */
101 if (config[0] == '/')
103 struct sockaddr_un *su = addr;
104 su->sun_family = PF_LOCAL;
105 clib_memcpy (&su->sun_path, config,
106 clib_min (sizeof (su->sun_path), 1 + strlen (config)));
107 *addr_len = sizeof (su[0]);
110 /* Hostname or hostname:port or port. */
115 struct sockaddr_in *sa = addr;
123 unformat_init_string (&i, config, strlen (config));
124 if (unformat (&i, "%s:%d", &host_name, &port)
125 || unformat (&i, "%s:0x%x", &host_name, &port))
127 else if (unformat (&i, "%s", &host_name))
130 error = clib_error_return (0, "unknown input `%U'",
131 format_unformat_error, &i);
138 sa->sin_family = PF_INET;
139 *addr_len = sizeof (sa[0]);
141 sa->sin_port = htons (port);
147 struct in_addr host_addr;
149 /* Recognize localhost to avoid host lookup in most common cast. */
150 if (!strcmp (host_name, "localhost"))
151 sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
153 else if (inet_aton (host_name, &host_addr))
154 sa->sin_addr = host_addr;
156 else if (host_name && strlen (host_name) > 0)
158 struct hostent *host = gethostbyname (host_name);
160 error = clib_error_return (0, "unknown host `%s'", config);
162 clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
167 sa->sin_addr.s_addr = htonl (ip4_default_address);
169 vec_free (host_name);
179 static clib_error_t *
180 default_socket_write (clib_socket_t * s)
182 clib_error_t *err = 0;
189 /* Map standard input to standard output.
190 Typically, fd is a socket for which read/write both work. */
194 tx_len = vec_len (s->tx_buffer);
195 written = write (fd, s->tx_buffer, tx_len);
197 /* Ignore certain errors. */
198 if (written < 0 && !unix_error_is_fatal (errno))
201 /* A "real" error occurred. */
204 err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
205 tx_len, s->fd, s->config);
206 vec_free (s->tx_buffer);
210 /* Reclaim the transmitted part of the tx buffer on successful writes. */
211 else if (written > 0)
213 if (written == tx_len)
214 _vec_len (s->tx_buffer) = 0;
216 vec_delete (s->tx_buffer, written, 0);
219 /* If a non-fatal error occurred AND
220 the buffer is full, then we must free it. */
221 else if (written == 0 && tx_len > 64 * 1024)
223 vec_free (s->tx_buffer);
230 static clib_error_t *
231 default_socket_read (clib_socket_t * sock, int n_bytes)
236 /* RX side of socket is down once end of file is reached. */
237 if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
242 n_bytes = clib_max (n_bytes, 4096);
243 vec_add2 (sock->rx_buffer, buf, n_bytes);
245 if ((n_read = read (fd, buf, n_bytes)) < 0)
249 /* Ignore certain errors. */
250 if (!unix_error_is_fatal (errno))
253 return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
254 n_bytes, sock->fd, sock->config);
257 /* Other side closed the socket. */
259 sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
262 _vec_len (sock->rx_buffer) += n_read - n_bytes;
267 static clib_error_t *
268 default_socket_close (clib_socket_t * s)
270 if (close (s->fd) < 0)
271 return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
275 static clib_error_t *
276 default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
277 int fds[], int num_fds)
279 struct msghdr mh = { 0 };
281 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
284 iov[0].iov_base = msg;
285 iov[0].iov_len = msglen;
291 struct cmsghdr *cmsg;
292 clib_memset (&ctl, 0, sizeof (ctl));
293 mh.msg_control = ctl;
294 mh.msg_controllen = sizeof (ctl);
295 cmsg = CMSG_FIRSTHDR (&mh);
296 cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
297 cmsg->cmsg_level = SOL_SOCKET;
298 cmsg->cmsg_type = SCM_RIGHTS;
299 memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
301 rv = sendmsg (s->fd, &mh, 0);
303 return clib_error_return_unix (0, "sendmsg");
308 static clib_error_t *
309 default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
310 int fds[], int num_fds)
313 char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
314 CMSG_SPACE (sizeof (struct ucred))];
315 struct ucred *cr = 0;
317 char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
319 struct msghdr mh = { 0 };
322 struct cmsghdr *cmsg;
324 iov[0].iov_base = msg;
325 iov[0].iov_len = msglen;
328 mh.msg_control = ctl;
329 mh.msg_controllen = sizeof (ctl);
331 clib_memset (ctl, 0, sizeof (ctl));
333 /* receive the incoming message */
334 size = recvmsg (s->fd, &mh, 0);
337 return (size == 0) ? clib_error_return (0, "disconnected") :
338 clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
342 cmsg = CMSG_FIRSTHDR (&mh);
345 if (cmsg->cmsg_level == SOL_SOCKET)
348 if (cmsg->cmsg_type == SCM_CREDENTIALS)
350 cr = (struct ucred *) CMSG_DATA (cmsg);
357 if (cmsg->cmsg_type == SCM_RIGHTS)
359 clib_memcpy_fast (fds, CMSG_DATA (cmsg),
360 num_fds * sizeof (int));
363 cmsg = CMSG_NXTHDR (&mh, cmsg);
369 socket_init_funcs (clib_socket_t * s)
372 s->write_func = default_socket_write;
374 s->read_func = default_socket_read;
376 s->close_func = default_socket_close;
377 if (!s->sendmsg_func)
378 s->sendmsg_func = default_socket_sendmsg;
379 if (!s->recvmsg_func)
380 s->recvmsg_func = default_socket_recvmsg;
384 clib_socket_init (clib_socket_t * s)
389 struct sockaddr_un su;
391 socklen_t addr_len = 0;
393 clib_error_t *error = 0;
396 error = socket_config (s->config, &addr.sa, &addr_len,
397 (s->flags & CLIB_SOCKET_F_IS_SERVER
398 ? INADDR_LOOPBACK : INADDR_ANY));
402 socket_init_funcs (s);
404 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
405 SOCK_SEQPACKET : SOCK_STREAM;
407 s->fd = socket (addr.sa.sa_family, socket_type, 0);
410 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
416 if (addr.sa.sa_family == PF_INET)
417 port = ((struct sockaddr_in *) &addr)->sin_port;
419 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
423 if (addr.sa.sa_family == PF_INET)
427 port = find_free_port (s->fd);
430 error = clib_error_return (0, "no free port (fd %d, '%s')",
437 if (addr.sa.sa_family == PF_LOCAL)
438 unlink (((struct sockaddr_un *) &addr)->sun_path);
440 /* Make address available for multiple users. */
443 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
444 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
448 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
451 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
453 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
454 "fd %d, '%s')", s->fd,
461 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
463 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
468 if (listen (s->fd, 5) < 0)
470 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
474 if (addr.sa.sa_family == PF_LOCAL
475 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
477 struct stat st = { 0 };
478 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
480 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
484 st.st_mode |= S_IWGRP;
485 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
489 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
490 s->fd, s->config, st.st_mode);
497 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
498 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
500 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
505 while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
508 if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
509 errno == EINPROGRESS))
511 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
526 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
528 clib_error_t *err = 0;
531 clib_memset (client, 0, sizeof (client[0]));
533 /* Accept the new socket connection. */
534 client->fd = accept (server->fd, 0, 0);
536 return clib_error_return_unix (0, "accept (fd %d, '%s')",
537 server->fd, server->config);
539 /* Set the new socket to be non-blocking. */
540 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
542 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
548 len = sizeof (client->peer);
549 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
551 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
555 client->flags = CLIB_SOCKET_F_IS_CLIENT;
557 socket_init_funcs (client);
566 * fd.io coding-style-patch-verification: ON
569 * eval: (c-set-style "gnu")