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