d0cf2b913670d1c810de0545df7e1b06b214c9e4
[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       do
384         {
385           for (i = 0; i < iovcnt; ++i)
386             {
387               rv = vls_read (vlsh, iov[i].iov_base, iov[i].iov_len);
388               if (rv < 0)
389                 break;
390               else
391                 {
392                   total += rv;
393                   if (rv < iov[i].iov_len)
394                     break;
395                 }
396             }
397         }
398       while ((rv >= 0) && (total == 0));
399
400       if (rv < 0)
401         {
402           errno = -rv;
403           size = -1;
404         }
405       else
406         size = total;
407     }
408   else
409     {
410       size = libc_readv (fd, iov, iovcnt);
411     }
412
413   return size;
414 }
415
416 ssize_t
417 write (int fd, const void *buf, size_t nbytes)
418 {
419   vls_handle_t vlsh;
420   ssize_t size = 0;
421
422   if ((errno = -ldp_init ()))
423     return -1;
424
425   vlsh = ldp_fd_to_vlsh (fd);
426   if (vlsh != VLS_INVALID_HANDLE)
427     {
428       size = vls_write_msg (vlsh, (void *) buf, nbytes);
429       if (size < 0)
430         {
431           errno = -size;
432           size = -1;
433         }
434     }
435   else
436     {
437       size = libc_write (fd, buf, nbytes);
438     }
439
440   return size;
441 }
442
443 ssize_t
444 writev (int fd, const struct iovec * iov, int iovcnt)
445 {
446   ssize_t size = 0, total = 0;
447   vls_handle_t vlsh;
448   int i, rv = 0;
449
450   if ((errno = -ldp_init ()))
451     return -1;
452
453   vlsh = ldp_fd_to_vlsh (fd);
454   if (vlsh != VLS_INVALID_HANDLE)
455     {
456       do
457         {
458           for (i = 0; i < iovcnt; ++i)
459             {
460               rv = vls_write_msg (vlsh, iov[i].iov_base, iov[i].iov_len);
461               if (rv < 0)
462                 break;
463               else
464                 {
465                   total += rv;
466                   if (rv < iov[i].iov_len)
467                     break;
468                 }
469             }
470         }
471       while ((rv >= 0) && (total == 0));
472
473       if (rv < 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 #ifdef HAVE_FCNTL64
490 int
491 fcntl64 (int fd, int cmd, ...)
492 #else
493 int
494 fcntl (int fd, int cmd, ...)
495 #endif
496 {
497   vls_handle_t vlsh;
498   int rv = 0;
499   va_list ap;
500
501   if ((errno = -ldp_init ()))
502     return -1;
503
504   va_start (ap, cmd);
505
506   vlsh = ldp_fd_to_vlsh (fd);
507   LDBG (0, "fd %u vlsh %d, cmd %u", fd, vlsh, cmd);
508   if (vlsh != VLS_INVALID_HANDLE)
509     {
510       int flags = va_arg (ap, int);
511       u32 size;
512
513       size = sizeof (flags);
514       rv = -EOPNOTSUPP;
515       switch (cmd)
516         {
517         case F_SETFL:
518           rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
519           break;
520
521         case F_GETFL:
522           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
523           if (rv == VPPCOM_OK)
524             rv = flags;
525           break;
526         case F_SETFD:
527           /* TODO handle this */
528           LDBG (0, "F_SETFD ignored flags %u", flags);
529           rv = 0;
530           break;
531         default:
532           rv = -EOPNOTSUPP;
533           break;
534         }
535       if (rv < 0)
536         {
537           errno = -rv;
538           rv = -1;
539         }
540     }
541   else
542     {
543 #ifdef HAVE_FCNTL64
544       rv = libc_vfcntl64 (fd, cmd, ap);
545 #else
546       rv = libc_vfcntl (fd, cmd, ap);
547 #endif
548     }
549
550   va_end (ap);
551
552   return rv;
553 }
554
555 int
556 ioctl (int fd, unsigned long int cmd, ...)
557 {
558   vls_handle_t vlsh;
559   va_list ap;
560   int rv;
561
562   if ((errno = -ldp_init ()))
563     return -1;
564
565   va_start (ap, cmd);
566
567   vlsh = ldp_fd_to_vlsh (fd);
568   if (vlsh != VLS_INVALID_HANDLE)
569     {
570       switch (cmd)
571         {
572         case FIONREAD:
573           rv = vls_attr (vlsh, VPPCOM_ATTR_GET_NREAD, 0, 0);
574           break;
575
576         case FIONBIO:
577           {
578             u32 flags = va_arg (ap, int) ? O_NONBLOCK : 0;
579             u32 size = sizeof (flags);
580
581             /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
582              *      non-blocking, the flags should be read here and merged
583              *      with O_NONBLOCK.
584              */
585             rv = vls_attr (vlsh, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
586           }
587           break;
588
589         default:
590           rv = -EOPNOTSUPP;
591           break;
592         }
593       if (rv < 0)
594         {
595           errno = -rv;
596           rv = -1;
597         }
598     }
599   else
600     {
601       rv = libc_vioctl (fd, cmd, ap);
602     }
603
604   va_end (ap);
605   return rv;
606 }
607
608 always_inline void
609 ldp_select_init_maps (fd_set * __restrict original,
610                       clib_bitmap_t ** resultb, clib_bitmap_t ** libcb,
611                       clib_bitmap_t ** vclb, int nfds, u32 minbits,
612                       u32 n_bytes, uword * si_bits, uword * libc_bits)
613 {
614   uword si_bits_set, libc_bits_set;
615   vls_handle_t vlsh;
616   int fd;
617
618   clib_bitmap_validate (*vclb, minbits);
619   clib_bitmap_validate (*libcb, minbits);
620   clib_bitmap_validate (*resultb, minbits);
621   clib_memcpy_fast (*resultb, original, n_bytes);
622   memset (original, 0, n_bytes);
623
624   /* *INDENT-OFF* */
625   clib_bitmap_foreach (fd, *resultb, ({
626     if (fd > nfds)
627       break;
628     vlsh = ldp_fd_to_vlsh (fd);
629     if (vlsh == VLS_INVALID_HANDLE)
630       clib_bitmap_set_no_check (*libcb, fd, 1);
631     else
632       clib_bitmap_set_no_check (*vclb, vlsh_to_session_index (vlsh), 1);
633   }));
634   /* *INDENT-ON* */
635
636   si_bits_set = clib_bitmap_last_set (*vclb) + 1;
637   *si_bits = (si_bits_set > *si_bits) ? si_bits_set : *si_bits;
638
639   libc_bits_set = clib_bitmap_last_set (*libcb) + 1;
640   *libc_bits = (libc_bits_set > *libc_bits) ? libc_bits_set : *libc_bits;
641 }
642
643 always_inline int
644 ldp_select_vcl_map_to_libc (clib_bitmap_t * vclb, fd_set * __restrict libcb)
645 {
646   vls_handle_t vlsh;
647   uword si;
648   int fd;
649
650   if (!libcb)
651     return 0;
652
653   /* *INDENT-OFF* */
654   clib_bitmap_foreach (si, vclb, ({
655     vlsh = vls_session_index_to_vlsh (si);
656     ASSERT (vlsh != VLS_INVALID_HANDLE);
657     fd = ldp_vlsh_to_fd (vlsh);
658     if (PREDICT_FALSE (fd < 0))
659       {
660         errno = EBADFD;
661         return -1;
662       }
663     FD_SET (fd, libcb);
664   }));
665   /* *INDENT-ON* */
666
667   return 0;
668 }
669
670 always_inline void
671 ldp_select_libc_map_merge (clib_bitmap_t * result, fd_set * __restrict libcb)
672 {
673   uword fd;
674
675   if (!libcb)
676     return;
677
678   /* *INDENT-OFF* */
679   clib_bitmap_foreach (fd, result, ({
680     FD_SET ((int)fd, libcb);
681   }));
682   /* *INDENT-ON* */
683 }
684
685 int
686 ldp_pselect (int nfds, fd_set * __restrict readfds,
687              fd_set * __restrict writefds,
688              fd_set * __restrict exceptfds,
689              const struct timespec *__restrict timeout,
690              const __sigset_t * __restrict sigmask)
691 {
692   u32 minbits = clib_max (nfds, BITS (uword)), n_bytes;
693   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
694   struct timespec libc_tspec = { 0 };
695   f64 time_out, vcl_timeout = 0;
696   uword si_bits, libc_bits;
697   int rv, bits_set = 0;
698
699   if (nfds < 0)
700     {
701       errno = EINVAL;
702       return -1;
703     }
704
705   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
706     clib_time_init (&ldpw->clib_time);
707
708   if (timeout)
709     {
710       time_out = (timeout->tv_sec == 0 && timeout->tv_nsec == 0) ?
711         (f64) 0 : (f64) timeout->tv_sec + (f64) timeout->tv_nsec / (f64) 1e9;
712
713       /* select as fine grained sleep */
714       if (!nfds)
715         {
716           time_out += clib_time_now (&ldpw->clib_time);
717           while (clib_time_now (&ldpw->clib_time) < time_out)
718             ;
719           return 0;
720         }
721     }
722   else if (!nfds)
723     {
724       errno = EINVAL;
725       return -1;
726     }
727   else
728     time_out = -1;
729
730   if (nfds <= ldp->vlsh_bit_val)
731     {
732       rv = libc_pselect (nfds, readfds, writefds, exceptfds,
733                          timeout, sigmask);
734       goto done;
735     }
736
737   si_bits = libc_bits = 0;
738   n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0);
739
740   if (readfds)
741     ldp_select_init_maps (readfds, &ldpw->rd_bitmap, &ldpw->libc_rd_bitmap,
742                           &ldpw->si_rd_bitmap, nfds, minbits, n_bytes,
743                           &si_bits, &libc_bits);
744   if (writefds)
745     ldp_select_init_maps (writefds, &ldpw->wr_bitmap,
746                           &ldpw->libc_wr_bitmap, &ldpw->si_wr_bitmap, nfds,
747                           minbits, n_bytes, &si_bits, &libc_bits);
748   if (exceptfds)
749     ldp_select_init_maps (exceptfds, &ldpw->ex_bitmap,
750                           &ldpw->libc_ex_bitmap, &ldpw->si_ex_bitmap, nfds,
751                           minbits, n_bytes, &si_bits, &libc_bits);
752
753   if (PREDICT_FALSE (!si_bits && !libc_bits))
754     {
755       errno = EINVAL;
756       rv = -1;
757       goto done;
758     }
759
760   if (!si_bits)
761     libc_tspec = timeout ? *timeout : libc_tspec;
762
763   do
764     {
765       if (si_bits)
766         {
767           if (readfds)
768             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->si_rd_bitmap,
769                               vec_len (ldpw->rd_bitmap) *
770                               sizeof (clib_bitmap_t));
771           if (writefds)
772             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->si_wr_bitmap,
773                               vec_len (ldpw->wr_bitmap) *
774                               sizeof (clib_bitmap_t));
775           if (exceptfds)
776             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->si_ex_bitmap,
777                               vec_len (ldpw->ex_bitmap) *
778                               sizeof (clib_bitmap_t));
779
780           rv = vls_select (si_bits, readfds ? ldpw->rd_bitmap : NULL,
781                            writefds ? ldpw->wr_bitmap : NULL,
782                            exceptfds ? ldpw->ex_bitmap : NULL, vcl_timeout);
783           if (rv < 0)
784             {
785               errno = -rv;
786               rv = -1;
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         errno = -size;
1515     }
1516   else
1517     {
1518       size = libc_recv (fd, buf, n, flags);
1519     }
1520
1521   return size;
1522 }
1523
1524 ssize_t
1525 sendto (int fd, const void *buf, size_t n, int flags,
1526         __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1527 {
1528   vls_handle_t vlsh;
1529   ssize_t size;
1530
1531   if ((errno = -ldp_init ()))
1532     return -1;
1533
1534   vlsh = ldp_fd_to_vlsh (fd);
1535   if (vlsh != INVALID_SESSION_ID)
1536     {
1537       vppcom_endpt_t *ep = 0;
1538       vppcom_endpt_t _ep;
1539
1540       if (addr)
1541         {
1542           ep = &_ep;
1543           switch (addr->sa_family)
1544             {
1545             case AF_INET:
1546               ep->is_ip4 = VPPCOM_IS_IP4;
1547               ep->ip =
1548                 (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
1549               ep->port =
1550                 (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
1551               break;
1552
1553             case AF_INET6:
1554               ep->is_ip4 = VPPCOM_IS_IP6;
1555               ep->ip =
1556                 (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1557               ep->port =
1558                 (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
1559               break;
1560
1561             default:
1562               errno = EAFNOSUPPORT;
1563               size = -1;
1564               goto done;
1565             }
1566         }
1567
1568       size = vls_sendto (vlsh, (void *) buf, n, flags, ep);
1569       if (size < 0)
1570         {
1571           errno = -size;
1572           size = -1;
1573         }
1574     }
1575   else
1576     {
1577       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
1578     }
1579
1580 done:
1581   return size;
1582 }
1583
1584 ssize_t
1585 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
1586           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1587 {
1588   vls_handle_t sid;
1589   ssize_t size, rv;
1590
1591   if ((errno = -ldp_init ()))
1592     return -1;
1593
1594   sid = ldp_fd_to_vlsh (fd);
1595   if (sid != VLS_INVALID_HANDLE)
1596     {
1597       vppcom_endpt_t ep;
1598       u8 src_addr[sizeof (struct sockaddr_in6)];
1599
1600       if (addr)
1601         {
1602           ep.ip = src_addr;
1603           size = vls_recvfrom (sid, buf, n, flags, &ep);
1604
1605           if (size > 0)
1606             {
1607               rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1608               if (rv < 0)
1609                 size = rv;
1610             }
1611         }
1612       else
1613         size = vls_recvfrom (sid, buf, n, flags, NULL);
1614
1615       if (size < 0)
1616         {
1617           errno = -size;
1618           size = -1;
1619         }
1620     }
1621   else
1622     {
1623       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
1624     }
1625
1626   return size;
1627 }
1628
1629 ssize_t
1630 sendmsg (int fd, const struct msghdr * message, int flags)
1631 {
1632   vls_handle_t vlsh;
1633   ssize_t size;
1634
1635   if ((errno = -ldp_init ()))
1636     return -1;
1637
1638   vlsh = ldp_fd_to_vlsh (fd);
1639   if (vlsh != VLS_INVALID_HANDLE)
1640     {
1641       LDBG (0, "LDP-TBD");
1642       errno = ENOSYS;
1643       size = -1;
1644     }
1645   else
1646     {
1647       size = libc_sendmsg (fd, message, flags);
1648     }
1649
1650   return size;
1651 }
1652
1653 #ifdef USE_GNU
1654 int
1655 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1656 {
1657   ssize_t size;
1658   const char *func_str;
1659   u32 sh = ldp_fd_to_vlsh (fd);
1660
1661   if ((errno = -ldp_init ()))
1662     return -1;
1663
1664   if (sh != INVALID_SESSION_ID)
1665     {
1666       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1667       errno = ENOSYS;
1668       size = -1;
1669     }
1670   else
1671     {
1672       func_str = "libc_sendmmsg";
1673
1674       if (LDP_DEBUG > 2)
1675         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1676                       "vmessages %p, vlen %u, flags 0x%x",
1677                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1678
1679       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1680     }
1681
1682   if (LDP_DEBUG > 2)
1683     {
1684       if (size < 0)
1685         {
1686           int errno_val = errno;
1687           perror (func_str);
1688           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1689                         "rv %d, errno = %d", getpid (), fd, fd,
1690                         func_str, size, errno_val);
1691           errno = errno_val;
1692         }
1693       else
1694         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1695                       getpid (), fd, fd, size, size);
1696     }
1697   return size;
1698 }
1699 #endif
1700
1701 ssize_t
1702 recvmsg (int fd, struct msghdr * message, int flags)
1703 {
1704   vls_handle_t vlsh;
1705   ssize_t size;
1706
1707   if ((errno = -ldp_init ()))
1708     return -1;
1709
1710   vlsh = ldp_fd_to_vlsh (fd);
1711   if (vlsh != VLS_INVALID_HANDLE)
1712     {
1713       LDBG (0, "LDP-TBD");
1714       errno = ENOSYS;
1715       size = -1;
1716     }
1717   else
1718     {
1719       size = libc_recvmsg (fd, message, flags);
1720     }
1721
1722   return size;
1723 }
1724
1725 #ifdef USE_GNU
1726 int
1727 recvmmsg (int fd, struct mmsghdr *vmessages,
1728           unsigned int vlen, int flags, struct timespec *tmo)
1729 {
1730   ssize_t size;
1731   const char *func_str;
1732   u32 sh = ldp_fd_to_vlsh (fd);
1733
1734   if ((errno = -ldp_init ()))
1735     return -1;
1736
1737   if (sh != INVALID_SESSION_ID)
1738     {
1739       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1740       errno = ENOSYS;
1741       size = -1;
1742     }
1743   else
1744     {
1745       func_str = "libc_recvmmsg";
1746
1747       if (LDP_DEBUG > 2)
1748         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1749                       "vmessages %p, vlen %u, flags 0x%x, tmo %p",
1750                       getpid (), fd, fd, func_str, vmessages, vlen,
1751                       flags, tmo);
1752
1753       size = libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1754     }
1755
1756   if (LDP_DEBUG > 2)
1757     {
1758       if (size < 0)
1759         {
1760           int errno_val = errno;
1761           perror (func_str);
1762           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1763                         "rv %d, errno = %d", getpid (), fd, fd,
1764                         func_str, size, errno_val);
1765           errno = errno_val;
1766         }
1767       else
1768         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1769                       getpid (), fd, fd, size, size);
1770     }
1771   return size;
1772 }
1773 #endif
1774
1775 int
1776 getsockopt (int fd, int level, int optname,
1777             void *__restrict optval, socklen_t * __restrict optlen)
1778 {
1779   vls_handle_t vlsh;
1780   int rv;
1781
1782   if ((errno = -ldp_init ()))
1783     return -1;
1784
1785   vlsh = ldp_fd_to_vlsh (fd);
1786   if (vlsh != VLS_INVALID_HANDLE)
1787     {
1788       rv = -EOPNOTSUPP;
1789
1790       switch (level)
1791         {
1792         case SOL_TCP:
1793           switch (optname)
1794             {
1795             case TCP_NODELAY:
1796               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
1797                              optval, optlen);
1798               break;
1799             case TCP_MAXSEG:
1800               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
1801                              optval, optlen);
1802               break;
1803             case TCP_KEEPIDLE:
1804               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
1805                              optval, optlen);
1806               break;
1807             case TCP_KEEPINTVL:
1808               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
1809                              optval, optlen);
1810               break;
1811             case TCP_INFO:
1812               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
1813                 {
1814                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
1815                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
1816                   memset (optval, 0, *optlen);
1817                   rv = VPPCOM_OK;
1818                 }
1819               else
1820                 rv = -EFAULT;
1821               break;
1822             case TCP_CONGESTION:
1823               strcpy (optval, "cubic");
1824               *optlen = strlen ("cubic");
1825               rv = 0;
1826               break;
1827             default:
1828               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
1829                     "optname %d unsupported!", fd, vlsh, optname);
1830               break;
1831             }
1832           break;
1833         case SOL_IPV6:
1834           switch (optname)
1835             {
1836             case IPV6_V6ONLY:
1837               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
1838               break;
1839             default:
1840               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
1841                     "optname %d unsupported!", fd, vlsh, optname);
1842               break;
1843             }
1844           break;
1845         case SOL_SOCKET:
1846           switch (optname)
1847             {
1848             case SO_ACCEPTCONN:
1849               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
1850               break;
1851             case SO_KEEPALIVE:
1852               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
1853               break;
1854             case SO_PROTOCOL:
1855               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
1856               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
1857               break;
1858             case SO_SNDBUF:
1859               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
1860                              optval, optlen);
1861               break;
1862             case SO_RCVBUF:
1863               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
1864                              optval, optlen);
1865               break;
1866             case SO_REUSEADDR:
1867               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
1868               break;
1869             case SO_BROADCAST:
1870               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
1871               break;
1872             case SO_ERROR:
1873               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
1874               break;
1875             default:
1876               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
1877                     "optname %d unsupported!", fd, vlsh, optname);
1878               break;
1879             }
1880           break;
1881         default:
1882           break;
1883         }
1884
1885       if (rv != VPPCOM_OK)
1886         {
1887           errno = -rv;
1888           rv = -1;
1889         }
1890     }
1891   else
1892     {
1893       rv = libc_getsockopt (fd, level, optname, optval, optlen);
1894     }
1895
1896   return rv;
1897 }
1898
1899 int
1900 setsockopt (int fd, int level, int optname,
1901             const void *optval, socklen_t optlen)
1902 {
1903   vls_handle_t vlsh;
1904   int rv;
1905
1906   if ((errno = -ldp_init ()))
1907     return -1;
1908
1909   vlsh = ldp_fd_to_vlsh (fd);
1910   if (vlsh != VLS_INVALID_HANDLE)
1911     {
1912       rv = -EOPNOTSUPP;
1913
1914       switch (level)
1915         {
1916         case SOL_TCP:
1917           switch (optname)
1918             {
1919             case TCP_NODELAY:
1920               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
1921                              (void *) optval, &optlen);
1922               break;
1923             case TCP_MAXSEG:
1924               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
1925                              (void *) optval, &optlen);
1926               break;
1927             case TCP_KEEPIDLE:
1928               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
1929                              (void *) optval, &optlen);
1930               break;
1931             case TCP_KEEPINTVL:
1932               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
1933                              (void *) optval, &optlen);
1934               break;
1935             case TCP_CONGESTION:
1936             case TCP_CORK:
1937               /* Ignore */
1938               rv = 0;
1939               break;
1940             default:
1941               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
1942                     "optname %d unsupported!", fd, vlsh, optname);
1943               break;
1944             }
1945           break;
1946         case SOL_IPV6:
1947           switch (optname)
1948             {
1949             case IPV6_V6ONLY:
1950               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
1951                              (void *) optval, &optlen);
1952               break;
1953             default:
1954               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
1955                     "optname %d unsupported!", fd, vlsh, optname);
1956               break;
1957             }
1958           break;
1959         case SOL_SOCKET:
1960           switch (optname)
1961             {
1962             case SO_KEEPALIVE:
1963               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
1964                              (void *) optval, &optlen);
1965               break;
1966             case SO_REUSEADDR:
1967               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
1968                              (void *) optval, &optlen);
1969               break;
1970             case SO_BROADCAST:
1971               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
1972                              (void *) optval, &optlen);
1973               break;
1974             default:
1975               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
1976                     "optname %d unsupported!", fd, vlsh, optname);
1977               break;
1978             }
1979           break;
1980         default:
1981           break;
1982         }
1983
1984       if (rv != VPPCOM_OK)
1985         {
1986           errno = -rv;
1987           rv = -1;
1988         }
1989     }
1990   else
1991     {
1992       rv = libc_setsockopt (fd, level, optname, optval, optlen);
1993     }
1994
1995   return rv;
1996 }
1997
1998 int
1999 listen (int fd, int n)
2000 {
2001   vls_handle_t vlsh;
2002   int rv;
2003
2004   if ((errno = -ldp_init ()))
2005     return -1;
2006
2007   vlsh = ldp_fd_to_vlsh (fd);
2008   if (vlsh != VLS_INVALID_HANDLE)
2009     {
2010       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
2011
2012       rv = vls_listen (vlsh, n);
2013       if (rv != VPPCOM_OK)
2014         {
2015           errno = -rv;
2016           rv = -1;
2017         }
2018     }
2019   else
2020     {
2021       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
2022       rv = libc_listen (fd, n);
2023     }
2024
2025   LDBG (1, "fd %d: returning %d", fd, rv);
2026   return rv;
2027 }
2028
2029 static inline int
2030 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
2031              socklen_t * __restrict addr_len, int flags)
2032 {
2033   vls_handle_t listen_vlsh, accept_vlsh;
2034   int rv;
2035
2036   if ((errno = -ldp_init ()))
2037     return -1;
2038
2039   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
2040   if (listen_vlsh != VLS_INVALID_HANDLE)
2041     {
2042       vppcom_endpt_t ep;
2043       u8 src_addr[sizeof (struct sockaddr_in6)];
2044       memset (&ep, 0, sizeof (ep));
2045       ep.ip = src_addr;
2046
2047       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
2048             " ep %p, flags 0x%x", listen_fd, listen_vlsh, ep, flags);
2049
2050       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
2051       if (accept_vlsh < 0)
2052         {
2053           errno = -accept_vlsh;
2054           rv = -1;
2055         }
2056       else
2057         {
2058           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2059           if (rv != VPPCOM_OK)
2060             {
2061               (void) vls_close (accept_vlsh);
2062               errno = -rv;
2063               rv = -1;
2064             }
2065           else
2066             {
2067               rv = ldp_vlsh_to_fd (accept_vlsh);
2068             }
2069         }
2070     }
2071   else
2072     {
2073       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
2074             " flags 0x%x", listen_fd, addr, addr_len, flags);
2075
2076       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2077     }
2078
2079   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
2080
2081   return rv;
2082 }
2083
2084 int
2085 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
2086          int flags)
2087 {
2088   return ldp_accept4 (fd, addr, addr_len, flags);
2089 }
2090
2091 int
2092 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2093 {
2094   return ldp_accept4 (fd, addr, addr_len, 0);
2095 }
2096
2097 int
2098 shutdown (int fd, int how)
2099 {
2100   vls_handle_t vlsh;
2101   int rv = 0, flags;
2102   u32 flags_len = sizeof (flags);
2103
2104   if ((errno = -ldp_init ()))
2105     return -1;
2106
2107   vlsh = ldp_fd_to_vlsh (fd);
2108   if (vlsh != VLS_INVALID_HANDLE)
2109     {
2110       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
2111
2112       if (vls_attr (vlsh, VPPCOM_ATTR_SET_SHUT, &how, &flags_len))
2113         {
2114           close (fd);
2115           return -1;
2116         }
2117
2118       if (vls_attr (vlsh, VPPCOM_ATTR_GET_SHUT, &flags, &flags_len))
2119         {
2120           close (fd);
2121           return -1;
2122         }
2123
2124       if (flags == SHUT_RDWR)
2125         rv = close (fd);
2126     }
2127   else
2128     {
2129       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2130       rv = libc_shutdown (fd, how);
2131     }
2132
2133   return rv;
2134 }
2135
2136 int
2137 epoll_create1 (int flags)
2138 {
2139   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2140   vls_handle_t vlsh;
2141   int rv;
2142
2143   if ((errno = -ldp_init ()))
2144     return -1;
2145
2146   if (ldp->vcl_needs_real_epoll)
2147     {
2148       /* Make sure workers have been allocated */
2149       if (!ldp->workers)
2150         {
2151           ldp_alloc_workers ();
2152           ldpw = ldp_worker_get_current ();
2153         }
2154       rv = libc_epoll_create1 (flags);
2155       ldp->vcl_needs_real_epoll = 0;
2156       ldpw->vcl_mq_epfd = rv;
2157       LDBG (0, "created vcl epfd %u", rv);
2158       return rv;
2159     }
2160
2161   vlsh = vls_epoll_create ();
2162   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2163     {
2164       errno = -vlsh;
2165       rv = -1;
2166     }
2167   else
2168     {
2169       rv = ldp_vlsh_to_fd (vlsh);
2170     }
2171   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2172   return rv;
2173 }
2174
2175 int
2176 epoll_create (int size)
2177 {
2178   return epoll_create1 (0);
2179 }
2180
2181 int
2182 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2183 {
2184   vls_handle_t vep_vlsh, vlsh;
2185   int rv;
2186
2187   if ((errno = -ldp_init ()))
2188     return -1;
2189
2190   vep_vlsh = ldp_fd_to_vlsh (epfd);
2191   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2192     {
2193       /* The LDP epoll_create1 always creates VCL epfd's.
2194        * The app should never have a kernel base epoll fd unless it
2195        * was acquired outside of the LD_PRELOAD process context.
2196        * In any case, if we get one, punt it to libc_epoll_ctl.
2197        */
2198       LDBG (1, "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2199             " event %p", epfd, op, fd, event);
2200
2201       rv = libc_epoll_ctl (epfd, op, fd, event);
2202       goto done;
2203     }
2204
2205   vlsh = ldp_fd_to_vlsh (fd);
2206
2207   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2208         vlsh, op);
2209
2210   if (vlsh != VLS_INVALID_HANDLE)
2211     {
2212       LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2213             " event %p", epfd, vep_vlsh, vlsh, event);
2214
2215       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2216       if (rv != VPPCOM_OK)
2217         {
2218           errno = -rv;
2219           rv = -1;
2220         }
2221     }
2222   else
2223     {
2224       int libc_epfd;
2225       u32 size = sizeof (epfd);
2226
2227       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2228       if (!libc_epfd)
2229         {
2230           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2231                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2232
2233           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2234           if (libc_epfd < 0)
2235             {
2236               rv = libc_epfd;
2237               goto done;
2238             }
2239
2240           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2241                          &size);
2242           if (rv < 0)
2243             {
2244               errno = -rv;
2245               rv = -1;
2246               goto done;
2247             }
2248         }
2249       else if (PREDICT_FALSE (libc_epfd < 0))
2250         {
2251           errno = -epfd;
2252           rv = -1;
2253           goto done;
2254         }
2255
2256       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2257             " event %p", epfd, libc_epfd, op, fd, event);
2258
2259       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2260     }
2261
2262 done:
2263   return rv;
2264 }
2265
2266 static inline int
2267 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2268                  int timeout, const sigset_t * sigmask)
2269 {
2270   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2271   double time_to_wait = (double) 0, max_time;
2272   int libc_epfd, rv = 0;
2273   vls_handle_t ep_vlsh;
2274
2275   if ((errno = -ldp_init ()))
2276     return -1;
2277
2278   if (PREDICT_FALSE (!events || (timeout < -1)))
2279     {
2280       errno = EFAULT;
2281       return -1;
2282     }
2283
2284   if (epfd == ldpw->vcl_mq_epfd)
2285     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2286
2287   ep_vlsh = ldp_fd_to_vlsh (epfd);
2288   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2289     {
2290       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2291       errno = EBADFD;
2292       return -1;
2293     }
2294
2295   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2296     clib_time_init (&ldpw->clib_time);
2297   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2298   max_time = clib_time_now (&ldpw->clib_time) + time_to_wait;
2299
2300   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2301   if (PREDICT_FALSE (libc_epfd < 0))
2302     {
2303       errno = -libc_epfd;
2304       rv = -1;
2305       goto done;
2306     }
2307
2308   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2309         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2310         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait);
2311   do
2312     {
2313       if (!ldpw->epoll_wait_vcl)
2314         {
2315           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2316           if (rv > 0)
2317             {
2318               ldpw->epoll_wait_vcl = 1;
2319               goto done;
2320             }
2321           else if (rv < 0)
2322             {
2323               errno = -rv;
2324               rv = -1;
2325               goto done;
2326             }
2327         }
2328       else
2329         ldpw->epoll_wait_vcl = 0;
2330
2331       if (libc_epfd > 0)
2332         {
2333           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2334           if (rv != 0)
2335             goto done;
2336         }
2337     }
2338   while ((timeout == -1) || (clib_time_now (&ldpw->clib_time) < max_time));
2339
2340 done:
2341   return rv;
2342 }
2343
2344 int
2345 epoll_pwait (int epfd, struct epoll_event *events,
2346              int maxevents, int timeout, const sigset_t * sigmask)
2347 {
2348   return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2349 }
2350
2351 int
2352 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2353 {
2354   return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2355 }
2356
2357 int
2358 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2359 {
2360   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2361   int rv, i, n_revents = 0;
2362   vls_handle_t vlsh;
2363   vcl_poll_t *vp;
2364   double max_time;
2365
2366   LDBG (3, "fds %p, nfds %d, timeout %d", fds, nfds, timeout);
2367
2368   if (PREDICT_FALSE (ldpw->clib_time.init_cpu_time == 0))
2369     clib_time_init (&ldpw->clib_time);
2370
2371   max_time = (timeout >= 0) ? (f64) timeout / 1000 : 0;
2372   max_time += clib_time_now (&ldpw->clib_time);
2373
2374   for (i = 0; i < nfds; i++)
2375     {
2376       if (fds[i].fd < 0)
2377         continue;
2378
2379       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2380       if (vlsh != VLS_INVALID_HANDLE)
2381         {
2382           fds[i].fd = -fds[i].fd;
2383           vec_add2 (ldpw->vcl_poll, vp, 1);
2384           vp->fds_ndx = i;
2385           vp->sh = vlsh_to_sh (vlsh);
2386           vp->events = fds[i].events;
2387 #ifdef __USE_XOPEN2K
2388           if (fds[i].events & POLLRDNORM)
2389             vp->events |= POLLIN;
2390           if (fds[i].events & POLLWRNORM)
2391             vp->events |= POLLOUT;
2392 #endif
2393           vp->revents = fds[i].revents;
2394         }
2395       else
2396         {
2397           vec_add1 (ldpw->libc_poll, fds[i]);
2398           vec_add1 (ldpw->libc_poll_idxs, i);
2399         }
2400     }
2401
2402   do
2403     {
2404       if (vec_len (ldpw->vcl_poll))
2405         {
2406           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2407           if (rv < 0)
2408             {
2409               errno = -rv;
2410               rv = -1;
2411               goto done;
2412             }
2413           else
2414             n_revents += rv;
2415         }
2416
2417       if (vec_len (ldpw->libc_poll))
2418         {
2419           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2420           if (rv < 0)
2421             goto done;
2422           else
2423             n_revents += rv;
2424         }
2425
2426       if (n_revents)
2427         {
2428           rv = n_revents;
2429           goto done;
2430         }
2431     }
2432   while ((timeout < 0) || (clib_time_now (&ldpw->clib_time) < max_time));
2433   rv = 0;
2434
2435 done:
2436   vec_foreach (vp, ldpw->vcl_poll)
2437   {
2438     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2439     fds[vp->fds_ndx].revents = vp->revents;
2440 #ifdef __USE_XOPEN2K
2441     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2442         (fds[vp->fds_ndx].events & POLLRDNORM))
2443       fds[vp->fds_ndx].revents |= POLLRDNORM;
2444     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2445         (fds[vp->fds_ndx].events & POLLWRNORM))
2446       fds[vp->fds_ndx].revents |= POLLWRNORM;
2447 #endif
2448   }
2449   vec_reset_length (ldpw->vcl_poll);
2450
2451   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2452     {
2453       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2454     }
2455   vec_reset_length (ldpw->libc_poll_idxs);
2456   vec_reset_length (ldpw->libc_poll);
2457
2458   return rv;
2459 }
2460
2461 #ifdef USE_GNU
2462 int
2463 ppoll (struct pollfd *fds, nfds_t nfds,
2464        const struct timespec *timeout, const sigset_t * sigmask)
2465 {
2466   if ((errno = -ldp_init ()))
2467     return -1;
2468
2469   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2470   errno = ENOSYS;
2471
2472
2473   return -1;
2474 }
2475 #endif
2476
2477 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2478
2479 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2480
2481 /*
2482  * This function is called when the library is loaded
2483  */
2484 void
2485 ldp_constructor (void)
2486 {
2487   swrap_constructor ();
2488   if (ldp_init () != 0)
2489     {
2490       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2491                getpid ());
2492       _exit (1);
2493     }
2494   else if (LDP_DEBUG > 0)
2495     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2496 }
2497
2498 /*
2499  * This function is called when the library is unloaded
2500  */
2501 void
2502 ldp_destructor (void)
2503 {
2504   /*
2505      swrap_destructor ();
2506      if (ldp->init)
2507      ldp->init = 0;
2508    */
2509
2510   /* Don't use clib_warning() here because that calls writev()
2511    * which will call ldp_init().
2512    */
2513   if (LDP_DEBUG > 0)
2514     fprintf (stderr, "%s:%d: LDP<%d>: LDP destructor: done!\n",
2515              __func__, __LINE__, getpid ());
2516 }
2517
2518
2519 /*
2520  * fd.io coding-style-patch-verification: ON
2521  *
2522  * Local Variables:
2523  * eval: (c-set-style "gnu")
2524  * End:
2525  */