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