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