vppinfra: refactor clib_socket_init, add linux netns support
[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 = format (0, "/var/run/netns/%v%c", str, 0);
454           if ((netns_fd = open ((char *) pathname, O_RDONLY)) < 0)
455             err = clib_error_return_unix (0, "open('%s')", pathname);
456           vec_free (str);
457           vec_free (pathname);
458           if (err)
459             goto done;
460         }
461       else if (s->type == CLIB_SOCKET_TYPE_LINUX_ABSTRACT && netns_fd == -1 &&
462                strncmp (p, "netns_pid=", 10) == 0)
463         {
464           char *old_p = p = p + 10;
465           u32 pid = (u32) strtol (old_p, &p, 0);
466
467           if (p == old_p)
468             err = clib_error_return (0, "invalid pid");
469           else
470             {
471               u8 *pathname = format (0, "/proc/%u/ns/net%c", pid, 0);
472               if ((netns_fd = open ((char *) pathname, O_RDONLY)) < 0)
473                 err = clib_error_return_unix (0, "open('%s')", pathname);
474               vec_free (pathname);
475             }
476           if (err)
477             goto done;
478         }
479 #endif
480       else
481         break;
482     }
483
484   if (p[0] != 0)
485     {
486       err = clib_error_return (0, "unknown input `%s'", p);
487       goto done;
488     }
489
490 #if CLIB_LINUX
491   /* change netns if requested */
492   if (s->type != CLIB_SOCKET_TYPE_INET && netns_fd != -1)
493     {
494       int fd = open ("/proc/self/ns/net", O_RDONLY);
495
496       if (setns (netns_fd, CLONE_NEWNET) < 0)
497         {
498           close (fd);
499           err = clib_error_return_unix (0, "setns(%d)", netns_fd);
500           goto done;
501         }
502       netns_fd = fd;
503     }
504 #endif
505
506   if (s->type == CLIB_SOCKET_TYPE_INET)
507     {
508       addr_len = sizeof (si);
509       si.sin_port = htons (port);
510
511       if (name)
512         {
513           struct in_addr host_addr;
514           vec_add1 (name, 0);
515
516           /* Recognize localhost to avoid host lookup in most common cast. */
517           if (!strcmp ((char *) name, "localhost"))
518             si.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
519
520           else if (inet_aton ((char *) name, &host_addr))
521             si.sin_addr = host_addr;
522
523           else if (strlen ((char *) name) > 0)
524             {
525               struct hostent *host = gethostbyname ((char *) name);
526               if (!host)
527                 err = clib_error_return (0, "unknown host `%s'", name);
528               else
529                 clib_memcpy (&si.sin_addr.s_addr, host->h_addr_list[0],
530                              host->h_length);
531             }
532
533           else
534             si.sin_addr.s_addr =
535               htonl (s->is_server ? INADDR_LOOPBACK : INADDR_ANY);
536
537           if (err)
538             goto done;
539         }
540       sa = (struct sockaddr *) &si;
541     }
542   else if (s->type == CLIB_SOCKET_TYPE_UNIX)
543     {
544       struct stat st = { 0 };
545       char *path = (char *) &su.sun_path;
546
547       if (vec_len (name) > sizeof (su.sun_path) - 1)
548         {
549           err = clib_error_return (0, "File path '%v' too long", name);
550           goto done;
551         }
552
553       clib_memcpy (path, s->config, vec_len (name));
554       addr_len = sizeof (su);
555       sa = (struct sockaddr *) &su;
556
557       rv = stat (path, &st);
558       if (!s->is_server && rv < 0)
559         {
560           err = clib_error_return_unix (0, "stat ('%s')", path);
561           goto done;
562         }
563
564       if (s->is_server && rv == 0)
565         {
566           if (S_ISSOCK (st.st_mode))
567             {
568               int client_fd = socket (AF_UNIX, SOCK_STREAM, 0);
569               int ret = connect (client_fd, (const struct sockaddr *) &su,
570                                  sizeof (su));
571               typeof (errno) connect_errno = errno;
572               close (client_fd);
573
574               if (ret == 0 || (ret < 0 && connect_errno != ECONNREFUSED))
575                 {
576                   err = clib_error_return (0, "Active listener on '%s'", path);
577                   goto done;
578                 }
579
580               if (unlink (path) < 0)
581                 {
582                   err = clib_error_return_unix (0, "unlink ('%s')", path);
583                   goto done;
584                 }
585             }
586           else
587             {
588               err = clib_error_return (0, "File '%s' already exists", path);
589               goto done;
590             }
591         }
592     }
593 #if CLIB_LINUX
594   else if (s->type == CLIB_SOCKET_TYPE_LINUX_ABSTRACT)
595     {
596       if (vec_len (name) > sizeof (su.sun_path) - 2)
597         {
598           err = clib_error_return (0, "Socket name '%v' too long", name);
599           goto done;
600         }
601
602       clib_memcpy (&su.sun_path[1], name, vec_len (name));
603       addr_len = sizeof (su.sun_family) + vec_len (name);
604       sa = (struct sockaddr *) &su;
605       s->allow_group_write = 0;
606     }
607 #endif
608   else
609     {
610       err = clib_error_return_unix (0, "unknown socket family");
611       goto done;
612     }
613
614   socket_init_funcs (s);
615
616   if ((s->fd = socket (sa->sa_family,
617                        s->is_seqpacket ? SOCK_SEQPACKET : SOCK_STREAM, 0)) < 0)
618     {
619       err =
620         clib_error_return_unix (0, "socket (fd %d, '%s')", s->fd, s->config);
621       goto done;
622     }
623
624   if (s->is_server)
625     {
626       uword need_bind = 1;
627
628       if (sa->sa_family == AF_INET && si.sin_port == 0)
629         {
630           word port = find_free_port (s->fd);
631           if (port < 0)
632             {
633               err = clib_error_return (0, "no free port (fd %d, '%s')", s->fd,
634                                        s->config);
635               goto done;
636             }
637           si.sin_port = port;
638           need_bind = 0;
639         }
640
641       if (setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, &((int){ 1 }),
642                       sizeof (int)) < 0)
643         clib_unix_warning ("setsockopt SO_REUSEADDR fails");
644
645 #if CLIB_LINUX
646       if (sa->sa_family == AF_UNIX && s->passcred)
647         {
648           if (setsockopt (s->fd, SOL_SOCKET, SO_PASSCRED, &((int){ 1 }),
649                           sizeof (int)) < 0)
650             {
651               err = clib_error_return_unix (0,
652                                             "setsockopt (SO_PASSCRED, "
653                                             "fd %d, '%s')",
654                                             s->fd, s->config);
655               goto done;
656             }
657         }
658 #endif
659
660       if (need_bind && bind (s->fd, sa, addr_len) < 0)
661         {
662           err =
663             clib_error_return_unix (0, "bind (fd %d, '%s')", s->fd, s->config);
664           goto done;
665         }
666
667       if (listen (s->fd, 5) < 0)
668         {
669           err = clib_error_return_unix (0, "listen (fd %d, '%s')", s->fd,
670                                         s->config);
671           goto done;
672         }
673
674       if (s->local_only && s->allow_group_write)
675         {
676           if (fchmod (s->fd, S_IWGRP) < 0)
677             {
678               err = clib_error_return_unix (
679                 0, "fchmod (fd %d, '%s', mode S_IWGRP)", s->fd, s->config);
680               goto done;
681             }
682         }
683     }
684   else
685     {
686       if (s->non_blocking_connect && fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
687         {
688           err = clib_error_return_unix (0, "fcntl NONBLOCK (fd %d, '%s')",
689                                         s->fd, s->config);
690           goto done;
691         }
692
693       while ((rv = connect (s->fd, sa, addr_len)) < 0 && errno == EAGAIN)
694         ;
695       if (rv < 0 && !(s->non_blocking_connect && errno == EINPROGRESS))
696         {
697           err = clib_error_return_unix (0, "connect (fd %d, '%s')", s->fd,
698                                         s->config);
699           goto done;
700         }
701       /* Connect was blocking so set fd to non-blocking now unless
702        * blocking mode explicitly requested. */
703       if (!s->non_blocking_connect && !s->is_blocking &&
704           fcntl (s->fd, F_SETFL, O_NONBLOCK) < 0)
705         {
706           err = clib_error_return_unix (0, "fcntl NONBLOCK2 (fd %d, '%s')",
707                                         s->fd, s->config);
708           goto done;
709         }
710     }
711
712 done:
713   if (err && s->fd > -1)
714     {
715       close (s->fd);
716       s->fd = -1;
717     }
718 #if CLIB_LINUX
719   if (netns_fd != -1)
720     {
721       setns (CLONE_NEWNET, netns_fd);
722       close (netns_fd);
723     }
724 #endif
725   vec_free (name);
726   return err;
727 }
728
729 __clib_export clib_error_t *
730 clib_socket_init_netns (clib_socket_t *s, u8 *namespace)
731 {
732   if (namespace == NULL || namespace[0] == 0)
733     return clib_socket_init (s);
734
735   clib_error_t *error;
736   int old_netns_fd, nfd = -1;
737
738   old_netns_fd = clib_netns_open (NULL /* self */);
739   if (old_netns_fd < 0)
740     return clib_error_return_unix (0, "get current netns failed");
741
742   if ((nfd = clib_netns_open (namespace)) == -1)
743     {
744       error = clib_error_return_unix (0, "clib_netns_open '%s'", namespace);
745       goto done;
746     }
747
748   if (clib_setns (nfd) == -1)
749     {
750       error = clib_error_return_unix (0, "setns '%s'", namespace);
751       goto done;
752     }
753
754   error = clib_socket_init (s);
755
756 done:
757   if (clib_setns (old_netns_fd) == -1)
758     clib_warning ("Cannot set old ns");
759
760   close (old_netns_fd);
761
762   if (-1 != nfd)
763     close (nfd);
764
765   return error;
766 }
767
768 __clib_export clib_error_t *
769 clib_socket_accept (clib_socket_t * server, clib_socket_t * client)
770 {
771   clib_error_t *err = 0;
772   socklen_t len = 0;
773
774   clib_memset (client, 0, sizeof (client[0]));
775
776   /* Accept the new socket connection. */
777   client->fd = accept (server->fd, 0, 0);
778   if (client->fd < 0)
779     return clib_error_return_unix (0, "accept (fd %d, '%s')",
780                                    server->fd, server->config);
781
782   /* Set the new socket to be non-blocking. */
783   if (fcntl (client->fd, F_SETFL, O_NONBLOCK) < 0)
784     {
785       err = clib_error_return_unix (0, "fcntl O_NONBLOCK (fd %d)",
786                                     client->fd);
787       goto close_client;
788     }
789
790   /* Get peer info. */
791   len = sizeof (client->peer);
792   if (getpeername (client->fd, (struct sockaddr *) &client->peer, &len) < 0)
793     {
794       err = clib_error_return_unix (0, "getpeername (fd %d)", client->fd);
795       goto close_client;
796     }
797
798   client->flags = CLIB_SOCKET_F_IS_CLIENT;
799
800   socket_init_funcs (client);
801   return 0;
802
803 close_client:
804   close (client->fd);
805   return err;
806 }
807
808 /*
809  * fd.io coding-style-patch-verification: ON
810  *
811  * Local Variables:
812  * eval: (c-set-style "gnu")
813  * End:
814  */