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