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