vcl: basic support for apps that fork
[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/vppcom.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_fd_entry_
55 {
56   u32 session_index;
57   u32 fd;
58   u32 fd_index;
59 } ldp_fd_entry_t;
60
61 typedef struct ldp_worker_ctx_
62 {
63   u8 *io_buffer;
64   clib_time_t clib_time;
65
66   /*
67    * Select state
68    */
69   clib_bitmap_t *rd_bitmap;
70   clib_bitmap_t *wr_bitmap;
71   clib_bitmap_t *ex_bitmap;
72   clib_bitmap_t *sid_rd_bitmap;
73   clib_bitmap_t *sid_wr_bitmap;
74   clib_bitmap_t *sid_ex_bitmap;
75   clib_bitmap_t *libc_rd_bitmap;
76   clib_bitmap_t *libc_wr_bitmap;
77   clib_bitmap_t *libc_ex_bitmap;
78   u8 select_vcl;
79
80   /*
81    * Poll state
82    */
83   vcl_poll_t *vcl_poll;
84   struct pollfd *libc_poll;
85   u16 *libc_poll_idxs;
86
87   /*
88    * Epoll state
89    */
90   u8 epoll_wait_vcl;
91   int vcl_mq_epfd;
92
93 } ldp_worker_ctx_t;
94
95 typedef struct
96 {
97   ldp_worker_ctx_t *workers;
98   int init;
99   char app_name[LDP_APP_NAME_MAX];
100   u32 sid_bit_val;
101   u32 sid_bit_mask;
102   u32 debug;
103   ldp_fd_entry_t *fd_pool;
104   clib_rwlock_t fd_table_lock;
105   uword *session_index_to_fd_table;
106
107   /** vcl needs next epoll_create to go to libc_epoll */
108   u8 vcl_needs_real_epoll;
109 } ldp_main_t;
110
111 #define LDP_DEBUG ldp->debug
112
113 #define LDBG(_lvl, _fmt, _args...)                                      \
114   if (ldp->debug > _lvl)                                                \
115     clib_warning (_fmt, ##_args)
116
117 static ldp_main_t ldp_main = {
118   .sid_bit_val = (1 << LDP_SID_BIT_MIN),
119   .sid_bit_mask = (1 << LDP_SID_BIT_MIN) - 1,
120   .debug = LDP_DEBUG_INIT,
121 };
122
123 static ldp_main_t *ldp = &ldp_main;
124
125 static inline ldp_worker_ctx_t *
126 ldp_worker_get_current (void)
127 {
128   return (ldp->workers + vppcom_worker_index ());
129 }
130
131 /*
132  * RETURN:  0 on success or -1 on error.
133  * */
134 static inline void
135 ldp_set_app_name (char *app_name)
136 {
137   int rv = snprintf (ldp->app_name, LDP_APP_NAME_MAX,
138                      "ldp-%d-%s", getpid (), app_name);
139
140   if (rv >= LDP_APP_NAME_MAX)
141     app_name[LDP_APP_NAME_MAX - 1] = 0;
142 }
143
144 static inline char *
145 ldp_get_app_name ()
146 {
147   if (ldp->app_name[0] == '\0')
148     ldp_set_app_name ("app");
149
150   return ldp->app_name;
151 }
152
153 static int
154 ldp_fd_alloc (u32 sid)
155 {
156   ldp_fd_entry_t *fde;
157
158   clib_rwlock_writer_lock (&ldp->fd_table_lock);
159   if (pool_elts (ldp->fd_pool) >= (1ULL << 32) - ldp->sid_bit_val)
160     {
161       clib_rwlock_writer_unlock (&ldp->fd_table_lock);
162       return -1;
163     }
164   pool_get (ldp->fd_pool, fde);
165   fde->session_index = vppcom_session_index (sid);
166   fde->fd_index = fde - ldp->fd_pool;
167   fde->fd = fde->fd_index + ldp->sid_bit_val;
168   hash_set (ldp->session_index_to_fd_table, fde->session_index, fde->fd);
169   clib_rwlock_writer_unlock (&ldp->fd_table_lock);
170   return fde->fd;
171 }
172
173 static ldp_fd_entry_t *
174 ldp_fd_entry_get_w_lock (u32 fd_index)
175 {
176   clib_rwlock_reader_lock (&ldp->fd_table_lock);
177   if (pool_is_free_index (ldp->fd_pool, fd_index))
178     return 0;
179
180   return pool_elt_at_index (ldp->fd_pool, fd_index);
181 }
182
183 static inline int
184 ldp_fd_from_sid (u32 sid)
185 {
186   uword *fdp;
187   int fd;
188
189   clib_rwlock_reader_lock (&ldp->fd_table_lock);
190   fdp = hash_get (ldp->session_index_to_fd_table, vppcom_session_index (sid));
191   fd = fdp ? *fdp : -EMFILE;
192   clib_rwlock_reader_unlock (&ldp->fd_table_lock);
193
194   return fd;
195 }
196
197 static inline int
198 ldp_fd_is_sid (int fd)
199 {
200   return fd >= ldp->sid_bit_val;
201 }
202
203 static inline u32
204 ldp_sid_from_fd (int fd)
205 {
206   u32 fd_index, session_index;
207   ldp_fd_entry_t *fde;
208
209   if (!ldp_fd_is_sid (fd))
210     return INVALID_SESSION_ID;
211
212   fd_index = fd - ldp->sid_bit_val;
213   fde = ldp_fd_entry_get_w_lock (fd_index);
214   if (!fde)
215     {
216       LDBG (0, "unknown fd %d", fd);
217       clib_rwlock_reader_unlock (&ldp->fd_table_lock);
218       return INVALID_SESSION_ID;
219     }
220   session_index = fde->session_index;
221   clib_rwlock_reader_unlock (&ldp->fd_table_lock);
222
223   return vppcom_session_handle (session_index);
224 }
225
226 static void
227 ldp_fd_free_w_sid (u32 sid)
228 {
229   ldp_fd_entry_t *fde;
230   u32 fd_index;
231   int fd;
232
233   fd = ldp_fd_from_sid (sid);
234   if (!fd)
235     return;
236
237   fd_index = fd - ldp->sid_bit_val;
238   fde = ldp_fd_entry_get_w_lock (fd_index);
239   if (fde)
240     {
241       hash_unset (ldp->session_index_to_fd_table, fde->session_index);
242       pool_put (ldp->fd_pool, fde);
243     }
244   clib_rwlock_writer_unlock (&ldp->fd_table_lock);
245 }
246
247 static inline int
248 ldp_init (void)
249 {
250   ldp_worker_ctx_t *ldpw;
251   int rv;
252
253   if (PREDICT_TRUE (ldp->init))
254     return 0;
255
256   ldp->init = 1;
257   ldp->vcl_needs_real_epoll = 1;
258   rv = vppcom_app_create (ldp_get_app_name ());
259   if (rv != VPPCOM_OK)
260     {
261       fprintf (stderr, "\nLDP<%d>: ERROR: ldp_init: vppcom_app_create()"
262                " failed!  rv = %d (%s)\n",
263                getpid (), rv, vppcom_retval_str (rv));
264       ldp->init = 0;
265       return rv;
266     }
267   ldp->vcl_needs_real_epoll = 0;
268   pool_alloc (ldp->workers, LDP_MAX_NWORKERS);
269   ldpw = ldp_worker_get_current ();
270
271   char *env_var_str = getenv (LDP_ENV_DEBUG);
272   if (env_var_str)
273     {
274       u32 tmp;
275       if (sscanf (env_var_str, "%u", &tmp) != 1)
276         clib_warning ("LDP<%d>: WARNING: Invalid LDP debug level specified in"
277                       " the env var " LDP_ENV_DEBUG " (%s)!", getpid (),
278                       env_var_str);
279       else
280         {
281           ldp->debug = tmp;
282           LDBG (0, "LDP<%d>: configured LDP debug level (%u) from env var "
283                 LDP_ENV_DEBUG "!", getpid (), ldp->debug);
284         }
285     }
286
287   env_var_str = getenv (LDP_ENV_APP_NAME);
288   if (env_var_str)
289     {
290       ldp_set_app_name (env_var_str);
291       LDBG (0, "LDP<%d>: configured LDP app name (%s) from the env var "
292             LDP_ENV_APP_NAME "!", getpid (), ldp->app_name);
293     }
294
295   env_var_str = getenv (LDP_ENV_SID_BIT);
296   if (env_var_str)
297     {
298       u32 sb;
299       if (sscanf (env_var_str, "%u", &sb) != 1)
300         {
301           clib_warning ("LDP<%d>: WARNING: Invalid LDP sid bit specified in"
302                         " the env var " LDP_ENV_SID_BIT " (%s)! sid bit "
303                         "value %d (0x%x)", getpid (), env_var_str,
304                         ldp->sid_bit_val, ldp->sid_bit_val);
305         }
306       else if (sb < LDP_SID_BIT_MIN)
307         {
308           ldp->sid_bit_val = (1 << LDP_SID_BIT_MIN);
309           ldp->sid_bit_mask = ldp->sid_bit_val - 1;
310
311           clib_warning ("LDP<%d>: WARNING: LDP sid bit (%u) specified in the"
312                         " env var " LDP_ENV_SID_BIT " (%s) is too small. "
313                         "Using LDP_SID_BIT_MIN (%d)! sid bit value %d (0x%x)",
314                         getpid (), sb, env_var_str, LDP_SID_BIT_MIN,
315                         ldp->sid_bit_val, ldp->sid_bit_val);
316         }
317       else if (sb > LDP_SID_BIT_MAX)
318         {
319           ldp->sid_bit_val = (1 << LDP_SID_BIT_MAX);
320           ldp->sid_bit_mask = ldp->sid_bit_val - 1;
321
322           clib_warning ("LDP<%d>: WARNING: LDP sid bit (%u) specified in the"
323                         " env var " LDP_ENV_SID_BIT " (%s) is too big. Using"
324                         " LDP_SID_BIT_MAX (%d)! sid bit value %d (0x%x)",
325                         getpid (), sb, env_var_str, LDP_SID_BIT_MAX,
326                         ldp->sid_bit_val, ldp->sid_bit_val);
327         }
328       else
329         {
330           ldp->sid_bit_val = (1 << sb);
331           ldp->sid_bit_mask = ldp->sid_bit_val - 1;
332
333           LDBG (0, "LDP<%d>: configured LDP sid bit (%u) from "
334                 LDP_ENV_SID_BIT "!  sid bit value %d (0x%x)", getpid (), sb,
335                 ldp->sid_bit_val, ldp->sid_bit_val);
336         }
337     }
338
339   clib_time_init (&ldpw->clib_time);
340   clib_rwlock_init (&ldp->fd_table_lock);
341   LDBG (0, "LDP<%d>: LDP initialization: done!", getpid ());
342
343   return 0;
344 }
345
346 int
347 close (int fd)
348 {
349   int rv, refcnt;
350   const char *func_str;
351   u32 sid = ldp_sid_from_fd (fd);
352
353   if ((errno = -ldp_init ()))
354     return -1;
355
356   if (sid != INVALID_SESSION_ID)
357     {
358       int epfd;
359
360       func_str = "vppcom_session_attr[GET_LIBC_EPFD]";
361       epfd = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
362       if (epfd > 0)
363         {
364           func_str = "libc_close";
365
366           LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s(): epfd %u (0x%x)",
367                 getpid (), fd, fd, func_str, epfd, epfd);
368
369           rv = libc_close (epfd);
370           if (rv < 0)
371             {
372               u32 size = sizeof (epfd);
373               epfd = 0;
374
375               (void) vppcom_session_attr (sid, VPPCOM_ATTR_SET_LIBC_EPFD,
376                                           &epfd, &size);
377             }
378         }
379       else if (PREDICT_FALSE (epfd < 0))
380         {
381           errno = -epfd;
382           rv = -1;
383           goto done;
384         }
385
386       func_str = "vppcom_session_close";
387
388       LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x)",
389             getpid (), fd, fd, func_str, sid, sid);
390
391       refcnt = vppcom_session_attr (sid, VPPCOM_ATTR_GET_REFCNT, 0, 0);
392       rv = vppcom_session_close (sid);
393       if (rv != VPPCOM_OK)
394         {
395           errno = -rv;
396           rv = -1;
397         }
398       if (refcnt == 1)
399         ldp_fd_free_w_sid (sid);
400     }
401   else
402     {
403       func_str = "libc_close";
404
405       LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s()", getpid (), fd, fd,
406             func_str);
407
408       rv = libc_close (fd);
409     }
410
411 done:
412   if (LDP_DEBUG > 0)
413     {
414       if (rv < 0)
415         {
416           int errno_val = errno;
417           perror (func_str);
418           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
419                         "rv %d, errno = %d", getpid (), fd, fd,
420                         func_str, rv, errno_val);
421           errno = errno_val;
422         }
423       else
424         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
425                       getpid (), fd, fd, rv, rv);
426     }
427   return rv;
428 }
429
430 ssize_t
431 read (int fd, void *buf, size_t nbytes)
432 {
433   ssize_t size;
434   const char *func_str;
435   u32 sid = ldp_sid_from_fd (fd);
436
437   if ((errno = -ldp_init ()))
438     return -1;
439
440   if (sid != INVALID_SESSION_ID)
441     {
442       func_str = "vppcom_session_read";
443
444       if (LDP_DEBUG > 2)
445         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
446                       "sid %u (0x%x), buf %p, nbytes %u", getpid (),
447                       fd, fd, func_str, sid, sid, buf, nbytes);
448
449       size = vppcom_session_read (sid, buf, nbytes);
450       if (size < 0)
451         {
452           errno = -size;
453           size = -1;
454         }
455     }
456   else
457     {
458       func_str = "libc_read";
459
460       if (LDP_DEBUG > 2)
461         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
462                       "buf %p, nbytes %u", getpid (),
463                       fd, fd, func_str, buf, nbytes);
464
465       size = libc_read (fd, buf, nbytes);
466     }
467
468   if (LDP_DEBUG > 2)
469     {
470       if (size < 0)
471         {
472           int errno_val = errno;
473           perror (func_str);
474           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
475                         "rv %d, errno = %d", getpid (), fd, fd,
476                         func_str, size, errno_val);
477           errno = errno_val;
478         }
479       else
480         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
481                       getpid (), fd, fd, size, size);
482     }
483   return size;
484 }
485
486 ssize_t
487 readv (int fd, const struct iovec * iov, int iovcnt)
488 {
489   const char *func_str;
490   ssize_t size = 0;
491   u32 sid = ldp_sid_from_fd (fd);
492   int rv = 0, i, total = 0;
493
494   if ((errno = -ldp_init ()))
495     return -1;
496
497   if (sid != INVALID_SESSION_ID)
498     {
499       func_str = "vppcom_session_read";
500       do
501         {
502           for (i = 0; i < iovcnt; ++i)
503             {
504               if (LDP_DEBUG > 2)
505                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s() [%d]: "
506                               "sid %u (0x%x), iov %p, iovcnt %d, total %d",
507                               getpid (), fd, fd, func_str, i, sid, sid,
508                               iov, iovcnt, total);
509
510               rv = vppcom_session_read (sid, iov[i].iov_base, iov[i].iov_len);
511               if (rv < 0)
512                 break;
513               else
514                 {
515                   total += rv;
516                   if (rv < iov[i].iov_len)
517                     {
518                       if (LDP_DEBUG > 2)
519                         clib_warning ("LDP<%d>: fd %d (0x%x): "
520                                       "rv (%d) < iov[%d].iov_len (%d)",
521                                       getpid (), fd, fd, rv, i,
522                                       iov[i].iov_len);
523                       break;
524                     }
525                 }
526             }
527         }
528       while ((rv >= 0) && (total == 0));
529
530       if (rv < 0)
531         {
532           errno = -rv;
533           size = -1;
534         }
535       else
536         size = total;
537     }
538   else
539     {
540       func_str = "libc_readv";
541
542       if (LDP_DEBUG > 2)
543         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
544                       "iov %p, iovcnt %d", getpid (), fd, fd, iov, iovcnt);
545
546       size = libc_readv (fd, iov, iovcnt);
547     }
548
549   if (LDP_DEBUG > 2)
550     {
551       if (size < 0)
552         {
553           int errno_val = errno;
554           perror (func_str);
555           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
556                         "rv %d, errno = %d", getpid (), fd, fd,
557                         func_str, size, errno_val);
558           errno = errno_val;
559         }
560       else
561         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
562                       getpid (), fd, fd, size, size);
563     }
564   return size;
565 }
566
567 ssize_t
568 write (int fd, const void *buf, size_t nbytes)
569 {
570   const char *func_str;
571   ssize_t size = 0;
572   u32 sid = ldp_sid_from_fd (fd);
573
574   if ((errno = -ldp_init ()))
575     return -1;
576
577   if (sid != INVALID_SESSION_ID)
578     {
579       func_str = "vppcom_session_write";
580
581       if (LDP_DEBUG > 2)
582         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
583                       "sid %u (0x%x), buf %p, nbytes %u", getpid (),
584                       fd, fd, func_str, sid, sid, buf, nbytes);
585
586       size = vppcom_session_write (sid, (void *) buf, nbytes);
587       if (size < 0)
588         {
589           errno = -size;
590           size = -1;
591         }
592     }
593   else
594     {
595       func_str = "libc_write";
596
597       if (LDP_DEBUG > 2)
598         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
599                       "buf %p, nbytes %u", getpid (),
600                       fd, fd, func_str, buf, nbytes);
601
602       size = libc_write (fd, buf, nbytes);
603     }
604
605   if (LDP_DEBUG > 2)
606     {
607       if (size < 0)
608         {
609           int errno_val = errno;
610           perror (func_str);
611           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
612                         "rv %d, errno = %d", getpid (), fd, fd,
613                         func_str, size, errno_val);
614           errno = errno_val;
615         }
616       else
617         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
618                       getpid (), fd, fd, size, size);
619     }
620   return size;
621 }
622
623 ssize_t
624 writev (int fd, const struct iovec * iov, int iovcnt)
625 {
626   const char *func_str;
627   ssize_t size = 0, total = 0;
628   u32 sid = ldp_sid_from_fd (fd);
629   int i, rv = 0;
630
631   /*
632    * Use [f]printf() instead of clib_warning() to prevent recursion SIGSEGV.
633    */
634
635   if ((errno = -ldp_init ()))
636     return -1;
637
638   if (sid != INVALID_SESSION_ID)
639     {
640       func_str = "vppcom_session_write";
641       do
642         {
643           for (i = 0; i < iovcnt; ++i)
644             {
645               if (LDP_DEBUG > 4)
646                 printf ("%s:%d: LDP<%d>: fd %d (0x%x): calling %s() [%d]: "
647                         "sid %u (0x%x), buf %p, nbytes %ld, total %ld",
648                         __func__, __LINE__, getpid (), fd, fd, func_str,
649                         i, sid, sid, iov[i].iov_base, iov[i].iov_len, total);
650
651               rv = vppcom_session_write (sid, iov[i].iov_base,
652                                          iov[i].iov_len);
653               if (rv < 0)
654                 break;
655               else
656                 {
657                   total += rv;
658                   if (rv < iov[i].iov_len)
659                     {
660                       if (LDP_DEBUG > 4)
661                         printf ("%s:%d: LDP<%d>: fd %d (0x%x): "
662                                 "rv (%d) < iov[%d].iov_len (%ld)",
663                                 __func__, __LINE__, getpid (), fd, fd,
664                                 rv, i, iov[i].iov_len);
665                       break;
666                     }
667                 }
668             }
669         }
670       while ((rv >= 0) && (total == 0));
671
672       if (rv < 0)
673         {
674           errno = -rv;
675           size = -1;
676         }
677       else
678         size = total;
679     }
680   else
681     {
682       func_str = "libc_writev";
683
684       if (LDP_DEBUG > 4)
685         printf ("%s:%d: LDP<%d>: fd %d (0x%x): calling %s(): "
686                 "iov %p, iovcnt %d\n", __func__, __LINE__, getpid (),
687                 fd, fd, func_str, iov, iovcnt);
688
689       size = libc_writev (fd, iov, iovcnt);
690     }
691
692   if (LDP_DEBUG > 4)
693     {
694       if (size < 0)
695         {
696           int errno_val = errno;
697           perror (func_str);
698           fprintf (stderr,
699                    "%s:%d: LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
700                    "rv %ld, errno = %d\n", __func__, __LINE__, getpid (), fd,
701                    fd, func_str, size, errno_val);
702           errno = errno_val;
703         }
704       else
705         printf ("%s:%d: LDP<%d>: fd %d (0x%x): returning %ld\n",
706                 __func__, __LINE__, getpid (), fd, fd, size);
707     }
708   return size;
709 }
710
711 int
712 fcntl (int fd, int cmd, ...)
713 {
714   const char *func_str = __func__;
715   int rv = 0;
716   va_list ap;
717   u32 sid = ldp_sid_from_fd (fd);
718
719   if ((errno = -ldp_init ()))
720     return -1;
721
722   va_start (ap, cmd);
723   if (sid != INVALID_SESSION_ID)
724     {
725       int flags = va_arg (ap, int);
726       u32 size;
727
728       size = sizeof (flags);
729       rv = -EOPNOTSUPP;
730       switch (cmd)
731         {
732         case F_SETFL:
733           func_str = "vppcom_session_attr[SET_FLAGS]";
734           LDBG (2, "LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x) "
735                 "flags %d (0x%x), size %d", getpid (), fd, fd, func_str, sid,
736                 sid, flags, flags, size);
737
738           rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_FLAGS, &flags,
739                                     &size);
740           break;
741
742         case F_GETFL:
743           func_str = "vppcom_session_attr[GET_FLAGS]";
744           LDBG (2, "LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
745                 "flags %d (0x%x), size %d", getpid (), fd, fd, func_str, sid,
746                 sid, flags, flags, size);
747
748           rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_FLAGS, &flags,
749                                     &size);
750           if (rv == VPPCOM_OK)
751             {
752               LDBG (2, "LDP<%d>: fd %d (0x%x), cmd %d (F_GETFL): %s() "
753                     "returned flags %d (0x%x)", getpid (), fd, fd, cmd,
754                     func_str, flags, flags);
755               rv = flags;
756             }
757           break;
758         case F_SETFD:
759           /* TODO handle this */
760           LDBG (0, "F_SETFD ignored flags %u", flags);
761           rv = 0;
762           break;
763         default:
764           rv = -EOPNOTSUPP;
765           break;
766         }
767       if (rv < 0)
768         {
769           errno = -rv;
770           rv = -1;
771         }
772     }
773   else
774     {
775       func_str = "libc_vfcntl";
776
777       if (LDP_DEBUG > 2)
778         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): cmd %d",
779                       getpid (), fd, fd, func_str, cmd);
780
781       rv = libc_vfcntl (fd, cmd, ap);
782     }
783
784   va_end (ap);
785
786   if (LDP_DEBUG > 2)
787     {
788       if (rv < 0)
789         {
790           int errno_val = errno;
791           perror (func_str);
792           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
793                         "rv %d, errno = %d", getpid (), fd, fd,
794                         func_str, rv, errno_val);
795           errno = errno_val;
796         }
797       else
798         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
799                       getpid (), fd, fd, rv, rv);
800     }
801   return rv;
802 }
803
804 int
805 ioctl (int fd, unsigned long int cmd, ...)
806 {
807   const char *func_str;
808   int rv;
809   va_list ap;
810   u32 sid = ldp_sid_from_fd (fd);
811
812   if ((errno = -ldp_init ()))
813     return -1;
814
815   va_start (ap, cmd);
816   if (sid != INVALID_SESSION_ID)
817     {
818       func_str = "vppcom_session_attr[GET_NREAD]";
819
820       switch (cmd)
821         {
822         case FIONREAD:
823           if (LDP_DEBUG > 2)
824             clib_warning
825               ("LDP<%d>: fd %d (0x%x): calling  %s(): sid %u (0x%x)",
826                getpid (), fd, fd, func_str, sid, sid);
827
828           rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
829           break;
830
831         case FIONBIO:
832           {
833             u32 flags = va_arg (ap, int) ? O_NONBLOCK : 0;
834             u32 size = sizeof (flags);
835
836             /* TBD: When VPPCOM_ATTR_[GS]ET_FLAGS supports flags other than
837              *      non-blocking, the flags should be read here and merged
838              *      with O_NONBLOCK.
839              */
840             if (LDP_DEBUG > 2)
841               clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
842                             "sid %u (0x%x), flags %d (0x%x), size %d",
843                             getpid (), fd, fd, func_str, sid, sid,
844                             flags, flags, size);
845
846             rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_FLAGS, &flags,
847                                       &size);
848           }
849           break;
850
851         default:
852           rv = -EOPNOTSUPP;
853           break;
854         }
855       if (rv < 0)
856         {
857           errno = -rv;
858           rv = -1;
859         }
860     }
861   else
862     {
863       func_str = "libc_vioctl";
864
865       if (LDP_DEBUG > 2)
866         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): cmd %d",
867                       getpid (), fd, fd, func_str, cmd);
868
869       rv = libc_vioctl (fd, cmd, ap);
870     }
871
872   if (LDP_DEBUG > 2)
873     {
874       if (rv < 0)
875         {
876           int errno_val = errno;
877           perror (func_str);
878           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
879                         "rv %d, errno = %d", getpid (), fd, fd,
880                         func_str, rv, errno_val);
881           errno = errno_val;
882         }
883       else
884         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
885                       getpid (), fd, fd, rv, rv);
886     }
887   va_end (ap);
888   return rv;
889 }
890
891 int
892 ldp_pselect (int nfds, fd_set * __restrict readfds,
893              fd_set * __restrict writefds,
894              fd_set * __restrict exceptfds,
895              const struct timespec *__restrict timeout,
896              const __sigset_t * __restrict sigmask)
897 {
898   uword sid_bits, sid_bits_set, libc_bits, libc_bits_set;
899   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
900   u32 minbits = clib_max (nfds, BITS (uword)), sid;
901   char *func_str = "##";
902   f64 time_out;
903   int rv, fd;
904
905   if (nfds < 0)
906     {
907       errno = EINVAL;
908       return -1;
909     }
910
911   if (timeout)
912     {
913       time_out = (timeout->tv_sec == 0 && timeout->tv_nsec == 0) ?
914         (f64) 0 : (f64) timeout->tv_sec +
915         (f64) timeout->tv_nsec / (f64) 1000000000;
916
917       /* select as fine grained sleep */
918       if (!nfds)
919         {
920           LDBG (3, "LDP<%d>: sleeping for %.02f seconds", getpid (),
921                 time_out);
922
923           time_out += clib_time_now (&ldpw->clib_time);
924           while (clib_time_now (&ldpw->clib_time) < time_out)
925             ;
926           return 0;
927         }
928     }
929   else if (!nfds)
930     {
931       errno = EINVAL;
932       return -1;
933     }
934   else
935     time_out = -1;
936
937
938   if (nfds <= ldp->sid_bit_val)
939     {
940       func_str = "libc_pselect";
941
942       LDBG (3, "LDP<%d>: calling %s(): nfds %d, readfds %p, writefds %p, "
943             "exceptfds %p, timeout %p, sigmask %p", getpid (), func_str, nfds,
944             readfds, writefds, exceptfds, timeout, sigmask);
945
946       rv = libc_pselect (nfds, readfds, writefds, exceptfds,
947                          timeout, sigmask);
948       goto done;
949     }
950
951   if (PREDICT_FALSE (ldp->sid_bit_val > FD_SETSIZE / 2))
952     {
953       clib_warning ("LDP<%d>: ERROR: LDP sid bit value %d (0x%x) > "
954                     "FD_SETSIZE/2 %d (0x%x)!", getpid (),
955                     ldp->sid_bit_val, ldp->sid_bit_val,
956                     FD_SETSIZE / 2, FD_SETSIZE / 2);
957       errno = EOVERFLOW;
958       return -1;
959     }
960
961   sid_bits = libc_bits = 0;
962   u32 n_bytes = nfds / 8 + ((nfds % 8) ? 1 : 0);
963   if (readfds)
964     {
965       clib_bitmap_validate (ldpw->sid_rd_bitmap, minbits);
966       clib_bitmap_validate (ldpw->libc_rd_bitmap, minbits);
967       clib_bitmap_validate (ldpw->rd_bitmap, minbits);
968       clib_memcpy_fast (ldpw->rd_bitmap, readfds, n_bytes);
969       memset (readfds, 0, n_bytes);
970
971       /* *INDENT-OFF* */
972       clib_bitmap_foreach (fd, ldpw->rd_bitmap, ({
973         if (fd > nfds)
974           break;
975         sid = ldp_sid_from_fd (fd);
976         LDBG (3, "LDP<%d>: readfds: fd %d (0x%x), sid %u (0x%x)",
977               getpid (), fd, fd, sid, sid);
978         if (sid == INVALID_SESSION_ID)
979           clib_bitmap_set_no_check (ldpw->libc_rd_bitmap, fd, 1);
980         else
981           clib_bitmap_set_no_check (ldpw->sid_rd_bitmap,
982                                     vppcom_session_index (sid), 1);
983       }));
984       /* *INDENT-ON* */
985
986       sid_bits_set = clib_bitmap_last_set (ldpw->sid_rd_bitmap) + 1;
987       sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits;
988
989       libc_bits_set = clib_bitmap_last_set (ldpw->libc_rd_bitmap) + 1;
990       libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits;
991
992       LDBG (3, "LDP<%d>: readfds: sid_bits_set %d, sid_bits %d, "
993             "libc_bits_set %d, libc_bits %d", getpid (), sid_bits_set,
994             sid_bits, libc_bits_set, libc_bits);
995     }
996   if (writefds)
997     {
998       clib_bitmap_validate (ldpw->sid_wr_bitmap, minbits);
999       clib_bitmap_validate (ldpw->libc_wr_bitmap, minbits);
1000       clib_bitmap_validate (ldpw->wr_bitmap, minbits);
1001       clib_memcpy_fast (ldpw->wr_bitmap, writefds, n_bytes);
1002       memset (writefds, 0, n_bytes);
1003
1004       /* *INDENT-OFF* */
1005       clib_bitmap_foreach (fd, ldpw->wr_bitmap, ({
1006         if (fd > nfds)
1007           break;
1008         sid = ldp_sid_from_fd (fd);
1009         LDBG (3, "LDP<%d>: writefds: fd %d (0x%x), sid %u (0x%x)",
1010                         getpid (), fd, fd, sid, sid);
1011         if (sid == INVALID_SESSION_ID)
1012           clib_bitmap_set_no_check (ldpw->libc_wr_bitmap, fd, 1);
1013         else
1014           clib_bitmap_set_no_check (ldpw->sid_wr_bitmap,
1015                                     vppcom_session_index (sid), 1);
1016       }));
1017       /* *INDENT-ON* */
1018
1019       sid_bits_set = clib_bitmap_last_set (ldpw->sid_wr_bitmap) + 1;
1020       sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits;
1021
1022       libc_bits_set = clib_bitmap_last_set (ldpw->libc_wr_bitmap) + 1;
1023       libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits;
1024
1025       LDBG (3, "LDP<%d>: writefds: sid_bits_set %d, sid_bits %d, "
1026             "libc_bits_set %d, libc_bits %d", getpid (),
1027             sid_bits_set, sid_bits, libc_bits_set, libc_bits);
1028     }
1029   if (exceptfds)
1030     {
1031       clib_bitmap_validate (ldpw->sid_ex_bitmap, minbits);
1032       clib_bitmap_validate (ldpw->libc_ex_bitmap, minbits);
1033       clib_bitmap_validate (ldpw->ex_bitmap, minbits);
1034       clib_memcpy_fast (ldpw->ex_bitmap, exceptfds, n_bytes);
1035       memset (exceptfds, 0, n_bytes);
1036
1037       /* *INDENT-OFF* */
1038       clib_bitmap_foreach (fd, ldpw->ex_bitmap, ({
1039         if (fd > nfds)
1040           break;
1041         sid = ldp_sid_from_fd (fd);
1042         LDBG (3, "LDP<%d>: exceptfds: fd %d (0x%x), sid %u (0x%x)",
1043                         getpid (), fd, fd, sid, sid);
1044         if (sid == INVALID_SESSION_ID)
1045           clib_bitmap_set_no_check (ldpw->libc_ex_bitmap, fd, 1);
1046         else
1047           clib_bitmap_set_no_check (ldpw->sid_ex_bitmap,
1048                                     vppcom_session_index (sid), 1);
1049       }));
1050       /* *INDENT-ON* */
1051
1052       sid_bits_set = clib_bitmap_last_set (ldpw->sid_ex_bitmap) + 1;
1053       sid_bits = (sid_bits_set > sid_bits) ? sid_bits_set : sid_bits;
1054
1055       libc_bits_set = clib_bitmap_last_set (ldpw->libc_ex_bitmap) + 1;
1056       libc_bits = (libc_bits_set > libc_bits) ? libc_bits_set : libc_bits;
1057
1058       LDBG (3, "LDP<%d>: exceptfds: sid_bits_set %d, sid_bits %d, "
1059             "libc_bits_set %d, libc_bits %d", getpid (),
1060             sid_bits_set, sid_bits, libc_bits_set, libc_bits);
1061     }
1062
1063   if (PREDICT_FALSE (!sid_bits && !libc_bits))
1064     {
1065       errno = EINVAL;
1066       rv = -1;
1067       goto done;
1068     }
1069
1070   do
1071     {
1072       if (sid_bits)
1073         {
1074           if (!ldpw->select_vcl)
1075             {
1076               func_str = "vppcom_select";
1077
1078               if (readfds)
1079                 clib_memcpy_fast (ldpw->rd_bitmap, ldpw->sid_rd_bitmap,
1080                                   vec_len (ldpw->rd_bitmap) *
1081                                   sizeof (clib_bitmap_t));
1082               if (writefds)
1083                 clib_memcpy_fast (ldpw->wr_bitmap, ldpw->sid_wr_bitmap,
1084                                   vec_len (ldpw->wr_bitmap) *
1085                                   sizeof (clib_bitmap_t));
1086               if (exceptfds)
1087                 clib_memcpy_fast (ldpw->ex_bitmap, ldpw->sid_ex_bitmap,
1088                                   vec_len (ldpw->ex_bitmap) *
1089                                   sizeof (clib_bitmap_t));
1090
1091               rv = vppcom_select (sid_bits,
1092                                   readfds ? ldpw->rd_bitmap : NULL,
1093                                   writefds ? ldpw->wr_bitmap : NULL,
1094                                   exceptfds ? ldpw->ex_bitmap : NULL, 0);
1095               if (rv < 0)
1096                 {
1097                   errno = -rv;
1098                   rv = -1;
1099                 }
1100               else if (rv > 0)
1101                 {
1102                   if (readfds)
1103                     {
1104                       /* *INDENT-OFF* */
1105                       clib_bitmap_foreach (sid, ldpw->rd_bitmap,
1106                         ({
1107                           fd = ldp_fd_from_sid (vppcom_session_handle (sid));
1108                           if (PREDICT_FALSE (fd < 0))
1109                             {
1110                               errno = EBADFD;
1111                               rv = -1;
1112                               goto done;
1113                             }
1114                           FD_SET (fd, readfds);
1115                         }));
1116                       /* *INDENT-ON* */
1117                     }
1118                   if (writefds)
1119                     {
1120                       /* *INDENT-OFF* */
1121                       clib_bitmap_foreach (sid, ldpw->wr_bitmap,
1122                         ({
1123                           fd = ldp_fd_from_sid (vppcom_session_handle (sid));
1124                           if (PREDICT_FALSE (fd < 0))
1125                             {
1126                               errno = EBADFD;
1127                               rv = -1;
1128                               goto done;
1129                             }
1130                           FD_SET (fd, writefds);
1131                         }));
1132                       /* *INDENT-ON* */
1133                     }
1134                   if (exceptfds)
1135                     {
1136                       /* *INDENT-OFF* */
1137                       clib_bitmap_foreach (sid, ldpw->ex_bitmap,
1138                         ({
1139                           fd = ldp_fd_from_sid (vppcom_session_handle (sid));
1140                           if (PREDICT_FALSE (fd < 0))
1141                             {
1142                               errno = EBADFD;
1143                               rv = -1;
1144                               goto done;
1145                             }
1146                           FD_SET (fd, exceptfds);
1147                         }));
1148                       /* *INDENT-ON* */
1149                     }
1150                   ldpw->select_vcl = 1;
1151                   goto done;
1152                 }
1153             }
1154           else
1155             ldpw->select_vcl = 0;
1156         }
1157       if (libc_bits)
1158         {
1159           struct timespec tspec;
1160
1161           func_str = "libc_pselect";
1162
1163           if (readfds)
1164             clib_memcpy_fast (readfds, ldpw->libc_rd_bitmap,
1165                               vec_len (ldpw->rd_bitmap) *
1166                               sizeof (clib_bitmap_t));
1167           if (writefds)
1168             clib_memcpy_fast (writefds, ldpw->libc_wr_bitmap,
1169                               vec_len (ldpw->wr_bitmap) *
1170                               sizeof (clib_bitmap_t));
1171           if (exceptfds)
1172             clib_memcpy_fast (exceptfds, ldpw->libc_ex_bitmap,
1173                               vec_len (ldpw->ex_bitmap) *
1174                               sizeof (clib_bitmap_t));
1175           tspec.tv_sec = tspec.tv_nsec = 0;
1176           rv = libc_pselect (libc_bits,
1177                              readfds ? readfds : NULL,
1178                              writefds ? writefds : NULL,
1179                              exceptfds ? exceptfds : NULL, &tspec, sigmask);
1180           if (rv != 0)
1181             goto done;
1182         }
1183     }
1184   while ((time_out == -1) || (clib_time_now (&ldpw->clib_time) < time_out));
1185   rv = 0;
1186
1187 done:
1188   /* TBD: set timeout to amount of time left */
1189   clib_bitmap_zero (ldpw->rd_bitmap);
1190   clib_bitmap_zero (ldpw->sid_rd_bitmap);
1191   clib_bitmap_zero (ldpw->libc_rd_bitmap);
1192   clib_bitmap_zero (ldpw->wr_bitmap);
1193   clib_bitmap_zero (ldpw->sid_wr_bitmap);
1194   clib_bitmap_zero (ldpw->libc_wr_bitmap);
1195   clib_bitmap_zero (ldpw->ex_bitmap);
1196   clib_bitmap_zero (ldpw->sid_ex_bitmap);
1197   clib_bitmap_zero (ldpw->libc_ex_bitmap);
1198
1199   if (LDP_DEBUG > 3)
1200     {
1201       if (rv < 0)
1202         {
1203           int errno_val = errno;
1204           perror (func_str);
1205           clib_warning ("LDP<%d>: ERROR: %s() failed! "
1206                         "rv %d, errno = %d", getpid (),
1207                         func_str, rv, errno_val);
1208           errno = errno_val;
1209         }
1210       else
1211         clib_warning ("LDP<%d>: returning %d (0x%x)", getpid (), rv, rv);
1212     }
1213   return rv;
1214 }
1215
1216 int
1217 select (int nfds, fd_set * __restrict readfds,
1218         fd_set * __restrict writefds,
1219         fd_set * __restrict exceptfds, struct timeval *__restrict timeout)
1220 {
1221   struct timespec tspec;
1222
1223   if (timeout)
1224     {
1225       tspec.tv_sec = timeout->tv_sec;
1226       tspec.tv_nsec = timeout->tv_usec * 1000;
1227     }
1228   return ldp_pselect (nfds, readfds, writefds, exceptfds,
1229                       timeout ? &tspec : NULL, NULL);
1230 }
1231
1232 #ifdef __USE_XOPEN2K
1233 int
1234 pselect (int nfds, fd_set * __restrict readfds,
1235          fd_set * __restrict writefds,
1236          fd_set * __restrict exceptfds,
1237          const struct timespec *__restrict timeout,
1238          const __sigset_t * __restrict sigmask)
1239 {
1240   return ldp_pselect (nfds, readfds, writefds, exceptfds, timeout, 0);
1241 }
1242 #endif
1243
1244 int
1245 socket (int domain, int type, int protocol)
1246 {
1247   const char *func_str;
1248   int rv;
1249   u8 is_nonblocking = type & SOCK_NONBLOCK ? 1 : 0;
1250   int sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
1251
1252   if ((errno = -ldp_init ()))
1253     return -1;
1254
1255   if (((domain == AF_INET) || (domain == AF_INET6)) &&
1256       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
1257     {
1258       int sid;
1259       u8 proto = ((sock_type == SOCK_DGRAM) ?
1260                   VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
1261
1262       func_str = "vppcom_session_create";
1263
1264       LDBG (0, "LDP<%d>: : calling %s(): proto %u (%s), is_nonblocking %u",
1265             getpid (), func_str, proto, vppcom_proto_str (proto),
1266             is_nonblocking);
1267
1268       sid = vppcom_session_create (proto, is_nonblocking);
1269       if (sid < 0)
1270         {
1271           errno = -sid;
1272           rv = -1;
1273         }
1274       else
1275         {
1276           func_str = "ldp_fd_from_sid";
1277           rv = ldp_fd_alloc (sid);
1278           if (rv < 0)
1279             {
1280               (void) vppcom_session_close (sid);
1281               errno = -rv;
1282               rv = -1;
1283             }
1284         }
1285     }
1286   else
1287     {
1288       func_str = "libc_socket";
1289
1290       LDBG (0, "LDP<%d>: : calling %s()", getpid (), func_str);
1291
1292       rv = libc_socket (domain, type, protocol);
1293     }
1294
1295   if (LDP_DEBUG > 0)
1296     {
1297       if (rv < 0)
1298         {
1299           int errno_val = errno;
1300           perror (func_str);
1301           clib_warning ("LDP<%d>: ERROR: %s() failed! "
1302                         "rv %d, errno = %d",
1303                         getpid (), func_str, rv, errno_val);
1304           errno = errno_val;
1305         }
1306       else
1307         clib_warning ("LDP<%d>: : returning fd %d (0x%x)", getpid (), rv, rv);
1308     }
1309   return rv;
1310 }
1311
1312 /*
1313  * Create two new sockets, of type TYPE in domain DOMAIN and using
1314  * protocol PROTOCOL, which are connected to each other, and put file
1315  * descriptors for them in FDS[0] and FDS[1].  If PROTOCOL is zero,
1316  * one will be chosen automatically.
1317  * Returns 0 on success, -1 for errors.
1318  * */
1319 int
1320 socketpair (int domain, int type, int protocol, int fds[2])
1321 {
1322   const char *func_str;
1323   int rv;
1324   int sock_type = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
1325
1326   if ((errno = -ldp_init ()))
1327     return -1;
1328
1329   if (((domain == AF_INET) || (domain == AF_INET6)) &&
1330       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
1331     {
1332       func_str = __func__;
1333
1334       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
1335       errno = ENOSYS;
1336       rv = -1;
1337     }
1338   else
1339     {
1340       func_str = "libc_socket";
1341
1342       LDBG (1, "LDP<%d>: : calling %s()", getpid (), func_str);
1343
1344       rv = libc_socketpair (domain, type, protocol, fds);
1345     }
1346
1347   if (LDP_DEBUG > 1)
1348     {
1349       if (rv < 0)
1350         {
1351           int errno_val = errno;
1352           perror (func_str);
1353           clib_warning ("LDP<%d>: ERROR: %s() failed! "
1354                         "rv %d, errno = %d",
1355                         getpid (), func_str, rv, errno_val);
1356           errno = errno_val;
1357         }
1358       else
1359         clib_warning ("LDP<%d>: : returning fd %d (0x%x)", getpid (), rv, rv);
1360     }
1361   return rv;
1362 }
1363
1364 int
1365 bind (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
1366 {
1367   int rv;
1368   const char *func_str;
1369   u32 sid = ldp_sid_from_fd (fd);
1370
1371   if ((errno = -ldp_init ()))
1372     return -1;
1373
1374   if (sid != INVALID_SESSION_ID)
1375     {
1376       vppcom_endpt_t ep;
1377
1378       func_str = "vppcom_session_bind";
1379
1380       switch (addr->sa_family)
1381         {
1382         case AF_INET:
1383           if (len != sizeof (struct sockaddr_in))
1384             {
1385               clib_warning
1386                 ("LDP<%d>: ERROR: fd %d (0x%x): sid %u (0x%x): Invalid "
1387                  "AF_INET addr len %u!", getpid (), fd, fd, sid, sid, len);
1388               errno = EINVAL;
1389               rv = -1;
1390               goto done;
1391             }
1392           ep.is_ip4 = VPPCOM_IS_IP4;
1393           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1394           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1395           break;
1396
1397         case AF_INET6:
1398           if (len != sizeof (struct sockaddr_in6))
1399             {
1400               clib_warning
1401                 ("LDP<%d>: ERROR: fd %d (0x%x): sid %u (0x%x): Invalid "
1402                  "AF_INET6 addr len %u!", getpid (), fd, fd, sid, sid, len);
1403               errno = EINVAL;
1404               rv = -1;
1405               goto done;
1406             }
1407           ep.is_ip4 = VPPCOM_IS_IP6;
1408           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1409           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1410           break;
1411
1412         default:
1413           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): sid %u (0x%x): "
1414                         "Unsupported address family %u!",
1415                         getpid (), fd, fd, sid, sid, addr->sa_family);
1416           errno = EAFNOSUPPORT;
1417           rv = -1;
1418           goto done;
1419         }
1420       if (LDP_DEBUG > 0)
1421         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
1422                       "addr %p, len %u",
1423                       getpid (), fd, fd, func_str, sid, sid, addr, len);
1424
1425       rv = vppcom_session_bind (sid, &ep);
1426       if (rv != VPPCOM_OK)
1427         {
1428           errno = -rv;
1429           rv = -1;
1430         }
1431     }
1432   else
1433     {
1434       func_str = "libc_bind";
1435
1436       if (LDP_DEBUG > 0)
1437         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1438                       "addr %p, len %u",
1439                       getpid (), fd, fd, func_str, addr, len);
1440
1441       rv = libc_bind (fd, addr, len);
1442     }
1443
1444 done:
1445   if (LDP_DEBUG > 0)
1446     {
1447       if (rv < 0)
1448         {
1449           int errno_val = errno;
1450           perror (func_str);
1451           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1452                         "rv %d, errno = %d", getpid (), fd, fd,
1453                         func_str, rv, errno_val);
1454           errno = errno_val;
1455         }
1456       else
1457         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1458                       getpid (), fd, fd, rv, rv);
1459     }
1460   return rv;
1461 }
1462
1463 static inline int
1464 ldp_copy_ep_to_sockaddr (__SOCKADDR_ARG addr, socklen_t * __restrict len,
1465                          vppcom_endpt_t * ep)
1466 {
1467   int rv = 0;
1468   int sa_len, copy_len;
1469
1470   if ((errno = -ldp_init ()))
1471     return -1;
1472
1473   if (addr && len && ep)
1474     {
1475       addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1476       switch (addr->sa_family)
1477         {
1478         case AF_INET:
1479           ((struct sockaddr_in *) addr)->sin_port = ep->port;
1480           if (*len > sizeof (struct sockaddr_in))
1481             *len = sizeof (struct sockaddr_in);
1482           sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1483           copy_len = *len - sa_len;
1484           if (copy_len > 0)
1485             memcpy (&((struct sockaddr_in *) addr)->sin_addr, ep->ip,
1486                     copy_len);
1487           break;
1488
1489         case AF_INET6:
1490           ((struct sockaddr_in6 *) addr)->sin6_port = ep->port;
1491           if (*len > sizeof (struct sockaddr_in6))
1492             *len = sizeof (struct sockaddr_in6);
1493           sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1494           copy_len = *len - sa_len;
1495           if (copy_len > 0)
1496             memcpy (((struct sockaddr_in6 *) addr)->sin6_addr.
1497                     __in6_u.__u6_addr8, ep->ip, copy_len);
1498           break;
1499
1500         default:
1501           /* Not possible */
1502           rv = -EAFNOSUPPORT;
1503           break;
1504         }
1505     }
1506   return rv;
1507 }
1508
1509 int
1510 getsockname (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1511 {
1512   int rv;
1513   const char *func_str;
1514   u32 sid = ldp_sid_from_fd (fd);
1515
1516   if ((errno = -ldp_init ()))
1517     return -1;
1518
1519   if (sid != INVALID_SESSION_ID)
1520     {
1521       vppcom_endpt_t ep;
1522       u8 addr_buf[sizeof (struct in6_addr)];
1523       u32 size = sizeof (ep);
1524
1525       ep.ip = addr_buf;
1526       func_str = "vppcom_session_attr[GET_LCL_ADDR]";
1527
1528       if (LDP_DEBUG > 2)
1529         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
1530                       "addr %p, len %u",
1531                       getpid (), fd, fd, func_str, sid, sid, addr, len);
1532
1533       rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, &ep, &size);
1534       if (rv != VPPCOM_OK)
1535         {
1536           errno = -rv;
1537           rv = -1;
1538         }
1539       else
1540         {
1541           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1542           if (rv != VPPCOM_OK)
1543             {
1544               errno = -rv;
1545               rv = -1;
1546             }
1547         }
1548     }
1549   else
1550     {
1551       func_str = "libc_getsockname";
1552
1553       if (LDP_DEBUG > 2)
1554         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1555                       "addr %p, len %u",
1556                       getpid (), fd, fd, func_str, addr, len);
1557
1558       rv = libc_getsockname (fd, addr, len);
1559     }
1560
1561   if (LDP_DEBUG > 2)
1562     {
1563       if (rv < 0)
1564         {
1565           int errno_val = errno;
1566           perror (func_str);
1567           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1568                         "rv %d, errno = %d", getpid (), fd, fd,
1569                         func_str, rv, errno_val);
1570           errno = errno_val;
1571         }
1572       else
1573         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1574                       getpid (), fd, fd, rv, rv);
1575     }
1576   return rv;
1577 }
1578
1579 int
1580 connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t len)
1581 {
1582   int rv;
1583   const char *func_str = __func__;
1584   u32 sid = ldp_sid_from_fd (fd);
1585
1586   if ((errno = -ldp_init ()))
1587     return -1;
1588
1589   if (!addr)
1590     {
1591       clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): NULL addr, len %u",
1592                     getpid (), fd, fd, len);
1593       errno = EINVAL;
1594       rv = -1;
1595       goto done;
1596     }
1597
1598   if (sid != INVALID_SESSION_ID)
1599     {
1600       vppcom_endpt_t ep;
1601
1602       func_str = "vppcom_session_connect";
1603
1604       switch (addr->sa_family)
1605         {
1606         case AF_INET:
1607           if (len != sizeof (struct sockaddr_in))
1608             {
1609               clib_warning
1610                 ("LDP<%d>: fd %d (0x%x): ERROR sid %u (0x%x): Invalid "
1611                  "AF_INET addr len %u!", getpid (), fd, fd, sid, sid, len);
1612               errno = EINVAL;
1613               rv = -1;
1614               goto done;
1615             }
1616           ep.is_ip4 = VPPCOM_IS_IP4;
1617           ep.ip = (u8 *) & ((const struct sockaddr_in *) addr)->sin_addr;
1618           ep.port = (u16) ((const struct sockaddr_in *) addr)->sin_port;
1619           break;
1620
1621         case AF_INET6:
1622           if (len != sizeof (struct sockaddr_in6))
1623             {
1624               clib_warning
1625                 ("LDP<%d>: fd %d (0x%x): ERROR sid %u (0x%x): Invalid "
1626                  "AF_INET6 addr len %u!", getpid (), fd, fd, sid, sid, len);
1627               errno = EINVAL;
1628               rv = -1;
1629               goto done;
1630             }
1631           ep.is_ip4 = VPPCOM_IS_IP6;
1632           ep.ip = (u8 *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
1633           ep.port = (u16) ((const struct sockaddr_in6 *) addr)->sin6_port;
1634           break;
1635
1636         default:
1637           clib_warning ("LDP<%d>: fd %d (0x%x): ERROR sid %u (0x%x): "
1638                         "Unsupported address family %u!",
1639                         getpid (), fd, fd, sid, sid, addr->sa_family);
1640           errno = EAFNOSUPPORT;
1641           rv = -1;
1642           goto done;
1643         }
1644       if (LDP_DEBUG > 0)
1645         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x) "
1646                       "addr %p len %u",
1647                       getpid (), fd, fd, func_str, sid, sid, addr, len);
1648
1649       rv = vppcom_session_connect (sid, &ep);
1650       if (rv != VPPCOM_OK)
1651         {
1652           errno = -rv;
1653           rv = -1;
1654         }
1655     }
1656   else
1657     {
1658       func_str = "libc_connect";
1659
1660       if (LDP_DEBUG > 0)
1661         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1662                       "addr %p, len %u",
1663                       getpid (), fd, fd, func_str, addr, len);
1664
1665       rv = libc_connect (fd, addr, len);
1666     }
1667
1668 done:
1669   if (LDP_DEBUG > 0)
1670     {
1671       if (rv < 0)
1672         {
1673           int errno_val = errno;
1674           perror (func_str);
1675           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1676                         "rv %d, errno = %d", getpid (), fd, fd,
1677                         func_str, rv, errno_val);
1678           errno = errno_val;
1679         }
1680       else
1681         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1682                       getpid (), fd, fd, rv, rv);
1683     }
1684   return rv;
1685 }
1686
1687 int
1688 getpeername (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict len)
1689 {
1690   int rv;
1691   const char *func_str;
1692   u32 sid = ldp_sid_from_fd (fd);
1693
1694   if ((errno = -ldp_init ()))
1695     return -1;
1696
1697   if (sid != INVALID_SESSION_ID)
1698     {
1699       vppcom_endpt_t ep;
1700       u8 addr_buf[sizeof (struct in6_addr)];
1701       u32 size = sizeof (ep);
1702
1703       ep.ip = addr_buf;
1704       func_str = "vppcom_session_attr[GET_PEER_ADDR]";
1705
1706       if (LDP_DEBUG > 2)
1707         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
1708                       "addr %p, len %u",
1709                       getpid (), fd, fd, func_str, sid, sid, addr, len);
1710
1711       rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, &ep, &size);
1712       if (rv != VPPCOM_OK)
1713         {
1714           errno = -rv;
1715           rv = -1;
1716         }
1717       else
1718         {
1719           rv = ldp_copy_ep_to_sockaddr (addr, len, &ep);
1720           if (rv != VPPCOM_OK)
1721             {
1722               errno = -rv;
1723               rv = -1;
1724             }
1725         }
1726     }
1727   else
1728     {
1729       func_str = "libc_getpeername";
1730
1731       if (LDP_DEBUG > 2)
1732         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1733                       "addr %p, len %u",
1734                       getpid (), fd, fd, func_str, addr, len);
1735
1736       rv = libc_getpeername (fd, addr, len);
1737     }
1738
1739   if (LDP_DEBUG > 2)
1740     {
1741       if (rv < 0)
1742         {
1743           int errno_val = errno;
1744           perror (func_str);
1745           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1746                         "rv %d, errno = %d", getpid (), fd, fd,
1747                         func_str, rv, errno_val);
1748           errno = errno_val;
1749         }
1750       else
1751         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1752                       getpid (), fd, fd, rv, rv);
1753     }
1754   return rv;
1755 }
1756
1757 ssize_t
1758 send (int fd, const void *buf, size_t n, int flags)
1759 {
1760   ssize_t size;
1761   const char *func_str;
1762   u32 sid = ldp_sid_from_fd (fd);
1763
1764   if ((errno = -ldp_init ()))
1765     return -1;
1766
1767   if (sid != INVALID_SESSION_ID)
1768     {
1769
1770       func_str = "vppcom_session_sendto";
1771
1772       if (LDP_DEBUG > 2)
1773         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
1774                       "buf %p, n %u, flags 0x%x",
1775                       getpid (), fd, fd, func_str, sid, sid, buf, n, flags);
1776
1777       size = vppcom_session_sendto (sid, (void *) buf, n, flags, NULL);
1778       if (size < VPPCOM_OK)
1779         {
1780           errno = -size;
1781           size = -1;
1782         }
1783     }
1784   else
1785     {
1786       func_str = "libc_send";
1787
1788       if (LDP_DEBUG > 2)
1789         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
1790                       "buf %p, n %u, flags 0x%x",
1791                       getpid (), fd, fd, func_str, buf, n, flags);
1792
1793       size = libc_send (fd, buf, n, flags);
1794     }
1795
1796   if (LDP_DEBUG > 2)
1797     {
1798       if (size < 0)
1799         {
1800           int errno_val = errno;
1801           perror (func_str);
1802           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
1803                         "rv %d, errno = %d", getpid (), fd, fd,
1804                         func_str, size, errno_val);
1805           errno = errno_val;
1806         }
1807       else
1808         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
1809                       getpid (), fd, fd, size, size);
1810     }
1811   return size;
1812 }
1813
1814 ssize_t
1815 sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
1816 {
1817   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
1818   ssize_t size = 0;
1819   const char *func_str;
1820   u32 sid = ldp_sid_from_fd (out_fd);
1821
1822   if ((errno = -ldp_init ()))
1823     return -1;
1824
1825   if (sid != INVALID_SESSION_ID)
1826     {
1827       int rv;
1828       ssize_t results = 0;
1829       size_t n_bytes_left = len;
1830       size_t bytes_to_read;
1831       int nbytes;
1832       int errno_val;
1833       u8 eagain = 0;
1834       u32 flags, flags_len = sizeof (flags);
1835
1836       func_str = "vppcom_session_attr[GET_FLAGS]";
1837       rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_FLAGS, &flags,
1838                                 &flags_len);
1839       if (PREDICT_FALSE (rv != VPPCOM_OK))
1840         {
1841           clib_warning ("LDP<%d>: ERROR: out fd %d (0x%x): %s(): "
1842                         "sid %u (0x%x), returned %d (%s)!", getpid (),
1843                         out_fd, out_fd, func_str, sid, sid, rv,
1844                         vppcom_retval_str (rv));
1845
1846           vec_reset_length (ldpw->io_buffer);
1847           errno = -rv;
1848           size = -1;
1849           goto done;
1850         }
1851
1852       if (offset)
1853         {
1854           off_t off = lseek (in_fd, *offset, SEEK_SET);
1855           if (PREDICT_FALSE (off == -1))
1856             {
1857               func_str = "lseek";
1858               errno_val = errno;
1859               clib_warning ("LDP<%d>: ERROR: out fd %d (0x%x): %s(): "
1860                             "SEEK_SET failed: in_fd %d, offset %p, "
1861                             "*offset %ld, rv %ld, errno %d", getpid (),
1862                             out_fd, out_fd, in_fd, offset, *offset, off,
1863                             errno_val);
1864               errno = errno_val;
1865               size = -1;
1866               goto done;
1867             }
1868
1869           ASSERT (off == *offset);
1870         }
1871
1872       do
1873         {
1874           func_str = "vppcom_session_attr[GET_NWRITE]";
1875           size = vppcom_session_attr (sid, VPPCOM_ATTR_GET_NWRITE, 0, 0);
1876           if (size < 0)
1877             {
1878               clib_warning
1879                 ("LDP<%d>: ERROR: fd %d (0x%x): %s(): sid %u (0x%x), "
1880                  "returned %d (%s)!", getpid (), out_fd, out_fd, func_str,
1881                  sid, sid, size, vppcom_retval_str (size));
1882               vec_reset_length (ldpw->io_buffer);
1883               errno = -size;
1884               size = -1;
1885               goto done;
1886             }
1887
1888           bytes_to_read = size;
1889           if (LDP_DEBUG > 2)
1890             clib_warning
1891               ("LDP<%d>: fd %d (0x%x): called %s(): sid %u (0x%x), "
1892                "results %ld, n_bytes_left %lu, bytes_to_read %lu", getpid (),
1893                out_fd, out_fd, func_str, sid, sid, results, n_bytes_left,
1894                bytes_to_read);
1895
1896           if (bytes_to_read == 0)
1897             {
1898               if (flags & O_NONBLOCK)
1899                 {
1900                   if (!results)
1901                     {
1902                       if (LDP_DEBUG > 2)
1903                         clib_warning ("LDP<%d>: fd %d (0x%x): sid %u (0x%x): "
1904                                       "EAGAIN",
1905                                       getpid (), out_fd, out_fd, sid, sid);
1906                       eagain = 1;
1907                     }
1908                   goto update_offset;
1909                 }
1910               else
1911                 continue;
1912             }
1913           bytes_to_read = clib_min (n_bytes_left, bytes_to_read);
1914           vec_validate (ldpw->io_buffer, bytes_to_read);
1915           nbytes = libc_read (in_fd, ldpw->io_buffer, bytes_to_read);
1916           if (nbytes < 0)
1917             {
1918               func_str = "libc_read";
1919               errno_val = errno;
1920               clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): in_fd (%d), "
1921                             "io_buffer %p, bytes_to_read %lu, rv %d, "
1922                             "errno %d", getpid (), out_fd, out_fd, func_str,
1923                             in_fd, ldpw->io_buffer, bytes_to_read, nbytes,
1924                             errno_val);
1925               errno = errno_val;
1926
1927               if (results == 0)
1928                 {
1929                   vec_reset_length (ldpw->io_buffer);
1930                   size = -1;
1931                   goto done;
1932                 }
1933               goto update_offset;
1934             }
1935           func_str = "vppcom_session_write";
1936           if (LDP_DEBUG > 2)
1937             clib_warning
1938               ("LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), "
1939                "buf %p, nbytes %u: results %d, n_bytes_left %d", getpid (),
1940                out_fd, out_fd, func_str, sid, sid, ldpw->io_buffer, nbytes,
1941                results, n_bytes_left);
1942
1943           size = vppcom_session_write (sid, ldpw->io_buffer, nbytes);
1944           if (size < 0)
1945             {
1946               if (size == VPPCOM_EAGAIN)
1947                 {
1948                   if (flags & O_NONBLOCK)
1949                     {
1950                       if (!results)
1951                         {
1952                           if (LDP_DEBUG > 2)
1953                             clib_warning
1954                               ("LDP<%d>: fd %d (0x%x): sid %u (0x%x): "
1955                                "EAGAIN", getpid (), out_fd, out_fd, sid, sid);
1956                           eagain = 1;
1957                         }
1958                       goto update_offset;
1959                     }
1960                   else
1961                     continue;
1962                 }
1963               else
1964                 {
1965                   clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s():"
1966                                 "sid %u, io_buffer %p, nbytes %u "
1967                                 "returned %d (%s)",
1968                                 getpid (), out_fd, out_fd, func_str,
1969                                 sid, ldpw->io_buffer, nbytes,
1970                                 size, vppcom_retval_str (size));
1971                 }
1972               if (results == 0)
1973                 {
1974                   vec_reset_length (ldpw->io_buffer);
1975                   errno = -size;
1976                   size = -1;
1977                   goto done;
1978                 }
1979               goto update_offset;
1980             }
1981
1982           results += nbytes;
1983           ASSERT (n_bytes_left >= nbytes);
1984           n_bytes_left = n_bytes_left - nbytes;
1985         }
1986       while (n_bytes_left > 0);
1987
1988     update_offset:
1989       vec_reset_length (ldpw->io_buffer);
1990       if (offset)
1991         {
1992           off_t off = lseek (in_fd, *offset, SEEK_SET);
1993           if (PREDICT_FALSE (off == -1))
1994             {
1995               func_str = "lseek";
1996               errno_val = errno;
1997               clib_warning ("LDP<%d>: ERROR: %s(): SEEK_SET failed: "
1998                             "in_fd %d, offset %p, *offset %ld, "
1999                             "rv %ld, errno %d", getpid (), in_fd,
2000                             offset, *offset, off, errno_val);
2001               errno = errno_val;
2002               size = -1;
2003               goto done;
2004             }
2005
2006           ASSERT (off == *offset);
2007           *offset += results + 1;
2008         }
2009       if (eagain)
2010         {
2011           errno = EAGAIN;
2012           size = -1;
2013         }
2014       else
2015         size = results;
2016     }
2017   else
2018     {
2019       func_str = "libc_send";
2020
2021       if (LDP_DEBUG > 2)
2022         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2023                       "in_fd %d, offset %p, len %u",
2024                       getpid (), out_fd, out_fd, func_str,
2025                       in_fd, offset, len);
2026
2027       size = libc_sendfile (out_fd, in_fd, offset, len);
2028     }
2029
2030 done:
2031   if (LDP_DEBUG > 2)
2032     {
2033       if (size < 0)
2034         {
2035           int errno_val = errno;
2036           perror (func_str);
2037           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2038                         "rv %d, errno = %d", getpid (), out_fd, out_fd,
2039                         func_str, size, errno_val);
2040           errno = errno_val;
2041         }
2042       else
2043         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2044                       getpid (), out_fd, out_fd, size, size);
2045     }
2046   return size;
2047 }
2048
2049 ssize_t
2050 sendfile64 (int out_fd, int in_fd, off_t * offset, size_t len)
2051 {
2052   return sendfile (out_fd, in_fd, offset, len);
2053 }
2054
2055 ssize_t
2056 recv (int fd, void *buf, size_t n, int flags)
2057 {
2058   ssize_t size;
2059   const char *func_str;
2060   u32 sid = ldp_sid_from_fd (fd);
2061
2062   if ((errno = -ldp_init ()))
2063     return -1;
2064
2065   if (sid != INVALID_SESSION_ID)
2066     {
2067       func_str = "vppcom_session_recvfrom";
2068
2069       if (LDP_DEBUG > 2)
2070         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2071                       "sid %u (0x%x), buf %p, n %u, flags 0x%x", getpid (),
2072                       fd, fd, func_str, sid, sid, buf, n, flags);
2073
2074       size = vppcom_session_recvfrom (sid, buf, n, flags, NULL);
2075       if (size < 0)
2076         {
2077           errno = -size;
2078           size = -1;
2079         }
2080     }
2081   else
2082     {
2083       func_str = "libc_recv";
2084
2085       if (LDP_DEBUG > 2)
2086         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2087                       "buf %p, n %u, flags 0x%x", getpid (),
2088                       fd, fd, func_str, buf, n, flags);
2089
2090       size = libc_recv (fd, buf, n, flags);
2091     }
2092
2093   if (LDP_DEBUG > 2)
2094     {
2095       if (size < 0)
2096         {
2097           int errno_val = errno;
2098           perror (func_str);
2099           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2100                         "rv %d, errno = %d", getpid (), fd, fd,
2101                         func_str, size, errno_val);
2102           errno = errno_val;
2103         }
2104       else
2105         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2106                       getpid (), fd, fd, size, size);
2107     }
2108   return size;
2109 }
2110
2111 ssize_t
2112 sendto (int fd, const void *buf, size_t n, int flags,
2113         __CONST_SOCKADDR_ARG addr, socklen_t addr_len)
2114 {
2115   ssize_t size;
2116   const char *func_str = __func__;
2117   u32 sid = ldp_sid_from_fd (fd);
2118
2119   if ((errno = -ldp_init ()))
2120     return -1;
2121
2122   if (sid != INVALID_SESSION_ID)
2123     {
2124       vppcom_endpt_t *ep = 0;
2125       vppcom_endpt_t _ep;
2126
2127       if (addr)
2128         {
2129           ep = &_ep;
2130           switch (addr->sa_family)
2131             {
2132             case AF_INET:
2133               ep->is_ip4 = VPPCOM_IS_IP4;
2134               ep->ip =
2135                 (uint8_t *) & ((const struct sockaddr_in *) addr)->sin_addr;
2136               ep->port =
2137                 (uint16_t) ((const struct sockaddr_in *) addr)->sin_port;
2138               break;
2139
2140             case AF_INET6:
2141               ep->is_ip4 = VPPCOM_IS_IP6;
2142               ep->ip =
2143                 (uint8_t *) & ((const struct sockaddr_in6 *) addr)->sin6_addr;
2144               ep->port =
2145                 (uint16_t) ((const struct sockaddr_in6 *) addr)->sin6_port;
2146               break;
2147
2148             default:
2149               errno = EAFNOSUPPORT;
2150               size = -1;
2151               goto done;
2152             }
2153         }
2154
2155       func_str = "vppcom_session_sendto";
2156
2157       if (LDP_DEBUG > 2)
2158         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2159                       "sid %u (0x%x), buf %p, n %u, flags 0x%x, ep %p",
2160                       getpid (), fd, fd, func_str, sid, sid, buf, n,
2161                       flags, ep);
2162
2163       size = vppcom_session_sendto (sid, (void *) buf, n, flags, ep);
2164       if (size < 0)
2165         {
2166           errno = -size;
2167           size = -1;
2168         }
2169     }
2170   else
2171     {
2172       func_str = "libc_sendto";
2173
2174       if (LDP_DEBUG > 2)
2175         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2176                       "buf %p, n %u, flags 0x%x, addr %p, addr_len %d",
2177                       getpid (), fd, fd, func_str, buf, n, flags,
2178                       addr, addr_len);
2179
2180       size = libc_sendto (fd, buf, n, flags, addr, addr_len);
2181     }
2182
2183 done:
2184   if (LDP_DEBUG > 2)
2185     {
2186       if (size < 0)
2187         {
2188           int errno_val = errno;
2189           perror (func_str);
2190           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2191                         "rv %d, errno = %d", getpid (), fd, fd,
2192                         func_str, size, errno_val);
2193           errno = errno_val;
2194         }
2195       else
2196         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2197                       getpid (), fd, fd, size, size);
2198     }
2199   return size;
2200 }
2201
2202 ssize_t
2203 recvfrom (int fd, void *__restrict buf, size_t n, int flags,
2204           __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
2205 {
2206   ssize_t size;
2207   const char *func_str;
2208   u32 sid = ldp_sid_from_fd (fd);
2209
2210   if ((errno = -ldp_init ()))
2211     return -1;
2212
2213   if (sid != INVALID_SESSION_ID)
2214     {
2215       vppcom_endpt_t ep;
2216       u8 src_addr[sizeof (struct sockaddr_in6)];
2217
2218       func_str = "vppcom_session_recvfrom";
2219
2220       if (LDP_DEBUG > 2)
2221         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2222                       "sid %u (0x%x), buf %p, n %u, flags 0x%x, ep %p",
2223                       getpid (), fd, fd, func_str, sid, sid, buf, n,
2224                       flags, &ep);
2225       if (addr)
2226         {
2227           ep.ip = src_addr;
2228           size = vppcom_session_recvfrom (sid, buf, n, flags, &ep);
2229
2230           if (size > 0)
2231             size = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2232         }
2233       else
2234         size = vppcom_session_recvfrom (sid, buf, n, flags, NULL);
2235
2236       if (size < 0)
2237         {
2238           errno = -size;
2239           size = -1;
2240         }
2241     }
2242   else
2243     {
2244       func_str = "libc_recvfrom";
2245
2246       if (LDP_DEBUG > 2)
2247         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2248                       "buf %p, n %u, flags 0x%x, addr %p, addr_len %d",
2249                       getpid (), fd, fd, func_str, buf, n, flags,
2250                       addr, addr_len);
2251
2252       size = libc_recvfrom (fd, buf, n, flags, addr, addr_len);
2253     }
2254
2255   if (LDP_DEBUG > 2)
2256     {
2257       if (size < 0)
2258         {
2259           int errno_val = errno;
2260           perror (func_str);
2261           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2262                         "rv %d, errno = %d", getpid (), fd, fd,
2263                         func_str, size, errno_val);
2264           errno = errno_val;
2265         }
2266       else
2267         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2268                       getpid (), fd, fd, size, size);
2269     }
2270   return size;
2271 }
2272
2273 ssize_t
2274 sendmsg (int fd, const struct msghdr * message, int flags)
2275 {
2276   ssize_t size;
2277   const char *func_str;
2278   u32 sid = ldp_sid_from_fd (fd);
2279
2280   if ((errno = -ldp_init ()))
2281     return -1;
2282
2283   if (sid != INVALID_SESSION_ID)
2284     {
2285       func_str = __func__;
2286
2287       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2288       errno = ENOSYS;
2289       size = -1;
2290     }
2291   else
2292     {
2293       func_str = "libc_sendmsg";
2294
2295       if (LDP_DEBUG > 2)
2296         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2297                       "message %p, flags 0x%x",
2298                       getpid (), fd, fd, func_str, message, flags);
2299
2300       size = libc_sendmsg (fd, message, flags);
2301     }
2302
2303   if (LDP_DEBUG > 2)
2304     {
2305       if (size < 0)
2306         {
2307           int errno_val = errno;
2308           perror (func_str);
2309           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2310                         "rv %d, errno = %d", getpid (), fd, fd,
2311                         func_str, size, errno_val);
2312           errno = errno_val;
2313         }
2314       else
2315         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2316                       getpid (), fd, fd, size, size);
2317     }
2318   return size;
2319 }
2320
2321 #ifdef USE_GNU
2322 int
2323 sendmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags)
2324 {
2325   ssize_t size;
2326   const char *func_str;
2327   u32 sid = ldp_sid_from_fd (fd);
2328
2329   if ((errno = -ldp_init ()))
2330     return -1;
2331
2332   if (sid != INVALID_SESSION_ID)
2333     {
2334       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2335       errno = ENOSYS;
2336       size = -1;
2337     }
2338   else
2339     {
2340       func_str = "libc_sendmmsg";
2341
2342       if (LDP_DEBUG > 2)
2343         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2344                       "vmessages %p, vlen %u, flags 0x%x",
2345                       getpid (), fd, fd, func_str, vmessages, vlen, flags);
2346
2347       size = libc_sendmmsg (fd, vmessages, vlen, flags);
2348     }
2349
2350   if (LDP_DEBUG > 2)
2351     {
2352       if (size < 0)
2353         {
2354           int errno_val = errno;
2355           perror (func_str);
2356           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2357                         "rv %d, errno = %d", getpid (), fd, fd,
2358                         func_str, size, errno_val);
2359           errno = errno_val;
2360         }
2361       else
2362         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2363                       getpid (), fd, fd, size, size);
2364     }
2365   return size;
2366 }
2367 #endif
2368
2369 ssize_t
2370 recvmsg (int fd, struct msghdr * message, int flags)
2371 {
2372   ssize_t size;
2373   const char *func_str;
2374   u32 sid = ldp_sid_from_fd (fd);
2375
2376   if ((errno = -ldp_init ()))
2377     return -1;
2378
2379   if (sid != INVALID_SESSION_ID)
2380     {
2381       func_str = __func__;
2382
2383       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2384       errno = ENOSYS;
2385       size = -1;
2386     }
2387   else
2388     {
2389       func_str = "libc_recvmsg";
2390
2391       if (LDP_DEBUG > 2)
2392         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2393                       "message %p, flags 0x%x",
2394                       getpid (), fd, fd, func_str, message, flags);
2395
2396       size = libc_recvmsg (fd, message, flags);
2397     }
2398
2399   if (LDP_DEBUG > 2)
2400     {
2401       if (size < 0)
2402         {
2403           int errno_val = errno;
2404           perror (func_str);
2405           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2406                         "rv %d, errno = %d", getpid (), fd, fd,
2407                         func_str, size, errno_val);
2408           errno = errno_val;
2409         }
2410       else
2411         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2412                       getpid (), fd, fd, size, size);
2413     }
2414   return size;
2415 }
2416
2417 #ifdef USE_GNU
2418 int
2419 recvmmsg (int fd, struct mmsghdr *vmessages,
2420           unsigned int vlen, int flags, struct timespec *tmo)
2421 {
2422   ssize_t size;
2423   const char *func_str;
2424   u32 sid = ldp_sid_from_fd (fd);
2425
2426   if ((errno = -ldp_init ()))
2427     return -1;
2428
2429   if (sid != INVALID_SESSION_ID)
2430     {
2431       clib_warning ("LDP<%d>: LDP-TBD", getpid ());
2432       errno = ENOSYS;
2433       size = -1;
2434     }
2435   else
2436     {
2437       func_str = "libc_recvmmsg";
2438
2439       if (LDP_DEBUG > 2)
2440         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2441                       "vmessages %p, vlen %u, flags 0x%x, tmo %p",
2442                       getpid (), fd, fd, func_str, vmessages, vlen,
2443                       flags, tmo);
2444
2445       size = libc_recvmmsg (fd, vmessages, vlen, flags, tmo);
2446     }
2447
2448   if (LDP_DEBUG > 2)
2449     {
2450       if (size < 0)
2451         {
2452           int errno_val = errno;
2453           perror (func_str);
2454           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2455                         "rv %d, errno = %d", getpid (), fd, fd,
2456                         func_str, size, errno_val);
2457           errno = errno_val;
2458         }
2459       else
2460         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2461                       getpid (), fd, fd, size, size);
2462     }
2463   return size;
2464 }
2465 #endif
2466
2467 int
2468 getsockopt (int fd, int level, int optname,
2469             void *__restrict optval, socklen_t * __restrict optlen)
2470 {
2471   int rv;
2472   const char *func_str = __func__;
2473   u32 sid = ldp_sid_from_fd (fd);
2474   u32 buflen = optlen ? (u32) * optlen : 0;
2475
2476   if ((errno = -ldp_init ()))
2477     return -1;
2478
2479   if (sid != INVALID_SESSION_ID)
2480     {
2481       rv = -EOPNOTSUPP;
2482
2483       switch (level)
2484         {
2485         case SOL_TCP:
2486           switch (optname)
2487             {
2488             case TCP_NODELAY:
2489               func_str = "vppcom_session_attr[SOL_TCP,GET_TCP_NODELAY]";
2490               if (LDP_DEBUG > 1)
2491                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2492                               "sid %u (0x%x)",
2493                               getpid (), fd, fd, func_str, sid, sid);
2494               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_TCP_NODELAY,
2495                                         optval, optlen);
2496               break;
2497             case TCP_MAXSEG:
2498               func_str = "vppcom_session_attr[SOL_TCP,GET_TCP_USER_MSS]";
2499               if (LDP_DEBUG > 1)
2500                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2501                               "sid %u (0x%x)",
2502                               getpid (), fd, fd, func_str, sid, sid);
2503               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_TCP_USER_MSS,
2504                                         optval, optlen);
2505               break;
2506             case TCP_KEEPIDLE:
2507               func_str = "vppcom_session_attr[SOL_TCP,GET_TCP_KEEPIDLE]";
2508               if (LDP_DEBUG > 1)
2509                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2510                               "sid %u (0x%x)",
2511                               getpid (), fd, fd, func_str, sid, sid);
2512               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_TCP_KEEPIDLE,
2513                                         optval, optlen);
2514               break;
2515             case TCP_KEEPINTVL:
2516               func_str = "vppcom_session_attr[SOL_TCP,GET_TCP_KEEPINTVL]";
2517               if (LDP_DEBUG > 1)
2518                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2519                               "sid %u (0x%x), SOL_TCP",
2520                               getpid (), fd, fd, func_str, sid, sid);
2521               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_TCP_KEEPINTVL,
2522                                         optval, optlen);
2523               break;
2524             case TCP_INFO:
2525               if (optval && optlen && (*optlen == sizeof (struct tcp_info)))
2526                 {
2527                   if (LDP_DEBUG > 1)
2528                     clib_warning ("LDP<%d>: fd %d (0x%x): sid %u (0x%x), "
2529                                   "SOL_TCP, TCP_INFO, optval %p, "
2530                                   "optlen %d: #LDP-NOP#",
2531                                   getpid (), fd, fd, sid, sid,
2532                                   optval, *optlen);
2533                   memset (optval, 0, *optlen);
2534                   rv = VPPCOM_OK;
2535                 }
2536               else
2537                 rv = -EFAULT;
2538               break;
2539             default:
2540               if (LDP_DEBUG > 1)
2541                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2542                               "sid %u (0x%x), SOL_TCP, "
2543                               "optname %d unsupported!",
2544                               getpid (), fd, fd, func_str, sid, sid, optname);
2545               break;
2546             }
2547           break;
2548         case SOL_IPV6:
2549           switch (optname)
2550             {
2551             case IPV6_V6ONLY:
2552               func_str = "vppcom_session_attr[SOL_IPV6,GET_V6ONLY]";
2553               if (LDP_DEBUG > 1)
2554                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2555                               "sid %u (0x%x)",
2556                               getpid (), fd, fd, func_str, sid, sid);
2557               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_V6ONLY,
2558                                         optval, optlen);
2559               break;
2560             default:
2561               if (LDP_DEBUG > 1)
2562                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2563                               "sid %u (0x%x), SOL_IPV6, "
2564                               "optname %d unsupported!",
2565                               getpid (), fd, fd, func_str, sid, sid, optname);
2566               break;
2567             }
2568           break;
2569         case SOL_SOCKET:
2570           switch (optname)
2571             {
2572             case SO_ACCEPTCONN:
2573               func_str = "vppcom_session_attr[SOL_SOCKET,GET_ACCEPTCONN]";
2574               if (LDP_DEBUG > 1)
2575                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2576                               "sid %u (0x%x)",
2577                               getpid (), fd, fd, func_str, sid, sid);
2578               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LISTEN,
2579                                         optval, optlen);
2580               break;
2581             case SO_KEEPALIVE:
2582               func_str = "vppcom_session_attr[SOL_SOCKET,GET_KEEPALIVE]";
2583               if (LDP_DEBUG > 1)
2584                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2585                               "sid %u (0x%x)",
2586                               getpid (), fd, fd, func_str, sid, sid);
2587               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_KEEPALIVE,
2588                                         optval, optlen);
2589               break;
2590             case SO_PROTOCOL:
2591               func_str = "vppcom_session_attr[SOL_SOCKET,GET_PROTOCOL]";
2592               if (LDP_DEBUG > 1)
2593                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2594                               "sid %u (0x%x)",
2595                               getpid (), fd, fd, func_str, sid, sid);
2596               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PROTOCOL,
2597                                         optval, optlen);
2598               *(int *) optval = *(int *) optval ? SOCK_DGRAM : SOCK_STREAM;
2599               break;
2600             case SO_SNDBUF:
2601               func_str = "vppcom_session_attr[SOL_SOCKET,GET_TX_FIFO_LEN]";
2602               if (LDP_DEBUG > 1)
2603                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2604                               "sid %u (0x%x), optlen %d",
2605                               getpid (), fd, fd, func_str, sid, sid, buflen);
2606               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_TX_FIFO_LEN,
2607                                         optval, optlen);
2608               break;
2609             case SO_RCVBUF:
2610               func_str = "vppcom_session_attr[SOL_SOCKET,GET_RX_FIFO_LEN]";
2611               if (LDP_DEBUG > 1)
2612                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2613                               "sid %u (0x%x), optlen %d",
2614                               getpid (), fd, fd, func_str, sid, sid, buflen);
2615               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_RX_FIFO_LEN,
2616                                         optval, optlen);
2617               break;
2618             case SO_REUSEADDR:
2619               func_str = "vppcom_session_attr[SOL_SOCKET,GET_REUSEADDR]";
2620               if (LDP_DEBUG > 1)
2621                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2622                               "sid %u (0x%x)",
2623                               getpid (), fd, fd, func_str, sid, sid);
2624               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_REUSEADDR,
2625                                         optval, optlen);
2626               break;
2627             case SO_BROADCAST:
2628               func_str = "vppcom_session_attr[SOL_SOCKET,GET_BROADCAST]";
2629               if (LDP_DEBUG > 1)
2630                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2631                               "sid %u (0x%x)",
2632                               getpid (), fd, fd, func_str, sid, sid);
2633               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_BROADCAST,
2634                                         optval, optlen);
2635               break;
2636             case SO_ERROR:
2637               func_str = "vppcom_session_attr[SOL_SOCKET,GET_ERROR]";
2638               if (LDP_DEBUG > 1)
2639                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2640                               "sid %u (0x%x)",
2641                               getpid (), fd, fd, func_str, sid, sid);
2642               rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_ERROR,
2643                                         optval, optlen);
2644               break;
2645             default:
2646               if (LDP_DEBUG > 1)
2647                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2648                               "sid %u (0x%x), SOL_SOCKET, "
2649                               "optname %d unsupported!",
2650                               getpid (), fd, fd, func_str, sid, sid, optname);
2651               break;
2652             }
2653           break;
2654         default:
2655           break;
2656         }
2657
2658       if (rv != VPPCOM_OK)
2659         {
2660           errno = -rv;
2661           rv = -1;
2662         }
2663     }
2664   else
2665     {
2666       func_str = "libc_getsockopt";
2667
2668       if (LDP_DEBUG > 1)
2669         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): level %d, "
2670                       "optname %d, optval %p, optlen %d",
2671                       getpid (), fd, fd, func_str, level, optname,
2672                       optval, optlen);
2673
2674       rv = libc_getsockopt (fd, level, optname, optval, optlen);
2675     }
2676
2677   if (LDP_DEBUG > 1)
2678     {
2679       if (rv < 0)
2680         {
2681           int errno_val = errno;
2682           perror (func_str);
2683           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2684                         "rv %d, errno = %d", getpid (), fd, fd,
2685                         func_str, rv, errno_val);
2686           errno = errno_val;
2687         }
2688       else
2689         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2690                       getpid (), fd, fd, rv, rv);
2691     }
2692   return rv;
2693 }
2694
2695 int
2696 setsockopt (int fd, int level, int optname,
2697             const void *optval, socklen_t optlen)
2698 {
2699   int rv;
2700   const char *func_str = __func__;
2701   u32 sid = ldp_sid_from_fd (fd);
2702
2703   if ((errno = -ldp_init ()))
2704     return -1;
2705
2706   if (sid != INVALID_SESSION_ID)
2707     {
2708       rv = -EOPNOTSUPP;
2709
2710       switch (level)
2711         {
2712         case SOL_TCP:
2713           switch (optname)
2714             {
2715             case TCP_NODELAY:
2716               func_str = "vppcom_session_attr[SOL_TCP,SET_TCP_NODELAY]";
2717               if (LDP_DEBUG > 1)
2718                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2719                               "sid %u (0x%x)",
2720                               getpid (), fd, fd, func_str, sid, sid);
2721               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_TCP_NODELAY,
2722                                         (void *) optval, &optlen);
2723               break;
2724             case TCP_MAXSEG:
2725               func_str = "vppcom_session_attr[SOL_TCP,SET_TCP_USER_MSS]";
2726               if (LDP_DEBUG > 1)
2727                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2728                               "sid %u (0x%x)",
2729                               getpid (), fd, fd, func_str, sid, sid);
2730               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_TCP_USER_MSS,
2731                                         (void *) optval, &optlen);
2732               break;
2733             case TCP_KEEPIDLE:
2734               func_str = "vppcom_session_attr[SOL_TCP,SET_TCP_KEEPIDLE]";
2735               if (LDP_DEBUG > 1)
2736                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2737                               "sid %u (0x%x)",
2738                               getpid (), fd, fd, func_str, sid, sid);
2739               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE,
2740                                         (void *) optval, &optlen);
2741               break;
2742             case TCP_KEEPINTVL:
2743               func_str = "vppcom_session_attr[SOL_TCP,SET_TCP_KEEPINTVL]";
2744               if (LDP_DEBUG > 1)
2745                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2746                               "sid %u (0x%x), SOL_TCP",
2747                               getpid (), fd, fd, func_str, sid, sid);
2748               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL,
2749                                         (void *) optval, &optlen);
2750               break;
2751             default:
2752               if (LDP_DEBUG > 1)
2753                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2754                               "sid %u (0x%x), SOL_TCP, "
2755                               "optname %d unsupported!",
2756                               getpid (), fd, fd, func_str, sid, sid, optname);
2757               break;
2758             }
2759           break;
2760         case SOL_IPV6:
2761           switch (optname)
2762             {
2763             case IPV6_V6ONLY:
2764               func_str = "vppcom_session_attr[SOL_IPV6,SET_V6ONLY]";
2765               if (LDP_DEBUG > 1)
2766                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2767                               "sid %u (0x%x)",
2768                               getpid (), fd, fd, func_str, sid, sid);
2769               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_V6ONLY,
2770                                         (void *) optval, &optlen);
2771               break;
2772             default:
2773               if (LDP_DEBUG > 1)
2774                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2775                               "sid %u (0x%x), SOL_IPV6, "
2776                               "optname %d unsupported!",
2777                               getpid (), fd, fd, func_str, sid, sid, optname);
2778               break;
2779             }
2780           break;
2781         case SOL_SOCKET:
2782           switch (optname)
2783             {
2784             case SO_KEEPALIVE:
2785               func_str = "vppcom_session_attr[SOL_SOCKET,SET_KEEPALIVE]";
2786               if (LDP_DEBUG > 1)
2787                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2788                               "sid %u (0x%x)",
2789                               getpid (), fd, fd, func_str, sid, sid);
2790               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_KEEPALIVE,
2791                                         (void *) optval, &optlen);
2792               break;
2793             case SO_REUSEADDR:
2794               func_str = "vppcom_session_attr[SOL_SOCKET,SET_REUSEADDR]";
2795               if (LDP_DEBUG > 1)
2796                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2797                               "sid %u (0x%x)",
2798                               getpid (), fd, fd, func_str, sid, sid);
2799               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_REUSEADDR,
2800                                         (void *) optval, &optlen);
2801               break;
2802             case SO_BROADCAST:
2803               func_str = "vppcom_session_attr[SOL_SOCKET,SET_BROADCAST]";
2804               if (LDP_DEBUG > 1)
2805                 clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): "
2806                               "sid %u (0x%x)",
2807                               getpid (), fd, fd, func_str, sid, sid);
2808               rv = vppcom_session_attr (sid, VPPCOM_ATTR_SET_BROADCAST,
2809                                         (void *) optval, &optlen);
2810               break;
2811             default:
2812               if (LDP_DEBUG > 1)
2813                 clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s(): "
2814                               "sid %u (0x%x), SOL_SOCKET, "
2815                               "optname %d unsupported!",
2816                               getpid (), fd, fd, func_str, sid, sid, optname);
2817               break;
2818             }
2819           break;
2820         default:
2821           break;
2822         }
2823
2824       if (rv != VPPCOM_OK)
2825         {
2826           errno = -rv;
2827           rv = -1;
2828         }
2829     }
2830   else
2831     {
2832       func_str = "libc_setsockopt";
2833
2834       if (LDP_DEBUG > 1)
2835         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): level %d, "
2836                       "optname %d, optval %p, optlen %d",
2837                       getpid (), fd, fd, func_str, level, optname,
2838                       optval, optlen);
2839
2840       rv = libc_setsockopt (fd, level, optname, optval, optlen);
2841     }
2842
2843   if (LDP_DEBUG > 1)
2844     {
2845       if (rv < 0)
2846         {
2847           int errno_val = errno;
2848           perror (func_str);
2849           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2850                         "rv %d, errno = %d", getpid (), fd, fd,
2851                         func_str, rv, errno_val);
2852           errno = errno_val;
2853         }
2854       else
2855         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2856                       getpid (), fd, fd, rv, rv);
2857     }
2858   return rv;
2859 }
2860
2861 int
2862 listen (int fd, int n)
2863 {
2864   int rv;
2865   const char *func_str;
2866   u32 sid = ldp_sid_from_fd (fd);
2867
2868   if ((errno = -ldp_init ()))
2869     return -1;
2870
2871   if (sid != INVALID_SESSION_ID)
2872     {
2873       func_str = "vppcom_session_listen";
2874
2875       LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s(): sid %u (0x%x), n %d",
2876             getpid (), fd, fd, func_str, sid, sid, n);
2877
2878       rv = vppcom_session_listen (sid, n);
2879       if (rv != VPPCOM_OK)
2880         {
2881           errno = -rv;
2882           rv = -1;
2883         }
2884     }
2885   else
2886     {
2887       func_str = "libc_listen";
2888
2889       LDBG (0, "LDP<%d>: fd %d (0x%x): calling %s(): n %d", getpid (), fd,
2890             fd, func_str, n);
2891
2892       rv = libc_listen (fd, n);
2893     }
2894
2895   if (LDP_DEBUG > 0)
2896     {
2897       if (rv < 0)
2898         {
2899           int errno_val = errno;
2900           perror (func_str);
2901           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
2902                         "rv %d, errno = %d", getpid (), fd, fd,
2903                         func_str, rv, errno_val);
2904           errno = errno_val;
2905         }
2906       else
2907         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
2908                       getpid (), fd, fd, rv, rv);
2909     }
2910   return rv;
2911 }
2912
2913 static inline int
2914 ldp_accept4 (int listen_fd, __SOCKADDR_ARG addr,
2915              socklen_t * __restrict addr_len, int flags)
2916 {
2917   int rv;
2918   const char *func_str;
2919   u32 listen_sid = ldp_sid_from_fd (listen_fd);
2920   int accept_sid;
2921
2922   if ((errno = -ldp_init ()))
2923     return -1;
2924
2925   if (listen_sid != INVALID_SESSION_ID)
2926     {
2927       vppcom_endpt_t ep;
2928       u8 src_addr[sizeof (struct sockaddr_in6)];
2929       memset (&ep, 0, sizeof (ep));
2930       ep.ip = src_addr;
2931
2932       func_str = "vppcom_session_accept";
2933
2934       if (LDP_DEBUG > 0)
2935         clib_warning ("LDP<%d>: listen fd %d (0x%x): calling %s(): "
2936                       "listen sid %u (0x%x), ep %p, flags 0x%x",
2937                       getpid (), listen_fd, listen_fd, func_str,
2938                       listen_sid, listen_sid, ep, flags);
2939
2940       accept_sid = vppcom_session_accept (listen_sid, &ep, flags);
2941       if (accept_sid < 0)
2942         {
2943           errno = -accept_sid;
2944           rv = -1;
2945         }
2946       else
2947         {
2948           rv = ldp_copy_ep_to_sockaddr (addr, addr_len, &ep);
2949           if (rv != VPPCOM_OK)
2950             {
2951               (void) vppcom_session_close ((u32) accept_sid);
2952               errno = -rv;
2953               rv = -1;
2954             }
2955           else
2956             {
2957               func_str = "ldp_fd_from_sid";
2958               if (LDP_DEBUG > 0)
2959                 clib_warning ("LDP<%d>: listen fd %d (0x%x): calling %s(): "
2960                               "accept sid %u (0x%x), ep %p, flags 0x%x",
2961                               getpid (), listen_fd, listen_fd,
2962                               func_str, accept_sid, accept_sid, ep, flags);
2963               rv = ldp_fd_alloc ((u32) accept_sid);
2964               if (rv < 0)
2965                 {
2966                   (void) vppcom_session_close ((u32) accept_sid);
2967                   errno = -rv;
2968                   rv = -1;
2969                 }
2970             }
2971         }
2972     }
2973   else
2974     {
2975       func_str = "libc_accept4";
2976
2977       if (LDP_DEBUG > 0)
2978         clib_warning ("LDP<%d>: listen fd %d (0x%x): calling %s(): "
2979                       "addr %p, addr_len %p, flags 0x%x",
2980                       getpid (), listen_fd, listen_fd, func_str,
2981                       addr, addr_len, flags);
2982
2983       rv = libc_accept4 (listen_fd, addr, addr_len, flags);
2984     }
2985
2986   if (LDP_DEBUG > 0)
2987     {
2988       if (rv < 0)
2989         {
2990           int errno_val = errno;
2991           perror (func_str);
2992           clib_warning ("LDP<%d>: ERROR: listen fd %d (0x%x): %s() failed! "
2993                         "rv %d, errno = %d", getpid (), listen_fd,
2994                         listen_fd, func_str, rv, errno_val);
2995           errno = errno_val;
2996         }
2997       else
2998         clib_warning ("LDP<%d>: listen fd %d (0x%x): returning %d (0x%x)",
2999                       getpid (), listen_fd, listen_fd, rv, rv);
3000     }
3001   return rv;
3002 }
3003
3004 int
3005 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len,
3006          int flags)
3007 {
3008   return ldp_accept4 (fd, addr, addr_len, flags);
3009 }
3010
3011 int
3012 accept (int fd, __SOCKADDR_ARG addr, socklen_t * __restrict addr_len)
3013 {
3014   return ldp_accept4 (fd, addr, addr_len, 0);
3015 }
3016
3017 int
3018 shutdown (int fd, int how)
3019 {
3020   int rv;
3021   const char *func_str;
3022   u32 sid = ldp_sid_from_fd (fd);
3023
3024   if ((errno = -ldp_init ()))
3025     return -1;
3026
3027   if (sid != INVALID_SESSION_ID)
3028     {
3029       func_str = "vppcom_session_close[TODO]";
3030       rv = close (fd);
3031     }
3032   else
3033     {
3034       func_str = "libc_shutdown";
3035
3036       if (LDP_DEBUG > 1)
3037         clib_warning ("LDP<%d>: fd %d (0x%x): calling %s(): how %d",
3038                       getpid (), fd, fd, func_str, how);
3039
3040       rv = libc_shutdown (fd, how);
3041     }
3042
3043   if (LDP_DEBUG > 1)
3044     {
3045       if (rv < 0)
3046         {
3047           int errno_val = errno;
3048           perror (func_str);
3049           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
3050                         "rv %d, errno = %d", getpid (), fd, fd,
3051                         func_str, rv, errno_val);
3052           errno = errno_val;
3053         }
3054       else
3055         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
3056                       getpid (), fd, fd, rv, rv);
3057     }
3058   return rv;
3059 }
3060
3061 int
3062 epoll_create1 (int flags)
3063 {
3064   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
3065   const char *func_str;
3066   int rv;
3067
3068   if ((errno = -ldp_init ()))
3069     return -1;
3070
3071   if (ldp->vcl_needs_real_epoll)
3072     {
3073       rv = libc_epoll_create1 (flags);
3074       ldp->vcl_needs_real_epoll = 0;
3075       ldpw->vcl_mq_epfd = rv;
3076       LDBG (0, "LDP<%d>: created vcl epfd %u", getpid (), rv);
3077       return rv;
3078     }
3079   func_str = "vppcom_epoll_create";
3080
3081   LDBG (1, "LDP<%d>: calling %s()", getpid (), func_str);
3082
3083   rv = vppcom_epoll_create ();
3084
3085   if (PREDICT_FALSE (rv < 0))
3086     {
3087       errno = -rv;
3088       rv = -1;
3089     }
3090   else
3091     rv = ldp_fd_alloc ((u32) rv);
3092
3093   if (LDP_DEBUG > 1)
3094     {
3095       if (rv < 0)
3096         {
3097           int errno_val = errno;
3098           perror (func_str);
3099           clib_warning ("LDP<%d>: ERROR: %s() failed! "
3100                         "rv %d, errno = %d",
3101                         getpid (), func_str, rv, errno_val);
3102           errno = errno_val;
3103         }
3104       else
3105         clib_warning ("LDP<%d>: returning epfd %d (0x%x)", getpid (), rv, rv);
3106     }
3107   return rv;
3108 }
3109
3110 int
3111 epoll_create (int size)
3112 {
3113   return epoll_create1 (0);
3114 }
3115
3116 int
3117 epoll_ctl (int epfd, int op, int fd, struct epoll_event *event)
3118 {
3119   u32 vep_idx = ldp_sid_from_fd (epfd), sid;
3120   const char *func_str;
3121   int rv;
3122
3123   if ((errno = -ldp_init ()))
3124     return -1;
3125
3126   if (PREDICT_FALSE (vep_idx == INVALID_SESSION_ID))
3127     {
3128       /* The LDP epoll_create1 always creates VCL epfd's.
3129        * The app should never have a kernel base epoll fd unless it
3130        * was acquired outside of the LD_PRELOAD process context.
3131        * In any case, if we get one, punt it to libc_epoll_ctl.
3132        */
3133       func_str = "libc_epoll_ctl";
3134
3135       LDBG (1, "LDP<%d>: epfd %d (0x%x): calling %s(): op %d, fd %d (0x%x),"
3136             " event %p", getpid (), epfd, epfd, func_str, op, fd, fd, event);
3137
3138       rv = libc_epoll_ctl (epfd, op, fd, event);
3139       goto done;
3140     }
3141
3142   sid = ldp_sid_from_fd (fd);
3143
3144   LDBG (0, "LDP<%d>: epfd %d (0x%x), vep_idx %d (0x%x), sid %d (0x%x)",
3145         getpid (), epfd, epfd, vep_idx, vep_idx, sid, sid);
3146
3147   if (sid != INVALID_SESSION_ID)
3148     {
3149       func_str = "vppcom_epoll_ctl";
3150
3151       LDBG (1, "LDP<%d>: epfd %d (0x%x): calling %s(): vep_idx %d (0x%x),"
3152             " op %d, sid %u (0x%x), event %p", getpid (), epfd, epfd,
3153             func_str, vep_idx, vep_idx, sid, sid, event);
3154
3155       rv = vppcom_epoll_ctl (vep_idx, op, sid, event);
3156       if (rv != VPPCOM_OK)
3157         {
3158           errno = -rv;
3159           rv = -1;
3160         }
3161     }
3162   else
3163     {
3164       int libc_epfd;
3165       u32 size = sizeof (epfd);
3166
3167       func_str = "vppcom_session_attr[GET_LIBC_EPFD]";
3168       libc_epfd = vppcom_session_attr (vep_idx, VPPCOM_ATTR_GET_LIBC_EPFD, 0,
3169                                        0);
3170       LDBG (1, "LDP<%d>: epfd %d (0x%x), vep_idx %d (0x%x): %s() "
3171             "returned libc_epfd %d (0x%x)", getpid (), epfd, epfd,
3172             vep_idx, vep_idx, func_str, libc_epfd, libc_epfd);
3173
3174       if (!libc_epfd)
3175         {
3176           func_str = "libc_epoll_create1";
3177
3178           LDBG (1, "LDP<%d>: epfd %d (0x%x), vep_idx %d (0x%x): "
3179                 "calling %s(): EPOLL_CLOEXEC", getpid (), epfd, epfd,
3180                 vep_idx, vep_idx, func_str);
3181
3182           libc_epfd = libc_epoll_create1 (EPOLL_CLOEXEC);
3183           if (libc_epfd < 0)
3184             {
3185               rv = libc_epfd;
3186               goto done;
3187             }
3188
3189           func_str = "vppcom_session_attr[SET_LIBC_EPFD]";
3190           LDBG (1, "LDP<%d>: epfd %d (0x%x): calling %s(): vep_idx %d (0x%x),"
3191                 " VPPCOM_ATTR_SET_LIBC_EPFD, libc_epfd %d (0x%x), size %d",
3192                 getpid (), epfd, epfd, func_str, vep_idx, vep_idx, libc_epfd,
3193                 libc_epfd, size);
3194
3195           rv = vppcom_session_attr (vep_idx, VPPCOM_ATTR_SET_LIBC_EPFD,
3196                                     &libc_epfd, &size);
3197           if (rv < 0)
3198             {
3199               errno = -rv;
3200               rv = -1;
3201               goto done;
3202             }
3203         }
3204       else if (PREDICT_FALSE (libc_epfd < 0))
3205         {
3206           errno = -epfd;
3207           rv = -1;
3208           goto done;
3209         }
3210
3211       func_str = "libc_epoll_ctl";
3212
3213       LDBG (1, "LDP<%d>: epfd %d (0x%x): calling %s(): libc_epfd %d (0x%x), "
3214             "op %d, fd %d (0x%x), event %p", getpid (), epfd, epfd, func_str,
3215             libc_epfd, libc_epfd, op, fd, fd, event);
3216
3217       rv = libc_epoll_ctl (libc_epfd, op, fd, event);
3218     }
3219
3220 done:
3221   if (LDP_DEBUG > 1)
3222     {
3223       if (rv < 0)
3224         {
3225           int errno_val = errno;
3226           perror (func_str);
3227           clib_warning ("LDP<%d>: ERROR: fd %d (0x%x): %s() failed! "
3228                         "rv %d, errno = %d", getpid (), fd, fd,
3229                         func_str, rv, errno_val);
3230           errno = errno_val;
3231         }
3232       else
3233         clib_warning ("LDP<%d>: fd %d (0x%x): returning %d (0x%x)",
3234                       getpid (), fd, fd, rv, rv);
3235     }
3236   return rv;
3237 }
3238
3239 static inline int
3240 ldp_epoll_pwait (int epfd, struct epoll_event *events, int maxevents,
3241                  int timeout, const sigset_t * sigmask)
3242 {
3243   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
3244   double time_to_wait = (double) 0, time_out, now = 0;
3245   u32 vep_idx = ldp_sid_from_fd (epfd);
3246   int libc_epfd, rv = 0;
3247   const char *func_str;
3248
3249   if ((errno = -ldp_init ()))
3250     return -1;
3251
3252   if (PREDICT_FALSE (!events || (timeout < -1)))
3253     {
3254       errno = EFAULT;
3255       return -1;
3256     }
3257
3258   if (epfd == ldpw->vcl_mq_epfd)
3259     return libc_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
3260
3261   if (PREDICT_FALSE (vep_idx == INVALID_SESSION_ID))
3262     {
3263       clib_warning ("LDP<%d>: ERROR: epfd %d (0x%x): bad vep_idx %d (0x%x)!",
3264                     getpid (), epfd, epfd, vep_idx, vep_idx);
3265       errno = EBADFD;
3266       return -1;
3267     }
3268
3269   time_to_wait = ((timeout >= 0) ? (double) timeout : 0);
3270   time_out = clib_time_now (&ldpw->clib_time) + time_to_wait;
3271
3272   func_str = "vppcom_session_attr[GET_LIBC_EPFD]";
3273   libc_epfd = vppcom_session_attr (vep_idx, VPPCOM_ATTR_GET_LIBC_EPFD, 0, 0);
3274   if (PREDICT_FALSE (libc_epfd < 0))
3275     {
3276       errno = -libc_epfd;
3277       rv = -1;
3278       goto done;
3279     }
3280
3281   LDBG (2, "LDP<%d>: epfd %d (0x%x): vep_idx %d (0x%x), libc_epfd %d (0x%x), "
3282         "events %p, maxevents %d, timeout %d, sigmask %p: time_to_wait %.02f",
3283         getpid (), epfd, epfd, vep_idx, vep_idx, libc_epfd, libc_epfd, events,
3284         maxevents, timeout, sigmask, time_to_wait, time_out);
3285   do
3286     {
3287       if (!ldpw->epoll_wait_vcl)
3288         {
3289           func_str = "vppcom_epoll_wait";
3290
3291           LDBG (3, "LDP<%d>: epfd %d (0x%x): calling %s(): vep_idx %d (0x%x),"
3292                 " events %p, maxevents %d", getpid (), epfd, epfd, func_str,
3293                 vep_idx, vep_idx, events, maxevents);
3294
3295           rv = vppcom_epoll_wait (vep_idx, events, maxevents, 0);
3296           if (rv > 0)
3297             {
3298               ldpw->epoll_wait_vcl = 1;
3299               goto done;
3300             }
3301           else if (rv < 0)
3302             {
3303               errno = -rv;
3304               rv = -1;
3305               goto done;
3306             }
3307         }
3308       else
3309         ldpw->epoll_wait_vcl = 0;
3310
3311       if (libc_epfd > 0)
3312         {
3313           func_str = "libc_epoll_pwait";
3314
3315           LDBG (3, "LDP<%d>: epfd %d (0x%x): calling %s(): libc_epfd %d "
3316                 "(0x%x), events %p, maxevents %d, sigmask %p", getpid (),
3317                 epfd, epfd, func_str, libc_epfd, libc_epfd, events,
3318                 maxevents, sigmask);
3319
3320           rv = libc_epoll_pwait (libc_epfd, events, maxevents, 1, sigmask);
3321           if (rv != 0)
3322             goto done;
3323         }
3324
3325       if (timeout != -1)
3326         now = clib_time_now (&ldpw->clib_time);
3327     }
3328   while (now < time_out);
3329
3330 done:
3331   if (LDP_DEBUG > 3)
3332     {
3333       if (libc_epfd > 0)
3334         epfd = libc_epfd;
3335       if (rv < 0)
3336         {
3337           int errno_val = errno;
3338           perror (func_str);
3339           clib_warning ("LDP<%d>: ERROR: epfd %d (0x%x): %s() failed! "
3340                         "rv %d, errno = %d", getpid (), epfd, epfd,
3341                         func_str, rv, errno_val);
3342           errno = errno_val;
3343         }
3344       else
3345         clib_warning ("LDP<%d>: epfd %d (0x%x): returning %d (0x%x)",
3346                       getpid (), epfd, epfd, rv, rv);
3347     }
3348   return rv;
3349 }
3350
3351 int
3352 epoll_pwait (int epfd, struct epoll_event *events,
3353              int maxevents, int timeout, const sigset_t * sigmask)
3354 {
3355   return ldp_epoll_pwait (epfd, events, maxevents, timeout, sigmask);
3356 }
3357
3358 int
3359 epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout)
3360 {
3361   return ldp_epoll_pwait (epfd, events, maxevents, timeout, NULL);
3362 }
3363
3364 int
3365 poll (struct pollfd *fds, nfds_t nfds, int timeout)
3366 {
3367   ldp_worker_ctx_t *ldpw = ldp_worker_get_current ();
3368   const char *func_str = __func__;
3369   int rv, i, n_revents = 0;
3370   u32 sid;
3371   vcl_poll_t *vp;
3372   double wait_for_time;
3373
3374   LDBG (3, "LDP<%d>: fds %p, nfds %d, timeout %d", getpid (), fds, nfds,
3375         timeout);
3376
3377   if (timeout >= 0)
3378     wait_for_time = (f64) timeout / 1000;
3379   else
3380     wait_for_time = -1;
3381
3382   for (i = 0; i < nfds; i++)
3383     {
3384       if (fds[i].fd < 0)
3385         continue;
3386
3387       LDBG (3, "LDP<%d>: fds[%d] fd %d (0x%0x) events = 0x%x revents = 0x%x",
3388             getpid (), i, fds[i].fd, fds[i].fd, fds[i].events,
3389             fds[i].revents);
3390
3391       sid = ldp_sid_from_fd (fds[i].fd);
3392       if (sid != INVALID_SESSION_ID)
3393         {
3394           fds[i].fd = -fds[i].fd;
3395           vec_add2 (ldpw->vcl_poll, vp, 1);
3396           vp->fds_ndx = i;
3397           vp->sid = sid;
3398           vp->events = fds[i].events;
3399 #ifdef __USE_XOPEN2K
3400           if (fds[i].events & POLLRDNORM)
3401             vp->events |= POLLIN;
3402           if (fds[i].events & POLLWRNORM)
3403             vp->events |= POLLOUT;
3404 #endif
3405           vp->revents = fds[i].revents;
3406         }
3407       else
3408         {
3409           vec_add1 (ldpw->libc_poll, fds[i]);
3410           vec_add1 (ldpw->libc_poll_idxs, i);
3411         }
3412     }
3413
3414   do
3415     {
3416       if (vec_len (ldpw->vcl_poll))
3417         {
3418           func_str = "vppcom_poll";
3419
3420           LDBG (3, "LDP<%d>: calling %s(): vcl_poll %p, n_sids %u (0x%x): "
3421                 "n_libc_fds %u", getpid (), func_str, ldpw->vcl_poll,
3422                 vec_len (ldpw->vcl_poll), vec_len (ldpw->vcl_poll),
3423                 vec_len (ldpw->libc_poll));
3424
3425           rv = vppcom_poll (ldpw->vcl_poll, vec_len (ldpw->vcl_poll), 0);
3426           if (rv < 0)
3427             {
3428               errno = -rv;
3429               rv = -1;
3430               goto done;
3431             }
3432           else
3433             n_revents += rv;
3434         }
3435
3436       if (vec_len (ldpw->libc_poll))
3437         {
3438           func_str = "libc_poll";
3439
3440           LDBG (3, "LDP<%d>: calling %s(): fds %p, nfds %u: n_sids %u",
3441                 getpid (), fds, nfds, vec_len (ldpw->vcl_poll));
3442
3443           rv = libc_poll (ldpw->libc_poll, vec_len (ldpw->libc_poll), 0);
3444           if (rv < 0)
3445             goto done;
3446           else
3447             n_revents += rv;
3448         }
3449
3450       if (n_revents)
3451         {
3452           rv = n_revents;
3453           goto done;
3454         }
3455     }
3456   while ((wait_for_time == -1) ||
3457          (clib_time_now (&ldpw->clib_time) < wait_for_time));
3458   rv = 0;
3459
3460 done:
3461   vec_foreach (vp, ldpw->vcl_poll)
3462   {
3463     fds[vp->fds_ndx].fd = -fds[vp->fds_ndx].fd;
3464     fds[vp->fds_ndx].revents = vp->revents;
3465 #ifdef __USE_XOPEN2K
3466     if ((fds[vp->fds_ndx].revents & POLLIN) &&
3467         (fds[vp->fds_ndx].events & POLLRDNORM))
3468       fds[vp->fds_ndx].revents |= POLLRDNORM;
3469     if ((fds[vp->fds_ndx].revents & POLLOUT) &&
3470         (fds[vp->fds_ndx].events & POLLWRNORM))
3471       fds[vp->fds_ndx].revents |= POLLWRNORM;
3472 #endif
3473   }
3474   vec_reset_length (ldpw->vcl_poll);
3475
3476   for (i = 0; i < vec_len (ldpw->libc_poll); i++)
3477     {
3478       fds[ldpw->libc_poll_idxs[i]].revents = ldpw->libc_poll[i].revents;
3479     }
3480   vec_reset_length (ldpw->libc_poll_idxs);
3481   vec_reset_length (ldpw->libc_poll);
3482
3483   if (LDP_DEBUG > 3)
3484     {
3485       if (rv < 0)
3486         {
3487           int errno_val = errno;
3488           perror (func_str);
3489           clib_warning ("LDP<%d>: ERROR: %s() failed! "
3490                         "rv %d, errno = %d", getpid (),
3491                         func_str, rv, errno_val);
3492           errno = errno_val;
3493         }
3494       else
3495         {
3496           clib_warning ("LDP<%d>: returning %d (0x%x): n_sids %u, "
3497                         "n_libc_fds %d", getpid (), rv, rv,
3498                         vec_len (ldpw->vcl_poll), vec_len (ldpw->libc_poll));
3499
3500           for (i = 0; i < nfds; i++)
3501             {
3502               if (fds[i].fd >= 0)
3503                 {
3504                   if (LDP_DEBUG > 3)
3505                     clib_warning ("LDP<%d>: fds[%d].fd %d (0x%0x), "
3506                                   ".events = 0x%x, .revents = 0x%x",
3507                                   getpid (), i, fds[i].fd, fds[i].fd,
3508                                   fds[i].events, fds[i].revents);
3509                 }
3510             }
3511         }
3512     }
3513
3514   return rv;
3515 }
3516
3517 #ifdef USE_GNU
3518 int
3519 ppoll (struct pollfd *fds, nfds_t nfds,
3520        const struct timespec *timeout, const sigset_t * sigmask)
3521 {
3522   if ((errno = -ldp_init ()))
3523     return -1;
3524
3525   clib_warning ("LDP<%d>: LDP-TBD", getpid ());
3526   errno = ENOSYS;
3527
3528
3529   return -1;
3530 }
3531 #endif
3532
3533 void CONSTRUCTOR_ATTRIBUTE ldp_constructor (void);
3534
3535 void DESTRUCTOR_ATTRIBUTE ldp_destructor (void);
3536
3537 /*
3538  * This function is called when the library is loaded
3539  */
3540 void
3541 ldp_constructor (void)
3542 {
3543   swrap_constructor ();
3544   if (ldp_init () != 0)
3545     fprintf (stderr, "\nLDP<%d>: ERROR: ldp_constructor: failed!\n",
3546              getpid ());
3547   else if (LDP_DEBUG > 0)
3548     clib_warning ("LDP<%d>: LDP constructor: done!\n", getpid ());
3549 }
3550
3551 /*
3552  * This function is called when the library is unloaded
3553  */
3554 void
3555 ldp_destructor (void)
3556 {
3557   swrap_destructor ();
3558   if (ldp->init)
3559     {
3560       vppcom_app_destroy ();
3561       ldp->init = 0;
3562     }
3563
3564   /* Don't use clib_warning() here because that calls writev()
3565    * which will call ldp_init().
3566    */
3567   if (LDP_DEBUG > 0)
3568     printf ("%s:%d: LDP<%d>: LDP destructor: done!\n",
3569             __func__, __LINE__, getpid ());
3570 }
3571
3572
3573 /*
3574  * fd.io coding-style-patch-verification: ON
3575  *
3576  * Local Variables:
3577  * eval: (c-set-style "gnu")
3578  * End:
3579  */