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