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