a8062b4ca8dbafbc0d2809b5faf2a168a0983ae7
[vpp.git] / src / vcl / ldp.c
1 /*
2  * Copyright (c) 2016-2019 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 #ifdef HAVE_GNU_SOURCE
17 #define _GNU_SOURCE
18 #endif
19
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <signal.h>
23 #include <dlfcn.h>
24 #include <pthread.h>
25 #include <time.h>
26 #include <stdarg.h>
27 #include <sys/resource.h>
28 #include <netinet/tcp.h>
29 #include <netinet/udp.h>
30
31 #include <vcl/ldp_socket_wrapper.h>
32 #include <vcl/ldp.h>
33 #include <sys/time.h>
34
35 #include <vcl/vcl_locked.h>
36 #include <vppinfra/time.h>
37 #include <vppinfra/bitmap.h>
38 #include <vppinfra/lock.h>
39 #include <vppinfra/pool.h>
40 #include <vppinfra/hash.h>
41
42 #define HAVE_CONSTRUCTOR_ATTRIBUTE
43 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
44 #define CONSTRUCTOR_ATTRIBUTE                       \
45     __attribute__ ((constructor))
46 #else
47 #define CONSTRUCTOR_ATTRIBUTE
48 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
49
50 #define HAVE_DESTRUCTOR_ATTRIBUTE
51 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
52 #define DESTRUCTOR_ATTRIBUTE                        \
53     __attribute__ ((destructor))
54 #else
55 #define DESTRUCTOR_ATTRIBUTE
56 #endif
57
58 #define LDP_MAX_NWORKERS 32
59
60 #ifdef HAVE_GNU_SOURCE
61 #define SOCKADDR_GET_SA(__addr) __addr.__sockaddr__;
62 #else
63 #define SOCKADDR_GET_SA(__addr) _addr;
64 #endif
65
66 #ifndef UDP_SEGMENT
67 #define UDP_SEGMENT 103
68 #endif
69
70 #ifndef SO_ORIGINAL_DST
71 /* from <linux/netfilter_ipv4.h> */
72 #define SO_ORIGINAL_DST 80
73 #endif
74 typedef struct ldp_worker_ctx_
75 {
76   u8 *io_buffer;
77   clib_time_t clib_time;
78
79   /*
80    * Select state
81    */
82   clib_bitmap_t *rd_bitmap;
83   clib_bitmap_t *wr_bitmap;
84   clib_bitmap_t *ex_bitmap;
85   clib_bitmap_t *si_rd_bitmap;
86   clib_bitmap_t *si_wr_bitmap;
87   clib_bitmap_t *si_ex_bitmap;
88   clib_bitmap_t *libc_rd_bitmap;
89   clib_bitmap_t *libc_wr_bitmap;
90   clib_bitmap_t *libc_ex_bitmap;
91
92   /*
93    * Poll state
94    */
95   vcl_poll_t *vcl_poll;
96   struct pollfd *libc_poll;
97   u16 *libc_poll_idxs;
98
99   /*
100    * Epoll state
101    */
102   u8 epoll_wait_vcl;
103   u8 mq_epfd_added;
104   int vcl_mq_epfd;
105
106 } ldp_worker_ctx_t;
107
108 /* clib_bitmap_t, fd_mask and vcl_si_set are used interchangeably. Make sure
109  * they are the same size */
110 STATIC_ASSERT (sizeof (clib_bitmap_t) == sizeof (fd_mask),
111                "ldp bitmap size mismatch");
112 STATIC_ASSERT (sizeof (vcl_si_set) == sizeof (fd_mask),
113                "ldp bitmap size mismatch");
114
115 typedef struct
116 {
117   ldp_worker_ctx_t *workers;
118   int init;
119   char app_name[LDP_APP_NAME_MAX];
120   u32 vlsh_bit_val;
121   u32 vlsh_bit_mask;
122   u32 debug;
123
124   /** vcl needs next epoll_create to go to libc_epoll */
125   u8 vcl_needs_real_epoll;
126
127   /**
128    * crypto state used only for testing
129    */
130   u8 transparent_tls;
131   u32 ckpair_index;
132 } ldp_main_t;
133
134 #define LDP_DEBUG ldp->debug
135
136 #define LDBG(_lvl, _fmt, _args...)                                      \
137   if (ldp->debug > _lvl)                                                \
138     {                                                                   \
139       int errno_saved = errno;                                          \
140       fprintf (stderr, "ldp<%d>: " _fmt "\n", getpid(), ##_args);       \
141       errno = errno_saved;                                              \
142     }
143
144 static ldp_main_t ldp_main = {
145   .vlsh_bit_val = (1 << LDP_SID_BIT_MIN),
146   .vlsh_bit_mask = (1 << LDP_SID_BIT_MIN) - 1,
147   .debug = LDP_DEBUG_INIT,
148   .transparent_tls = 0,
149   .ckpair_index = ~0,
150 };
151
152 static ldp_main_t *ldp = &ldp_main;
153
154 static inline ldp_worker_ctx_t *
155 ldp_worker_get_current (void)
156 {
157   return (ldp->workers + vppcom_worker_index ());
158 }
159
160 /*
161  * RETURN:  0 on success or -1 on error.
162  * */
163 static inline void
164 ldp_set_app_name (char *app_name)
165 {
166   snprintf (ldp->app_name, LDP_APP_NAME_MAX, "%s-ldp-%d", app_name, getpid ());
167 }
168
169 static inline char *
170 ldp_get_app_name ()
171 {
172   if (ldp->app_name[0] == '\0')
173     ldp_set_app_name (program_invocation_short_name);
174
175   return ldp->app_name;
176 }
177
178 static inline int
179 ldp_vlsh_to_fd (vls_handle_t vlsh)
180 {
181   return (vlsh + ldp->vlsh_bit_val);
182 }
183
184 static inline vls_handle_t
185 ldp_fd_to_vlsh (int fd)
186 {
187   if (fd < ldp->vlsh_bit_val)
188     return VLS_INVALID_HANDLE;
189
190   return (fd - ldp->vlsh_bit_val);
191 }
192
193 static void
194 ldp_alloc_workers (void)
195 {
196   if (ldp->workers)
197     return;
198   pool_alloc (ldp->workers, LDP_MAX_NWORKERS);
199 }
200
201 static void
202 ldp_init_cfg (void)
203 {
204   char *env_var_str = getenv (LDP_ENV_DEBUG);
205   if (env_var_str)
206     {
207       u32 tmp;
208       if (sscanf (env_var_str, "%u", &tmp) != 1)
209         clib_warning ("LDP<%d>: WARNING: Invalid LDP debug level specified in"
210                       " the env var " LDP_ENV_DEBUG " (%s)!", getpid (),
211                       env_var_str);
212       else
213         {
214           ldp->debug = tmp;
215           LDBG (0, "configured LDP debug level (%u) from env var "
216                 LDP_ENV_DEBUG "!", ldp->debug);
217         }
218     }
219
220   env_var_str = getenv (LDP_ENV_APP_NAME);
221   if (env_var_str)
222     {
223       ldp_set_app_name (env_var_str);
224       LDBG (0, "configured LDP app name (%s) from the env var "
225             LDP_ENV_APP_NAME "!", ldp->app_name);
226     }
227
228   env_var_str = getenv (LDP_ENV_SID_BIT);
229   if (env_var_str)
230     {
231       u32 sb;
232       if (sscanf (env_var_str, "%u", &sb) != 1)
233         {
234           LDBG (0, "WARNING: Invalid LDP sid bit specified in the env var "
235                 LDP_ENV_SID_BIT " (%s)! sid bit value %d (0x%x)", env_var_str,
236                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
237         }
238       else if (sb < LDP_SID_BIT_MIN)
239         {
240           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MIN);
241           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
242
243           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
244                 LDP_ENV_SID_BIT " (%s) is too small. Using LDP_SID_BIT_MIN"
245                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
246                 LDP_SID_BIT_MIN, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
247         }
248       else if (sb > LDP_SID_BIT_MAX)
249         {
250           ldp->vlsh_bit_val = (1 << LDP_SID_BIT_MAX);
251           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
252
253           LDBG (0, "WARNING: LDP sid bit (%u) specified in the env var "
254                 LDP_ENV_SID_BIT " (%s) is too big. Using LDP_SID_BIT_MAX"
255                 " (%d)! sid bit value %d (0x%x)", sb, env_var_str,
256                 LDP_SID_BIT_MAX, ldp->vlsh_bit_val, ldp->vlsh_bit_val);
257         }
258       else
259         {
260           ldp->vlsh_bit_val = (1 << sb);
261           ldp->vlsh_bit_mask = ldp->vlsh_bit_val - 1;
262
263           LDBG (0, "configured LDP sid bit (%u) from "
264                 LDP_ENV_SID_BIT "!  sid bit value %d (0x%x)", sb,
265                 ldp->vlsh_bit_val, ldp->vlsh_bit_val);
266         }
267
268       /* Make sure there are enough bits in the fd set for vcl sessions */
269       if (ldp->vlsh_bit_val > FD_SETSIZE / 2)
270         {
271           /* Only valid for select/pselect, so just WARNING and not exit */
272           LDBG (0,
273                 "WARNING: LDP vlsh bit value %d > FD_SETSIZE/2 %d, "
274                 "select/pselect not supported now!",
275                 ldp->vlsh_bit_val, FD_SETSIZE / 2);
276         }
277     }
278   env_var_str = getenv (LDP_ENV_TLS_TRANS);
279   if (env_var_str)
280     {
281       ldp->transparent_tls = 1;
282     }
283 }
284
285 static int
286 ldp_init (void)
287 {
288   ldp_worker_ctx_t *ldpw;
289   int rv;
290
291   ASSERT (!ldp->init);
292
293   ldp_init_cfg ();
294   ldp->init = 1;
295   ldp->vcl_needs_real_epoll = 1;
296   rv = vls_app_create (ldp_get_app_name ());
297   if (rv != VPPCOM_OK)
298     {
299       ldp->vcl_needs_real_epoll = 0;
300       if (rv == VPPCOM_EEXIST)
301         return 0;
302       LDBG (2,
303             "\nERROR: ldp_init: vppcom_app_create()"
304             " failed!  rv = %d (%s)\n",
305             rv, vppcom_retval_str (rv));
306       ldp->init = 0;
307       return rv;
308     }
309   ldp->vcl_needs_real_epoll = 0;
310   ldp_alloc_workers ();
311   ldpw = ldp_worker_get_current ();
312
313   pool_foreach (ldpw, ldp->workers)  {
314     clib_memset (&ldpw->clib_time, 0, sizeof (ldpw->clib_time));
315   }
316
317   LDBG (0, "LDP initialization: done!");
318
319   return 0;
320 }
321
322 #define ldp_init_check()                                                      \
323   if (PREDICT_FALSE (!ldp->init))                                             \
324     {                                                                         \
325       if ((errno = -ldp_init ()))                                             \
326         return -1;                                                            \
327     }
328
329 int
330 close (int fd)
331 {
332   vls_handle_t vlsh;
333   int rv, epfd;
334
335   ldp_init_check ();
336
337   vlsh = ldp_fd_to_vlsh (fd);
338   if (vlsh != VLS_INVALID_HANDLE)
339     {
340       epfd = vls_attr (vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
341       if (epfd > 0)
342         {
343           ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
344           u32 size = sizeof (epfd);
345
346           LDBG (0, "fd %d: calling libc_close: epfd %u", fd, epfd);
347
348           libc_close (epfd);
349           ldpw->mq_epfd_added = 0;
350
351           epfd = 0;
352           (void) vls_attr (vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &epfd, &size);
353         }
354       else if (PREDICT_FALSE (epfd < 0))
355         {
356           errno = -epfd;
357           rv = -1;
358           goto done;
359         }
360
361       LDBG (0, "fd %d: calling vls_close: vlsh %u", fd, vlsh);
362
363       rv = vls_close (vlsh);
364       if (rv != VPPCOM_OK)
365         {
366           errno = -rv;
367           rv = -1;
368         }
369     }
370   else
371     {
372       LDBG (0, "fd %d: calling libc_close", fd);
373       rv = libc_close (fd);
374     }
375
376 done:
377   return rv;
378 }
379
380 ssize_t
381 read (int fd, void *buf, size_t nbytes)
382 {
383   vls_handle_t vlsh;
384   ssize_t size;
385
386   ldp_init_check ();
387
388   vlsh = ldp_fd_to_vlsh (fd);
389   if (vlsh != VLS_INVALID_HANDLE)
390     {
391       size = vls_read (vlsh, buf, nbytes);
392       if (size < 0)
393         {
394           errno = -size;
395           size = -1;
396         }
397     }
398   else
399     {
400       size = libc_read (fd, buf, nbytes);
401     }
402
403   return size;
404 }
405
406 ssize_t
407 readv (int fd, const struct iovec * iov, int iovcnt)
408 {
409   int rv = 0, i, total = 0;
410   vls_handle_t vlsh;
411   ssize_t size = 0;
412
413   ldp_init_check ();
414
415   vlsh = ldp_fd_to_vlsh (fd);
416   if (vlsh != VLS_INVALID_HANDLE)
417     {
418       for (i = 0; i < iovcnt; ++i)
419         {
420           rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len);
421           if (rv <= 0)
422             break;
423           else
424             {
425               total += rv;
426               if (rv < iov[i].iov_len)
427                 break;
428             }
429         }
430       if (rv < 0 && total == 0)
431         {
432           errno = -rv;
433           size = -1;
434         }
435       else
436         size = total;
437     }
438   else
439     {
440       size = libc_readv (fd, iov, iovcnt);
441     }
442
443   return size;
444 }
445
446 ssize_t
447 write (int fd, const void *buf, size_t nbytes)
448 {
449   vls_handle_t vlsh;
450   ssize_t size = 0;
451
452   ldp_init_check ();
453
454   vlsh = ldp_fd_to_vlsh (fd);
455   if (vlsh != VLS_INVALID_HANDLE)
456     {
457       size = vls_write_msg (vlsh, (void *) buf, nbytes);
458       if (size < 0)
459         {
460           errno = -size;
461           size = -1;
462         }
463     }
464   else
465     {
466       size = libc_write (fd, buf, nbytes);
467     }
468
469   return size;
470 }
471
472 ssize_t
473 writev (int fd, const struct iovec * iov, int iovcnt)
474 {
475   ssize_t size = 0, total = 0;
476   vls_handle_t vlsh;
477   int i, rv = 0;
478
479   ldp_init_check ();
480
481   vlsh = ldp_fd_to_vlsh (fd);
482   if (vlsh != VLS_INVALID_HANDLE)
483     {
484       for (i = 0; i < iovcnt; ++i)
485         {
486           rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len);
487           if (rv < 0)
488             break;
489           else
490             {
491               total += rv;
492               if (rv < iov[i].iov_len)
493                 break;
494             }
495         }
496
497       if (rv < 0 && total == 0)
498         {
499           errno = -rv;
500           size = -1;
501         }
502       else
503         size = total;
504     }
505   else
506     {
507       size = libc_writev (fd, iov, iovcnt);
508     }
509
510   return size;
511 }
512
513 static int
514 fcntl_internal (int fd, int cmd, va_list ap)
515 {
516   vls_handle_t vlsh;
517   int rv = 0;
518
519   vlsh = ldp_fd_to_vlsh (fd);
520   LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd);
521   if (vlsh != VLS_INVALID_HANDLE)
522     {
523       int flags = va_arg (ap, int);
524       u32 size;
525
526       size = sizeof (flags);
527       rv = -EOPNOTSUPP;
528       switch (cmd)
529         {
530         case F_SETFL:
531           rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
532           break;
533
534         case F_GETFL:
535           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
536           if (rv == VPPCOM_OK)
537             rv = flags;
538           break;
539         case F_SETFD:
540           /* TODO handle this */
541           LDBG (0, "F_SETFD ignored flags %u", flags);
542           rv = 0;
543           break;
544         default:
545           rv = -EOPNOTSUPP;
546           break;
547         }
548       if (rv < 0)
549         {
550           errno = -rv;
551           rv = -1;
552         }
553     }
554   else
555     {
556 #ifdef HAVE_FCNTL64
557       rv = libc_vfcntl64 (fd, cmd, ap);
558 #else
559       rv = libc_vfcntl (fd, cmd, ap);
560 #endif
561     }
562
563   return rv;
564 }
565
566 int
567 fcntl (int fd, int cmd, ...)
568 {
569   va_list ap;
570   int rv;
571
572   ldp_init_check ();
573
574   va_start (ap, cmd);
575   rv = fcntl_internal (fd, cmd, ap);
576   va_end (ap);
577
578   return rv;
579 }
580
581 int
582 fcntl64 (int fd, int cmd, ...)
583 {
584   va_list ap;
585   int rv;
586
587   ldp_init_check ();
588
589   va_start (ap, cmd);
590   rv = fcntl_internal (fd, cmd, ap);
591   va_end (ap);
592   return rv;
593 }
594
595 int
596 ioctl (int fd, unsigned long int cmd, ...)
597 {
598   vls_handle_t vlsh;
599   va_list ap;
600   int rv;
601
602   ldp_init_check ();
603
604   va_start (ap, cmd);
605
606   vlsh = ldp_fd_to_vlsh (fd);
607   if (vlsh != VLS_INVALID_HANDLE)
608     {
609       switch (cmd)
610         {
611         case FIONREAD:
612           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
613           break;
614
615         case FIONBIO:
616           {
617             u32 flags = *(va_arg (ap, int *)) ? O_NONBLOCK : 0;
618             u32 size = sizeof (flags);
619
620             /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
621              *      non-blocking, the flags should be read here and merged
622              *      with O_NONBLOCK.
623              */
624             rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
625           }
626           break;
627
628         default:
629           rv = -EOPNOTSUPP;
630           break;
631         }
632       if (rv < 0)
633         {
634           errno = -rv;
635           rv = -1;
636         }
637     }
638   else
639     {
640       rv = libc_vioctl (fd, cmd, ap);
641     }
642
643   va_end (ap);
644   return rv;
645 }
646
647 always_inline void
648 ldp_select_init_maps (fd_set * __restrict original,
649                       clib_bitmap_t ** resultb, clib_bitmap_t ** libcb,
650                       clib_bitmap_t ** vclb, int nfds, u32 minbits,
651                       u32 n_bytes, uword * si_bits, uword * libc_bits)
652 {
653   uword si_bits_set, libc_bits_set;
654   vls_handle_t vlsh;
655   int fd;
656
657   clib_bitmap_validate (*vclb, minbits);
658   clib_bitmap_validate (*libcb, minbits);
659   clib_bitmap_validate (*resultb, minbits);
660   clib_memcpy_fast (*resultb, original, n_bytes);
661   memset (original, 0, n_bytes);
662
663   /* *INDENT-OFF* */
664   clib_bitmap_foreach (fd, *resultb)  {
665     if (fd > nfds)
666       break;
667     vlsh = ldp_fd_to_vlsh (fd);
668     if (vlsh == VLS_INVALID_HANDLE)
669       clib_bitmap_set_no_check (*libcb, fd, 1);
670     else
671       *vclb = clib_bitmap_set (*vclb, vlsh_to_session_index (vlsh), 1);
672   }
673   /* *INDENT-ON* */
674
675   si_bits_set = clib_bitmap_last_set (*vclb) + 1;
676   *si_bits = (si_bits_set > *si_bits) ? si_bits_set : *si_bits;
677   clib_bitmap_validate (*resultb, *si_bits);
678
679   libc_bits_set = clib_bitmap_last_set (*libcb) + 1;
680   *libc_bits = (libc_bits_set > *libc_bits) ? libc_bits_set : *libc_bits;
681 }
682
683 always_inline int
684 ldp_select_vcl_map_to_libc (clib_bitmap_t * vclb, fd_set * __restrict libcb)
685 {
686   vls_handle_t vlsh;
687   uword si;
688   int fd;
689
690   if (!libcb)
691     return 0;
692
693   /* *INDENT-OFF* */
694   clib_bitmap_foreach (si, vclb)  {
695     vlsh = vls_session_index_to_vlsh (si);
696     ASSERT (vlsh != VLS_INVALID_HANDLE);
697     fd = ldp_vlsh_to_fd (vlsh);
698     if (PREDICT_FALSE (fd < 0))
699       {
700         errno = EBADFD;
701         return -1;
702       }
703     FD_SET (fd, libcb);
704   }
705   /* *INDENT-ON* */
706
707   return 0;
708 }
709
710 always_inline void
711 ldp_select_libc_map_merge (clib_bitmap_t * result, fd_set * __restrict libcb)
712 {
713   uword fd;
714
715   if (!libcb)
716     return;
717
718   /* *INDENT-OFF* */
719   clib_bitmap_foreach (fd, result)
720     FD_SET ((int)fd, libcb);
721   /* *INDENT-ON* */
722 }
723
724 int
725 ldp_pselect (int nfds, fd_set * __restrict readfds,
726              fd_set * __restrict writefds,
727              fd_set * __restrict exceptfds,
728              const struct timespec *__restrict timeout,
729              const __sigset_t * __restrict sigmask)
730 {
731   u32 minbits = clib_max (nfds, BITS (uword)), n_bytes;
732   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
733   struct timespec libc_tspec = { 0 };
734   f64 time_out, vcl_timeout = 0;
735   uword si_bits, libc_bits;
736   int rv, bits_set = 0;
737
738   if (nfds < 0)
739     {
740       errno = EINVAL;
741       return -1;
742     }
743
744   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
745     clib_time_init (&ldpw->clib_time);
746
747   if (timeout)
748     {
749       time_out = (timeout->tv_sec == 0 && timeout->tv_nsec == 0) ?
750         (f64) 0 : (f64) timeout->tv_sec + (f64) timeout->tv_nsec / (f64) 1e9;
751
752       time_out += clib_time_now (&ldpw->clib_time);
753
754       /* select as fine grained sleep */
755       if (!nfds)
756         {
757           while (clib_time_now (&ldpw->clib_time) < time_out)
758             ;
759           return 0;
760         }
761     }
762   else if (!nfds)
763     {
764       errno = EINVAL;
765       return -1;
766     }
767   else
768     time_out = -1;
769
770   if (nfds <= ldp->vlsh_bit_val)
771     {
772       rv = libc_pselect (nfds, readfds, writefds, exceptfds,
773                          timeout, sigmask);
774       goto done;
775     }
776
777   si_bits = libc_bits = 0;
778   n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0);
779
780   if (readfds)
781     ldp_select_init_maps (readfds, &ldpw->rd_bitmap, &ldpw->libc_rd_bitmap,
782                           &ldpw->si_rd_bitmap, nfds, minbits, n_bytes,
783                           &si_bits, &libc_bits);
784   if (writefds)
785     ldp_select_init_maps (writefds, &ldpw->wr_bitmap,
786                           &ldpw->libc_wr_bitmap, &ldpw->si_wr_bitmap, nfds,
787                           minbits, n_bytes, &si_bits, &libc_bits);
788   if (exceptfds)
789     ldp_select_init_maps (exceptfds, &ldpw->ex_bitmap,
790                           &ldpw->libc_ex_bitmap, &ldpw->si_ex_bitmap, nfds,
791                           minbits, n_bytes, &si_bits, &libc_bits);
792
793   if (PREDICT_FALSE (!si_bits && !libc_bits))
794     {
795       errno = EINVAL;
796       rv = -1;
797       goto done;
798     }
799
800   if (!si_bits)
801     libc_tspec = timeout ? *timeout : libc_tspec;
802
803   do
804     {
805       if (si_bits)
806         {
807           if (readfds)
808             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->si_rd_bitmap,
809                               vec_len (ldpw->si_rd_bitmap) *
810                               sizeof (clib_bitmap_t));
811           if (writefds)
812             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->si_wr_bitmap,
813                               vec_len (ldpw->si_wr_bitmap) *
814                               sizeof (clib_bitmap_t));
815           if (exceptfds)
816             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->si_ex_bitmap,
817                               vec_len (ldpw->si_ex_bitmap) *
818                               sizeof (clib_bitmap_t));
819
820           rv = vls_select (si_bits, readfds ? ldpw->rd_bitmap : NULL,
821                            writefds ? ldpw->wr_bitmap : NULL,
822                            exceptfds ? ldpw->ex_bitmap : NULL, vcl_timeout);
823           if (rv < 0)
824             {
825               errno = -rv;
826               rv = -1;
827               goto done;
828             }
829           else if (rv > 0)
830             {
831               if (ldp_select_vcl_map_to_libc (ldpw->rd_bitmap, readfds))
832                 {
833                   rv = -1;
834                   goto done;
835                 }
836
837               if (ldp_select_vcl_map_to_libc (ldpw->wr_bitmap, writefds))
838                 {
839                   rv = -1;
840                   goto done;
841                 }
842
843               if (ldp_select_vcl_map_to_libc (ldpw->ex_bitmap, exceptfds))
844                 {
845                   rv = -1;
846                   goto done;
847                 }
848               bits_set = rv;
849             }
850         }
851       if (libc_bits)
852         {
853           if (readfds)
854             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->libc_rd_bitmap,
855                               vec_len (ldpw->libc_rd_bitmap) *
856                               sizeof (clib_bitmap_t));
857           if (writefds)
858             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->libc_wr_bitmap,
859                               vec_len (ldpw->libc_wr_bitmap) *
860                               sizeof (clib_bitmap_t));
861           if (exceptfds)
862             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->libc_ex_bitmap,
863                               vec_len (ldpw->libc_ex_bitmap) *
864                               sizeof (clib_bitmap_t));
865
866           rv = libc_pselect (libc_bits,
867                              readfds ? (fd_set *) ldpw->rd_bitmap : NULL,
868                              writefds ? (fd_set *) ldpw->wr_bitmap : NULL,
869                              exceptfds ? (fd_set *) ldpw->ex_bitmap : NULL,
870                              &libc_tspec, sigmask);
871           if (rv > 0)
872             {
873               ldp_select_libc_map_merge (ldpw->rd_bitmap, readfds);
874               ldp_select_libc_map_merge (ldpw->wr_bitmap, writefds);
875               ldp_select_libc_map_merge (ldpw->ex_bitmap, exceptfds);
876               bits_set += rv;
877             }
878         }
879
880       if (bits_set)
881         {
882           rv = bits_set;
883           goto done;
884         }
885     }
886   while ((time_out == -1) || (clib_time_now (&ldpw->clib_time) < time_out));
887   rv = 0;
888
889 done:
890   /* TBD: set timeout to amount of time left */
891   clib_bitmap_zero (ldpw->rd_bitmap);
892   clib_bitmap_zero (ldpw->si_rd_bitmap);
893   clib_bitmap_zero (ldpw->libc_rd_bitmap);
894   clib_bitmap_zero (ldpw->wr_bitmap);
895   clib_bitmap_zero (ldpw->si_wr_bitmap);
896   clib_bitmap_zero (ldpw->libc_wr_bitmap);
897   clib_bitmap_zero (ldpw->ex_bitmap);
898   clib_bitmap_zero (ldpw->si_ex_bitmap);
899   clib_bitmap_zero (ldpw->libc_ex_bitmap);
900
901   return rv;
902 }
903
904 int
905 select (int nfds, fd_set * __restrict readfds,
906         fd_set * __restrict writefds,
907         fd_set * __restrict exceptfds, struct timeval *__restrict timeout)
908 {
909   struct timespec tspec;
910
911   if (timeout)
912     {
913       tspec.tv_sec = timeout->tv_sec;
914       tspec.tv_nsec = timeout->tv_usec * 1000;
915     }
916   return ldp_pselect (nfds, readfds, writefds, exceptfds,
917                       timeout ? &tspec : NULL, NULL);
918 }
919
920 #ifdef __USE_XOPEN2K
921 int
922 pselect (int nfds, fd_set * __restrict readfds,
923          fd_set * __restrict writefds,
924          fd_set * __restrict exceptfds,
925          const struct timespec *__restrict timeout,
926          const __sigset_t * __restrict sigmask)
927 {
928   return ldp_pselect (nfds, readfds, writefds, exceptfds, timeout, 0);
929 }
930 #endif
931
932 /* If transparent TLS mode is turned on, then ldp will load key and cert.
933  */
934 static int
935 load_cert_key_pair (void)
936 {
937   char *cert_str = getenv (LDP_ENV_TLS_CERT);
938   char *key_str = getenv (LDP_ENV_TLS_KEY);
939   char cert_buf[4096], key_buf[4096];
940   int cert_size, key_size;
941   vppcom_cert_key_pair_t crypto;
942   int ckp_index;
943   FILE *fp;
944
945   if (!cert_str || !key_str)
946     {
947       LDBG (0, "ERROR: failed to read LDP environment %s\n",
948             LDP_ENV_TLS_CERT);
949       return -1;
950     }
951
952   fp = fopen (cert_str, "r");
953   if (fp == NULL)
954     {
955       LDBG (0, "ERROR: failed to open cert file %s \n", cert_str);
956       return -1;
957     }
958   cert_size = fread (cert_buf, sizeof (char), sizeof (cert_buf), fp);
959   fclose (fp);
960
961   fp = fopen (key_str, "r");
962   if (fp == NULL)
963     {
964       LDBG (0, "ERROR: failed to open key file %s \n", key_str);
965       return -1;
966     }
967   key_size = fread (key_buf, sizeof (char), sizeof (key_buf), fp);
968   fclose (fp);
969
970   crypto.cert = cert_buf;
971   crypto.key = key_buf;
972   crypto.cert_len = cert_size;
973   crypto.key_len = key_size;
974   ckp_index = vppcom_add_cert_key_pair (&crypto);
975   if (ckp_index < 0)
976     {
977       LDBG (0, "ERROR: failed to add cert key pair\n");
978       return -1;
979     }
980
981   ldp->ckpair_index = ckp_index;
982
983   return 0;
984 }
985
986 static int
987 assign_cert_key_pair (vls_handle_t vlsh)
988 {
989   uint32_t ckp_len;
990
991   if (ldp->ckpair_index == ~0 && load_cert_key_pair () < 0)
992     return -1;
993
994   ckp_len = sizeof (ldp->ckpair_index);
995   return vls_attr (vlsh, VPPCOM_ATTR_SET_CKPAIR, &ldp->ckpair_index, &ckp_len);
996 }
997
998 int
999 socket (int domain, int type, int protocol)
1000 {
1001   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
1002   u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0;
1003   vls_handle_t vlsh;
1004
1005   ldp_init_check ();
1006
1007   if (((domain == AF_INET) || (domain == AF_INET6)) &&
1008       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
1009     {
1010       u8 proto;
1011       if (ldp->transparent_tls)
1012         {
1013           proto = VPPCOM_PROTO_TLS;
1014         }
1015       else
1016         proto = ((sock_type == SOCK_DGRAM) ?
1017                  VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
1018
1019       LDBG (0, "calling vls_create: proto %u (%s), is_nonblocking %u",
1020             proto, vppcom_proto_str (proto), is_nonblocking);
1021
1022       vlsh = vls_create (proto, is_nonblocking);
1023       if (vlsh < 0)
1024         {
1025           errno = -vlsh;
1026           rv = -1;
1027         }
1028       else
1029         {
1030           if (ldp->transparent_tls)
1031             {
1032               if (assign_cert_key_pair (vlsh) < 0)
1033                 return -1;
1034             }
1035           rv = ldp_vlsh_to_fd (vlsh);
1036         }
1037     }
1038   else
1039     {
1040       LDBG (0, "calling libc_socket");
1041       rv = libc_socket (domain, type, protocol);
1042     }
1043
1044   return rv;
1045 }
1046
1047 /*
1048  * Create two new sockets, of type TYPE in domain DOMAIN and using
1049  * protocol PROTOCOL, which are connected to each other, and put file
1050  * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
1051  * one will be chosen automatically.
1052  * Returns 0 on success, -1 for errors.
1053  * */
1054 int
1055 socketpair (int domain, int type, int protocol, int fds[2])
1056 {
1057   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
1058
1059   ldp_init_check ();
1060
1061   if (((domain == AF_INET) || (domain == AF_INET6)) &&
1062       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
1063     {
1064       LDBG (0, "LDP-TBD");
1065       errno = ENOSYS;
1066       rv = -1;
1067     }
1068   else
1069     {
1070       LDBG (1, "calling libc_socketpair");
1071       rv = libc_socketpair (domain, type, protocol, fds);
1072     }
1073
1074   return rv;
1075 }
1076
1077 int
1078 bind (int fd, __CONST_SOCKADDR_ARG _addr, socklen_t len)
1079 {
1080   const struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1081   vls_handle_t vlsh;
1082   int rv;
1083
1084   ldp_init_check ();
1085
1086   vlsh = ldp_fd_to_vlsh (fd);
1087   if (vlsh != VLS_INVALID_HANDLE)
1088     {
1089       vppcom_endpt_t ep;
1090
1091       switch (addr->sa_family)
1092         {
1093         case AF_INET:
1094           if (len != sizeof (struct sockaddr_in))
1095             {
1096               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET addr len %u!",
1097                     fd, vlsh, len);
1098               errno = EINVAL;
1099               rv = -1;
1100               goto done;
1101             }
1102           ep.is_ip4 = VPPCOM_IS_IP4;
1103           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1104           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1105           break;
1106
1107         case AF_INET6:
1108           if (len != sizeof (struct sockaddr_in6))
1109             {
1110               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET6 addr len %u!",
1111                     fd, vlsh, len);
1112               errno = EINVAL;
1113               rv = -1;
1114               goto done;
1115             }
1116           ep.is_ip4 = VPPCOM_IS_IP6;
1117           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1118           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1119           break;
1120
1121         default:
1122           LDBG (0, "ERROR: fd %d: vlsh %u: Unsupported address family %u!",
1123                 fd, vlsh, addr->sa_family);
1124           errno = EAFNOSUPPORT;
1125           rv = -1;
1126           goto done;
1127         }
1128       LDBG (0, "fd %d: calling vls_bind: vlsh %u, addr %p, len %u", fd, vlsh,
1129             addr, len);
1130
1131       rv = vls_bind (vlsh, &ep);
1132       if (rv != VPPCOM_OK)
1133         {
1134           errno = -rv;
1135           rv = -1;
1136         }
1137     }
1138   else
1139     {
1140       LDBG (0, "fd %d: calling libc_bind: addr %p, len %u", fd, addr, len);
1141       rv = libc_bind (fd, addr, len);
1142     }
1143
1144 done:
1145   LDBG (1, "fd %d: returning %d", fd, rv);
1146
1147   return rv;
1148 }
1149
1150 static inline int
1151 ldp_copy_ep_to_sockaddr (struct sockaddr *addr, socklen_t *__restrict len,
1152                          vppcom_endpt_t *ep)
1153 {
1154   int rv = 0, sa_len, copy_len;
1155
1156   ldp_init_check ();
1157
1158   if (addr && len && ep)
1159     {
1160       addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1161       switch (addr->sa_family)
1162         {
1163         case AF_INET:
1164           ((struct sockaddr_in *) addr)->sin_port = ep->port;
1165           if (*len > sizeof (struct sockaddr_in))
1166             *len = sizeof (struct sockaddr_in);
1167           sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1168           copy_len = *len - sa_len;
1169           if (copy_len > 0)
1170             memcpy (&((struct sockaddr_in *) addr)->sin_addr, ep->ip,
1171                     copy_len);
1172           break;
1173
1174         case AF_INET6:
1175           ((struct sockaddr_in6 *) addr)->sin6_port = ep->port;
1176           if (*len > sizeof (struct sockaddr_in6))
1177             *len = sizeof (struct sockaddr_in6);
1178           sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1179           copy_len = *len - sa_len;
1180           if (copy_len > 0)
1181             memcpy (((struct sockaddr_in6 *) addr)->sin6_addr.
1182                     __in6_u.__u6_addr8, ep->ip, copy_len);
1183           break;
1184
1185         default:
1186           /* Not possible */
1187           rv = -EAFNOSUPPORT;
1188           break;
1189         }
1190     }
1191   return rv;
1192 }
1193
1194 int
1195 getsockname (int fd, __SOCKADDR_ARG _addr, socklen_t *__restrict len)
1196 {
1197   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1198   vls_handle_t vlsh;
1199   int rv;
1200
1201   ldp_init_check ();
1202
1203   vlsh = ldp_fd_to_vlsh (fd);
1204   if (vlsh != VLS_INVALID_HANDLE)
1205     {
1206       vppcom_endpt_t ep;
1207       u8 addr_buf[sizeof (struct in6_addr)];
1208       u32 size = sizeof (ep);
1209
1210       ep.ip = addr_buf;
1211
1212       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
1213       if (rv != VPPCOM_OK)
1214         {
1215           errno = -rv;
1216           rv = -1;
1217         }
1218       else
1219         {
1220           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1221           if (rv != VPPCOM_OK)
1222             {
1223               errno = -rv;
1224               rv = -1;
1225             }
1226         }
1227     }
1228   else
1229     {
1230       rv = libc_getsockname (fd, _addr, len);
1231     }
1232
1233   return rv;
1234 }
1235
1236 int
1237 connect (int fd, __CONST_SOCKADDR_ARG _addr, socklen_t len)
1238 {
1239   const struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1240   vls_handle_t vlsh;
1241   int rv;
1242
1243   ldp_init_check ();
1244
1245   if (!addr)
1246     {
1247       LDBG (0, "ERROR: fd %d: NULL addr, len %u", fd, len);
1248       errno = EINVAL;
1249       rv = -1;
1250       goto done;
1251     }
1252
1253   vlsh = ldp_fd_to_vlsh (fd);
1254   if (vlsh != VLS_INVALID_HANDLE)
1255     {
1256       vppcom_endpt_t ep;
1257
1258       switch (addr->sa_family)
1259         {
1260         case AF_INET:
1261           if (len != sizeof (struct sockaddr_in))
1262             {
1263               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET addr len %u!",
1264                     fd, vlsh, len);
1265               errno = EINVAL;
1266               rv = -1;
1267               goto done;
1268             }
1269           ep.is_ip4 = VPPCOM_IS_IP4;
1270           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1271           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1272           break;
1273
1274         case AF_INET6:
1275           if (len != sizeof (struct sockaddr_in6))
1276             {
1277               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET6 addr len %u!",
1278                     fd, vlsh, len);
1279               errno = EINVAL;
1280               rv = -1;
1281               goto done;
1282             }
1283           ep.is_ip4 = VPPCOM_IS_IP6;
1284           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1285           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1286           break;
1287
1288         default:
1289           LDBG (0, "fd %d: ERROR vlsh %u: Unsupported address family %u!",
1290                 fd, vlsh, addr->sa_family);
1291           errno = EAFNOSUPPORT;
1292           rv = -1;
1293           goto done;
1294         }
1295       LDBG (0, "fd %d: calling vls_connect(): vlsh %u addr %p len %u", fd,
1296             vlsh, addr, len);
1297
1298       rv = vls_connect (vlsh, &ep);
1299       if (rv != VPPCOM_OK)
1300         {
1301           errno = -rv;
1302           rv = -1;
1303         }
1304     }
1305   else
1306     {
1307       LDBG (0, "fd %d: calling libc_connect(): addr %p, len %u",
1308             fd, addr, len);
1309
1310       rv = libc_connect (fd, addr, len);
1311     }
1312
1313 done:
1314   LDBG (1, "fd %d: returning %d (0x%x)", fd, rv, rv);
1315   return rv;
1316 }
1317
1318 int
1319 getpeername (int fd, __SOCKADDR_ARG _addr, socklen_t *__restrict len)
1320 {
1321   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1322   vls_handle_t vlsh;
1323   int rv;
1324
1325   ldp_init_check ();
1326
1327   vlsh = ldp_fd_to_vlsh (fd);
1328   if (vlsh != VLS_INVALID_HANDLE)
1329     {
1330       vppcom_endpt_t ep;
1331       u8 addr_buf[sizeof (struct in6_addr)];
1332       u32 size = sizeof (ep);
1333
1334       ep.ip = addr_buf;
1335       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size);
1336       if (rv != VPPCOM_OK)
1337         {
1338           errno = -rv;
1339           rv = -1;
1340         }
1341       else
1342         {
1343           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1344           if (rv != VPPCOM_OK)
1345             {
1346               errno = -rv;
1347               rv = -1;
1348             }
1349         }
1350     }
1351   else
1352     {
1353       rv = libc_getpeername (fd, addr, len);
1354     }
1355
1356   return rv;
1357 }
1358
1359 ssize_t
1360 send (int fd, const void *buf, size_t n, int flags)
1361 {
1362   vls_handle_t vlsh = ldp_fd_to_vlsh (fd);
1363   ssize_t size;
1364
1365   ldp_init_check ();
1366
1367   if (vlsh != VLS_INVALID_HANDLE)
1368     {
1369       size = vls_sendto (vlsh, (void *) buf, n, flags, NULL);
1370       if (size < VPPCOM_OK)
1371         {
1372           errno = -size;
1373           size = -1;
1374         }
1375     }
1376   else
1377     {
1378       size = libc_send (fd, buf, n, flags);
1379     }
1380
1381   return size;
1382 }
1383
1384 ssize_t
1385 sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
1386 {
1387   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1388   vls_handle_t vlsh;
1389   ssize_t size = 0;
1390
1391   ldp_init_check ();
1392
1393   vlsh = ldp_fd_to_vlsh (out_fd);
1394   if (vlsh != VLS_INVALID_HANDLE)
1395     {
1396       int rv;
1397       ssize_t results = 0;
1398       size_t n_bytes_left = len;
1399       size_t bytes_to_read;
1400       int nbytes;
1401       u8 eagain = 0;
1402       u32 flags, flags_len = sizeof (flags);
1403
1404       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &flags_len);
1405       if (PREDICT_FALSE (rv != VPPCOM_OK))
1406         {
1407           LDBG (0, "ERROR: out fd %d: vls_attr: vlsh %u, returned %d (%s)!",
1408                 out_fd, vlsh, rv, vppcom_retval_str (rv));
1409
1410           vec_reset_length (ldpw->io_buffer);
1411           errno = -rv;
1412           size = -1;
1413           goto done;
1414         }
1415
1416       if (offset)
1417         {
1418           off_t off = lseek (in_fd, *offset, SEEK_SET);
1419           if (PREDICT_FALSE (off == -1))
1420             {
1421               size = -1;
1422               goto done;
1423             }
1424
1425           ASSERT (off == *offset);
1426         }
1427
1428       do
1429         {
1430           size = vls_attr (vlsh, VPPCOM_ATTR_GET_NWRITE, 0, 0);
1431           if (size < 0)
1432             {
1433               LDBG (0, "ERROR: fd %d: vls_attr: vlsh %u returned %ld (%s)!",
1434                     out_fd, vlsh, size, vppcom_retval_str (size));
1435               vec_reset_length (ldpw->io_buffer);
1436               errno = -size;
1437               size = -1;
1438               goto done;
1439             }
1440
1441           bytes_to_read = size;
1442           if (bytes_to_read == 0)
1443             {
1444               if (flags & O_NONBLOCK)
1445                 {
1446                   if (!results)
1447                     eagain = 1;
1448                   goto update_offset;
1449                 }
1450               else
1451                 continue;
1452             }
1453           bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1454           vec_validate (ldpw->io_buffer, bytes_to_read);
1455           nbytes = libc_read (in_fd, ldpw->io_buffer, bytes_to_read);
1456           if (nbytes < 0)
1457             {
1458               if (results == 0)
1459                 {
1460                   vec_reset_length (ldpw->io_buffer);
1461                   size = -1;
1462                   goto done;
1463                 }
1464               goto update_offset;
1465             }
1466
1467           size = vls_write (vlsh, ldpw->io_buffer, nbytes);
1468           if (size < 0)
1469             {
1470               if (size == VPPCOM_EAGAIN)
1471                 {
1472                   if (flags & O_NONBLOCK)
1473                     {
1474                       if (!results)
1475                         eagain = 1;
1476                       goto update_offset;
1477                     }
1478                   else
1479                     continue;
1480                 }
1481               if (results == 0)
1482                 {
1483                   vec_reset_length (ldpw->io_buffer);
1484                   errno = -size;
1485                   size = -1;
1486                   goto done;
1487                 }
1488               goto update_offset;
1489             }
1490
1491           results += nbytes;
1492           ASSERT (n_bytes_left >= nbytes);
1493           n_bytes_left = n_bytes_left - nbytes;
1494         }
1495       while (n_bytes_left > 0);
1496
1497     update_offset:
1498       vec_reset_length (ldpw->io_buffer);
1499       if (offset)
1500         {
1501           off_t off = lseek (in_fd, *offset, SEEK_SET);
1502           if (PREDICT_FALSE (off == -1))
1503             {
1504               size = -1;
1505               goto done;
1506             }
1507
1508           ASSERT (off == *offset);
1509           *offset += results + 1;
1510         }
1511       if (eagain)
1512         {
1513           errno = EAGAIN;
1514           size = -1;
1515         }
1516       else
1517         size = results;
1518     }
1519   else
1520     {
1521       size = libc_sendfile (out_fd, in_fd, offset, len);
1522     }
1523
1524 done:
1525   return size;
1526 }
1527
1528 ssize_t
1529 sendfile64 (int out_fd, int in_fd, off_t * offset, size_t len)
1530 {
1531   return sendfile (out_fd, in_fd, offset, len);
1532 }
1533
1534 ssize_t
1535 recv (int fd, void *buf, size_t n, int flags)
1536 {
1537   vls_handle_t vlsh;
1538   ssize_t size;
1539
1540   ldp_init_check ();
1541
1542   vlsh = ldp_fd_to_vlsh (fd);
1543   if (vlsh != VLS_INVALID_HANDLE)
1544     {
1545       size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1546       if (size < 0)
1547         {
1548           errno = -size;
1549           size = -1;
1550         }
1551     }
1552   else
1553     {
1554       size = libc_recv (fd, buf, n, flags);
1555     }
1556
1557   return size;
1558 }
1559
1560 ssize_t
1561 __recv_chk (int fd, void *buf, size_t n, size_t buflen, int flags)
1562 {
1563   if (n > buflen)
1564     return -1;
1565
1566   return recv (fd, buf, n, flags);
1567 }
1568
1569 static inline int
1570 ldp_vls_sendo (vls_handle_t vlsh, const void *buf, size_t n,
1571                vppcom_endpt_tlv_t *app_tlvs, int flags,
1572                __CONST_SOCKADDR_ARG _addr, socklen_t addr_len)
1573 {
1574   const struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1575   vppcom_endpt_t *ep = 0;
1576   vppcom_endpt_t _ep;
1577
1578   _ep.app_tlvs = app_tlvs;
1579
1580   if (addr)
1581     {
1582       ep = &_ep;
1583       switch (addr->sa_family)
1584         {
1585         case AF_INET:
1586           ep->is_ip4 = VPPCOM_IS_IP4;
1587           ep->ip =
1588             (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
1589           ep->port = (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
1590           break;
1591
1592         case AF_INET6:
1593           ep->is_ip4 = VPPCOM_IS_IP6;
1594           ep->ip =
1595             (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1596           ep->port =
1597             (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
1598           break;
1599
1600         default:
1601           return EAFNOSUPPORT;
1602         }
1603     }
1604
1605   return vls_sendto (vlsh, (void *) buf, n, flags, ep);
1606 }
1607
1608 static int
1609 ldp_vls_recvfrom (vls_handle_t vlsh, void *__restrict buf, size_t n, int flags,
1610                   __SOCKADDR_ARG _addr, socklen_t *__restrict addr_len)
1611 {
1612   u8 src_addr[sizeof (struct sockaddr_in6)];
1613   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1614   vppcom_endpt_t ep;
1615   ssize_t size;
1616   int rv;
1617
1618   if (addr)
1619     {
1620       ep.ip = src_addr;
1621       size = vls_recvfrom (vlsh, buf, n, flags, &ep);
1622
1623       if (size > 0)
1624         {
1625           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1626           if (rv < 0)
1627             size = rv;
1628         }
1629     }
1630   else
1631     size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1632
1633   return size;
1634 }
1635
1636 ssize_t
1637 sendto (int fd, const void *buf, size_t n, int flags,
1638         __CONST_SOCKADDR_ARG _addr, socklen_t addr_len)
1639 {
1640   const struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
1641   vls_handle_t vlsh;
1642   ssize_t size;
1643
1644   ldp_init_check ();
1645
1646   vlsh = ldp_fd_to_vlsh (fd);
1647   if (vlsh != VLS_INVALID_HANDLE)
1648     {
1649       size = ldp_vls_sendo (vlsh, buf, n, NULL, flags, addr, addr_len);
1650       if (size < 0)
1651         {
1652           errno = -size;
1653           size = -1;
1654         }
1655     }
1656   else
1657     {
1658       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
1659     }
1660
1661   return size;
1662 }
1663
1664 ssize_t
1665 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
1666           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1667 {
1668   vls_handle_t vlsh;
1669   ssize_t size;
1670
1671   ldp_init_check ();
1672
1673   vlsh = ldp_fd_to_vlsh (fd);
1674   if (vlsh != VLS_INVALID_HANDLE)
1675     {
1676       size = ldp_vls_recvfrom (vlsh, buf, n, flags, addr, addr_len);
1677       if (size < 0)
1678         {
1679           errno = -size;
1680           size = -1;
1681         }
1682     }
1683   else
1684     {
1685       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
1686     }
1687
1688   return size;
1689 }
1690
1691 static int
1692 ldp_parse_cmsg (vls_handle_t vlsh, const struct msghdr *msg,
1693                 vppcom_endpt_tlv_t **app_tlvs)
1694 {
1695   uint8_t *ad, *at = (uint8_t *) *app_tlvs;
1696   vppcom_endpt_tlv_t *adh;
1697   struct in_pktinfo *pi;
1698   struct cmsghdr *cmsg;
1699
1700   cmsg = CMSG_FIRSTHDR (msg);
1701
1702   while (cmsg != NULL)
1703     {
1704       switch (cmsg->cmsg_level)
1705         {
1706         case SOL_UDP:
1707           switch (cmsg->cmsg_type)
1708             {
1709             case UDP_SEGMENT:
1710               vec_add2 (at, adh, sizeof (*adh));
1711               adh->data_type = VCL_UDP_SEGMENT;
1712               adh->data_len = sizeof (uint16_t);
1713               vec_add2 (at, ad, sizeof (uint16_t));
1714               *(uint16_t *) ad = *(uint16_t *) CMSG_DATA (cmsg);
1715               break;
1716             default:
1717               LDBG (1, "SOL_UDP cmsg_type %u not supported", cmsg->cmsg_type);
1718               break;
1719             }
1720           break;
1721         case SOL_IP:
1722           switch (cmsg->cmsg_type)
1723             {
1724             case IP_PKTINFO:
1725               vec_add2 (at, adh, sizeof (*adh));
1726               adh->data_type = VCL_IP_PKTINFO;
1727               adh->data_len = sizeof (struct in_addr);
1728               vec_add2 (at, ad, sizeof (struct in_addr));
1729               pi = (void *) CMSG_DATA (cmsg);
1730               clib_memcpy_fast (ad, &pi->ipi_spec_dst,
1731                                 sizeof (struct in_addr));
1732               break;
1733             default:
1734               LDBG (1, "SOL_IP cmsg_type %u not supported", cmsg->cmsg_type);
1735               break;
1736             }
1737           break;
1738         default:
1739           LDBG (1, "cmsg_level %u not supported", cmsg->cmsg_level);
1740           break;
1741         }
1742       cmsg = CMSG_NXTHDR ((struct msghdr *) msg, cmsg);
1743     }
1744   *app_tlvs = (vppcom_endpt_tlv_t *) at;
1745   return 0;
1746 }
1747
1748 static int
1749 ldp_make_cmsg (vls_handle_t vlsh, struct msghdr *msg)
1750 {
1751   u32 optval, optlen = sizeof (optval);
1752   struct cmsghdr *cmsg;
1753
1754   cmsg = CMSG_FIRSTHDR (msg);
1755   memset (cmsg, 0, sizeof (*cmsg));
1756
1757   if (!vls_attr (vlsh, VPPCOM_ATTR_GET_IP_PKTINFO, (void *) &optval, &optlen))
1758     return 0;
1759
1760   if (optval)
1761     {
1762       vppcom_endpt_t ep;
1763       u8 addr_buf[sizeof (struct in_addr)];
1764       u32 size = sizeof (ep);
1765
1766       ep.ip = addr_buf;
1767
1768       if (!vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size))
1769         {
1770           struct in_pktinfo pi = {};
1771
1772           clib_memcpy (&pi.ipi_addr, ep.ip, sizeof (struct in_addr));
1773           cmsg->cmsg_level = SOL_IP;
1774           cmsg->cmsg_type = IP_PKTINFO;
1775           cmsg->cmsg_len = CMSG_LEN (sizeof (pi));
1776           clib_memcpy (CMSG_DATA (cmsg), &pi, sizeof (pi));
1777         }
1778     }
1779
1780   return 0;
1781 }
1782
1783 ssize_t
1784 sendmsg (int fd, const struct msghdr * msg, int flags)
1785 {
1786   vls_handle_t vlsh;
1787   ssize_t size;
1788
1789   ldp_init_check ();
1790
1791   vlsh = ldp_fd_to_vlsh (fd);
1792   if (vlsh != VLS_INVALID_HANDLE)
1793     {
1794       vppcom_endpt_tlv_t *app_tlvs = 0;
1795       struct iovec *iov = msg->msg_iov;
1796       ssize_t total = 0;
1797       int i, rv = 0;
1798
1799       ldp_parse_cmsg (vlsh, msg, &app_tlvs);
1800
1801       for (i = 0; i < msg->msg_iovlen; ++i)
1802         {
1803           rv = ldp_vls_sendo (vlsh, iov[i].iov_base, iov[i].iov_len, app_tlvs,
1804                               flags, msg->msg_name, msg->msg_namelen);
1805           if (rv < 0)
1806             break;
1807           else
1808             {
1809               total += rv;
1810               if (rv < iov[i].iov_len)
1811                 break;
1812             }
1813         }
1814
1815       vec_free (app_tlvs);
1816
1817       if (rv < 0 && total == 0)
1818         {
1819           errno = -rv;
1820           size = -1;
1821         }
1822       else
1823         size = total;
1824     }
1825   else
1826     {
1827       size = libc_sendmsg (fd, msg, flags);
1828     }
1829
1830   return size;
1831 }
1832
1833 #ifdef _GNU_SOURCE
1834 int
1835 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1836 {
1837   ssize_t size;
1838   const char *func_str;
1839   u32 sh = ldp_fd_to_vlsh (fd);
1840
1841   ldp_init_check ();
1842
1843   if (sh != VLS_INVALID_HANDLE)
1844     {
1845       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1846       errno = ENOSYS;
1847       size = -1;
1848     }
1849   else
1850     {
1851       func_str = "libc_sendmmsg";
1852
1853       if (LDP_DEBUG > 2)
1854         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1855                       "vmessages %p, vlen %u, flags 0x%x",
1856                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1857
1858       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1859     }
1860
1861   if (LDP_DEBUG > 2)
1862     {
1863       if (size < 0)
1864         {
1865           int errno_val = errno;
1866           perror (func_str);
1867           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1868                         "rv %d, errno = %d", getpid (), fd, fd,
1869                         func_str, size, errno_val);
1870           errno = errno_val;
1871         }
1872       else
1873         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1874                       getpid (), fd, fd, size, size);
1875     }
1876   return size;
1877 }
1878 #endif
1879
1880 ssize_t
1881 recvmsg (int fd, struct msghdr * msg, int flags)
1882 {
1883   vls_handle_t vlsh;
1884   ssize_t size;
1885
1886   ldp_init_check ();
1887
1888   vlsh = ldp_fd_to_vlsh (fd);
1889   if (vlsh != VLS_INVALID_HANDLE)
1890     {
1891       struct iovec *iov = msg->msg_iov;
1892       ssize_t max_deq, total = 0;
1893       int i, rv;
1894
1895       max_deq = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
1896       if (!max_deq)
1897         return 0;
1898
1899       for (i = 0; i < msg->msg_iovlen; i++)
1900         {
1901           rv = ldp_vls_recvfrom (vlsh, iov[i].iov_base, iov[i].iov_len, flags,
1902                                  (i == 0 ? msg->msg_name : NULL),
1903                                  (i == 0 ? &msg->msg_namelen : NULL));
1904           if (rv <= 0)
1905             break;
1906           else
1907             {
1908               total += rv;
1909               if (rv < iov[i].iov_len)
1910                 break;
1911             }
1912           if (total >= max_deq)
1913             break;
1914         }
1915
1916       if (rv < 0 && total == 0)
1917         {
1918           errno = -rv;
1919           size = -1;
1920         }
1921       else
1922         {
1923           if (msg->msg_controllen)
1924             ldp_make_cmsg (vlsh, msg);
1925           size = total;
1926         }
1927     }
1928   else
1929     {
1930       size = libc_recvmsg (fd, msg, flags);
1931     }
1932
1933   return size;
1934 }
1935
1936 #ifdef _GNU_SOURCE
1937 int
1938 recvmmsg (int fd, struct mmsghdr *vmessages,
1939           unsigned int vlen, int flags, struct timespec *tmo)
1940 {
1941   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1942   u32 sh;
1943
1944   ldp_init_check ();
1945
1946   sh = ldp_fd_to_vlsh (fd);
1947
1948   if (sh != VLS_INVALID_HANDLE)
1949     {
1950       struct mmsghdr *mh;
1951       ssize_t rv = 0;
1952       u32 nvecs = 0;
1953       f64 time_out;
1954
1955       if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
1956         clib_time_init (&ldpw->clib_time);
1957       if (tmo)
1958         {
1959           time_out = (f64) tmo->tv_sec + (f64) tmo->tv_nsec / (f64) 1e9;
1960           time_out += clib_time_now (&ldpw->clib_time);
1961         }
1962       else
1963         {
1964           time_out = (f64) ~0;
1965         }
1966
1967       while (nvecs < vlen)
1968         {
1969           mh = &vmessages[nvecs];
1970           rv = recvmsg (fd, &mh->msg_hdr, flags);
1971           if (rv > 0)
1972             {
1973               mh->msg_len = rv;
1974               nvecs += 1;
1975               continue;
1976             }
1977
1978           if (!time_out || clib_time_now (&ldpw->clib_time) >= time_out)
1979             break;
1980
1981           usleep (1);
1982         }
1983
1984       return nvecs > 0 ? nvecs : rv;
1985     }
1986   else
1987     {
1988       return libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1989     }
1990 }
1991 #endif
1992
1993 int
1994 getsockopt (int fd, int level, int optname,
1995             void *__restrict optval, socklen_t * __restrict optlen)
1996 {
1997   vls_handle_t vlsh;
1998   int rv;
1999
2000   ldp_init_check ();
2001
2002   vlsh = ldp_fd_to_vlsh (fd);
2003   if (vlsh != VLS_INVALID_HANDLE)
2004     {
2005       rv = -EOPNOTSUPP;
2006
2007       switch (level)
2008         {
2009         case SOL_TCP:
2010           switch (optname)
2011             {
2012             case TCP_NODELAY:
2013               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
2014                              optval, optlen);
2015               break;
2016             case TCP_MAXSEG:
2017               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
2018                              optval, optlen);
2019               break;
2020             case TCP_KEEPIDLE:
2021               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
2022                              optval, optlen);
2023               break;
2024             case TCP_KEEPINTVL:
2025               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
2026                              optval, optlen);
2027               break;
2028             case TCP_INFO:
2029               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
2030                 {
2031                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
2032                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
2033                   memset (optval, 0, *optlen);
2034                   rv = VPPCOM_OK;
2035                 }
2036               else
2037                 rv = -EFAULT;
2038               break;
2039             case TCP_CONGESTION:
2040               *optlen = strlen ("cubic");
2041               strncpy (optval, "cubic", *optlen + 1);
2042               rv = 0;
2043               break;
2044             default:
2045               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
2046                     "optname %d unsupported!", fd, vlsh, optname);
2047               break;
2048             }
2049           break;
2050         case SOL_IP:
2051           switch (optname)
2052             {
2053             case SO_ORIGINAL_DST:
2054               rv =
2055                 vls_attr (vlsh, VPPCOM_ATTR_GET_ORIGINAL_DST, optval, optlen);
2056               break;
2057             default:
2058               LDBG (0,
2059                     "ERROR: fd %d: getsockopt SOL_IP: vlsh %u "
2060                     "optname %d unsupported!",
2061                     fd, vlsh, optname);
2062               break;
2063             }
2064           break;
2065         case SOL_IPV6:
2066           switch (optname)
2067             {
2068             case IPV6_V6ONLY:
2069               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
2070               break;
2071             default:
2072               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
2073                     "optname %d unsupported!", fd, vlsh, optname);
2074               break;
2075             }
2076           break;
2077         case SOL_SOCKET:
2078           switch (optname)
2079             {
2080             case SO_ACCEPTCONN:
2081               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
2082               break;
2083             case SO_KEEPALIVE:
2084               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
2085               break;
2086             case SO_PROTOCOL:
2087               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
2088               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
2089               break;
2090             case SO_SNDBUF:
2091               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
2092                              optval, optlen);
2093               break;
2094             case SO_RCVBUF:
2095               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
2096                              optval, optlen);
2097               break;
2098             case SO_REUSEADDR:
2099               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
2100               break;
2101             case SO_REUSEPORT:
2102               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen);
2103               break;
2104             case SO_BROADCAST:
2105               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
2106               break;
2107             case SO_DOMAIN:
2108               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen);
2109               break;
2110             case SO_ERROR:
2111               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
2112               break;
2113             case SO_BINDTODEVICE:
2114               rv = 0;
2115               break;
2116             default:
2117               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
2118                     "optname %d unsupported!", fd, vlsh, optname);
2119               break;
2120             }
2121           break;
2122         default:
2123           break;
2124         }
2125
2126       if (rv != VPPCOM_OK)
2127         {
2128           errno = -rv;
2129           rv = -1;
2130         }
2131     }
2132   else
2133     {
2134       rv = libc_getsockopt (fd, level, optname, optval, optlen);
2135     }
2136
2137   return rv;
2138 }
2139
2140 int
2141 setsockopt (int fd, int level, int optname,
2142             const void *optval, socklen_t optlen)
2143 {
2144   vls_handle_t vlsh;
2145   int rv;
2146
2147   ldp_init_check ();
2148
2149   vlsh = ldp_fd_to_vlsh (fd);
2150   if (vlsh != VLS_INVALID_HANDLE)
2151     {
2152       rv = -EOPNOTSUPP;
2153
2154       switch (level)
2155         {
2156         case SOL_TCP:
2157           switch (optname)
2158             {
2159             case TCP_NODELAY:
2160               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
2161                              (void *) optval, &optlen);
2162               break;
2163             case TCP_MAXSEG:
2164               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
2165                              (void *) optval, &optlen);
2166               break;
2167             case TCP_KEEPIDLE:
2168               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2169                              (void *) optval, &optlen);
2170               break;
2171             case TCP_KEEPINTVL:
2172               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2173                              (void *) optval, &optlen);
2174               break;
2175             case TCP_CONGESTION:
2176             case TCP_CORK:
2177               /* Ignore */
2178               rv = 0;
2179               break;
2180             default:
2181               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2182                     "optname %d unsupported!", fd, vlsh, optname);
2183               break;
2184             }
2185           break;
2186         case SOL_IPV6:
2187           switch (optname)
2188             {
2189             case IPV6_V6ONLY:
2190               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2191                              (void *) optval, &optlen);
2192               break;
2193             default:
2194               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2195                     "optname %d unsupported!", fd, vlsh, optname);
2196               break;
2197             }
2198           break;
2199         case SOL_SOCKET:
2200           switch (optname)
2201             {
2202             case SO_KEEPALIVE:
2203               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2204                              (void *) optval, &optlen);
2205               break;
2206             case SO_REUSEADDR:
2207               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2208                              (void *) optval, &optlen);
2209               break;
2210             case SO_REUSEPORT:
2211               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval,
2212                              &optlen);
2213               break;
2214             case SO_BROADCAST:
2215               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2216                              (void *) optval, &optlen);
2217               break;
2218             case SO_LINGER:
2219               rv = 0;
2220               break;
2221             default:
2222               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2223                     "optname %d unsupported!", fd, vlsh, optname);
2224               break;
2225             }
2226           break;
2227         case SOL_IP:
2228           switch (optname)
2229             {
2230             case IP_PKTINFO:
2231               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_IP_PKTINFO, (void *) optval,
2232                              &optlen);
2233               break;
2234             default:
2235               LDBG (0,
2236                     "ERROR: fd %d: setsockopt SOL_IP: vlsh %u optname %d"
2237                     "unsupported!",
2238                     fd, vlsh, optname);
2239               break;
2240             }
2241           break;
2242         default:
2243           break;
2244         }
2245
2246       if (rv != VPPCOM_OK)
2247         {
2248           errno = -rv;
2249           rv = -1;
2250         }
2251     }
2252   else
2253     {
2254       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2255     }
2256
2257   return rv;
2258 }
2259
2260 int
2261 listen (int fd, int n)
2262 {
2263   vls_handle_t vlsh;
2264   int rv;
2265
2266   ldp_init_check ();
2267
2268   vlsh = ldp_fd_to_vlsh (fd);
2269   if (vlsh != VLS_INVALID_HANDLE)
2270     {
2271       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2272
2273       rv = vls_listen (vlsh, n);
2274       if (rv != VPPCOM_OK)
2275         {
2276           errno = -rv;
2277           rv = -1;
2278         }
2279     }
2280   else
2281     {
2282       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2283       rv = libc_listen (fd, n);
2284     }
2285
2286   LDBG (1, "fd %d: returning %d", fd, rv);
2287   return rv;
2288 }
2289
2290 static inline int
2291 ldp_accept4 (int listen_fd, __SOCKADDR_ARG _addr,
2292              socklen_t *__restrict addr_len, int flags)
2293 {
2294   struct sockaddr *addr = SOCKADDR_GET_SA (_addr);
2295   vls_handle_t listen_vlsh, accept_vlsh;
2296   int rv;
2297
2298   ldp_init_check ();
2299
2300   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2301   if (listen_vlsh != VLS_INVALID_HANDLE)
2302     {
2303       vppcom_endpt_t ep;
2304       u8 src_addr[sizeof (struct sockaddr_in6)];
2305       memset (&ep, 0, sizeof (ep));
2306       ep.ip = src_addr;
2307
2308       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2309             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2310
2311       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2312       if (accept_vlsh < 0)
2313         {
2314           errno = -accept_vlsh;
2315           rv = -1;
2316         }
2317       else
2318         {
2319           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2320           if (rv != VPPCOM_OK)
2321             {
2322               (void) vls_close (accept_vlsh);
2323               errno = -rv;
2324               rv = -1;
2325             }
2326           else
2327             {
2328               rv = ldp_vlsh_to_fd (accept_vlsh);
2329             }
2330         }
2331     }
2332   else
2333     {
2334       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2335             " flags 0x%x", listen_fd, addr, addr_len, flags);
2336
2337       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2338     }
2339
2340   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2341
2342   return rv;
2343 }
2344
2345 int
2346 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2347          int flags)
2348 {
2349   return ldp_accept4 (fd, addr, addr_len, flags);
2350 }
2351
2352 int
2353 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2354 {
2355   return ldp_accept4 (fd, addr, addr_len, 0);
2356 }
2357
2358 int
2359 shutdown (int fd, int how)
2360 {
2361   vls_handle_t vlsh;
2362   int rv = 0;
2363
2364   ldp_init_check ();
2365
2366   vlsh = ldp_fd_to_vlsh (fd);
2367   if (vlsh != VLS_INVALID_HANDLE)
2368     {
2369       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2370       rv = vls_shutdown (vlsh, how);
2371     }
2372   else
2373     {
2374       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2375       rv = libc_shutdown (fd, how);
2376     }
2377
2378   return rv;
2379 }
2380
2381 int
2382 epoll_create1 (int flags)
2383 {
2384   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2385   vls_handle_t vlsh;
2386   int rv;
2387
2388   ldp_init_check ();
2389
2390   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2391     {
2392       /* Make sure workers have been allocated */
2393       if (!ldp->workers)
2394         {
2395           ldp_alloc_workers ();
2396           ldpw = ldp_worker_get_current ();
2397         }
2398       rv = libc_epoll_create1 (flags);
2399       ldp->vcl_needs_real_epoll = 0;
2400       ldpw->vcl_mq_epfd = rv;
2401       LDBG (0, "created vcl epfd %u", rv);
2402       return rv;
2403     }
2404
2405   vlsh = vls_epoll_create ();
2406   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2407     {
2408       errno = -vlsh;
2409       rv = -1;
2410     }
2411   else
2412     {
2413       rv = ldp_vlsh_to_fd (vlsh);
2414     }
2415   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2416   return rv;
2417 }
2418
2419 int
2420 epoll_create (int size)
2421 {
2422   return epoll_create1 (0);
2423 }
2424
2425 int
2426 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2427 {
2428   vls_handle_t vep_vlsh, vlsh;
2429   int rv;
2430
2431   ldp_init_check ();
2432
2433   vep_vlsh = ldp_fd_to_vlsh (epfd);
2434   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2435     {
2436       /* The LDP epoll_create1 always creates VCL epfd's.
2437        * The app should never have a kernel base epoll fd unless it
2438        * was acquired outside of the LD_PRELOAD process context.
2439        * In any case, if we get one, punt it to libc_epoll_ctl.
2440        */
2441       LDBG (1,
2442             "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2443             " events 0x%x",
2444             epfd, op, fd, event ? event->events : 0);
2445
2446       rv = libc_epoll_ctl (epfd, op, fd, event);
2447       goto done;
2448     }
2449
2450   vlsh = ldp_fd_to_vlsh (fd);
2451
2452   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2453         vlsh, op);
2454
2455   if (vlsh != VLS_INVALID_HANDLE)
2456     {
2457       LDBG (1,
2458             "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2459             " events 0x%x",
2460             epfd, vep_vlsh, op, vlsh, event ? event->events : 0);
2461
2462       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2463       if (rv != VPPCOM_OK)
2464         {
2465           errno = -rv;
2466           rv = -1;
2467         }
2468     }
2469   else
2470     {
2471       int libc_epfd;
2472       u32 size = sizeof (epfd);
2473
2474       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2475       if (!libc_epfd)
2476         {
2477           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2478                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2479
2480           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2481           if (libc_epfd < 0)
2482             {
2483               rv = libc_epfd;
2484               goto done;
2485             }
2486
2487           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2488                          &size);
2489           if (rv < 0)
2490             {
2491               errno = -rv;
2492               rv = -1;
2493               goto done;
2494             }
2495         }
2496       else if (PREDICT_FALSE (libc_epfd < 0))
2497         {
2498           errno = -epfd;
2499           rv = -1;
2500           goto done;
2501         }
2502
2503       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2504             " event %p", epfd, libc_epfd, op, fd, event);
2505
2506       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2507     }
2508
2509 done:
2510   return rv;
2511 }
2512
2513 static inline int
2514 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2515                  int timeout, const sigset_t * sigmask)
2516 {
2517   ldp_worker_ctx_t *ldpw;
2518   double time_to_wait = (double) 0, max_time;
2519   int libc_epfd, rv = 0;
2520   vls_handle_t ep_vlsh;
2521
2522   ldp_init_check ();
2523
2524   if (PREDICT_FALSE (!events || (timeout < -1)))
2525     {
2526       errno = EFAULT;
2527       return -1;
2528     }
2529
2530   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2531     vls_register_vcl_worker ();
2532
2533   ldpw = ldp_worker_get_current ();
2534   if (epfd == ldpw->vcl_mq_epfd)
2535     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2536
2537   ep_vlsh = ldp_fd_to_vlsh (epfd);
2538   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2539     {
2540       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2541       errno = EBADFD;
2542       return -1;
2543     }
2544
2545   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2546     clib_time_init (&ldpw->clib_time);
2547   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2548   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2549
2550   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2551   if (PREDICT_FALSE (libc_epfd < 0))
2552     {
2553       errno = -libc_epfd;
2554       rv = -1;
2555       goto done;
2556     }
2557
2558   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2559         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2560         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2561   do
2562     {
2563       if (!ldpw->epoll_wait_vcl)
2564         {
2565           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2566           if (rv > 0)
2567             {
2568               ldpw->epoll_wait_vcl = 1;
2569               goto done;
2570             }
2571           else if (rv < 0)
2572             {
2573               errno = -rv;
2574               rv = -1;
2575               goto done;
2576             }
2577         }
2578       else
2579         ldpw->epoll_wait_vcl = 0;
2580
2581       if (libc_epfd > 0)
2582         {
2583           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2584           if (rv != 0)
2585             goto done;
2586         }
2587     }
2588   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2589
2590 done:
2591   return rv;
2592 }
2593
2594 static inline int
2595 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2596                          int maxevents, int timeout, const sigset_t * sigmask)
2597 {
2598   int libc_epfd, rv = 0, num_ev, libc_num_ev, vcl_wups = 0;
2599   struct epoll_event *libc_evts;
2600   ldp_worker_ctx_t *ldpw;
2601   vls_handle_t ep_vlsh;
2602
2603   ldp_init_check ();
2604
2605   if (PREDICT_FALSE (!events || (timeout < -1)))
2606     {
2607       errno = EFAULT;
2608       return -1;
2609     }
2610
2611   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2612    * one thread but it is now used on another */
2613   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2614     vls_register_vcl_worker ();
2615
2616   ldpw = ldp_worker_get_current ();
2617   if (epfd == ldpw->vcl_mq_epfd)
2618     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2619
2620   ep_vlsh = ldp_fd_to_vlsh (epfd);
2621   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2622     {
2623       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2624       errno = EBADFD;
2625       return -1;
2626     }
2627
2628   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2629   if (PREDICT_FALSE (!libc_epfd))
2630     {
2631       u32 size = sizeof (epfd);
2632
2633       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2634             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2635       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2636       if (libc_epfd < 0)
2637         {
2638           rv = libc_epfd;
2639           goto done;
2640         }
2641
2642       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2643       if (rv < 0)
2644         {
2645           errno = -rv;
2646           rv = -1;
2647           goto done;
2648         }
2649     }
2650   if (PREDICT_FALSE (libc_epfd <= 0))
2651     {
2652       errno = -libc_epfd;
2653       rv = -1;
2654       goto done;
2655     }
2656
2657   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2658     {
2659       struct epoll_event e = { 0 };
2660       e.events = EPOLLIN;
2661       e.data.fd = ldpw->vcl_mq_epfd;
2662       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2663           0)
2664         {
2665           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2666                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2667           rv = -1;
2668           goto done;
2669         }
2670       ldpw->mq_epfd_added = 1;
2671     }
2672
2673   /* Request to only drain unhandled to prevent libc_epoll_wait starved */
2674   rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2);
2675   if (rv > 0)
2676     {
2677       timeout = 0;
2678       if (rv >= maxevents)
2679         goto done;
2680     }
2681   else if (PREDICT_FALSE (rv < 0))
2682     {
2683       errno = -rv;
2684       rv = -1;
2685       goto done;
2686     }
2687
2688 epoll_again:
2689
2690   libc_evts = &events[rv];
2691   libc_num_ev =
2692     libc_epoll_pwait (libc_epfd, libc_evts, maxevents - rv, timeout, sigmask);
2693   if (libc_num_ev <= 0)
2694     {
2695       rv = rv >= 0 ? rv : -1;
2696       goto done;
2697     }
2698
2699   for (int i = 0; i < libc_num_ev; i++)
2700     {
2701       if (libc_evts[i].data.fd == ldpw->vcl_mq_epfd)
2702         {
2703           /* We should remove mq epoll fd from events. */
2704           libc_num_ev--;
2705           if (i != libc_num_ev)
2706             {
2707               libc_evts[i].events = libc_evts[libc_num_ev].events;
2708               libc_evts[i].data.u64 = libc_evts[libc_num_ev].data.u64;
2709             }
2710           num_ev = vls_epoll_wait (ep_vlsh, &libc_evts[libc_num_ev],
2711                                    maxevents - libc_num_ev, 0);
2712           if (PREDICT_TRUE (num_ev > 0))
2713             rv += num_ev;
2714           /* Woken up by vcl but no events generated. Accept it once */
2715           if (rv == 0 && libc_num_ev == 0 && timeout && vcl_wups++ < 1)
2716             goto epoll_again;
2717           break;
2718         }
2719     }
2720
2721   rv += libc_num_ev;
2722
2723 done:
2724   return rv;
2725 }
2726
2727 int
2728 epoll_pwait (int epfd, struct epoll_event *events,
2729              int maxevents, int timeout, const sigset_t * sigmask)
2730 {
2731   if (vls_use_eventfd ())
2732     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2733                                     sigmask);
2734   else
2735     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2736 }
2737
2738 int
2739 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2740 {
2741   if (vls_use_eventfd ())
2742     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2743   else
2744     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2745 }
2746
2747 int
2748 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2749 {
2750   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2751   int rv, i, n_revents = 0;
2752   vls_handle_t vlsh;
2753   vcl_poll_t *vp;
2754   double max_time;
2755
2756   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2757
2758   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2759     clib_time_init (&ldpw->clib_time);
2760
2761   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2762   max_time += clib_time_now (&ldpw->clib_time);
2763
2764   for (i = 0; i < nfds; i++)
2765     {
2766       if (fds[i].fd < 0)
2767         continue;
2768
2769       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2770       if (vlsh != VLS_INVALID_HANDLE)
2771         {
2772           fds[i].fd = -fds[i].fd;
2773           vec_add2 (ldpw->vcl_poll, vp, 1);
2774           vp->fds_ndx = i;
2775           vp->sh = vlsh_to_sh (vlsh);
2776           vp->events = fds[i].events;
2777 #ifdef __USE_XOPEN2K
2778           if (fds[i].events & POLLRDNORM)
2779             vp->events |= POLLIN;
2780           if (fds[i].events & POLLWRNORM)
2781             vp->events |= POLLOUT;
2782 #endif
2783           vp->revents = fds[i].revents;
2784         }
2785       else
2786         {
2787           vec_add1 (ldpw->libc_poll, fds[i]);
2788           vec_add1 (ldpw->libc_poll_idxs, i);
2789         }
2790     }
2791
2792   do
2793     {
2794       if (vec_len (ldpw->vcl_poll))
2795         {
2796           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2797           if (rv < 0)
2798             {
2799               errno = -rv;
2800               rv = -1;
2801               goto done;
2802             }
2803           else
2804             n_revents += rv;
2805         }
2806
2807       if (vec_len (ldpw->libc_poll))
2808         {
2809           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2810           if (rv < 0)
2811             goto done;
2812           else
2813             n_revents += rv;
2814         }
2815
2816       if (n_revents)
2817         {
2818           rv = n_revents;
2819           goto done;
2820         }
2821     }
2822   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2823   rv = 0;
2824
2825 done:
2826   vec_foreach (vp, ldpw->vcl_poll)
2827   {
2828     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2829     fds[vp->fds_ndx].revents = vp->revents;
2830 #ifdef __USE_XOPEN2K
2831     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2832         (fds[vp->fds_ndx].events & POLLRDNORM))
2833       fds[vp->fds_ndx].revents |= POLLRDNORM;
2834     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2835         (fds[vp->fds_ndx].events & POLLWRNORM))
2836       fds[vp->fds_ndx].revents |= POLLWRNORM;
2837 #endif
2838   }
2839   vec_reset_length (ldpw->vcl_poll);
2840
2841   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2842     {
2843       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2844     }
2845   vec_reset_length (ldpw->libc_poll_idxs);
2846   vec_reset_length (ldpw->libc_poll);
2847
2848   return rv;
2849 }
2850
2851 #ifdef _GNU_SOURCE
2852 int
2853 ppoll (struct pollfd *fds, nfds_t nfds,
2854        const struct timespec *timeout, const sigset_t * sigmask)
2855 {
2856   ldp_init_check ();
2857
2858   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2859   errno = ENOSYS;
2860
2861
2862   return -1;
2863 }
2864 #endif
2865
2866 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2867
2868 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2869
2870 /*
2871  * This function is called when the library is loaded
2872  */
2873 void
2874 ldp_constructor (void)
2875 {
2876   swrap_constructor ();
2877   if (ldp_init () != 0)
2878     {
2879       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2880                getpid ());
2881       _exit (1);
2882     }
2883   else if (LDP_DEBUG > 0)
2884     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2885 }
2886
2887 /*
2888  * This function is called when the library is unloaded
2889  */
2890 void
2891 ldp_destructor (void)
2892 {
2893   /*
2894      swrap_destructor ();
2895      if (ldp->init)
2896      ldp->init = 0;
2897    */
2898
2899   /* Don't use clib_warning() here because that calls writev()
2900    * which will call ldp_init().
2901    */
2902   if (LDP_DEBUG > 0)
2903     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2904              __func__, __LINE__, getpid ());
2905 }
2906
2907
2908 /*
2909  * fd.io coding-style-patch-verification: ON
2910  *
2911  * Local Variables:
2912  * eval: (c-set-style "gnu")
2913  * End:
2914  */