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