LCOV - code coverage report
Current view: top level - vppinfra - socket.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 169 344 49.1 %
Date: 2023-10-26 01:39:38 Functions: 9 13 69.2 %

          Line data    Source code
       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/linux/netns.h>
      56             : #include <vppinfra/format.h>
      57             : #include <vppinfra/error.h>
      58             : 
      59             : #ifndef __GLIBC__
      60             : /* IPPORT_USERRESERVED is not part of musl libc. */
      61             : #define IPPORT_USERRESERVED 5000
      62             : #endif
      63             : 
      64             : __clib_export void
      65           0 : clib_socket_tx_add_formatted (clib_socket_t * s, char *fmt, ...)
      66             : {
      67             :   va_list va;
      68           0 :   va_start (va, fmt);
      69           0 :   clib_socket_tx_add_va_formatted (s, fmt, &va);
      70           0 :   va_end (va);
      71           0 : }
      72             : 
      73             : /* Return and bind to an unused port. */
      74             : static word
      75           0 : find_free_port (word sock)
      76             : {
      77             :   word port;
      78             : 
      79           0 :   for (port = IPPORT_USERRESERVED; port < 1 << 16; port++)
      80             :     {
      81             :       struct sockaddr_in a;
      82             : 
      83           0 :       clib_memset (&a, 0, sizeof (a));      /* Warnings be gone */
      84             : 
      85           0 :       a.sin_family = PF_INET;
      86           0 :       a.sin_addr.s_addr = INADDR_ANY;
      87           0 :       a.sin_port = htons (port);
      88             : 
      89           0 :       if (bind (sock, (struct sockaddr *) &a, sizeof (a)) >= 0)
      90           0 :         break;
      91             :     }
      92             : 
      93           0 :   return port < 1 << 16 ? port : -1;
      94             : }
      95             : 
      96             : static clib_error_t *
      97           0 : default_socket_write (clib_socket_t * s)
      98             : {
      99           0 :   clib_error_t *err = 0;
     100           0 :   word written = 0;
     101           0 :   word fd = 0;
     102             :   word tx_len;
     103             : 
     104           0 :   fd = s->fd;
     105             : 
     106             :   /* Map standard input to standard output.
     107             :      Typically, fd is a socket for which read/write both work. */
     108           0 :   if (fd == 0)
     109           0 :     fd = 1;
     110             : 
     111           0 :   tx_len = vec_len (s->tx_buffer);
     112           0 :   written = write (fd, s->tx_buffer, tx_len);
     113             : 
     114             :   /* Ignore certain errors. */
     115           0 :   if (written < 0 && !unix_error_is_fatal (errno))
     116           0 :     written = 0;
     117             : 
     118             :   /* A "real" error occurred. */
     119           0 :   if (written < 0)
     120             :     {
     121           0 :       err = clib_error_return_unix (0, "write %wd bytes (fd %d, '%s')",
     122             :                                     tx_len, s->fd, s->config);
     123           0 :       vec_free (s->tx_buffer);
     124           0 :       goto done;
     125             :     }
     126             : 
     127             :   /* Reclaim the transmitted part of the tx buffer on successful writes. */
     128           0 :   else if (written > 0)
     129             :     {
     130           0 :       if (written == tx_len)
     131           0 :         vec_set_len (s->tx_buffer, 0);
     132             :       else
     133           0 :         vec_delete (s->tx_buffer, written, 0);
     134             :     }
     135             : 
     136             :   /* If a non-fatal error occurred AND
     137             :      the buffer is full, then we must free it. */
     138           0 :   else if (written == 0 && tx_len > 64 * 1024)
     139             :     {
     140           0 :       vec_free (s->tx_buffer);
     141             :     }
     142             : 
     143           0 : done:
     144           0 :   return err;
     145             : }
     146             : 
     147             : static clib_error_t *
     148           0 : default_socket_read (clib_socket_t * sock, int n_bytes)
     149             : {
     150             :   word fd, n_read;
     151             :   u8 *buf;
     152             : 
     153             :   /* RX side of socket is down once end of file is reached. */
     154           0 :   if (sock->rx_end_of_file)
     155           0 :     return 0;
     156             : 
     157           0 :   fd = sock->fd;
     158             : 
     159           0 :   n_bytes = clib_max (n_bytes, 4096);
     160           0 :   vec_add2 (sock->rx_buffer, buf, n_bytes);
     161             : 
     162           0 :   if ((n_read = read (fd, buf, n_bytes)) < 0)
     163             :     {
     164           0 :       n_read = 0;
     165             : 
     166             :       /* Ignore certain errors. */
     167           0 :       if (!unix_error_is_fatal (errno))
     168           0 :         goto non_fatal;
     169             : 
     170           0 :       return clib_error_return_unix (0, "read %d bytes (fd %d, '%s')",
     171             :                                      n_bytes, sock->fd, sock->config);
     172             :     }
     173             : 
     174             :   /* Other side closed the socket. */
     175           0 :   if (n_read == 0)
     176           0 :     sock->rx_end_of_file = 1;
     177             : 
     178           0 : non_fatal:
     179           0 :   vec_inc_len (sock->rx_buffer, n_read - n_bytes);
     180             : 
     181           0 :   return 0;
     182             : }
     183             : 
     184             : static clib_error_t *
     185         575 : default_socket_close (clib_socket_t * s)
     186             : {
     187         575 :   if (close (s->fd) < 0)
     188          14 :     return clib_error_return_unix (0, "close (fd %d, %s)", s->fd, s->config);
     189         561 :   return 0;
     190             : }
     191             : 
     192             : static clib_error_t *
     193         719 : default_socket_sendmsg (clib_socket_t * s, void *msg, int msglen,
     194             :                         int fds[], int num_fds)
     195         719 : {
     196         719 :   struct msghdr mh = { 0 };
     197             :   struct iovec iov[1];
     198         719 :   char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
     199             :   int rv;
     200             : 
     201         719 :   iov[0].iov_base = msg;
     202         719 :   iov[0].iov_len = msglen;
     203         719 :   mh.msg_iov = iov;
     204         719 :   mh.msg_iovlen = 1;
     205             : 
     206         719 :   if (num_fds > 0)
     207             :     {
     208             :       struct cmsghdr *cmsg;
     209         600 :       clib_memset (&ctl, 0, sizeof (ctl));
     210         600 :       mh.msg_control = ctl;
     211         600 :       mh.msg_controllen = sizeof (ctl);
     212         600 :       cmsg = CMSG_FIRSTHDR (&mh);
     213         600 :       cmsg->cmsg_len = CMSG_LEN (sizeof (int) * num_fds);
     214         600 :       cmsg->cmsg_level = SOL_SOCKET;
     215         600 :       cmsg->cmsg_type = SCM_RIGHTS;
     216         600 :       memcpy (CMSG_DATA (cmsg), fds, sizeof (int) * num_fds);
     217             :     }
     218         719 :   rv = sendmsg (s->fd, &mh, 0);
     219         719 :   if (rv < 0)
     220           6 :     return clib_error_return_unix (0, "sendmsg");
     221         713 :   return 0;
     222             : }
     223             : 
     224             : 
     225             : static clib_error_t *
     226         172 : default_socket_recvmsg (clib_socket_t * s, void *msg, int msglen,
     227             :                         int fds[], int num_fds)
     228         172 : {
     229             : #ifdef CLIB_LINUX
     230         172 :   char ctl[CMSG_SPACE (sizeof (int) * num_fds) +
     231             :            CMSG_SPACE (sizeof (struct ucred))];
     232         172 :   struct ucred *cr = 0;
     233             : #else
     234             :   char ctl[CMSG_SPACE (sizeof (int) * num_fds)];
     235             : #endif
     236         172 :   struct msghdr mh = { 0 };
     237             :   struct iovec iov[1];
     238             :   ssize_t size;
     239             :   struct cmsghdr *cmsg;
     240             : 
     241         172 :   iov[0].iov_base = msg;
     242         172 :   iov[0].iov_len = msglen;
     243         172 :   mh.msg_iov = iov;
     244         172 :   mh.msg_iovlen = 1;
     245         172 :   mh.msg_control = ctl;
     246         172 :   mh.msg_controllen = sizeof (ctl);
     247             : 
     248         172 :   clib_memset (ctl, 0, sizeof (ctl));
     249             : 
     250             :   /* receive the incoming message */
     251         172 :   size = recvmsg (s->fd, &mh, 0);
     252         172 :   if (size != msglen)
     253             :     {
     254           8 :       return (size == 0) ? clib_error_return (0, "disconnected") :
     255           0 :         clib_error_return_unix (0, "recvmsg: malformed message (fd %d, '%s')",
     256             :                                 s->fd, s->config);
     257             :     }
     258             : 
     259         164 :   cmsg = CMSG_FIRSTHDR (&mh);
     260         294 :   while (cmsg)
     261             :     {
     262         130 :       if (cmsg->cmsg_level == SOL_SOCKET)
     263             :         {
     264             : #ifdef CLIB_LINUX
     265         130 :           if (cmsg->cmsg_type == SCM_CREDENTIALS)
     266             :             {
     267          81 :               cr = (struct ucred *) CMSG_DATA (cmsg);
     268          81 :               s->uid = cr->uid;
     269          81 :               s->gid = cr->gid;
     270          81 :               s->pid = cr->pid;
     271             :             }
     272             :           else
     273             : #endif
     274          49 :           if (cmsg->cmsg_type == SCM_RIGHTS)
     275             :             {
     276          49 :               clib_memcpy_fast (fds, CMSG_DATA (cmsg),
     277             :                                 num_fds * sizeof (int));
     278             :             }
     279             :         }
     280         130 :       cmsg = CMSG_NXTHDR (&mh, cmsg);
     281             :     }
     282         164 :   return 0;
     283             : }
     284             : 
     285             : static void
     286        3008 : socket_init_funcs (clib_socket_t * s)
     287             : {
     288        3008 :   if (!s->write_func)
     289        3008 :     s->write_func = default_socket_write;
     290        3008 :   if (!s->read_func)
     291        3008 :     s->read_func = default_socket_read;
     292        3008 :   if (!s->close_func)
     293        3008 :     s->close_func = default_socket_close;
     294        3008 :   if (!s->sendmsg_func)
     295        3008 :     s->sendmsg_func = default_socket_sendmsg;
     296        3008 :   if (!s->recvmsg_func)
     297        3008 :     s->recvmsg_func = default_socket_recvmsg;
     298        3008 : }
     299             : 
     300             : static const struct
     301             : {
     302             :   char *prefix;
     303             :   sa_family_t family;
     304             :   clib_socket_type_t type;
     305             :   u16 skip_prefix : 1;
     306             :   u16 is_local : 1;
     307             : } clib_socket_type_data[] = {
     308             :   { .prefix = "unix:",
     309             :     .family = AF_UNIX,
     310             :     .type = CLIB_SOCKET_TYPE_UNIX,
     311             :     .skip_prefix = 1,
     312             :     .is_local = 1 },
     313             :   { .prefix = "tcp:",
     314             :     .family = AF_INET,
     315             :     .type = CLIB_SOCKET_TYPE_INET,
     316             :     .skip_prefix = 1 },
     317             :   { .prefix = "abstract:",
     318             :     .family = AF_UNIX,
     319             :     .type = CLIB_SOCKET_TYPE_LINUX_ABSTRACT,
     320             :     .skip_prefix = 1,
     321             :     .is_local = 1 },
     322             :   { .prefix = "/",
     323             :     .family = AF_UNIX,
     324             :     .type = CLIB_SOCKET_TYPE_UNIX,
     325             :     .skip_prefix = 0,
     326             :     .is_local = 1 },
     327             :   { .prefix = "",
     328             :     .family = AF_INET,
     329             :     .type = CLIB_SOCKET_TYPE_INET,
     330             :     .skip_prefix = 0,
     331             :     .is_local = 0 },
     332             :   { .prefix = "",
     333             :     .family = AF_UNIX,
     334             :     .type = CLIB_SOCKET_TYPE_UNIX,
     335             :     .skip_prefix = 0,
     336             :     .is_local = 1 },
     337             : };
     338             : 
     339             : static u8 *
     340        1820 : _clib_socket_get_string (char **p, int is_hostname)
     341             : {
     342        1820 :   u8 *s = 0;
     343       98464 :   while (**p)
     344             :     {
     345       96644 :       switch (**p)
     346             :         {
     347        3892 :         case '_':
     348        3892 :           if (is_hostname)
     349           0 :             return s;
     350             :         case 'a' ... 'z':
     351             :         case 'A' ... 'Z':
     352             :         case '0' ... '9':
     353             :         case '/':
     354             :         case '-':
     355             :         case '.':
     356       96644 :           vec_add1 (s, **p);
     357       96644 :           (*p)++;
     358       96644 :           break;
     359             :           break;
     360           0 :         default:
     361           0 :           return s;
     362             :         }
     363             :     }
     364        1820 :   return s;
     365             : }
     366             : 
     367             : __clib_export int
     368         590 : clib_socket_prefix_is_valid (char *s)
     369             : {
     370         590 :   for (typeof (clib_socket_type_data[0]) *d = clib_socket_type_data;
     371        4130 :        d - clib_socket_type_data < ARRAY_LEN (clib_socket_type_data); d++)
     372        3540 :     if (d->skip_prefix && strncmp (s, d->prefix, strlen (d->prefix)) == 0)
     373           0 :       return 1;
     374         590 :   return 0;
     375             : }
     376             : 
     377             : __clib_export int
     378          70 : clib_socket_prefix_get_type (char *s)
     379             : {
     380          70 :   for (typeof (clib_socket_type_data[0]) *d = clib_socket_type_data;
     381         280 :        d - clib_socket_type_data < ARRAY_LEN (clib_socket_type_data); d++)
     382         280 :     if (strncmp (s, d->prefix, strlen (d->prefix)) == 0)
     383          70 :       return d->type;
     384           0 :   return 0;
     385             : }
     386             : 
     387             : __clib_export clib_error_t *
     388        1820 : clib_socket_init (clib_socket_t *s)
     389             : {
     390        1820 :   struct sockaddr_un su = { .sun_family = AF_UNIX };
     391        1820 :   struct sockaddr_in si = { .sin_family = AF_INET };
     392        1820 :   struct sockaddr *sa = 0;
     393        1820 :   typeof (clib_socket_type_data[0]) *data = 0;
     394        1820 :   socklen_t addr_len = 0;
     395             :   int rv;
     396             :   char *p;
     397        1820 :   clib_error_t *err = 0;
     398        1820 :   u8 *name = 0;
     399        1820 :   u16 port = 0;
     400             : #if CLIB_LINUX
     401        1820 :   int netns_fd = -1;
     402             : #endif
     403             : 
     404        1820 :   s->fd = -1;
     405             : 
     406        1820 :   if (!s->config)
     407           0 :     s->config = "";
     408             : 
     409        7280 :   for (int i = 0; i < ARRAY_LEN (clib_socket_type_data); i++)
     410             :     {
     411        7280 :       typeof (clib_socket_type_data[0]) *d = clib_socket_type_data + i;
     412             : 
     413        7280 :       if (d->is_local == 0 && s->local_only)
     414          11 :         continue;
     415             : 
     416        7269 :       if (strncmp (s->config, d->prefix, strlen (d->prefix)) == 0)
     417             :         {
     418        1820 :           data = d;
     419        1820 :           break;
     420             :         }
     421             :     }
     422             : 
     423        1820 :   if (data == 0)
     424           0 :     return clib_error_return (0, "unsupported socket config '%s'", s->config);
     425             : 
     426        1820 :   s->type = data->type;
     427        1820 :   p = s->config + (data->skip_prefix ? strlen (data->prefix) : 0);
     428             : 
     429        1820 :   name = _clib_socket_get_string (&p, data->type == CLIB_SOCKET_TYPE_INET);
     430        1820 :   vec_add1 (name, 0);
     431             : 
     432             :   /* parse port type for INET sockets */
     433        1820 :   if (data->type == CLIB_SOCKET_TYPE_INET && p[0] == ':')
     434             :     {
     435           0 :       char *old_p = p + 1;
     436           0 :       long long ll = strtoll (old_p, &p, 0);
     437             : 
     438           0 :       if (p == old_p)
     439             :         {
     440           0 :           err = clib_error_return (0, "invalid port");
     441           0 :           goto done;
     442             :         }
     443             : 
     444           0 :       if (ll > CLIB_U16_MAX || ll < 1)
     445             :         {
     446           0 :           err = clib_error_return (0, "port out of range");
     447           0 :           goto done;
     448             :         }
     449           0 :       port = ll;
     450             :     }
     451             : 
     452        1820 :   while (p[0] == ',')
     453             :     {
     454           0 :       p++;
     455             :       if (0)
     456             :         ;
     457             : #if CLIB_LINUX
     458           0 :       else if (s->type == CLIB_SOCKET_TYPE_LINUX_ABSTRACT && netns_fd == -1 &&
     459           0 :                strncmp (p, "netns_name=", 11) == 0)
     460           0 :         {
     461           0 :           p += 11;
     462           0 :           u8 *str = _clib_socket_get_string (&p, 0);
     463           0 :           u8 *pathname = 0;
     464           0 :           if (str[0] == '/')
     465           0 :             pathname = format (0, "%v%c", str, 0);
     466             :           else
     467           0 :             pathname = format (0, "/var/run/netns/%v%c", str, 0);
     468           0 :           if ((netns_fd = open ((char *) pathname, O_RDONLY)) < 0)
     469           0 :             err = clib_error_return_unix (0, "open('%s')", pathname);
     470           0 :           vec_free (str);
     471           0 :           vec_free (pathname);
     472           0 :           if (err)
     473           0 :             goto done;
     474             :         }
     475           0 :       else if (s->type == CLIB_SOCKET_TYPE_LINUX_ABSTRACT && netns_fd == -1 &&
     476           0 :                strncmp (p, "netns_pid=", 10) == 0)
     477             :         {
     478           0 :           char *old_p = p = p + 10;
     479           0 :           u32 pid = (u32) strtol (old_p, &p, 0);
     480             : 
     481           0 :           if (p == old_p)
     482           0 :             err = clib_error_return (0, "invalid pid");
     483             :           else
     484             :             {
     485           0 :               u8 *pathname = format (0, "/proc/%u/ns/net%c", pid, 0);
     486           0 :               if ((netns_fd = open ((char *) pathname, O_RDONLY)) < 0)
     487           0 :                 err = clib_error_return_unix (0, "open('%s')", pathname);
     488           0 :               vec_free (pathname);
     489             :             }
     490           0 :           if (err)
     491           0 :             goto done;
     492             :         }
     493             : #endif
     494             :       else
     495             :         break;
     496             :     }
     497             : 
     498        1820 :   if (p[0] != 0)
     499             :     {
     500           0 :       err = clib_error_return (0, "unknown input `%s'", p);
     501           0 :       goto done;
     502             :     }
     503             : 
     504             : #if CLIB_LINUX
     505             :   /* change netns if requested */
     506        1820 :   if (s->type != CLIB_SOCKET_TYPE_INET && netns_fd != -1)
     507             :     {
     508           0 :       int fd = open ("/proc/self/ns/net", O_RDONLY);
     509             : 
     510           0 :       if (setns (netns_fd, CLONE_NEWNET) < 0)
     511             :         {
     512           0 :           close (fd);
     513           0 :           err = clib_error_return_unix (0, "setns(%d)", netns_fd);
     514           0 :           goto done;
     515             :         }
     516           0 :       netns_fd = fd;
     517             :     }
     518             : #endif
     519             : 
     520        1820 :   if (s->type == CLIB_SOCKET_TYPE_INET)
     521             :     {
     522           0 :       addr_len = sizeof (si);
     523           0 :       si.sin_port = htons (port);
     524             : 
     525           0 :       if (name)
     526             :         {
     527             :           struct in_addr host_addr;
     528           0 :           vec_add1 (name, 0);
     529             : 
     530             :           /* Recognize localhost to avoid host lookup in most common cast. */
     531           0 :           if (!strcmp ((char *) name, "localhost"))
     532           0 :             si.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
     533             : 
     534           0 :           else if (inet_aton ((char *) name, &host_addr))
     535           0 :             si.sin_addr = host_addr;
     536             : 
     537           0 :           else if (strlen ((char *) name) > 0)
     538             :             {
     539           0 :               struct hostent *host = gethostbyname ((char *) name);
     540           0 :               if (!host)
     541           0 :                 err = clib_error_return (0, "unknown host `%s'", name);
     542             :               else
     543           0 :                 clib_memcpy (&si.sin_addr.s_addr, host->h_addr_list[0],
     544             :                              host->h_length);
     545             :             }
     546             : 
     547             :           else
     548           0 :             si.sin_addr.s_addr =
     549           0 :               htonl (s->is_server ? INADDR_LOOPBACK : INADDR_ANY);
     550             : 
     551           0 :           if (err)
     552           0 :             goto done;
     553             :         }
     554           0 :       sa = (struct sockaddr *) &si;
     555             :     }
     556        1820 :   else if (s->type == CLIB_SOCKET_TYPE_UNIX)
     557             :     {
     558        1820 :       struct stat st = { 0 };
     559        1820 :       char *path = (char *) &su.sun_path;
     560             : 
     561        1820 :       if (vec_len (name) > sizeof (su.sun_path) - 1)
     562             :         {
     563           0 :           err = clib_error_return (0, "File path '%v' too long", name);
     564           0 :           goto done;
     565             :         }
     566             : 
     567        1820 :       clib_memcpy (path, s->config, vec_len (name));
     568        1820 :       addr_len = sizeof (su);
     569        1820 :       sa = (struct sockaddr *) &su;
     570             : 
     571        1820 :       rv = stat (path, &st);
     572        1820 :       if (!s->is_server && rv < 0)
     573             :         {
     574           0 :           err = clib_error_return_unix (0, "stat ('%s')", path);
     575           0 :           goto done;
     576             :         }
     577             : 
     578        1820 :       if (s->is_server && rv == 0)
     579             :         {
     580           4 :           if (S_ISSOCK (st.st_mode))
     581             :             {
     582           4 :               int client_fd = socket (AF_UNIX, SOCK_STREAM, 0);
     583           4 :               int ret = connect (client_fd, (const struct sockaddr *) &su,
     584             :                                  sizeof (su));
     585           4 :               typeof (errno) connect_errno = errno;
     586           4 :               close (client_fd);
     587             : 
     588           4 :               if (ret == 0 || (ret < 0 && connect_errno != ECONNREFUSED))
     589             :                 {
     590           0 :                   err = clib_error_return (0, "Active listener on '%s'", path);
     591           0 :                   goto done;
     592             :                 }
     593             : 
     594           4 :               if (unlink (path) < 0)
     595             :                 {
     596           0 :                   err = clib_error_return_unix (0, "unlink ('%s')", path);
     597           0 :                   goto done;
     598             :                 }
     599             :             }
     600             :           else
     601             :             {
     602           0 :               err = clib_error_return (0, "File '%s' already exists", path);
     603           0 :               goto done;
     604             :             }
     605             :         }
     606             :     }
     607             : #if CLIB_LINUX
     608           0 :   else if (s->type == CLIB_SOCKET_TYPE_LINUX_ABSTRACT)
     609             :     {
     610           0 :       if (vec_len (name) > sizeof (su.sun_path) - 2)
     611             :         {
     612           0 :           err = clib_error_return (0, "Socket name '%v' too long", name);
     613           0 :           goto done;
     614             :         }
     615             : 
     616           0 :       clib_memcpy (&su.sun_path[1], name, vec_len (name));
     617           0 :       addr_len = sizeof (su.sun_family) + vec_len (name);
     618           0 :       sa = (struct sockaddr *) &su;
     619           0 :       s->allow_group_write = 0;
     620             :     }
     621             : #endif
     622             :   else
     623             :     {
     624           0 :       err = clib_error_return_unix (0, "unknown socket family");
     625           0 :       goto done;
     626             :     }
     627             : 
     628        1820 :   socket_init_funcs (s);
     629             : 
     630        1820 :   if ((s->fd = socket (sa->sa_family,
     631        1820 :                        s->is_seqpacket ? SOCK_SEQPACKET : SOCK_STREAM, 0)) < 0)
     632             :     {
     633             :       err =
     634           0 :         clib_error_return_unix (0, "socket (fd %d, '%s')", s->fd, s->config);
     635           0 :       goto done;
     636             :     }
     637             : 
     638        1820 :   if (s->is_server)
     639             :     {
     640        1771 :       uword need_bind = 1;
     641             : 
     642        1771 :       if (sa->sa_family == AF_INET && si.sin_port == 0)
     643             :         {
     644           0 :           word port = find_free_port (s->fd);
     645           0 :           if (port < 0)
     646             :             {
     647           0 :               err = clib_error_return (0, "no free port (fd %d, '%s')", s->fd,
     648             :                                        s->config);
     649           0 :               goto done;
     650             :             }
     651           0 :           si.sin_port = port;
     652           0 :           need_bind = 0;
     653             :         }
     654             : 
     655        1771 :       if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &((int){ 1 }),
     656             :                       sizeof (int)) < 0)
     657           0 :         clib_unix_warning ("setsockopt SO_REUSEADDR fails");
     658             : 
     659             : #if CLIB_LINUX
     660        1771 :       if (sa->sa_family == AF_UNIX && s->passcred)
     661             :         {
     662        1196 :           if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &((int){ 1 }),
     663             :                           sizeof (int)) < 0)
     664             :             {
     665           0 :               err = clib_error_return_unix (0,
     666             :                                             "setsockopt (SO_PASSCRED, "
     667             :                                             "fd %d, '%s')",
     668             :                                             s->fd, s->config);
     669           0 :               goto done;
     670             :             }
     671             :         }
     672             : #endif
     673             : 
     674        1771 :       if (need_bind && bind (s->fd, sa, addr_len) < 0)
     675             :         {
     676             :           err =
     677           0 :             clib_error_return_unix (0, "bind (fd %d, '%s')", s->fd, s->config);
     678           0 :           goto done;
     679             :         }
     680             : 
     681        1771 :       if (listen (s->fd, 5) < 0)
     682             :         {
     683           0 :           err = clib_error_return_unix (0, "listen (fd %d, '%s')", s->fd,
     684             :                                         s->config);
     685           0 :           goto done;
     686             :         }
     687             : 
     688        1771 :       if (s->local_only && s->allow_group_write)
     689             :         {
     690          11 :           if (fchmod (s->fd, S_IWGRP) < 0)
     691             :             {
     692           0 :               err = clib_error_return_unix (
     693             :                 0, "fchmod (fd %d, '%s', mode S_IWGRP)", s->fd, s->config);
     694           0 :               goto done;
     695             :             }
     696             :         }
     697             :     }
     698             :   else
     699             :     {
     700          49 :       if (s->non_blocking_connect && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
     701             :         {
     702           0 :           err = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
     703             :                                         s->fd, s->config);
     704           0 :           goto done;
     705             :         }
     706             : 
     707          49 :       while ((rv = connect (s->fd, sa, addr_len)) < 0 && errno == EAGAIN)
     708             :         ;
     709          49 :       if (rv < 0 && !(s->non_blocking_connect && errno == EINPROGRESS))
     710             :         {
     711           1 :           err = clib_error_return_unix (0, "connect (fd %d, '%s')", s->fd,
     712             :                                         s->config);
     713           1 :           goto done;
     714             :         }
     715             :       /* Connect was blocking so set fd to non-blocking now unless
     716             :        * blocking mode explicitly requested. */
     717          77 :       if (!s->non_blocking_connect && !s->is_blocking &&
     718          29 :           fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
     719             :         {
     720           0 :           err = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
     721             :                                         s->fd, s->config);
     722           0 :           goto done;
     723             :         }
     724             :     }
     725             : 
     726          48 : done:
     727        1820 :   if (err && s->fd > -1)
     728             :     {
     729           1 :       close (s->fd);
     730           1 :       s->fd = -1;
     731             :     }
     732             : #if CLIB_LINUX
     733        1820 :   if (netns_fd != -1)
     734             :     {
     735           0 :       setns (netns_fd, CLONE_NEWNET);
     736           0 :       close (netns_fd);
     737             :     }
     738             : #endif
     739        1820 :   vec_free (name);
     740        1820 :   return err;
     741             : }
     742             : 
     743             : __clib_export clib_error_t *
     744        1188 : clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
     745             : {
     746        1188 :   clib_error_t *err = 0;
     747        1188 :   socklen_t len = 0;
     748             : 
     749        1188 :   clib_memset (client, 0, sizeof (client[0]));
     750             : 
     751             :   /* Accept the new socket connection. */
     752        1188 :   client->fd = accept (server->fd, 0, 0);
     753        1188 :   if (client->fd < 0)
     754           0 :     return clib_error_return_unix (0, "accept (fd %d, '%s')",
     755             :                                    server->fd, server->config);
     756             : 
     757             :   /* Set the new socket to be non-blocking. */
     758        1188 :   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
     759             :     {
     760           0 :       err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
     761             :                                     client->fd);
     762           0 :       goto close_client;
     763             :     }
     764             : 
     765             :   /* Get peer info. */
     766        1188 :   len = sizeof (client->peer);
     767        1188 :   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
     768             :     {
     769           0 :       err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
     770           0 :       goto close_client;
     771             :     }
     772             : 
     773        1188 :   client->flags = CLIB_SOCKET_F_IS_CLIENT;
     774             : 
     775        1188 :   socket_init_funcs (client);
     776        1188 :   return 0;
     777             : 
     778           0 : close_client:
     779           0 :   close (client->fd);
     780           0 :   return err;
     781             : }
     782             : 
     783             : /*
     784             :  * fd.io coding-style-patch-verification: ON
     785             :  *
     786             :  * Local Variables:
     787             :  * eval: (c-set-style "gnu")
     788             :  * End:
     789             :  */

Generated by: LCOV version 1.14