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