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