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