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