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