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