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