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