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