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