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