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