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