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