9f195c64a1bbb4bb4ea4d3e3e84115676902a0fc
[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 = vppcom_select (si_bits, readfds ? ldpw->rd_bitmap : NULL,
743                               writefds ? ldpw->wr_bitmap : NULL,
744                               exceptfds ? ldpw->ex_bitmap : NULL,
745                               vcl_timeout);
746           if (rv < 0)
747             {
748               errno = -rv;
749               rv = -1;
750             }
751           else if (rv > 0)
752             {
753               if (ldp_select_vcl_map_to_libc (ldpw->rd_bitmap, readfds))
754                 {
755                   rv = -1;
756                   goto done;
757                 }
758
759               if (ldp_select_vcl_map_to_libc (ldpw->wr_bitmap, writefds))
760                 {
761                   rv = -1;
762                   goto done;
763                 }
764
765               if (ldp_select_vcl_map_to_libc (ldpw->ex_bitmap, exceptfds))
766                 {
767                   rv = -1;
768                   goto done;
769                 }
770               bits_set = rv;
771             }
772         }
773       if (libc_bits)
774         {
775           if (readfds)
776             clib_memcpy_fast (ldpw->rd_bitmap, ldpw->libc_rd_bitmap,
777                               vec_len (ldpw->libc_rd_bitmap) *
778                               sizeof (clib_bitmap_t));
779           if (writefds)
780             clib_memcpy_fast (ldpw->wr_bitmap, ldpw->libc_wr_bitmap,
781                               vec_len (ldpw->libc_wr_bitmap) *
782                               sizeof (clib_bitmap_t));
783           if (exceptfds)
784             clib_memcpy_fast (ldpw->ex_bitmap, ldpw->libc_ex_bitmap,
785                               vec_len (ldpw->libc_ex_bitmap) *
786                               sizeof (clib_bitmap_t));
787
788           rv = libc_pselect (libc_bits,
789                              readfds ? (fd_set *) ldpw->rd_bitmap : NULL,
790                              writefds ? (fd_set *) ldpw->wr_bitmap : NULL,
791                              exceptfds ? (fd_set *) ldpw->ex_bitmap : NULL,
792                              &libc_tspec, sigmask);
793           if (rv > 0)
794             {
795               ldp_select_libc_map_merge (ldpw->rd_bitmap, readfds);
796               ldp_select_libc_map_merge (ldpw->wr_bitmap, writefds);
797               ldp_select_libc_map_merge (ldpw->ex_bitmap, exceptfds);
798               bits_set += rv;
799             }
800         }
801
802       if (bits_set)
803         {
804           rv = bits_set;
805           goto done;
806         }
807     }
808   while ((time_out == -1) || (clib_time_now (&ldpw->clib_time) < time_out));
809   rv = 0;
810
811 done:
812   /* TBD: set timeout to amount of time left */
813   clib_bitmap_zero (ldpw->rd_bitmap);
814   clib_bitmap_zero (ldpw->si_rd_bitmap);
815   clib_bitmap_zero (ldpw->libc_rd_bitmap);
816   clib_bitmap_zero (ldpw->wr_bitmap);
817   clib_bitmap_zero (ldpw->si_wr_bitmap);
818   clib_bitmap_zero (ldpw->libc_wr_bitmap);
819   clib_bitmap_zero (ldpw->ex_bitmap);
820   clib_bitmap_zero (ldpw->si_ex_bitmap);
821   clib_bitmap_zero (ldpw->libc_ex_bitmap);
822
823   return rv;
824 }
825
826 int
827 select (int nfds, fd_set * __restrict readfds,
828         fd_set * __restrict writefds,
829         fd_set * __restrict exceptfds, struct timeval *__restrict timeout)
830 {
831   struct timespec tspec;
832
833   if (timeout)
834     {
835       tspec.tv_sec = timeout->tv_sec;
836       tspec.tv_nsec = timeout->tv_usec * 1000;
837     }
838   return ldp_pselect (nfds, readfds, writefds, exceptfds,
839                       timeout ? &tspec : NULL, NULL);
840 }
841
842 #ifdef __USE_XOPEN2K
843 int
844 pselect (int nfds, fd_set * __restrict readfds,
845          fd_set * __restrict writefds,
846          fd_set * __restrict exceptfds,
847          const struct timespec *__restrict timeout,
848          const __sigset_t * __restrict sigmask)
849 {
850   return ldp_pselect (nfds, readfds, writefds, exceptfds, timeout, 0);
851 }
852 #endif
853
854 int
855 socket (int domain, int type, int protocol)
856 {
857   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
858   u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0;
859   vls_handle_t vlsh;
860
861   if ((errno = -ldp_init ()))
862     return -1;
863
864   if (((domain == AF_INET) || (domain == AF_INET6)) &&
865       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
866     {
867       u8 proto = ((sock_type == SOCK_DGRAM) ?
868                   VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
869
870       LDBG (0, "calling vls_create: proto %u (%s), is_nonblocking %u",
871             proto, vppcom_proto_str (proto), is_nonblocking);
872
873       vlsh = vls_create (proto, is_nonblocking);
874       if (vlsh < 0)
875         {
876           errno = -vlsh;
877           rv = -1;
878         }
879       else
880         {
881           rv = ldp_vlsh_to_fd (vlsh);
882         }
883     }
884   else
885     {
886       LDBG (0, "calling libc_socket");
887       rv = libc_socket (domain, type, protocol);
888     }
889
890   return rv;
891 }
892
893 /*
894  * Create two new sockets, of type TYPE in domain DOMAIN and using
895  * protocol PROTOCOL, which are connected to each other, and put file
896  * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
897  * one will be chosen automatically.
898  * Returns 0 on success, -1 for errors.
899  * */
900 int
901 socketpair (int domain, int type, int protocol, int fds[2])
902 {
903   int rv, sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
904
905   if ((errno = -ldp_init ()))
906     return -1;
907
908   if (((domain == AF_INET) || (domain == AF_INET6)) &&
909       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
910     {
911       LDBG (0, "LDP-TBD");
912       errno = ENOSYS;
913       rv = -1;
914     }
915   else
916     {
917       LDBG (1, "calling libc_socketpair");
918       rv = libc_socketpair (domain, type, protocol, fds);
919     }
920
921   return rv;
922 }
923
924 int
925 bind (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
926 {
927   vls_handle_t vlsh;
928   int rv;
929
930   if ((errno = -ldp_init ()))
931     return -1;
932
933   vlsh = ldp_fd_to_vlsh (fd);
934   if (vlsh != VLS_INVALID_HANDLE)
935     {
936       vppcom_endpt_t ep;
937
938       switch (addr->sa_family)
939         {
940         case AF_INET:
941           if (len != sizeof (struct sockaddr_in))
942             {
943               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET addr len %u!",
944                     fd, vlsh, len);
945               errno = EINVAL;
946               rv = -1;
947               goto done;
948             }
949           ep.is_ip4 = VPPCOM_IS_IP4;
950           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
951           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
952           break;
953
954         case AF_INET6:
955           if (len != sizeof (struct sockaddr_in6))
956             {
957               LDBG (0, "ERROR: fd %d: vlsh %u: Invalid AF_INET6 addr len %u!",
958                     fd, vlsh, len);
959               errno = EINVAL;
960               rv = -1;
961               goto done;
962             }
963           ep.is_ip4 = VPPCOM_IS_IP6;
964           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
965           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
966           break;
967
968         default:
969           LDBG (0, "ERROR: fd %d: vlsh %u: Unsupported address family %u!",
970                 fd, vlsh, addr->sa_family);
971           errno = EAFNOSUPPORT;
972           rv = -1;
973           goto done;
974         }
975       LDBG (0, "fd %d: calling vls_bind: vlsh %u, addr %p, len %u", fd, vlsh,
976             addr, len);
977
978       rv = vls_bind (vlsh, &ep);
979       if (rv != VPPCOM_OK)
980         {
981           errno = -rv;
982           rv = -1;
983         }
984     }
985   else
986     {
987       LDBG (0, "fd %d: calling libc_bind: addr %p, len %u", fd, addr, len);
988       rv = libc_bind (fd, addr, len);
989     }
990
991 done:
992   LDBG (1, "fd %d: returning %d", fd, rv);
993
994   return rv;
995 }
996
997 static inline int
998 ldp_copy_ep_to_sockaddr (__SOCKADDR_ARG addr, socklen_t * __restrict len,
999                          vppcom_endpt_t * ep)
1000 {
1001   int rv = 0;
1002   int sa_len, copy_len;
1003
1004   if ((errno = -ldp_init ()))
1005     return -1;
1006
1007   if (addr && len && ep)
1008     {
1009       addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1010       switch (addr->sa_family)
1011         {
1012         case AF_INET:
1013           ((struct sockaddr_in *) addr)->sin_port = ep->port;
1014           if (*len > sizeof (struct sockaddr_in))
1015             *len = sizeof (struct sockaddr_in);
1016           sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1017           copy_len = *len - sa_len;
1018           if (copy_len > 0)
1019             memcpy (&((struct sockaddr_in *) addr)->sin_addr, ep->ip,
1020                     copy_len);
1021           break;
1022
1023         case AF_INET6:
1024           ((struct sockaddr_in6 *) addr)->sin6_port = ep->port;
1025           if (*len > sizeof (struct sockaddr_in6))
1026             *len = sizeof (struct sockaddr_in6);
1027           sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1028           copy_len = *len - sa_len;
1029           if (copy_len > 0)
1030             memcpy (((struct sockaddr_in6 *) addr)->sin6_addr.
1031                     __in6_u.__u6_addr8, ep->ip, copy_len);
1032           break;
1033
1034         default:
1035           /* Not possible */
1036           rv = -EAFNOSUPPORT;
1037           break;
1038         }
1039     }
1040   return rv;
1041 }
1042
1043 int
1044 getsockname (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1045 {
1046   vls_handle_t vlsh;
1047   int rv;
1048
1049   if ((errno = -ldp_init ()))
1050     return -1;
1051
1052   vlsh = ldp_fd_to_vlsh (fd);
1053   if (vlsh != VLS_INVALID_HANDLE)
1054     {
1055       vppcom_endpt_t ep;
1056       u8 addr_buf[sizeof (struct in6_addr)];
1057       u32 size = sizeof (ep);
1058
1059       ep.ip = addr_buf;
1060
1061       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
1062       if (rv != VPPCOM_OK)
1063         {
1064           errno = -rv;
1065           rv = -1;
1066         }
1067       else
1068         {
1069           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1070           if (rv != VPPCOM_OK)
1071             {
1072               errno = -rv;
1073               rv = -1;
1074             }
1075         }
1076     }
1077   else
1078     {
1079       rv = libc_getsockname (fd, addr, len);
1080     }
1081
1082   return rv;
1083 }
1084
1085 int
1086 connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
1087 {
1088   vls_handle_t vlsh;
1089   int rv;
1090
1091   if ((errno = -ldp_init ()))
1092     return -1;
1093
1094   if (!addr)
1095     {
1096       LDBG (0, "ERROR: fd %d: NULL addr, len %u", fd, len);
1097       errno = EINVAL;
1098       rv = -1;
1099       goto done;
1100     }
1101
1102   vlsh = ldp_fd_to_vlsh (fd);
1103   if (vlsh != VLS_INVALID_HANDLE)
1104     {
1105       vppcom_endpt_t ep;
1106
1107       switch (addr->sa_family)
1108         {
1109         case AF_INET:
1110           if (len != sizeof (struct sockaddr_in))
1111             {
1112               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET addr len %u!",
1113                     fd, vlsh, len);
1114               errno = EINVAL;
1115               rv = -1;
1116               goto done;
1117             }
1118           ep.is_ip4 = VPPCOM_IS_IP4;
1119           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1120           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1121           break;
1122
1123         case AF_INET6:
1124           if (len != sizeof (struct sockaddr_in6))
1125             {
1126               LDBG (0, "fd %d: ERROR vlsh %u: Invalid AF_INET6 addr len %u!",
1127                     fd, vlsh, len);
1128               errno = EINVAL;
1129               rv = -1;
1130               goto done;
1131             }
1132           ep.is_ip4 = VPPCOM_IS_IP6;
1133           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1134           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1135           break;
1136
1137         default:
1138           LDBG (0, "fd %d: ERROR vlsh %u: Unsupported address family %u!",
1139                 fd, vlsh, addr->sa_family);
1140           errno = EAFNOSUPPORT;
1141           rv = -1;
1142           goto done;
1143         }
1144       LDBG (0, "fd %d: calling vls_connect(): vlsh %u addr %p len %u", fd,
1145             vlsh, addr, len);
1146
1147       rv = vls_connect (vlsh, &ep);
1148       if (rv != VPPCOM_OK)
1149         {
1150           errno = -rv;
1151           rv = -1;
1152         }
1153     }
1154   else
1155     {
1156       LDBG (0, "fd %d: calling libc_connect(): addr %p, len %u",
1157             fd, addr, len);
1158
1159       rv = libc_connect (fd, addr, len);
1160     }
1161
1162 done:
1163   LDBG (1, "fd %d: returning %d (0x%x)", fd, rv, rv);
1164   return rv;
1165 }
1166
1167 int
1168 getpeername (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1169 {
1170   vls_handle_t vlsh;
1171   int rv;
1172
1173   if ((errno = -ldp_init ()))
1174     return -1;
1175
1176   vlsh = ldp_fd_to_vlsh (fd);
1177   if (vlsh != VLS_INVALID_HANDLE)
1178     {
1179       vppcom_endpt_t ep;
1180       u8 addr_buf[sizeof (struct in6_addr)];
1181       u32 size = sizeof (ep);
1182
1183       ep.ip = addr_buf;
1184       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size);
1185       if (rv != VPPCOM_OK)
1186         {
1187           errno = -rv;
1188           rv = -1;
1189         }
1190       else
1191         {
1192           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1193           if (rv != VPPCOM_OK)
1194             {
1195               errno = -rv;
1196               rv = -1;
1197             }
1198         }
1199     }
1200   else
1201     {
1202       rv = libc_getpeername (fd, addr, len);
1203     }
1204
1205   return rv;
1206 }
1207
1208 ssize_t
1209 send (int fd, const void *buf, size_t n, int flags)
1210 {
1211   vls_handle_t vlsh = ldp_fd_to_vlsh (fd);
1212   ssize_t size;
1213
1214   if ((errno = -ldp_init ()))
1215     return -1;
1216
1217   if (vlsh != VLS_INVALID_HANDLE)
1218     {
1219       size = vls_sendto (vlsh, (void *) buf, n, flags, NULL);
1220       if (size < VPPCOM_OK)
1221         {
1222           errno = -size;
1223           size = -1;
1224         }
1225     }
1226   else
1227     {
1228       size = libc_send (fd, buf, n, flags);
1229     }
1230
1231   return size;
1232 }
1233
1234 ssize_t
1235 sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
1236 {
1237   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1238   vls_handle_t vlsh;
1239   ssize_t size = 0;
1240
1241   if ((errno = -ldp_init ()))
1242     return -1;
1243
1244   vlsh = ldp_fd_to_vlsh (out_fd);
1245   if (vlsh != VLS_INVALID_HANDLE)
1246     {
1247       int rv;
1248       ssize_t results = 0;
1249       size_t n_bytes_left = len;
1250       size_t bytes_to_read;
1251       int nbytes;
1252       u8 eagain = 0;
1253       u32 flags, flags_len = sizeof (flags);
1254
1255       rv = vls_attr (vlsh, VPPCOM_ATTR_GET_FLAGS, &flags, &flags_len);
1256       if (PREDICT_FALSE (rv != VPPCOM_OK))
1257         {
1258           LDBG (0, "ERROR: out fd %d: vls_attr: vlsh %u, returned %d (%s)!",
1259                 out_fd, vlsh, rv, vppcom_retval_str (rv));
1260
1261           vec_reset_length (ldpw->io_buffer);
1262           errno = -rv;
1263           size = -1;
1264           goto done;
1265         }
1266
1267       if (offset)
1268         {
1269           off_t off = lseek (in_fd, *offset, SEEK_SET);
1270           if (PREDICT_FALSE (off == -1))
1271             {
1272               size = -1;
1273               goto done;
1274             }
1275
1276           ASSERT (off == *offset);
1277         }
1278
1279       do
1280         {
1281           size = vls_attr (vlsh, VPPCOM_ATTR_GET_NWRITE, 0, 0);
1282           if (size < 0)
1283             {
1284               LDBG (0, "ERROR: fd %d: vls_attr: vlsh %u returned %d (%s)!",
1285                     out_fd, vlsh, size, vppcom_retval_str (size));
1286               vec_reset_length (ldpw->io_buffer);
1287               errno = -size;
1288               size = -1;
1289               goto done;
1290             }
1291
1292           bytes_to_read = size;
1293           if (bytes_to_read == 0)
1294             {
1295               if (flags & O_NONBLOCK)
1296                 {
1297                   if (!results)
1298                     eagain = 1;
1299                   goto update_offset;
1300                 }
1301               else
1302                 continue;
1303             }
1304           bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1305           vec_validate (ldpw->io_buffer, bytes_to_read);
1306           nbytes = libc_read (in_fd, ldpw->io_buffer, bytes_to_read);
1307           if (nbytes < 0)
1308             {
1309               if (results == 0)
1310                 {
1311                   vec_reset_length (ldpw->io_buffer);
1312                   size = -1;
1313                   goto done;
1314                 }
1315               goto update_offset;
1316             }
1317
1318           size = vls_write (vlsh, ldpw->io_buffer, nbytes);
1319           if (size < 0)
1320             {
1321               if (size == VPPCOM_EAGAIN)
1322                 {
1323                   if (flags & O_NONBLOCK)
1324                     {
1325                       if (!results)
1326                         eagain = 1;
1327                       goto update_offset;
1328                     }
1329                   else
1330                     continue;
1331                 }
1332               if (results == 0)
1333                 {
1334                   vec_reset_length (ldpw->io_buffer);
1335                   errno = -size;
1336                   size = -1;
1337                   goto done;
1338                 }
1339               goto update_offset;
1340             }
1341
1342           results += nbytes;
1343           ASSERT (n_bytes_left >= nbytes);
1344           n_bytes_left = n_bytes_left - nbytes;
1345         }
1346       while (n_bytes_left > 0);
1347
1348     update_offset:
1349       vec_reset_length (ldpw->io_buffer);
1350       if (offset)
1351         {
1352           off_t off = lseek (in_fd, *offset, SEEK_SET);
1353           if (PREDICT_FALSE (off == -1))
1354             {
1355               size = -1;
1356               goto done;
1357             }
1358
1359           ASSERT (off == *offset);
1360           *offset += results + 1;
1361         }
1362       if (eagain)
1363         {
1364           errno = EAGAIN;
1365           size = -1;
1366         }
1367       else
1368         size = results;
1369     }
1370   else
1371     {
1372       size = libc_sendfile (out_fd, in_fd, offset, len);
1373     }
1374
1375 done:
1376   return size;
1377 }
1378
1379 ssize_t
1380 sendfile64 (int out_fd, int in_fd, off_t * offset, size_t len)
1381 {
1382   return sendfile (out_fd, in_fd, offset, len);
1383 }
1384
1385 ssize_t
1386 recv (int fd, void *buf, size_t n, int flags)
1387 {
1388   vls_handle_t vlsh;
1389   ssize_t size;
1390
1391   if ((errno = -ldp_init ()))
1392     return -1;
1393
1394   vlsh = ldp_fd_to_vlsh (fd);
1395   if (vlsh != VLS_INVALID_HANDLE)
1396     {
1397       size = vls_recvfrom (vlsh, buf, n, flags, NULL);
1398       if (size < 0)
1399         errno = -size;
1400     }
1401   else
1402     {
1403       size = libc_recv (fd, buf, n, flags);
1404     }
1405
1406   return size;
1407 }
1408
1409 ssize_t
1410 sendto (int fd, const void *buf, size_t n, int flags,
1411         __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
1412 {
1413   vls_handle_t vlsh;
1414   ssize_t size;
1415
1416   if ((errno = -ldp_init ()))
1417     return -1;
1418
1419   vlsh = ldp_fd_to_vlsh (fd);
1420   if (vlsh != INVALID_SESSION_ID)
1421     {
1422       vppcom_endpt_t *ep = 0;
1423       vppcom_endpt_t _ep;
1424
1425       if (addr)
1426         {
1427           ep = &_ep;
1428           switch (addr->sa_family)
1429             {
1430             case AF_INET:
1431               ep->is_ip4 = VPPCOM_IS_IP4;
1432               ep->ip =
1433                 (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
1434               ep->port =
1435                 (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
1436               break;
1437
1438             case AF_INET6:
1439               ep->is_ip4 = VPPCOM_IS_IP6;
1440               ep->ip =
1441                 (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1442               ep->port =
1443                 (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
1444               break;
1445
1446             default:
1447               errno = EAFNOSUPPORT;
1448               size = -1;
1449               goto done;
1450             }
1451         }
1452
1453       size = vls_sendto (vlsh, (void *) buf, n, flags, ep);
1454       if (size < 0)
1455         {
1456           errno = -size;
1457           size = -1;
1458         }
1459     }
1460   else
1461     {
1462       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
1463     }
1464
1465 done:
1466   return size;
1467 }
1468
1469 ssize_t
1470 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
1471           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1472 {
1473   vls_handle_t sid;
1474   ssize_t size;
1475
1476   if ((errno = -ldp_init ()))
1477     return -1;
1478
1479   sid = ldp_fd_to_vlsh (fd);
1480   if (sid != VLS_INVALID_HANDLE)
1481     {
1482       vppcom_endpt_t ep;
1483       u8 src_addr[sizeof (struct sockaddr_in6)];
1484
1485       if (addr)
1486         {
1487           ep.ip = src_addr;
1488           size = vls_recvfrom (sid, buf, n, flags, &ep);
1489
1490           if (size > 0)
1491             size = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1492         }
1493       else
1494         size = vls_recvfrom (sid, buf, n, flags, NULL);
1495
1496       if (size < 0)
1497         {
1498           errno = -size;
1499           size = -1;
1500         }
1501     }
1502   else
1503     {
1504       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
1505     }
1506
1507   return size;
1508 }
1509
1510 ssize_t
1511 sendmsg (int fd, const struct msghdr * message, int flags)
1512 {
1513   vls_handle_t vlsh;
1514   ssize_t size;
1515
1516   if ((errno = -ldp_init ()))
1517     return -1;
1518
1519   vlsh = ldp_fd_to_vlsh (fd);
1520   if (vlsh != VLS_INVALID_HANDLE)
1521     {
1522       LDBG (0, "LDP-TBD");
1523       errno = ENOSYS;
1524       size = -1;
1525     }
1526   else
1527     {
1528       size = libc_sendmsg (fd, message, flags);
1529     }
1530
1531   return size;
1532 }
1533
1534 #ifdef USE_GNU
1535 int
1536 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
1537 {
1538   ssize_t size;
1539   const char *func_str;
1540   u32 sh = ldp_fd_to_vlsh (fd);
1541
1542   if ((errno = -ldp_init ()))
1543     return -1;
1544
1545   if (sh != INVALID_SESSION_ID)
1546     {
1547       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1548       errno = ENOSYS;
1549       size = -1;
1550     }
1551   else
1552     {
1553       func_str = "libc_sendmmsg";
1554
1555       if (LDP_DEBUG > 2)
1556         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1557                       "vmessages %p, vlen %u, flags 0x%x",
1558                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
1559
1560       size = libc_sendmmsg (fd, vmessages, vlen, flags);
1561     }
1562
1563   if (LDP_DEBUG > 2)
1564     {
1565       if (size < 0)
1566         {
1567           int errno_val = errno;
1568           perror (func_str);
1569           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1570                         "rv %d, errno = %d", getpid (), fd, fd,
1571                         func_str, size, errno_val);
1572           errno = errno_val;
1573         }
1574       else
1575         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1576                       getpid (), fd, fd, size, size);
1577     }
1578   return size;
1579 }
1580 #endif
1581
1582 ssize_t
1583 recvmsg (int fd, struct msghdr * message, int flags)
1584 {
1585   vls_handle_t vlsh;
1586   ssize_t size;
1587
1588   if ((errno = -ldp_init ()))
1589     return -1;
1590
1591   vlsh = ldp_fd_to_vlsh (fd);
1592   if (vlsh != VLS_INVALID_HANDLE)
1593     {
1594       LDBG (0, "LDP-TBD");
1595       errno = ENOSYS;
1596       size = -1;
1597     }
1598   else
1599     {
1600       size = libc_recvmsg (fd, message, flags);
1601     }
1602
1603   return size;
1604 }
1605
1606 #ifdef USE_GNU
1607 int
1608 recvmmsg (int fd, struct mmsghdr *vmessages,
1609           unsigned int vlen, int flags, struct timespec *tmo)
1610 {
1611   ssize_t size;
1612   const char *func_str;
1613   u32 sh = ldp_fd_to_vlsh (fd);
1614
1615   if ((errno = -ldp_init ()))
1616     return -1;
1617
1618   if (sh != INVALID_SESSION_ID)
1619     {
1620       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1621       errno = ENOSYS;
1622       size = -1;
1623     }
1624   else
1625     {
1626       func_str = "libc_recvmmsg";
1627
1628       if (LDP_DEBUG > 2)
1629         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1630                       "vmessages %p, vlen %u, flags 0x%x, tmo %p",
1631                       getpid (), fd, fd, func_str, vmessages, vlen,
1632                       flags, tmo);
1633
1634       size = libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
1635     }
1636
1637   if (LDP_DEBUG > 2)
1638     {
1639       if (size < 0)
1640         {
1641           int errno_val = errno;
1642           perror (func_str);
1643           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1644                         "rv %d, errno = %d", getpid (), fd, fd,
1645                         func_str, size, errno_val);
1646           errno = errno_val;
1647         }
1648       else
1649         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1650                       getpid (), fd, fd, size, size);
1651     }
1652   return size;
1653 }
1654 #endif
1655
1656 int
1657 getsockopt (int fd, int level, int optname,
1658             void *__restrict optval, socklen_t * __restrict optlen)
1659 {
1660   vls_handle_t vlsh;
1661   int rv;
1662
1663   if ((errno = -ldp_init ()))
1664     return -1;
1665
1666   vlsh = ldp_fd_to_vlsh (fd);
1667   if (vlsh != VLS_INVALID_HANDLE)
1668     {
1669       rv = -EOPNOTSUPP;
1670
1671       switch (level)
1672         {
1673         case SOL_TCP:
1674           switch (optname)
1675             {
1676             case TCP_NODELAY:
1677               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_NODELAY,
1678                              optval, optlen);
1679               break;
1680             case TCP_MAXSEG:
1681               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_USER_MSS,
1682                              optval, optlen);
1683               break;
1684             case TCP_KEEPIDLE:
1685               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
1686                              optval, optlen);
1687               break;
1688             case TCP_KEEPINTVL:
1689               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
1690                              optval, optlen);
1691               break;
1692             case TCP_INFO:
1693               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
1694                 {
1695                   LDBG (1, "fd %d: vlsh %u SOL_TCP, TCP_INFO, optval %p, "
1696                         "optlen %d: #LDP-NOP#", fd, vlsh, optval, *optlen);
1697                   memset (optval, 0, *optlen);
1698                   rv = VPPCOM_OK;
1699                 }
1700               else
1701                 rv = -EFAULT;
1702               break;
1703             default:
1704               LDBG (0, "ERROR: fd %d: getsockopt SOL_TCP: sid %u, "
1705                     "optname %d unsupported!", fd, vlsh, optname);
1706               break;
1707             }
1708           break;
1709         case SOL_IPV6:
1710           switch (optname)
1711             {
1712             case IPV6_V6ONLY:
1713               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_V6ONLY, optval, optlen);
1714               break;
1715             default:
1716               LDBG (0, "ERROR: fd %d: getsockopt SOL_IPV6: vlsh %u "
1717                     "optname %d unsupported!", fd, vlsh, optname);
1718               break;
1719             }
1720           break;
1721         case SOL_SOCKET:
1722           switch (optname)
1723             {
1724             case SO_ACCEPTCONN:
1725               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_LISTEN, optval, optlen);
1726               break;
1727             case SO_KEEPALIVE:
1728               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_KEEPALIVE, optval, optlen);
1729               break;
1730             case SO_PROTOCOL:
1731               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_PROTOCOL, optval, optlen);
1732               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
1733               break;
1734             case SO_SNDBUF:
1735               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_TX_FIFO_LEN,
1736                              optval, optlen);
1737               break;
1738             case SO_RCVBUF:
1739               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_RX_FIFO_LEN,
1740                              optval, optlen);
1741               break;
1742             case SO_REUSEADDR:
1743               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_REUSEADDR, optval, optlen);
1744               break;
1745             case SO_BROADCAST:
1746               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_BROADCAST, optval, optlen);
1747               break;
1748             case SO_ERROR:
1749               rv = vls_attr (vlsh, VPPCOM_ATTR_GET_ERROR, optval, optlen);
1750               break;
1751             default:
1752               LDBG (0, "ERROR: fd %d: getsockopt SOL_SOCKET: vlsh %u "
1753                     "optname %d unsupported!", fd, vlsh, optname);
1754               break;
1755             }
1756           break;
1757         default:
1758           break;
1759         }
1760
1761       if (rv != VPPCOM_OK)
1762         {
1763           errno = -rv;
1764           rv = -1;
1765         }
1766     }
1767   else
1768     {
1769       rv = libc_getsockopt (fd, level, optname, optval, optlen);
1770     }
1771
1772   return rv;
1773 }
1774
1775 int
1776 setsockopt (int fd, int level, int optname,
1777             const void *optval, socklen_t optlen)
1778 {
1779   vls_handle_t vlsh;
1780   int rv;
1781
1782   if ((errno = -ldp_init ()))
1783     return -1;
1784
1785   vlsh = ldp_fd_to_vlsh (fd);
1786   if (vlsh != VLS_INVALID_HANDLE)
1787     {
1788       rv = -EOPNOTSUPP;
1789
1790       switch (level)
1791         {
1792         case SOL_TCP:
1793           switch (optname)
1794             {
1795             case TCP_NODELAY:
1796               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_NODELAY,
1797                              (void *) optval, &optlen);
1798               break;
1799             case TCP_MAXSEG:
1800               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_USER_MSS,
1801                              (void *) optval, &optlen);
1802               break;
1803             case TCP_KEEPIDLE:
1804               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
1805                              (void *) optval, &optlen);
1806               break;
1807             case TCP_KEEPINTVL:
1808               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
1809                              (void *) optval, &optlen);
1810               break;
1811             default:
1812               LDBG (0, "ERROR: fd %d: setsockopt() SOL_TCP: vlsh %u"
1813                     "optname %d unsupported!", fd, vlsh, optname);
1814               break;
1815             }
1816           break;
1817         case SOL_IPV6:
1818           switch (optname)
1819             {
1820             case IPV6_V6ONLY:
1821               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_V6ONLY,
1822                              (void *) optval, &optlen);
1823               break;
1824             default:
1825               LDBG (0, "ERROR: fd %d: setsockopt SOL_IPV6: vlsh %u"
1826                     "optname %d unsupported!", fd, vlsh, optname);
1827               break;
1828             }
1829           break;
1830         case SOL_SOCKET:
1831           switch (optname)
1832             {
1833             case SO_KEEPALIVE:
1834               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_KEEPALIVE,
1835                              (void *) optval, &optlen);
1836               break;
1837             case SO_REUSEADDR:
1838               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_REUSEADDR,
1839                              (void *) optval, &optlen);
1840               break;
1841             case SO_BROADCAST:
1842               rv = vls_attr (vlsh, VPPCOM_ATTR_SET_BROADCAST,
1843                              (void *) optval, &optlen);
1844               break;
1845             default:
1846               LDBG (0, "ERROR: fd %d: setsockopt SOL_SOCKET: vlsh %u "
1847                     "optname %d unsupported!", fd, vlsh, optname);
1848               break;
1849             }
1850           break;
1851         default:
1852           break;
1853         }
1854
1855       if (rv != VPPCOM_OK)
1856         {
1857           errno = -rv;
1858           rv = -1;
1859         }
1860     }
1861   else
1862     {
1863       rv = libc_setsockopt (fd, level, optname, optval, optlen);
1864     }
1865
1866   return rv;
1867 }
1868
1869 int
1870 listen (int fd, int n)
1871 {
1872   vls_handle_t vlsh;
1873   int rv;
1874
1875   if ((errno = -ldp_init ()))
1876     return -1;
1877
1878   vlsh = ldp_fd_to_vlsh (fd);
1879   if (vlsh != VLS_INVALID_HANDLE)
1880     {
1881       LDBG (0, "fd %d: calling vls_listen: vlsh %u, n %d", fd, vlsh, n);
1882
1883       rv = vls_listen (vlsh, n);
1884       if (rv != VPPCOM_OK)
1885         {
1886           errno = -rv;
1887           rv = -1;
1888         }
1889     }
1890   else
1891     {
1892       LDBG (0, "fd %d: calling libc_listen(): n %d", fd, n);
1893       rv = libc_listen (fd, n);
1894     }
1895
1896   LDBG (1, "fd %d: returning %d", fd, rv);
1897   return rv;
1898 }
1899
1900 static inline int
1901 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
1902              socklen_t * __restrict addr_len, int flags)
1903 {
1904   vls_handle_t listen_vlsh, accept_vlsh;
1905   int rv;
1906
1907   if ((errno = -ldp_init ()))
1908     return -1;
1909
1910   listen_vlsh = ldp_fd_to_vlsh (listen_fd);
1911   if (listen_vlsh != VLS_INVALID_HANDLE)
1912     {
1913       vppcom_endpt_t ep;
1914       u8 src_addr[sizeof (struct sockaddr_in6)];
1915       memset (&ep, 0, sizeof (ep));
1916       ep.ip = src_addr;
1917
1918       LDBG (0, "listen fd %d: calling vppcom_session_accept: listen sid %u,"
1919             " ep %p, flags 0x%x", listen_fd, listen_vlsh, ep, flags);
1920
1921       accept_vlsh = vls_accept (listen_vlsh, &ep, flags);
1922       if (accept_vlsh < 0)
1923         {
1924           errno = -accept_vlsh;
1925           rv = -1;
1926         }
1927       else
1928         {
1929           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
1930           if (rv != VPPCOM_OK)
1931             {
1932               (void) vls_close (accept_vlsh);
1933               errno = -rv;
1934               rv = -1;
1935             }
1936           else
1937             {
1938               rv = ldp_vlsh_to_fd (accept_vlsh);
1939             }
1940         }
1941     }
1942   else
1943     {
1944       LDBG (0, "listen fd %d: calling libc_accept4(): addr %p, addr_len %p,"
1945             " flags 0x%x", listen_fd, addr, addr_len, flags);
1946
1947       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
1948     }
1949
1950   LDBG (1, "listen fd %d: accept returning %d", listen_fd, rv);
1951
1952   return rv;
1953 }
1954
1955 int
1956 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
1957          int flags)
1958 {
1959   return ldp_accept4 (fd, addr, addr_len, flags);
1960 }
1961
1962 int
1963 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
1964 {
1965   return ldp_accept4 (fd, addr, addr_len, 0);
1966 }
1967
1968 int
1969 shutdown (int fd, int how)
1970 {
1971   vls_handle_t vlsh;
1972   int rv = 0, flags;
1973   u32 flags_len = sizeof (flags);
1974
1975   if ((errno = -ldp_init ()))
1976     return -1;
1977
1978   vlsh = ldp_fd_to_vlsh (fd);
1979   if (vlsh != VLS_INVALID_HANDLE)
1980     {
1981       LDBG (0, "called shutdown: fd %u vlsh %u how %d", fd, vlsh, how);
1982
1983       if (vls_attr (vlsh, VPPCOM_ATTR_SET_SHUT, &how, &flags_len))
1984         {
1985           close (fd);
1986           return -1;
1987         }
1988
1989       if (vls_attr (vlsh, VPPCOM_ATTR_GET_SHUT, &flags, &flags_len))
1990         {
1991           close (fd);
1992           return -1;
1993         }
1994
1995       if (flags == SHUT_RDWR)
1996         rv = close (fd);
1997     }
1998   else
1999     {
2000       LDBG (0, "fd %d: calling libc_shutdown: how %d", fd, how);
2001       rv = libc_shutdown (fd, how);
2002     }
2003
2004   return rv;
2005 }
2006
2007 int
2008 epoll_create1 (int flags)
2009 {
2010   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2011   vls_handle_t vlsh;
2012   int rv;
2013
2014   if ((errno = -ldp_init ()))
2015     return -1;
2016
2017   if (ldp->vcl_needs_real_epoll)
2018     {
2019       rv = libc_epoll_create1 (flags);
2020       ldp->vcl_needs_real_epoll = 0;
2021       ldpw->vcl_mq_epfd = rv;
2022       LDBG (0, "created vcl epfd %u", rv);
2023       return rv;
2024     }
2025
2026   vlsh = vls_epoll_create ();
2027   if (PREDICT_FALSE (vlsh == VLS_INVALID_HANDLE))
2028     {
2029       errno = -vlsh;
2030       rv = -1;
2031     }
2032   else
2033     {
2034       rv = ldp_vlsh_to_fd (vlsh);
2035     }
2036   LDBG (0, "epoll_create epfd %u vlsh %u", rv, vlsh);
2037   return rv;
2038 }
2039
2040 int
2041 epoll_create (int size)
2042 {
2043   return epoll_create1 (0);
2044 }
2045
2046 int
2047 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
2048 {
2049   vls_handle_t vep_vlsh, vlsh;
2050   int rv;
2051
2052   if ((errno = -ldp_init ()))
2053     return -1;
2054
2055   vep_vlsh = ldp_fd_to_vlsh (epfd);
2056   if (PREDICT_FALSE (vep_vlsh == VLS_INVALID_HANDLE))
2057     {
2058       /* The LDP epoll_create1 always creates VCL epfd's.
2059        * The app should never have a kernel base epoll fd unless it
2060        * was acquired outside of the LD_PRELOAD process context.
2061        * In any case, if we get one, punt it to libc_epoll_ctl.
2062        */
2063       LDBG (1, "epfd %d: calling libc_epoll_ctl: op %d, fd %d"
2064             " event %p", epfd, op, fd, event);
2065
2066       rv = libc_epoll_ctl (epfd, op, fd, event);
2067       goto done;
2068     }
2069
2070   vlsh = ldp_fd_to_vlsh (fd);
2071
2072   LDBG (0, "epfd %d ep_vlsh %d, fd %u vlsh %d, op %u", epfd, vep_vlsh, fd,
2073         vlsh, op);
2074
2075   if (vlsh != VLS_INVALID_HANDLE)
2076     {
2077       LDBG (1, "epfd %d: calling vls_epoll_ctl: ep_vlsh %d op %d, vlsh %u,"
2078             " event %p", epfd, vep_vlsh, vlsh, event);
2079
2080       rv = vls_epoll_ctl (vep_vlsh, op, vlsh, event);
2081       if (rv != VPPCOM_OK)
2082         {
2083           errno = -rv;
2084           rv = -1;
2085         }
2086     }
2087   else
2088     {
2089       int libc_epfd;
2090       u32 size = sizeof (epfd);
2091
2092       libc_epfd = vls_attr (vep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2093       if (!libc_epfd)
2094         {
2095           LDBG (1, "epfd %d, vep_vlsh %d calling libc_epoll_create1: "
2096                 "EPOLL_CLOEXEC", epfd, vep_vlsh);
2097
2098           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
2099           if (libc_epfd < 0)
2100             {
2101               rv = libc_epfd;
2102               goto done;
2103             }
2104
2105           rv = vls_attr (vep_vlsh, VPPCOM_ATTR_SET_LIBC_EPFD, &libc_epfd,
2106                          &size);
2107           if (rv < 0)
2108             {
2109               errno = -rv;
2110               rv = -1;
2111               goto done;
2112             }
2113         }
2114       else if (PREDICT_FALSE (libc_epfd < 0))
2115         {
2116           errno = -epfd;
2117           rv = -1;
2118           goto done;
2119         }
2120
2121       LDBG (1, "epfd %d: calling libc_epoll_ctl: libc_epfd %d, op %d, fd %d,"
2122             " event %p", epfd, libc_epfd, op, fd, event);
2123
2124       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
2125     }
2126
2127 done:
2128   return rv;
2129 }
2130
2131 static inline int
2132 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
2133                  int timeout, const sigset_t * sigmask)
2134 {
2135   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2136   double time_to_wait = (double) 0, time_out, now = 0;
2137   int libc_epfd, rv = 0;
2138   vls_handle_t ep_vlsh;
2139
2140   if ((errno = -ldp_init ()))
2141     return -1;
2142
2143   if (PREDICT_FALSE (!events || (timeout < -1)))
2144     {
2145       errno = EFAULT;
2146       return -1;
2147     }
2148
2149   if (epfd == ldpw->vcl_mq_epfd)
2150     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2151
2152   ep_vlsh = ldp_fd_to_vlsh (epfd);
2153   if (PREDICT_FALSE (ep_vlsh == VLS_INVALID_HANDLE))
2154     {
2155       LDBG (0, "epfd %d: bad ep_vlsh %d!", epfd, ep_vlsh);
2156       errno = EBADFD;
2157       return -1;
2158     }
2159
2160   time_to_wait = ((timeout >= 0) ? (double) timeout / 1000 : 0);
2161   time_out = clib_time_now (&ldpw->clib_time) + time_to_wait;
2162
2163   libc_epfd = vls_attr (ep_vlsh, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
2164   if (PREDICT_FALSE (libc_epfd < 0))
2165     {
2166       errno = -libc_epfd;
2167       rv = -1;
2168       goto done;
2169     }
2170
2171   LDBG (2, "epfd %d: vep_idx %d, libc_epfd %d, events %p, maxevents %d, "
2172         "timeout %d, sigmask %p: time_to_wait %.02f", epfd, ep_vlsh,
2173         libc_epfd, events, maxevents, timeout, sigmask, time_to_wait,
2174         time_out);
2175   do
2176     {
2177       if (!ldpw->epoll_wait_vcl)
2178         {
2179           rv = vls_epoll_wait (ep_vlsh, events, maxevents, 0);
2180           if (rv > 0)
2181             {
2182               ldpw->epoll_wait_vcl = 1;
2183               goto done;
2184             }
2185           else if (rv < 0)
2186             {
2187               errno = -rv;
2188               rv = -1;
2189               goto done;
2190             }
2191         }
2192       else
2193         ldpw->epoll_wait_vcl = 0;
2194
2195       if (libc_epfd > 0)
2196         {
2197           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 0, sigmask);
2198           if (rv != 0)
2199             goto done;
2200         }
2201
2202       if (timeout != -1)
2203         now = clib_time_now (&ldpw->clib_time);
2204     }
2205   while (now < time_out);
2206
2207 done:
2208   return rv;
2209 }
2210
2211 int
2212 epoll_pwait (int epfd, struct epoll_event *events,
2213              int maxevents, int timeout, const sigset_t * sigmask)
2214 {
2215   return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
2216 }
2217
2218 int
2219 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
2220 {
2221   return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
2222 }
2223
2224 int
2225 poll (struct pollfd *fds, nfds_t nfds, int timeout)
2226 {
2227   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
2228   int rv, i, n_revents = 0;
2229   vls_handle_t vlsh;
2230   vcl_poll_t *vp;
2231   double wait_for_time;
2232
2233   LDBG (3, "fds %p, nfds %d, timeout %d", fds, nfds, timeout);
2234
2235   if (timeout >= 0)
2236     wait_for_time = (f64) timeout / 1000;
2237   else
2238     wait_for_time = -1;
2239
2240   for (i = 0; i < nfds; i++)
2241     {
2242       if (fds[i].fd < 0)
2243         continue;
2244
2245       vlsh = ldp_fd_to_vlsh (fds[i].fd);
2246       if (vlsh != VLS_INVALID_HANDLE)
2247         {
2248           fds[i].fd = -fds[i].fd;
2249           vec_add2 (ldpw->vcl_poll, vp, 1);
2250           vp->fds_ndx = i;
2251           vp->sh = vlsh_to_sh (vlsh);
2252           vp->events = fds[i].events;
2253 #ifdef __USE_XOPEN2K
2254           if (fds[i].events & POLLRDNORM)
2255             vp->events |= POLLIN;
2256           if (fds[i].events & POLLWRNORM)
2257             vp->events |= POLLOUT;
2258 #endif
2259           vp->revents = fds[i].revents;
2260         }
2261       else
2262         {
2263           vec_add1 (ldpw->libc_poll, fds[i]);
2264           vec_add1 (ldpw->libc_poll_idxs, i);
2265         }
2266     }
2267
2268   do
2269     {
2270       if (vec_len (ldpw->vcl_poll))
2271         {
2272           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
2273           if (rv < 0)
2274             {
2275               errno = -rv;
2276               rv = -1;
2277               goto done;
2278             }
2279           else
2280             n_revents += rv;
2281         }
2282
2283       if (vec_len (ldpw->libc_poll))
2284         {
2285           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
2286           if (rv < 0)
2287             goto done;
2288           else
2289             n_revents += rv;
2290         }
2291
2292       if (n_revents)
2293         {
2294           rv = n_revents;
2295           goto done;
2296         }
2297     }
2298   while ((wait_for_time == -1) ||
2299          (clib_time_now (&ldpw->clib_time) < wait_for_time));
2300   rv = 0;
2301
2302 done:
2303   vec_foreach (vp, ldpw->vcl_poll)
2304   {
2305     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
2306     fds[vp->fds_ndx].revents = vp->revents;
2307 #ifdef __USE_XOPEN2K
2308     if ((fds[vp->fds_ndx].revents & POLLIN) &&
2309         (fds[vp->fds_ndx].events & POLLRDNORM))
2310       fds[vp->fds_ndx].revents |= POLLRDNORM;
2311     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
2312         (fds[vp->fds_ndx].events & POLLWRNORM))
2313       fds[vp->fds_ndx].revents |= POLLWRNORM;
2314 #endif
2315   }
2316   vec_reset_length (ldpw->vcl_poll);
2317
2318   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
2319     {
2320       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
2321     }
2322   vec_reset_length (ldpw->libc_poll_idxs);
2323   vec_reset_length (ldpw->libc_poll);
2324
2325   return rv;
2326 }
2327
2328 #ifdef USE_GNU
2329 int
2330 ppoll (struct pollfd *fds, nfds_t nfds,
2331        const struct timespec *timeout, const sigset_t * sigmask)
2332 {
2333   if ((errno = -ldp_init ()))
2334     return -1;
2335
2336   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2337   errno = ENOSYS;
2338
2339
2340   return -1;
2341 }
2342 #endif
2343
2344 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
2345
2346 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
2347
2348 /*
2349  * This function is called when the library is loaded
2350  */
2351 void
2352 ldp_constructor (void)
2353 {
2354   swrap_constructor ();
2355   if (ldp_init () != 0)
2356     fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
2357              getpid ());
2358   else if (LDP_DEBUG > 0)
2359     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
2360 }
2361
2362 /*
2363  * This function is called when the library is unloaded
2364  */
2365 void
2366 ldp_destructor (void)
2367 {
2368   swrap_destructor ();
2369   if (ldp->init)
2370     ldp->init = 0;
2371
2372   /* Don't use clib_warning() here because that calls writev()
2373    * which will call ldp_init().
2374    */
2375   if (LDP_DEBUG > 0)
2376     printf ("%s:%d: LDP<%d>: LDP destructor: done!\n",
2377             __func__, __LINE__, getpid ());
2378 }
2379
2380
2381 /*
2382  * fd.io coding-style-patch-verification: ON
2383  *
2384  * Local Variables:
2385  * eval: (c-set-style "gnu")
2386  * End:
2387  */