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