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 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 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 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 (fds, CMSG_DATA (cmsg), num_fds * sizeof (int));
362 cmsg = CMSG_NXTHDR (&mh, cmsg);
368 socket_init_funcs (clib_socket_t * s)
371 s->write_func = default_socket_write;
373 s->read_func = default_socket_read;
375 s->close_func = default_socket_close;
376 if (!s->sendmsg_func)
377 s->sendmsg_func = default_socket_sendmsg;
378 if (!s->recvmsg_func)
379 s->recvmsg_func = default_socket_recvmsg;
383 clib_socket_init (clib_socket_t * s)
388 struct sockaddr_un su;
390 socklen_t addr_len = 0;
392 clib_error_t *error = 0;
395 error = socket_config (s->config, &addr.sa, &addr_len,
396 (s->flags & CLIB_SOCKET_F_IS_SERVER
397 ? INADDR_LOOPBACK : INADDR_ANY));
401 socket_init_funcs (s);
403 socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
404 SOCK_SEQPACKET : SOCK_STREAM;
406 s->fd = socket (addr.sa.sa_family, socket_type, 0);
409 error = clib_error_return_unix (0, "socket (fd %d, '%s')",
415 if (addr.sa.sa_family == PF_INET)
416 port = ((struct sockaddr_in *) &addr)->sin_port;
418 if (s->flags & CLIB_SOCKET_F_IS_SERVER)
422 if (addr.sa.sa_family == PF_INET)
426 port = find_free_port (s->fd);
429 error = clib_error_return (0, "no free port (fd %d, '%s')",
436 if (addr.sa.sa_family == PF_LOCAL)
437 unlink (((struct sockaddr_un *) &addr)->sun_path);
439 /* Make address available for multiple users. */
442 if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
443 clib_unix_warning ("setsockopt SO_REUSEADDR fails");
447 if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
450 if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
452 error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
453 "fd %d, '%s')", s->fd,
460 if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
462 error = clib_error_return_unix (0, "bind (fd %d, '%s')",
467 if (listen (s->fd, 5) < 0)
469 error = clib_error_return_unix (0, "listen (fd %d, '%s')",
473 if (addr.sa.sa_family == PF_LOCAL
474 && s->flags & CLIB_SOCKET_F_ALLOW_GROUP_WRITE)
476 struct stat st = { 0 };
477 if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
479 error = clib_error_return_unix (0, "stat (fd %d, '%s')",
483 st.st_mode |= S_IWGRP;
484 if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
488 clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
489 s->fd, s->config, st.st_mode);
496 if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
497 && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
499 error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
504 if (connect (s->fd, &addr.sa, addr_len) < 0
505 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
506 errno == EINPROGRESS))
508 error = clib_error_return_unix (0, "connect (fd %d, '%s')",
523 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
525 clib_error_t *err = 0;
528 memset (client, 0, sizeof (client[0]));
530 /* Accept the new socket connection. */
531 client->fd = accept (server->fd, 0, 0);
533 return clib_error_return_unix (0, "accept (fd %d, '%s')",
534 server->fd, server->config);
536 /* Set the new socket to be non-blocking. */
537 if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
539 err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
545 len = sizeof (client->peer);
546 if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
548 err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
552 client->flags = CLIB_SOCKET_F_IS_CLIENT;
554 socket_init_funcs (client);
563 * fd.io coding-style-patch-verification: ON
566 * eval: (c-set-style "gnu")