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