FD.io VPP  v21.06-3-gbb25fbf28
Vector Packet Processing
socket.c
Go to the documentation of this file.
1 /*
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 
38 #include <stdio.h>
39 #include <string.h> /* strchr */
40 #define __USE_GNU
41 #define _GNU_SOURCE
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 
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>
57 
58 #ifndef __GLIBC__
59 /* IPPORT_USERRESERVED is not part of musl libc. */
60 #define IPPORT_USERRESERVED 5000
61 #endif
62 
63 __clib_export void
65 {
66  va_list va;
67  va_start (va, fmt);
69  va_end (va);
70 }
71 
72 /* Return and bind to an unused port. */
73 static word
75 {
76  word port;
77 
78  for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
79  {
80  struct sockaddr_in a;
81 
82  clib_memset (&a, 0, sizeof (a)); /* Warnings be gone */
83 
84  a.sin_family = PF_INET;
85  a.sin_addr.s_addr = INADDR_ANY;
86  a.sin_port = htons (port);
87 
88  if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
89  break;
90  }
91 
92  return port < 1 << 16 ? port : -1;
93 }
94 
95 /* Convert a config string to a struct sockaddr and length for use
96  with bind or connect. */
97 static clib_error_t *
98 socket_config (char *config,
99  void *addr, socklen_t * addr_len, u32 ip4_default_address)
100 {
101  clib_error_t *error = 0;
102 
103  if (!config)
104  config = "";
105 
106  /* Anything that begins with a / is a local PF_LOCAL socket. */
107  if (config[0] == '/')
108  {
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]);
114  }
115 
116  /* Hostname or hostname:port or port. */
117  else
118  {
119  char *host_name;
120  int port = -1;
121  struct sockaddr_in *sa = addr;
122 
123  host_name = 0;
124  port = -1;
125  if (config[0] != 0)
126  {
128 
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))
132  ;
133  else if (unformat (&i, "%s", &host_name))
134  ;
135  else
136  error = clib_error_return (0, "unknown input `%U'",
138  unformat_free (&i);
139 
140  if (error)
141  goto done;
142  }
143 
144  sa->sin_family = PF_INET;
145  *addr_len = sizeof (sa[0]);
146  if (port != -1)
147  sa->sin_port = htons (port);
148  else
149  sa->sin_port = 0;
150 
151  if (host_name)
152  {
153  struct in_addr host_addr;
154 
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);
158 
159  else if (inet_aton (host_name, &host_addr))
160  sa->sin_addr = host_addr;
161 
162  else if (host_name && strlen (host_name) > 0)
163  {
164  struct hostent *host = gethostbyname (host_name);
165  if (!host)
166  error = clib_error_return (0, "unknown host `%s'", config);
167  else
168  clib_memcpy (&sa->sin_addr.s_addr, host->h_addr_list[0],
169  host->h_length);
170  }
171 
172  else
173  sa->sin_addr.s_addr = htonl (ip4_default_address);
174 
175  vec_free (host_name);
176  if (error)
177  goto done;
178  }
179  }
180 
181 done:
182  return error;
183 }
184 
185 static clib_error_t *
187 {
188  clib_error_t *err = 0;
189  word written = 0;
190  word fd = 0;
191  word tx_len;
192 
193  fd = s->fd;
194 
195  /* Map standard input to standard output.
196  Typically, fd is a socket for which read/write both work. */
197  if (fd == 0)
198  fd = 1;
199 
200  tx_len = vec_len (s->tx_buffer);
201  written = write (fd, s->tx_buffer, tx_len);
202 
203  /* Ignore certain errors. */
204  if (written < 0 && !unix_error_is_fatal (errno))
205  written = 0;
206 
207  /* A "real" error occurred. */
208  if (written < 0)
209  {
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);
213  goto done;
214  }
215 
216  /* Reclaim the transmitted part of the tx buffer on successful writes. */
217  else if (written > 0)
218  {
219  if (written == tx_len)
220  _vec_len (s->tx_buffer) = 0;
221  else
222  vec_delete (s->tx_buffer, written, 0);
223  }
224 
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)
228  {
229  vec_free (s->tx_buffer);
230  }
231 
232 done:
233  return err;
234 }
235 
236 static clib_error_t *
238 {
239  word fd, n_read;
240  u8 *buf;
241 
242  /* RX side of socket is down once end of file is reached. */
243  if (sock->flags & CLIB_SOCKET_F_RX_END_OF_FILE)
244  return 0;
245 
246  fd = sock->fd;
247 
248  n_bytes = clib_max (n_bytes, 4096);
249  vec_add2 (sock->rx_buffer, buf, n_bytes);
250 
251  if ((n_read = read (fd, buf, n_bytes)) < 0)
252  {
253  n_read = 0;
254 
255  /* Ignore certain errors. */
256  if (!unix_error_is_fatal (errno))
257  goto non_fatal;
258 
259  return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
260  n_bytes, sock->fd, sock->config);
261  }
262 
263  /* Other side closed the socket. */
264  if (n_read == 0)
265  sock->flags |= CLIB_SOCKET_F_RX_END_OF_FILE;
266 
267 non_fatal:
268  _vec_len (sock->rx_buffer) += n_read - n_bytes;
269 
270  return 0;
271 }
272 
273 static clib_error_t *
275 {
276  if (close (s->fd) < 0)
277  return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
278  return 0;
279 }
280 
281 static clib_error_t *
282 default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
283  int fds[], int num_fds)
284 {
285  struct msghdr mh = { 0 };
286  struct iovec iov[1];
287  char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
288  int rv;
289 
290  iov[0].iov_base = msg;
291  iov[0].iov_len = msglen;
292  mh.msg_iov = iov;
293  mh.msg_iovlen = 1;
294 
295  if (num_fds > 0)
296  {
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);
306  }
307  rv = sendmsg (s->fd, &mh, 0);
308  if (rv < 0)
309  return clib_error_return_unix (0, "sendmsg");
310  return 0;
311 }
312 
313 
314 static clib_error_t *
315 default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
316  int fds[], int num_fds)
317 {
318 #ifdef __linux__
319  char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
320  CMSG_SPACE (sizeof (struct ucred))];
321  struct ucred *cr = 0;
322 #else
323  char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
324 #endif
325  struct msghdr mh = { 0 };
326  struct iovec iov[1];
327  ssize_t size;
328  struct cmsghdr *cmsg;
329 
330  iov[0].iov_base = msg;
331  iov[0].iov_len = msglen;
332  mh.msg_iov = iov;
333  mh.msg_iovlen = 1;
334  mh.msg_control = ctl;
335  mh.msg_controllen = sizeof (ctl);
336 
337  clib_memset (ctl, 0, sizeof (ctl));
338 
339  /* receive the incoming message */
340  size = recvmsg (s->fd, &mh, 0);
341  if (size != msglen)
342  {
343  return (size == 0) ? clib_error_return (0, "disconnected") :
344  clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
345  s->fd, s->config);
346  }
347 
348  cmsg = CMSG_FIRSTHDR (&mh);
349  while (cmsg)
350  {
351  if (cmsg->cmsg_level == SOL_SOCKET)
352  {
353 #ifdef __linux__
354  if (cmsg->cmsg_type == SCM_CREDENTIALS)
355  {
356  cr = (struct ucred *) CMSG_DATA (cmsg);
357  s->uid = cr->uid;
358  s->gid = cr->gid;
359  s->pid = cr->pid;
360  }
361  else
362 #endif
363  if (cmsg->cmsg_type == SCM_RIGHTS)
364  {
365  clib_memcpy_fast (fds, CMSG_DATA (cmsg),
366  num_fds * sizeof (int));
367  }
368  }
369  cmsg = CMSG_NXTHDR (&mh, cmsg);
370  }
371  return 0;
372 }
373 
374 static void
376 {
377  if (!s->write_func)
378  s->write_func = default_socket_write;
379  if (!s->read_func)
380  s->read_func = default_socket_read;
381  if (!s->close_func)
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;
387 }
388 
389 __clib_export clib_error_t *
391 {
392  union
393  {
394  struct sockaddr sa;
395  struct sockaddr_un su;
396  } addr;
397  socklen_t addr_len = 0;
398  int socket_type, rv;
399  clib_error_t *error = 0;
400  word port;
401 
402  error = socket_config (s->config, &addr.sa, &addr_len,
403  (s->flags & CLIB_SOCKET_F_IS_SERVER
404  ? INADDR_LOOPBACK : INADDR_ANY));
405  if (error)
406  goto done;
407 
408  socket_init_funcs (s);
409 
410  socket_type = s->flags & CLIB_SOCKET_F_SEQPACKET ?
411  SOCK_SEQPACKET : SOCK_STREAM;
412 
413  s->fd = socket (addr.sa.sa_family, socket_type, 0);
414  if (s->fd < 0)
415  {
416  error = clib_error_return_unix (0, "socket (fd %d, '%s')",
417  s->fd, s->config);
418  goto done;
419  }
420 
421  port = 0;
422  if (addr.sa.sa_family == PF_INET)
423  port = ((struct sockaddr_in *) &addr)->sin_port;
424 
425  if (s->flags & CLIB_SOCKET_F_IS_SERVER)
426  {
427  uword need_bind = 1;
428 
429  if (addr.sa.sa_family == PF_INET)
430  {
431  if (port == 0)
432  {
433  port = find_free_port (s->fd);
434  if (port < 0)
435  {
436  error = clib_error_return (0, "no free port (fd %d, '%s')",
437  s->fd, s->config);
438  goto done;
439  }
440  need_bind = 0;
441  }
442  }
443  if (addr.sa.sa_family == PF_LOCAL)
444  unlink (((struct sockaddr_un *) &addr)->sun_path);
445 
446  /* Make address available for multiple users. */
447  {
448  int v = 1;
449  if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof (v)) < 0)
450  clib_unix_warning ("setsockopt SO_REUSEADDR fails");
451  }
452 
453 #if __linux__
454  if (addr.sa.sa_family == PF_LOCAL && s->flags & CLIB_SOCKET_F_PASSCRED)
455  {
456  int x = 1;
457  if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &x, sizeof (x)) < 0)
458  {
459  error = clib_error_return_unix (0, "setsockopt (SO_PASSCRED, "
460  "fd %d, '%s')", s->fd,
461  s->config);
462  goto done;
463  }
464  }
465 #endif
466 
467  if (need_bind && bind (s->fd, &addr.sa, addr_len) < 0)
468  {
469  error = clib_error_return_unix (0, "bind (fd %d, '%s')",
470  s->fd, s->config);
471  goto done;
472  }
473 
474  if (listen (s->fd, 5) < 0)
475  {
476  error = clib_error_return_unix (0, "listen (fd %d, '%s')",
477  s->fd, s->config);
478  goto done;
479  }
480  if (addr.sa.sa_family == PF_LOCAL
482  {
483  struct stat st = { 0 };
484  if (stat (((struct sockaddr_un *) &addr)->sun_path, &st) < 0)
485  {
486  error = clib_error_return_unix (0, "stat (fd %d, '%s')",
487  s->fd, s->config);
488  goto done;
489  }
490  st.st_mode |= S_IWGRP;
491  if (chmod (((struct sockaddr_un *) &addr)->sun_path, st.st_mode) <
492  0)
493  {
494  error =
495  clib_error_return_unix (0, "chmod (fd %d, '%s', mode %o)",
496  s->fd, s->config, st.st_mode);
497  goto done;
498  }
499  }
500  }
501  else
502  {
503  if ((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT)
504  && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
505  {
506  error = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
507  s->fd, s->config);
508  goto done;
509  }
510 
511  while ((rv = connect (s->fd, &addr.sa, addr_len)) < 0
512  && errno == EAGAIN)
513  ;
514  if (rv < 0 && !((s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
515  errno == EINPROGRESS))
516  {
517  error = clib_error_return_unix (0, "connect (fd %d, '%s')",
518  s->fd, s->config);
519  goto done;
520  }
521  /* Connect was blocking so set fd to non-blocking now unless
522  * blocking mode explicitly requested. */
523  if (!(s->flags & CLIB_SOCKET_F_NON_BLOCKING_CONNECT) &&
524  !(s->flags & CLIB_SOCKET_F_BLOCKING) &&
525  fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
526  {
527  error = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
528  s->fd, s->config);
529  goto done;
530  }
531  }
532 
533  return error;
534 
535 done:
536  if (s->fd > 0)
537  close (s->fd);
538  return error;
539 }
540 
541 __clib_export clib_error_t *
543 {
544  clib_error_t *err = 0;
545  socklen_t len = 0;
546 
547  clib_memset (client, 0, sizeof (client[0]));
548 
549  /* Accept the new socket connection. */
550  client->fd = accept (server->fd, 0, 0);
551  if (client->fd < 0)
552  return clib_error_return_unix (0, "accept (fd %d, '%s')",
553  server->fd, server->config);
554 
555  /* Set the new socket to be non-blocking. */
556  if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
557  {
558  err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
559  client->fd);
560  goto close_client;
561  }
562 
563  /* Get peer info. */
564  len = sizeof (client->peer);
565  if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
566  {
567  err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
568  goto close_client;
569  }
570 
571  client->flags = CLIB_SOCKET_F_IS_CLIENT;
572 
573  socket_init_funcs (client);
574  return 0;
575 
576 close_client:
577  close (client->fd);
578  return err;
579 }
580 
581 /*
582  * fd.io coding-style-patch-verification: ON
583  *
584  * Local Variables:
585  * eval: (c-set-style "gnu")
586  * End:
587  */
CLIB_SOCKET_F_IS_SERVER
#define CLIB_SOCKET_F_IS_SERVER
Definition: socket.h:58
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
default_socket_write
static clib_error_t * default_socket_write(clib_socket_t *s)
Definition: socket.c:186
default_socket_recvmsg
static clib_error_t * default_socket_recvmsg(clib_socket_t *s, void *msg, int msglen, int fds[], int num_fds)
Definition: socket.c:315
clib_max
#define clib_max(x, y)
Definition: clib.h:335
CLIB_SOCKET_F_IS_CLIENT
#define CLIB_SOCKET_F_IS_CLIENT
Definition: socket.h:59
unix_error_is_fatal
static word unix_error_is_fatal(word error)
Definition: error.h:118
string.h
clib_error_return
#define clib_error_return(e, args...)
Definition: error.h:99
clib_socket_tx_add_va_formatted
static void clib_socket_tx_add_va_formatted(clib_socket_t *s, char *fmt, va_list *va)
Definition: socket.h:133
vec_delete
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:875
port
u16 port
Definition: lb_types.api:73
unformat_input_t
struct _unformat_input_t unformat_input_t
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
clib_unix_warning
#define clib_unix_warning(format, args...)
Definition: error.h:68
error
Definition: cJSON.c:88
CLIB_SOCKET_F_BLOCKING
#define CLIB_SOCKET_F_BLOCKING
Definition: socket.h:65
unformat
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
vhost_vring_addr_t::flags
u32 flags
Definition: vhost_std.h:48
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
unformat_free
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
len
u8 len
Definition: ip_types.api:103
error.h
vec_add2
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:644
clib_socket_tx_add_formatted
__clib_export void clib_socket_tx_add_formatted(clib_socket_t *s, char *fmt,...)
Definition: socket.c:64
default_socket_read
static clib_error_t * default_socket_read(clib_socket_t *sock, int n_bytes)
Definition: socket.c:237
uword
u64 uword
Definition: types.h:112
i
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
format_unformat_error
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
format.h
clib_min
#define clib_min(x, y)
Definition: clib.h:342
fmt
int cJSON_bool fmt
Definition: cJSON.h:160
default_socket_close
static clib_error_t * default_socket_close(clib_socket_t *s)
Definition: socket.c:274
host
description ARP replies copied to host
Definition: lcp.api:169
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
size
u32 size
Definition: vhost_user.h:125
unformat_init_string
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1029
clib_socket_init
__clib_export clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:390
buf
u64 buf
Definition: application.c:493
u32
unsigned int u32
Definition: types.h:88
n_bytes
u32 n_bytes
Definition: interface_output.c:401
CLIB_SOCKET_F_ALLOW_GROUP_WRITE
#define CLIB_SOCKET_F_ALLOW_GROUP_WRITE
Definition: socket.h:62
find_free_port
static word find_free_port(word sock)
Definition: socket.c:74
clib_error_return_unix
#define clib_error_return_unix(e, args...)
Definition: error.h:102
default_socket_sendmsg
static clib_error_t * default_socket_sendmsg(clib_socket_t *s, void *msg, int msglen, int fds[], int num_fds)
Definition: socket.c:282
socket_config
static clib_error_t * socket_config(char *config, void *addr, socklen_t *addr_len, u32 ip4_default_address)
Definition: socket.c:98
vec.h
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u8
unsigned char u8
Definition: types.h:56
clib_error_t
Definition: clib_error.h:21
a
a
Definition: bitmap.h:544
CLIB_SOCKET_F_PASSCRED
#define CLIB_SOCKET_F_PASSCRED
Definition: socket.h:64
socket_init_funcs
static void socket_init_funcs(clib_socket_t *s)
Definition: socket.c:375
word
i64 word
Definition: types.h:111
rv
int __clib_unused rv
Definition: application.c:491
mem.h
socket.h
CLIB_SOCKET_F_NON_BLOCKING_CONNECT
#define CLIB_SOCKET_F_NON_BLOCKING_CONNECT
Definition: socket.h:61
clib_socket_t
struct _socket_t clib_socket_t
CLIB_SOCKET_F_SEQPACKET
#define CLIB_SOCKET_F_SEQPACKET
Definition: socket.h:63
clib_socket_accept
__clib_export clib_error_t * clib_socket_accept(clib_socket_t *server, clib_socket_t *client)
Definition: socket.c:542
CLIB_SOCKET_F_RX_END_OF_FILE
#define CLIB_SOCKET_F_RX_END_OF_FILE
Definition: socket.h:60