session: support half-close connection
[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_REUSEPORT:
1956               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEPORT, optval, optlen);
1957               break;
1958             case SO_BROADCAST:
1959               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
1960               break;
1961             case SO_DOMAIN:
1962               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_DOMAIN, optval, optlen);
1963               break;
1964             case SO_ERROR:
1965               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
1966               break;
1967             default:
1968               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
1969                     "optname %d unsupported!", fd, vlsh, optname);
1970               break;
1971             }
1972           break;
1973         default:
1974           break;
1975         }
1976
1977       if (rv != VPPCOM_OK)
1978         {
1979           errno = -rv;
1980           rv = -1;
1981         }
1982     }
1983   else
1984     {
1985       rv = libc_getsockopt (fd, level, optname, optval, optlen);
1986     }
1987
1988   return rv;
1989 }
1990
1991 int
1992 setsockopt (int fd, int level, int optname,
1993             const void *optval, socklen_t optlen)
1994 {
1995   vls_handle_t vlsh;
1996   int rv;
1997
1998   if ((errno = -ldp_init ()))
1999     return -1;
2000
2001   vlsh = ldp_fd_to_vlsh (fd);
2002   if (vlsh != VLS_INVALID_HANDLE)
2003     {
2004       rv = -EOPNOTSUPP;
2005
2006       switch (level)
2007         {
2008         case SOL_TCP:
2009           switch (optname)
2010             {
2011             case TCP_NODELAY:
2012               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
2013                              (void *) optval, &optlen);
2014               break;
2015             case TCP_MAXSEG:
2016               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
2017                              (void *) optval, &optlen);
2018               break;
2019             case TCP_KEEPIDLE:
2020               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2021                              (void *) optval, &optlen);
2022               break;
2023             case TCP_KEEPINTVL:
2024               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2025                              (void *) optval, &optlen);
2026               break;
2027             case TCP_CONGESTION:
2028             case TCP_CORK:
2029               /* Ignore */
2030               rv = 0;
2031               break;
2032             default:
2033               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
2034                     "optname %d unsupported!", fd, vlsh, optname);
2035               break;
2036             }
2037           break;
2038         case SOL_IPV6:
2039           switch (optname)
2040             {
2041             case IPV6_V6ONLY:
2042               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
2043                              (void *) optval, &optlen);
2044               break;
2045             default:
2046               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
2047                     "optname %d unsupported!", fd, vlsh, optname);
2048               break;
2049             }
2050           break;
2051         case SOL_SOCKET:
2052           switch (optname)
2053             {
2054             case SO_KEEPALIVE:
2055               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
2056                              (void *) optval, &optlen);
2057               break;
2058             case SO_REUSEADDR:
2059               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
2060                              (void *) optval, &optlen);
2061               break;
2062             case SO_REUSEPORT:
2063               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEPORT, (void *) optval,
2064                              &optlen);
2065               break;
2066             case SO_BROADCAST:
2067               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
2068                              (void *) optval, &optlen);
2069               break;
2070             default:
2071               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
2072                     "optname %d unsupported!", fd, vlsh, optname);
2073               break;
2074             }
2075           break;
2076         default:
2077           break;
2078         }
2079
2080       if (rv != VPPCOM_OK)
2081         {
2082           errno = -rv;
2083           rv = -1;
2084         }
2085     }
2086   else
2087     {
2088       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2089     }
2090
2091   return rv;
2092 }
2093
2094 int
2095 listen (int fd, int n)
2096 {
2097   vls_handle_t vlsh;
2098   int rv;
2099
2100   if ((errno = -ldp_init ()))
2101     return -1;
2102
2103   vlsh = ldp_fd_to_vlsh (fd);
2104   if (vlsh != VLS_INVALID_HANDLE)
2105     {
2106       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2107
2108       rv = vls_listen (vlsh, n);
2109       if (rv != VPPCOM_OK)
2110         {
2111           errno = -rv;
2112           rv = -1;
2113         }
2114     }
2115   else
2116     {
2117       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2118       rv = libc_listen (fd, n);
2119     }
2120
2121   LDBG (1, "fd %d: returning %d", fd, rv);
2122   return rv;
2123 }
2124
2125 static inline int
2126 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
2127              socklen_t * __restrict addr_len, int flags)
2128 {
2129   vls_handle_t listen_vlsh, accept_vlsh;
2130   int rv;
2131
2132   if ((errno = -ldp_init ()))
2133     return -1;
2134
2135   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2136   if (listen_vlsh != VLS_INVALID_HANDLE)
2137     {
2138       vppcom_endpt_t ep;
2139       u8 src_addr[sizeof (struct sockaddr_in6)];
2140       memset (&ep, 0, sizeof (ep));
2141       ep.ip = src_addr;
2142
2143       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2144             " ep %p, flags 0x%x", listen_fd, listen_vlsh, &ep, flags);
2145
2146       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2147       if (accept_vlsh < 0)
2148         {
2149           errno = -accept_vlsh;
2150           rv = -1;
2151         }
2152       else
2153         {
2154           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2155           if (rv != VPPCOM_OK)
2156             {
2157               (void) vls_close (accept_vlsh);
2158               errno = -rv;
2159               rv = -1;
2160             }
2161           else
2162             {
2163               rv = ldp_vlsh_to_fd (accept_vlsh);
2164             }
2165         }
2166     }
2167   else
2168     {
2169       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2170             " flags 0x%x", listen_fd, addr, addr_len, flags);
2171
2172       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2173     }
2174
2175   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2176
2177   return rv;
2178 }
2179
2180 int
2181 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2182          int flags)
2183 {
2184   return ldp_accept4 (fd, addr, addr_len, flags);
2185 }
2186
2187 int
2188 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2189 {
2190   return ldp_accept4 (fd, addr, addr_len, 0);
2191 }
2192
2193 int
2194 shutdown (int fd, int how)
2195 {
2196   vls_handle_t vlsh;
2197   int rv = 0, flags;
2198   u32 flags_len = sizeof (flags);
2199
2200   if ((errno = -ldp_init ()))
2201     return -1;
2202
2203   vlsh = ldp_fd_to_vlsh (fd);
2204   if (vlsh != VLS_INVALID_HANDLE)
2205     {
2206       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2207
2208       if (vls_attr (vlsh, VPPCOM_ATTR_SET_SHUT, &how, &flags_len))
2209         {
2210           close (fd);
2211           return -1;
2212         }
2213
2214       if (vls_attr (vlsh, VPPCOM_ATTR_GET_SHUT, &flags, &flags_len))
2215         {
2216           close (fd);
2217           return -1;
2218         }
2219
2220       if (flags == SHUT_RDWR)
2221         rv = close (fd);
2222       else if (flags == SHUT_WR)
2223         rv = vls_shutdown (vlsh);
2224     }
2225   else
2226     {
2227       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2228       rv = libc_shutdown (fd, how);
2229     }
2230
2231   return rv;
2232 }
2233
2234 int
2235 epoll_create1 (int flags)
2236 {
2237   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2238   vls_handle_t vlsh;
2239   int rv;
2240
2241   if ((errno = -ldp_init ()))
2242     return -1;
2243
2244   if (ldp->vcl_needs_real_epoll || vls_use_real_epoll ())
2245     {
2246       /* Make sure workers have been allocated */
2247       if (!ldp->workers)
2248         {
2249           ldp_alloc_workers ();
2250           ldpw = ldp_worker_get_current ();
2251         }
2252       rv = libc_epoll_create1 (flags);
2253       ldp->vcl_needs_real_epoll = 0;
2254       ldpw->vcl_mq_epfd = rv;
2255       LDBG (0, "created vcl epfd %u", rv);
2256       return rv;
2257     }
2258
2259   vlsh = vls_epoll_create ();
2260   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2261     {
2262       errno = -vlsh;
2263       rv = -1;
2264     }
2265   else
2266     {
2267       rv = ldp_vlsh_to_fd (vlsh);
2268     }
2269   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2270   return rv;
2271 }
2272
2273 int
2274 epoll_create (int size)
2275 {
2276   return epoll_create1 (0);
2277 }
2278
2279 int
2280 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2281 {
2282   vls_handle_t vep_vlsh, vlsh;
2283   int rv;
2284
2285   if ((errno = -ldp_init ()))
2286     return -1;
2287
2288   vep_vlsh = ldp_fd_to_vlsh (epfd);
2289   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2290     {
2291       /* The LDP epoll_create1 always creates VCL epfd's.
2292        * The app should never have a kernel base epoll fd unless it
2293        * was acquired outside of the LD_PRELOAD process context.
2294        * In any case, if we get one, punt it to libc_epoll_ctl.
2295        */
2296       LDBG (1, "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2297             " event %p", epfd, op, fd, event);
2298
2299       rv = libc_epoll_ctl (epfd, op, fd, event);
2300       goto done;
2301     }
2302
2303   vlsh = ldp_fd_to_vlsh (fd);
2304
2305   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2306         vlsh, op);
2307
2308   if (vlsh != VLS_INVALID_HANDLE)
2309     {
2310       LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2311             " event %p", epfd, vep_vlsh, op, vlsh, event);
2312
2313       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2314       if (rv != VPPCOM_OK)
2315         {
2316           errno = -rv;
2317           rv = -1;
2318         }
2319     }
2320   else
2321     {
2322       int libc_epfd;
2323       u32 size = sizeof (epfd);
2324
2325       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2326       if (!libc_epfd)
2327         {
2328           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2329                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2330
2331           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2332           if (libc_epfd < 0)
2333             {
2334               rv = libc_epfd;
2335               goto done;
2336             }
2337
2338           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2339                          &size);
2340           if (rv < 0)
2341             {
2342               errno = -rv;
2343               rv = -1;
2344               goto done;
2345             }
2346         }
2347       else if (PREDICT_FALSE (libc_epfd < 0))
2348         {
2349           errno = -epfd;
2350           rv = -1;
2351           goto done;
2352         }
2353
2354       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2355             " event %p", epfd, libc_epfd, op, fd, event);
2356
2357       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2358     }
2359
2360 done:
2361   return rv;
2362 }
2363
2364 static inline int
2365 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2366                  int timeout, const sigset_t * sigmask)
2367 {
2368   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2369   double time_to_wait = (double) 0, max_time;
2370   int libc_epfd, rv = 0;
2371   vls_handle_t ep_vlsh;
2372
2373   if ((errno = -ldp_init ()))
2374     return -1;
2375
2376   if (PREDICT_FALSE (!events || (timeout < -1)))
2377     {
2378       errno = EFAULT;
2379       return -1;
2380     }
2381
2382   if (epfd == ldpw->vcl_mq_epfd)
2383     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2384
2385   ep_vlsh = ldp_fd_to_vlsh (epfd);
2386   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2387     {
2388       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2389       errno = EBADFD;
2390       return -1;
2391     }
2392
2393   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2394     clib_time_init (&ldpw->clib_time);
2395   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2396   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2397
2398   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2399   if (PREDICT_FALSE (libc_epfd < 0))
2400     {
2401       errno = -libc_epfd;
2402       rv = -1;
2403       goto done;
2404     }
2405
2406   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2407         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2408         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2409   do
2410     {
2411       if (!ldpw->epoll_wait_vcl)
2412         {
2413           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2414           if (rv > 0)
2415             {
2416               ldpw->epoll_wait_vcl = 1;
2417               goto done;
2418             }
2419           else if (rv < 0)
2420             {
2421               errno = -rv;
2422               rv = -1;
2423               goto done;
2424             }
2425         }
2426       else
2427         ldpw->epoll_wait_vcl = 0;
2428
2429       if (libc_epfd > 0)
2430         {
2431           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2432           if (rv != 0)
2433             goto done;
2434         }
2435     }
2436   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2437
2438 done:
2439   return rv;
2440 }
2441
2442 static inline int
2443 ldp_epoll_pwait_eventfd (int epfd, struct epoll_event *events,
2444                          int maxevents, int timeout, const sigset_t * sigmask)
2445 {
2446   ldp_worker_ctx_t *ldpw;
2447   int libc_epfd, rv = 0, num_ev;
2448   vls_handle_t ep_vlsh;
2449
2450   if ((errno = -ldp_init ()))
2451     return -1;
2452
2453   if (PREDICT_FALSE (!events || (timeout < -1)))
2454     {
2455       errno = EFAULT;
2456       return -1;
2457     }
2458
2459   /* Make sure the vcl worker is valid. Could be that epoll fd was created on
2460    * one thread but it is now used on another */
2461   if (PREDICT_FALSE (vppcom_worker_index () == ~0))
2462     vls_register_vcl_worker ();
2463
2464   ldpw = ldp_worker_get_current ();
2465   if (epfd == ldpw->vcl_mq_epfd)
2466     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2467
2468   ep_vlsh = ldp_fd_to_vlsh (epfd);
2469   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2470     {
2471       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2472       errno = EBADFD;
2473       return -1;
2474     }
2475
2476   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2477   if (PREDICT_FALSE (!libc_epfd))
2478     {
2479       u32 size = sizeof (epfd);
2480
2481       LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2482             "EPOLL_CLOEXEC", epfd, ep_vlsh);
2483       libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2484       if (libc_epfd < 0)
2485         {
2486           rv = libc_epfd;
2487           goto done;
2488         }
2489
2490       rv = vls_attr (ep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd, &size);
2491       if (rv < 0)
2492         {
2493           errno = -rv;
2494           rv = -1;
2495           goto done;
2496         }
2497     }
2498   if (PREDICT_FALSE (libc_epfd <= 0))
2499     {
2500       errno = -libc_epfd;
2501       rv = -1;
2502       goto done;
2503     }
2504
2505   if (PREDICT_FALSE (!ldpw->mq_epfd_added))
2506     {
2507       struct epoll_event e = { 0 };
2508       e.events = EPOLLIN;
2509       e.data.fd = ldpw->vcl_mq_epfd;
2510       if (libc_epoll_ctl (libc_epfd, EPOLL_CTL_ADD, ldpw->vcl_mq_epfd, &e) <
2511           0)
2512         {
2513           LDBG (0, "epfd %d, add libc mq epoll fd %d to libc epoll fd %d",
2514                 epfd, ldpw->vcl_mq_epfd, libc_epfd);
2515           rv = -1;
2516           goto done;
2517         }
2518       ldpw->mq_epfd_added = 1;
2519     }
2520
2521   /* Request to only drain unhandled to prevent libc_epoll_wait starved */
2522   rv = vls_epoll_wait (ep_vlsh, events, maxevents, -2);
2523   if (rv > 0)
2524     goto done;
2525   else if (PREDICT_FALSE (rv < 0))
2526     {
2527       errno = -rv;
2528       rv = -1;
2529       goto done;
2530     }
2531
2532   rv = libc_epoll_pwait (libc_epfd, events, maxevents, timeout, sigmask);
2533   if (rv <= 0)
2534     goto done;
2535   for (int i = 0; i < rv; i++)
2536     {
2537       if (events[i].data.fd == ldpw->vcl_mq_epfd)
2538         {
2539           /* We should remove mq epoll fd from events. */
2540           rv--;
2541           if (i != rv)
2542             {
2543               events[i].events = events[rv].events;
2544               events[i].data.u64 = events[rv].data.u64;
2545             }
2546           num_ev = vls_epoll_wait (ep_vlsh, &events[rv], maxevents - rv, 0);
2547           if (PREDICT_TRUE (num_ev > 0))
2548             rv += num_ev;
2549           break;
2550         }
2551     }
2552
2553 done:
2554   return rv;
2555 }
2556
2557 int
2558 epoll_pwait (int epfd, struct epoll_event *events,
2559              int maxevents, int timeout, const sigset_t * sigmask)
2560 {
2561   if (vls_use_eventfd ())
2562     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout,
2563                                     sigmask);
2564   else
2565     return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2566 }
2567
2568 int
2569 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2570 {
2571   if (vls_use_eventfd ())
2572     return ldp_epoll_pwait_eventfd (epfd, events, maxevents, timeout, NULL);
2573   else
2574     return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2575 }
2576
2577 int
2578 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2579 {
2580   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2581   int rv, i, n_revents = 0;
2582   vls_handle_t vlsh;
2583   vcl_poll_t *vp;
2584   double max_time;
2585
2586   LDBG (3, "fds %p, nfds %ld, timeout %d", fds, nfds, timeout);
2587
2588   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2589     clib_time_init (&ldpw->clib_time);
2590
2591   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2592   max_time += clib_time_now (&ldpw->clib_time);
2593
2594   for (i = 0; i < nfds; i++)
2595     {
2596       if (fds[i].fd < 0)
2597         continue;
2598
2599       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2600       if (vlsh != VLS_INVALID_HANDLE)
2601         {
2602           fds[i].fd = -fds[i].fd;
2603           vec_add2 (ldpw->vcl_poll, vp, 1);
2604           vp->fds_ndx = i;
2605           vp->sh = vlsh_to_sh (vlsh);
2606           vp->events = fds[i].events;
2607 #ifdef __USE_XOPEN2K
2608           if (fds[i].events & POLLRDNORM)
2609             vp->events |= POLLIN;
2610           if (fds[i].events & POLLWRNORM)
2611             vp->events |= POLLOUT;
2612 #endif
2613           vp->revents = fds[i].revents;
2614         }
2615       else
2616         {
2617           vec_add1 (ldpw->libc_poll, fds[i]);
2618           vec_add1 (ldpw->libc_poll_idxs, i);
2619         }
2620     }
2621
2622   do
2623     {
2624       if (vec_len (ldpw->vcl_poll))
2625         {
2626           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2627           if (rv < 0)
2628             {
2629               errno = -rv;
2630               rv = -1;
2631               goto done;
2632             }
2633           else
2634             n_revents += rv;
2635         }
2636
2637       if (vec_len (ldpw->libc_poll))
2638         {
2639           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2640           if (rv < 0)
2641             goto done;
2642           else
2643             n_revents += rv;
2644         }
2645
2646       if (n_revents)
2647         {
2648           rv = n_revents;
2649           goto done;
2650         }
2651     }
2652   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2653   rv = 0;
2654
2655 done:
2656   vec_foreach (vp, ldpw->vcl_poll)
2657   {
2658     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2659     fds[vp->fds_ndx].revents = vp->revents;
2660 #ifdef __USE_XOPEN2K
2661     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2662         (fds[vp->fds_ndx].events & POLLRDNORM))
2663       fds[vp->fds_ndx].revents |= POLLRDNORM;
2664     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2665         (fds[vp->fds_ndx].events & POLLWRNORM))
2666       fds[vp->fds_ndx].revents |= POLLWRNORM;
2667 #endif
2668   }
2669   vec_reset_length (ldpw->vcl_poll);
2670
2671   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2672     {
2673       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2674     }
2675   vec_reset_length (ldpw->libc_poll_idxs);
2676   vec_reset_length (ldpw->libc_poll);
2677
2678   return rv;
2679 }
2680
2681 #ifdef USE_GNU
2682 int
2683 ppoll (struct pollfd *fds, nfds_t nfds,
2684        const struct timespec *timeout, const sigset_t * sigmask)
2685 {
2686   if ((errno = -ldp_init ()))
2687     return -1;
2688
2689   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2690   errno = ENOSYS;
2691
2692
2693   return -1;
2694 }
2695 #endif
2696
2697 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2698
2699 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2700
2701 /*
2702  * This function is called when the library is loaded
2703  */
2704 void
2705 ldp_constructor (void)
2706 {
2707   swrap_constructor ();
2708   if (ldp_init () != 0)
2709     {
2710       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2711                getpid ());
2712       _exit (1);
2713     }
2714   else if (LDP_DEBUG > 0)
2715     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2716 }
2717
2718 /*
2719  * This function is called when the library is unloaded
2720  */
2721 void
2722 ldp_destructor (void)
2723 {
2724   /*
2725      swrap_destructor ();
2726      if (ldp->init)
2727      ldp->init = 0;
2728    */
2729
2730   /* Don't use clib_warning() here because that calls writev()
2731    * which will call ldp_init().
2732    */
2733   if (LDP_DEBUG > 0)
2734     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2735              __func__, __LINE__, getpid ());
2736 }
2737
2738
2739 /*
2740  * fd.io coding-style-patch-verification: ON
2741  *
2742  * Local Variables:
2743  * eval: (c-set-style "gnu")
2744  * End:
2745  */