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