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