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