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