7b5f6c84f83c455c0eb60f58e00f4d3dc91f9086
[vpp.git] / extras / vcl-ldpreload / src / libvcl-ldpreload / vcom_socket.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 <sys/uio.h>
18 #include <limits.h>
19 #define __need_IOV_MAX
20 #include <bits/stdio_lim.h>
21 #include <netinet/tcp.h>
22
23 #include <vppinfra/types.h>
24 #include <vppinfra/hash.h>
25 #include <vppinfra/pool.h>
26
27 #include <libvcl-ldpreload/vcom_socket.h>
28 #include <libvcl-ldpreload/vcom_socket_wrapper.h>
29 #include <libvcl-ldpreload/vcom.h>
30
31 #include <uri/vppcom.h>
32
33
34 /*
35  * VCOM_SOCKET Private definitions and functions.
36  */
37
38 typedef struct vcom_socket_main_t_
39 {
40   u8 init;
41
42   /* vcom_socket pool */
43   vcom_socket_t *vsockets;
44
45   /* Hash table for socketidx to fd mapping */
46   uword *sockidx_by_fd;
47
48   /* vcom_epoll pool */
49   vcom_epoll_t *vepolls;
50
51   /* Hash table for epollidx to epfd mapping */
52   uword *epollidx_by_epfd;
53
54
55   /* common epitem poll for all epfd */
56   /* TBD: epitem poll per epfd */
57   /* vcom_epitem pool */
58   vcom_epitem_t *vepitems;
59
60   /* Hash table for epitemidx to epfdfd mapping */
61   uword *epitemidx_by_epfdfd;
62
63   /* Hash table - key:epfd, value:vec of epitemidx */
64   uword *epitemidxs_by_epfd;
65   /* Hash table - key:fd, value:vec of epitemidx */
66   uword *epitemidxs_by_fd;
67
68 } vcom_socket_main_t;
69
70 vcom_socket_main_t vcom_socket_main;
71
72
73 static int
74 vcom_socket_open_socket (int domain, int type, int protocol)
75 {
76   int rv = -1;
77
78   /* handle domains implemented by vpp */
79   switch (domain)
80     {
81     case AF_INET:
82     case AF_INET6:
83       /* get socket type and
84        * handle the socket types supported by vpp */
85       switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
86         {
87         case SOCK_STREAM:
88         case SOCK_DGRAM:
89           /* the type argument serves a second purpose,
90            * in addition to specifying a socket type,
91            * it may include the bitwise OR of any of
92            * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
93            * the behavior of socket. */
94           rv = libc_socket (domain, type, protocol);
95           if (rv == -1)
96             rv = -errno;
97           break;
98
99         default:
100           break;
101         }
102
103       break;
104
105     default:
106       break;
107     }
108
109   return rv;
110 }
111
112 static int
113 vcom_socket_open_epoll (int flags)
114 {
115   int rv = -1;
116
117   if (flags < 0)
118     {
119       return -EINVAL;
120     }
121   if (flags && (flags & ~EPOLL_CLOEXEC))
122     {
123       return -EINVAL;
124     }
125
126   /* flags can be either zero or EPOLL_CLOEXEC */
127   rv = libc_epoll_create1 (flags);
128   if (rv == -1)
129     rv = -errno;
130
131   return rv;
132 }
133
134 static int
135 vcom_socket_close_socket (int fd)
136 {
137   int rv;
138
139   rv = libc_close (fd);
140   if (rv == -1)
141     rv = -errno;
142
143   return rv;
144 }
145
146 static int
147 vcom_socket_close_epoll (int epfd)
148 {
149   int rv;
150
151   rv = libc_close (epfd);
152   if (rv == -1)
153     rv = -errno;
154
155   return rv;
156 }
157
158 /*
159  * Public API functions
160  */
161
162
163 int
164 vcom_socket_is_vcom_fd (int fd)
165 {
166   vcom_socket_main_t *vsm = &vcom_socket_main;
167   uword *p;
168   vcom_socket_t *vsock;
169
170   p = hash_get (vsm->sockidx_by_fd, fd);
171
172   if (p)
173     {
174       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
175       if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
176         return 1;
177     }
178   return 0;
179 }
180
181 int
182 vcom_socket_is_vcom_epfd (int epfd)
183 {
184   vcom_socket_main_t *vsm = &vcom_socket_main;
185   uword *p;
186   vcom_epoll_t *vepoll;
187
188   p = hash_get (vsm->epollidx_by_epfd, epfd);
189
190   if (p)
191     {
192       vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
193       if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
194         return 1;
195     }
196   return 0;
197 }
198
199 static inline int
200 vcom_socket_get_sid (int fd)
201 {
202   vcom_socket_main_t *vsm = &vcom_socket_main;
203   uword *p;
204   vcom_socket_t *vsock;
205
206   p = hash_get (vsm->sockidx_by_fd, fd);
207
208   if (p)
209     {
210       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
211       if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
212         return vsock->sid;
213     }
214   return INVALID_SESSION_ID;
215 }
216
217 static inline int
218 vcom_socket_get_vep_idx (int epfd)
219 {
220   vcom_socket_main_t *vsm = &vcom_socket_main;
221   uword *p;
222   vcom_epoll_t *vepoll;
223
224   p = hash_get (vsm->epollidx_by_epfd, epfd);
225
226   if (p)
227     {
228       vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
229       if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
230         return vepoll->vep_idx;
231     }
232   return INVALID_VEP_IDX;
233 }
234
235 static inline int
236 vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t ** vsockp)
237 {
238   vcom_socket_main_t *vsm = &vcom_socket_main;
239   uword *p;
240   vcom_socket_t *vsock;
241
242   p = hash_get (vsm->sockidx_by_fd, fd);
243
244   if (p)
245     {
246       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
247       if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
248         {
249           *vsockp = vsock;
250           return vsock->sid;
251         }
252     }
253   return INVALID_SESSION_ID;
254 }
255
256 static inline int
257 vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t ** vepollp)
258 {
259   vcom_socket_main_t *vsm = &vcom_socket_main;
260   uword *p;
261   vcom_epoll_t *vepoll;
262
263   p = hash_get (vsm->epollidx_by_epfd, epfd);
264
265   if (p)
266     {
267       vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
268       if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
269         {
270           *vepollp = vepoll;
271           return vepoll->vep_idx;
272         }
273     }
274   return INVALID_VEP_IDX;
275 }
276
277
278 static int
279 vcom_socket_close_vepoll (int epfd)
280 {
281   int rv = -1;
282   vcom_socket_main_t *vsm = &vcom_socket_main;
283   uword *p;
284   vcom_epoll_t *vepoll;
285
286   p = hash_get (vsm->epollidx_by_epfd, epfd);
287   if (!p)
288     return -EBADF;
289
290   vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
291   if (!vepoll)
292     return -EBADF;
293
294   if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
295     return -EINVAL;
296
297   if (vepoll->count)
298     {
299       if (!vepoll->close)
300         {
301           vepoll->close = 1;
302           return 0;
303         }
304       else
305         {
306           return -EBADF;
307         }
308     }
309
310   /* count is zero */
311   rv = vppcom_session_close (vepoll->vep_idx);
312   rv = vcom_socket_close_epoll (vepoll->epfd);
313
314   vepoll_init (vepoll);
315   hash_unset (vsm->epollidx_by_epfd, epfd);
316   pool_put (vsm->vepolls, vepoll);
317
318   return rv;
319 }
320
321 static int
322 vcom_socket_close_vsock (int fd)
323 {
324   int rv = -1;
325   vcom_socket_main_t *vsm = &vcom_socket_main;
326   uword *p;
327   vcom_socket_t *vsock;
328
329   vcom_epitem_t *vepitem;
330
331   i32 *vepitemidxs = 0;
332   i32 *vepitemidxs_var = 0;
333
334   p = hash_get (vsm->sockidx_by_fd, fd);
335   if (!p)
336     return -EBADF;
337
338   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
339   if (!vsock)
340     return -ENOTSOCK;
341
342   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
343     return -EINVAL;
344
345   rv = vppcom_session_close (vsock->sid);
346   rv = vcom_socket_close_socket (vsock->fd);
347
348   vsocket_init (vsock);
349   hash_unset (vsm->sockidx_by_fd, fd);
350   pool_put (vsm->vsockets, vsock);
351
352   /*
353    * NOTE:
354    * Before calling close(), user should remove
355    * this fd from the epoll-set of all epoll instances,
356    * otherwise resource(epitems) leaks ensues.
357    */
358
359   /*
360    * 00. close all epoll instances that are marked as "close"
361    *     of which this fd is the "last" remaining member.
362    * 01. epitems associated with this fd are intentionally
363    *     not removed, see NOTE: above.
364    * */
365
366   /* does this fd participate in epoll */
367   p = hash_get (vsm->epitemidxs_by_fd, fd);
368   if (p)
369     {
370       vepitemidxs = *(i32 **) p;
371       vec_foreach (vepitemidxs_var, vepitemidxs)
372       {
373         vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
374         if (vepitem && vepitem->fd == fd &&
375             vepitem->type == FD_TYPE_VCOM_SOCKET)
376           {
377             i32 vep_idx;
378             vcom_epoll_t *vepoll;
379             if ((vep_idx =
380                  vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd,
381                                                      &vepoll)) !=
382                 INVALID_VEP_IDX)
383               {
384                 if (vepoll->close)
385                   {
386                     if (vepoll->count == 1)
387                       {
388                         /*
389                          * force count to zero and
390                          * close this epoll instance
391                          * */
392                         vepoll->count = 0;
393                         vcom_socket_close_vepoll (vepoll->epfd);
394                       }
395                     else
396                       {
397                         vepoll->count -= 1;
398                       }
399                   }
400               }
401           }
402
403       }
404     }
405
406   return rv;
407 }
408
409 int
410 vcom_socket_close (int __fd)
411 {
412   int rv;
413
414   if (vcom_socket_is_vcom_fd (__fd))
415     {
416       rv = vcom_socket_close_vsock (__fd);
417     }
418   else if (vcom_socket_is_vcom_epfd (__fd))
419     {
420       rv = vcom_socket_close_vepoll (__fd);
421     }
422   else
423     {
424       rv = -EBADF;
425     }
426
427   return rv;
428 }
429
430 ssize_t
431 vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
432 {
433   int rv = -1;
434   vcom_socket_main_t *vsm = &vcom_socket_main;
435   uword *p;
436   vcom_socket_t *vsock;
437
438   p = hash_get (vsm->sockidx_by_fd, __fd);
439   if (!p)
440     return -EBADF;
441
442   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
443   if (!vsock)
444     return -ENOTSOCK;
445
446   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
447     return -EINVAL;
448
449   if (!__buf || __nbytes < 0)
450     {
451       return -EINVAL;
452     }
453
454   rv = vcom_fcntl (__fd, F_GETFL, 0);
455   if (rv < 0)
456     {
457       return rv;
458
459     }
460
461   /* is blocking */
462   if (!(rv & O_NONBLOCK))
463     {
464       do
465         {
466           rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
467         }
468       while (rv == -EAGAIN || rv == -EWOULDBLOCK);
469       return rv;
470     }
471   /* The file descriptor refers to a socket and has been
472    * marked nonblocking(O_NONBLOCK) and the read would
473    * block.
474    * */
475   /* is non blocking */
476   rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
477   return rv;
478 }
479
480 ssize_t
481 vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
482 {
483   int rv;
484   vcom_socket_main_t *vsm = &vcom_socket_main;
485   uword *p;
486   vcom_socket_t *vsock;
487   ssize_t total = 0, len = 0;
488
489   p = hash_get (vsm->sockidx_by_fd, __fd);
490   if (!p)
491     return -EBADF;
492
493   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
494   if (!vsock)
495     return -ENOTSOCK;
496
497   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
498     return -EINVAL;
499
500   if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
501     return -EINVAL;
502
503   /* Sanity check */
504   for (int i = 0; i < __iovcnt; ++i)
505     {
506       if (SSIZE_MAX - len < __iov[i].iov_len)
507         return -EINVAL;
508       len += __iov[i].iov_len;
509     }
510
511   rv = vcom_fcntl (__fd, F_GETFL, 0);
512   if (rv < 0)
513     {
514       return rv;
515     }
516
517   /* is blocking */
518   if (!(rv & O_NONBLOCK))
519     {
520       do
521         {
522           for (int i = 0; i < __iovcnt; ++i)
523             {
524               rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
525                                         __iov[i].iov_len);
526               if (rv < 0)
527                 break;
528               else
529                 {
530                   total += rv;
531                   if (rv < __iov[i].iov_len)
532                     /* Read less than buffer provided, no point to continue */
533                     break;
534                 }
535             }
536         }
537       while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
538       return total;
539     }
540
541   /* is non blocking */
542   for (int i = 0; i < __iovcnt; ++i)
543     {
544       rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
545                                 __iov[i].iov_len);
546       if (rv < 0)
547         {
548           if (total > 0)
549             break;
550           else
551             {
552               errno = rv;
553               return rv;
554             }
555         }
556       else
557         {
558           total += rv;
559           if (rv < __iov[i].iov_len)
560             /* Read less than buffer provided, no point to continue */
561             break;
562         }
563     }
564   return total;
565 }
566
567 ssize_t
568 vcom_socket_write (int __fd, const void *__buf, size_t __n)
569 {
570   int rv = -1;
571   vcom_socket_main_t *vsm = &vcom_socket_main;
572   uword *p;
573   vcom_socket_t *vsock;
574
575   p = hash_get (vsm->sockidx_by_fd, __fd);
576   if (!p)
577     return -EBADF;
578
579   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
580   if (!vsock)
581     return -ENOTSOCK;
582
583   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
584     return -EINVAL;
585
586   if (!__buf || __n < 0)
587     {
588       return -EINVAL;
589     }
590
591   rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
592   return rv;
593 }
594
595 ssize_t
596 vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
597 {
598   int rv = -1;
599   ssize_t total = 0;
600   vcom_socket_main_t *vsm = &vcom_socket_main;
601   uword *p;
602   vcom_socket_t *vsock;
603
604   p = hash_get (vsm->sockidx_by_fd, __fd);
605   if (!p)
606     return -EBADF;
607
608   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
609   if (!vsock)
610     return -ENOTSOCK;
611
612   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
613     return -EINVAL;
614
615   if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
616     return -EINVAL;
617
618   for (int i = 0; i < __iovcnt; ++i)
619     {
620       rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
621                                  __iov[i].iov_len);
622       if (rv < 0)
623         {
624           if (total > 0)
625             break;
626           else
627             return rv;
628         }
629       else
630         total += rv;
631     }
632   return total;
633 }
634
635 /*
636  * RETURN:  0 - invalid cmd
637  *          1 - cmd not handled by vcom and vppcom
638  *          2 - cmd handled by vcom socket resource
639  *          3 - cmd handled by vppcom
640  * */
641 /* TBD: incomplete list of cmd */
642 static int
643 vcom_socket_check_fcntl_cmd (int __cmd)
644 {
645   switch (__cmd)
646     {
647       /*cmd not handled by vcom and vppcom */
648       /* Fallthrough */
649     case F_DUPFD:
650     case F_DUPFD_CLOEXEC:
651       return 1;
652
653       /* cmd handled by vcom socket resource */
654       /* Fallthrough */
655     case F_GETFD:
656     case F_SETFD:
657     case F_GETLK:
658     case F_SETLK:
659     case F_SETLKW:
660     case F_GETOWN:
661     case F_SETOWN:
662       return 2;
663
664       /* cmd handled by vcom and vppcom */
665     case F_SETFL:
666     case F_GETFL:
667       return 3;
668
669       /* cmd not handled by vcom and vppcom */
670     default:
671       return 1;
672     }
673   return 0;
674 }
675
676 static inline int
677 vcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
678 {
679   int flags = va_arg (__ap, int);
680   int rv = -EOPNOTSUPP;
681   uint32_t size;
682
683   size = sizeof (flags);
684   if (__cmd == F_SETFL)
685     {
686       rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
687     }
688   else if (__cmd == F_GETFL)
689     {
690       rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
691       if (rv == VPPCOM_OK)
692         rv = flags;
693     }
694
695   return rv;
696 }
697
698 int
699 vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
700 {
701   int rv = -EBADF;
702   vcom_socket_main_t *vsm = &vcom_socket_main;
703   uword *p;
704   vcom_socket_t *vsock;
705
706   p = hash_get (vsm->sockidx_by_fd, __fd);
707   if (!p)
708     return -EBADF;
709
710   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
711   if (!vsock)
712     return -ENOTSOCK;
713
714   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
715     return -EINVAL;
716
717   switch (vcom_socket_check_fcntl_cmd (__cmd))
718     {
719       /* invalid cmd */
720     case 0:
721       rv = -EBADF;
722       break;
723       /*cmd not handled by vcom and vppcom */
724     case 1:
725       rv = libc_vfcntl (vsock->fd, __cmd, __ap);
726       break;
727       /* cmd handled by vcom socket resource */
728     case 2:
729       rv = libc_vfcntl (vsock->fd, __cmd, __ap);
730       break;
731       /* cmd handled by vppcom */
732     case 3:
733       rv = vcom_session_fcntl_va (vsock->sid, __cmd, __ap);
734       break;
735
736     default:
737       rv = -EINVAL;
738       break;
739     }
740
741   return rv;
742 }
743
744 /*
745  * RETURN:  0 - invalid cmd
746  *          1 - cmd not handled by vcom and vppcom
747  *          2 - cmd handled by vcom socket resource
748  *          3 - cmd handled by vppcom
749  */
750 static int
751 vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
752 {
753   int rc;
754
755   switch (__cmd)
756     {
757       /* cmd handled by vppcom */
758     case FIONREAD:
759       rc = 3;
760       break;
761
762       /* cmd not handled by vcom and vppcom */
763     default:
764       rc = 1;
765       break;
766     }
767   return rc;
768 }
769
770 static inline int
771 vcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
772 {
773   int rv;
774
775   if (__cmd == FIONREAD)
776     rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
777   else
778     rv = -EOPNOTSUPP;
779   return rv;
780 }
781
782 int
783 vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
784 {
785   int rv = -EBADF;
786   vcom_socket_main_t *vsm = &vcom_socket_main;
787   uword *p;
788   vcom_socket_t *vsock;
789
790   p = hash_get (vsm->sockidx_by_fd, __fd);
791   if (!p)
792     return -EBADF;
793
794   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
795   if (!vsock)
796     return -ENOTSOCK;
797
798   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
799     return -EINVAL;
800
801   switch (vcom_socket_check_ioctl_cmd (__cmd))
802     {
803       /* Not supported cmd */
804     case 0:
805       rv = -EOPNOTSUPP;
806       break;
807
808       /* cmd not handled by vcom and vppcom */
809     case 1:
810       rv = libc_vioctl (vsock->fd, __cmd, __ap);
811       break;
812
813       /* cmd handled by vcom socket resource */
814     case 2:
815       rv = libc_vioctl (vsock->fd, __cmd, __ap);
816       break;
817
818       /* cmd handled by vppcom */
819     case 3:
820       rv = vcom_session_ioctl_va (vsock->sid, __cmd, __ap);
821       break;
822
823     default:
824       rv = -EINVAL;
825       break;
826     }
827
828   return rv;
829 }
830
831 static inline int
832 vcom_socket_fds_2_sid_fds (
833                             /* dest */
834                             int *vcom_nsid_fds,
835                             fd_set * __restrict vcom_rd_sid_fds,
836                             fd_set * __restrict vcom_wr_sid_fds,
837                             fd_set * __restrict vcom_ex_sid_fds,
838                             /* src */
839                             int vcom_nfds,
840                             fd_set * __restrict vcom_readfds,
841                             fd_set * __restrict vcom_writefds,
842                             fd_set * __restrict vcom_exceptfds)
843 {
844   int rv = 0;
845   int fd;
846   int sid;
847   /* invalid max_sid is -1 */
848   int max_sid = -1;
849   int nsid = 0;
850
851   /*
852    *  set sid in sid sets corresponding to fd's in fd sets
853    *  compute nsid and vcom_nsid_fds from sid sets
854    */
855
856   for (fd = 0; fd < vcom_nfds; fd++)
857     {
858       /*
859        * F fd set, src
860        * S sid set, dest
861        */
862 #define _(S,F)                              \
863       if ((F) && (S) && FD_ISSET (fd, (F))) \
864         {                                   \
865           sid = vcom_socket_get_sid (fd);   \
866           if (sid != INVALID_SESSION_ID)    \
867             {                               \
868               FD_SET (sid, (S));            \
869               if (sid > max_sid)            \
870                 {                           \
871                   max_sid = sid;            \
872                 }                           \
873               ++nsid;                       \
874             }                               \
875           else                              \
876             {                               \
877               rv = -EBADFD;                 \
878               goto done;                    \
879             }                               \
880         }
881
882
883       _(vcom_rd_sid_fds, vcom_readfds);
884       _(vcom_wr_sid_fds, vcom_writefds);
885       _(vcom_ex_sid_fds, vcom_exceptfds);
886 #undef _
887     }
888
889   *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
890   rv = nsid;
891
892 done:
893   return rv;
894 }
895
896 /*
897  * PRE: 00. sid sets were derived from fd sets
898  *      01. sid sets were updated with sids that actually changed
899  *          status
900  *      02. fd sets still has watched fds
901  *
902  * This function will modify in place fd sets to indicate which fd's
903  * actually changed status(inferred from sid sets)
904  */
905 static inline int
906 vcom_socket_sid_fds_2_fds (
907                             /* dest */
908                             int *new_vcom_nfds,
909                             int vcom_nfds,
910                             fd_set * __restrict vcom_readfds,
911                             fd_set * __restrict vcom_writefds,
912                             fd_set * __restrict vcom_exceptfds,
913                             /* src */
914                             int vcom_nsid_fds,
915                             fd_set * __restrict vcom_rd_sid_fds,
916                             fd_set * __restrict vcom_wr_sid_fds,
917                             fd_set * __restrict vcom_ex_sid_fds)
918 {
919   int rv = 0;
920   int fd;
921   int sid;
922   /* invalid max_fd is -1 */
923   int max_fd = -1;
924   int nfd = 0;
925
926
927   /*
928    *  modify in place fd sets to indicate which fd's
929    * actually changed status(inferred from sid sets)
930    */
931   for (fd = 0; fd < vcom_nfds; fd++)
932     {
933       /*
934        * F fd set, dest
935        * S sid set, src
936        */
937 #define _(S,F)                              \
938       if ((F) && (S) && FD_ISSET (fd, (F))) \
939         {                                   \
940           sid = vcom_socket_get_sid (fd);   \
941           if (sid != INVALID_SESSION_ID)    \
942             {                               \
943               if (!FD_ISSET (sid, (S)))     \
944                 {                           \
945                    FD_CLR(fd, (F));         \
946                 }                           \
947             }                               \
948           else                              \
949             {                               \
950               rv = -EBADFD;                 \
951               goto done;                    \
952             }                               \
953         }
954
955
956       _(vcom_rd_sid_fds, vcom_readfds);
957       _(vcom_wr_sid_fds, vcom_writefds);
958       _(vcom_ex_sid_fds, vcom_exceptfds);
959 #undef _
960     }
961
962   /*
963    *  compute nfd and new_vcom_nfds from fd sets
964    */
965   for (fd = 0; fd < vcom_nfds; fd++)
966     {
967
968 #define _(F)                                \
969       if ((F) && FD_ISSET (fd, (F)))        \
970         {                                   \
971           if (fd > max_fd)                  \
972             {                               \
973               max_fd = fd;                  \
974             }                               \
975           ++nfd;                            \
976         }
977
978
979       _(vcom_readfds);
980       _(vcom_writefds);
981       _(vcom_exceptfds);
982 #undef _
983
984     }
985
986   *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
987   rv = nfd;
988
989 done:
990   return rv;
991 }
992
993 /*
994  * PRE:
995  * vom_socket_select is always called with
996  * timeout->tv_sec and timeout->tv_usec set to zero.
997  * hence vppcom_select return immediately.
998  */
999 /*
1000  * TBD: do{body;} while(timeout conditional); timeout loop
1001  */
1002 int
1003 vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
1004                     fd_set * __restrict vcom_writefds,
1005                     fd_set * __restrict vcom_exceptfds,
1006                     struct timeval *__restrict timeout)
1007 {
1008   static unsigned long vcom_nsid_fds = 0;
1009   int vcom_nsid = 0;
1010   int rv = -EBADF;
1011   pid_t pid = getpid ();
1012
1013   int new_vcom_nfds = 0;
1014   int new_vcom_nfd = 0;
1015
1016   /* vcom sid fds */
1017   fd_set vcom_rd_sid_fds;
1018   fd_set vcom_wr_sid_fds;
1019   fd_set vcom_ex_sid_fds;
1020
1021   /* in seconds eg. 3.123456789 seconds */
1022   double time_to_wait = (double) 0;
1023
1024   /* validate inputs */
1025   if (vcom_nfds < 0)
1026     {
1027       return -EINVAL;
1028     }
1029
1030   /* convert timeval timeout to double time_to_wait */
1031   if (timeout)
1032     {
1033       if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1034         {
1035           /* polling: vppcom_select returns immediately */
1036           time_to_wait = (double) 0;
1037         }
1038       else
1039         {
1040           /*TBD:  use timeval api */
1041           time_to_wait = (double) timeout->tv_sec +
1042             (double) timeout->tv_usec / (double) 1000000 +
1043             (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1044         }
1045     }
1046   else
1047     {
1048       /*
1049        * no timeout: vppcom_select can block indefinitely
1050        * waiting for a file descriptor to become ready
1051        * */
1052       /* set to a phantom value */
1053       time_to_wait = ~0;
1054     }
1055
1056   /* zero the sid_sets */
1057   /*
1058    * F fd set
1059    * S sid set
1060    */
1061 #define _(S,F)                          \
1062   if ((F))                              \
1063     {                                   \
1064       FD_ZERO ((S));                    \
1065     }
1066
1067
1068   _(&vcom_rd_sid_fds, vcom_readfds);
1069   _(&vcom_wr_sid_fds, vcom_writefds);
1070   _(&vcom_ex_sid_fds, vcom_exceptfds);
1071 #undef _
1072
1073   if (vcom_nfds == 0)
1074     {
1075       if (time_to_wait > 0)
1076         {
1077           if (VCOM_DEBUG > 0)
1078             fprintf (stderr,
1079                      "[%d] vcom_socket_select called to "
1080                      "emulate delay_ns()!\n", pid);
1081           rv = vppcom_select (0, NULL, NULL, NULL, time_to_wait);
1082         }
1083       else
1084         {
1085           fprintf (stderr, "[%d] vcom_socket_select called vcom_nfds = 0 "
1086                    "and invalid time_to_wait (%f)!\n", pid, time_to_wait);
1087         }
1088       return 0;
1089     }
1090
1091   /* populate read, write and except sid_sets */
1092   vcom_nsid = vcom_socket_fds_2_sid_fds (
1093                                           /* dest */
1094                                           vcom_readfds || vcom_writefds
1095                                           || vcom_exceptfds ? (int *)
1096                                           &vcom_nsid_fds : NULL,
1097                                           vcom_readfds ? &vcom_rd_sid_fds :
1098                                           NULL,
1099                                           vcom_writefds ? &vcom_wr_sid_fds :
1100                                           NULL,
1101                                           vcom_exceptfds ? &vcom_ex_sid_fds :
1102                                           NULL,
1103                                           /* src */
1104                                           vcom_nfds,
1105                                           vcom_readfds,
1106                                           vcom_writefds, vcom_exceptfds);
1107   if (vcom_nsid < 0)
1108     {
1109       return vcom_nsid;
1110     }
1111   if (vcom_nsid_fds < 0)
1112     {
1113       return -EINVAL;
1114     }
1115
1116   rv = vppcom_select (vcom_nsid_fds,
1117                       vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1118                       NULL,
1119                       vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1120                       NULL,
1121                       vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1122                       NULL, time_to_wait);
1123   if (VCOM_DEBUG > 2)
1124     fprintf (stderr, "[%d] called vppcom_select(): "
1125              "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1126
1127   /* check if any file descriptors changed status */
1128   if (rv > 0)
1129     {
1130       /*
1131        * on exit, sets are modified in place to indicate which
1132        * file descriptors actually changed status
1133        * */
1134
1135       /*
1136        * comply with pre-condition
1137        * do not clear vcom fd sets befor calling
1138        * vcom_socket_sid_fds_2_fds
1139        */
1140       new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1141                                                  /* dest */
1142                                                  &new_vcom_nfds,
1143                                                  vcom_nfds,
1144                                                  vcom_readfds,
1145                                                  vcom_writefds,
1146                                                  vcom_exceptfds,
1147                                                  /* src */
1148                                                  vcom_nsid_fds,
1149                                                  vcom_readfds ?
1150                                                  &vcom_rd_sid_fds : NULL,
1151                                                  vcom_writefds ?
1152                                                  &vcom_wr_sid_fds : NULL,
1153                                                  vcom_exceptfds ?
1154                                                  &vcom_ex_sid_fds : NULL);
1155       if (new_vcom_nfd < 0)
1156         {
1157           return new_vcom_nfd;
1158         }
1159       if (new_vcom_nfds < 0)
1160         {
1161           return -EINVAL;
1162         }
1163       rv = new_vcom_nfd;
1164     }
1165   return rv;
1166 }
1167
1168
1169 int
1170 vcom_socket_socket (int __domain, int __type, int __protocol)
1171 {
1172   int rv = -1;
1173   vcom_socket_main_t *vsm = &vcom_socket_main;
1174   vcom_socket_t *vsock;
1175
1176   i32 fd;
1177   i32 sid;
1178   i32 sockidx;
1179   u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1180   int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1181
1182   fd = vcom_socket_open_socket (__domain, __type, __protocol);
1183   if (fd < 0)
1184     {
1185       rv = fd;
1186       goto out;
1187     }
1188
1189   sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1190                                (type == SOCK_DGRAM) ?
1191                                VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1192                                is_nonblocking);
1193   if (sid < 0)
1194     {
1195       rv = sid;
1196       goto out_close_socket;
1197     }
1198
1199   pool_get (vsm->vsockets, vsock);
1200   vsocket_init (vsock);
1201
1202   sockidx = vsock - vsm->vsockets;
1203   hash_set (vsm->sockidx_by_fd, fd, sockidx);
1204
1205   vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1206   return fd;
1207
1208 out_close_socket:
1209   vcom_socket_close_socket (fd);
1210 out:
1211   return rv;
1212 }
1213
1214 int
1215 vcom_socket_socketpair (int __domain, int __type, int __protocol,
1216                         int __fds[2])
1217 {
1218 /* TBD: */
1219   return 0;
1220 }
1221
1222 int
1223 vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1224 {
1225   int rv = -1;
1226   vcom_socket_main_t *vsm = &vcom_socket_main;
1227   uword *p;
1228   vcom_socket_t *vsock;
1229
1230   vppcom_endpt_t ep;
1231
1232   p = hash_get (vsm->sockidx_by_fd, __fd);
1233   if (!p)
1234     return -EBADF;
1235
1236   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1237   if (!vsock)
1238     return -ENOTSOCK;
1239
1240   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1241     return -EINVAL;
1242
1243   if (!__addr)
1244     {
1245       return -EINVAL;
1246     }
1247
1248   ep.vrf = VPPCOM_VRF_DEFAULT;
1249   switch (__addr->sa_family)
1250     {
1251     case AF_INET:
1252       if (__len != sizeof (struct sockaddr_in))
1253         {
1254           return -EINVAL;
1255         }
1256       ep.is_ip4 = VPPCOM_IS_IP4;
1257       ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1258       ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1259       break;
1260
1261     case AF_INET6:
1262       if (__len != sizeof (struct sockaddr_in6))
1263         {
1264           return -EINVAL;
1265         }
1266       ep.is_ip4 = VPPCOM_IS_IP6;
1267       ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1268       ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1269       break;
1270
1271     default:
1272       return -1;
1273       break;
1274     }
1275
1276   rv = vppcom_session_bind (vsock->sid, &ep);
1277   return rv;
1278 }
1279
1280 static inline int
1281 vcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1282 {
1283   int rv;
1284   uint32_t size = sizeof (*ep);
1285
1286   rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_LCL_ADDR, ep, &size);
1287   return rv;
1288 }
1289
1290 int
1291 vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1292                          socklen_t * __restrict __len)
1293 {
1294   int rv = -1;
1295   vcom_socket_main_t *vsm = &vcom_socket_main;
1296   uword *p;
1297   vcom_socket_t *vsock;
1298
1299
1300   p = hash_get (vsm->sockidx_by_fd, __fd);
1301   if (!p)
1302     return -EBADF;
1303
1304   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1305   if (!vsock)
1306     return -ENOTSOCK;
1307
1308   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1309     return -EINVAL;
1310
1311   if (!__addr || !__len)
1312     return -EFAULT;
1313
1314   if (*__len < 0)
1315     {
1316       return -EINVAL;
1317     }
1318
1319   vppcom_endpt_t ep;
1320   ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1321   rv = vcom_session_getsockname (vsock->sid, &ep);
1322   if (rv == 0)
1323     {
1324       if (ep.vrf == VPPCOM_VRF_DEFAULT)
1325         {
1326           __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1327           switch (__addr->sa_family)
1328             {
1329             case AF_INET:
1330               ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1331               *__len = sizeof (struct sockaddr_in);
1332               break;
1333
1334             case AF_INET6:
1335               ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1336               *__len = sizeof (struct sockaddr_in6);
1337               break;
1338
1339             default:
1340               break;
1341             }
1342         }
1343     }
1344
1345   return rv;
1346 }
1347
1348 int
1349 vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1350 {
1351   int rv = -1;
1352   vcom_socket_main_t *vsm = &vcom_socket_main;
1353   uword *p;
1354   vcom_socket_t *vsock;
1355
1356   vppcom_endpt_t ep;
1357
1358   p = hash_get (vsm->sockidx_by_fd, __fd);
1359   if (p)
1360     {
1361       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1362
1363       ep.vrf = VPPCOM_VRF_DEFAULT;
1364       switch (__addr->sa_family)
1365         {
1366         case AF_INET:
1367           ep.is_ip4 = VPPCOM_IS_IP4;
1368           ep.ip =
1369             (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1370           ep.port =
1371             (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1372           break;
1373
1374         case AF_INET6:
1375           ep.is_ip4 = VPPCOM_IS_IP6;
1376           ep.ip =
1377             (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1378           ep.port =
1379             (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1380           break;
1381
1382         default:
1383           return -1;
1384           break;
1385         }
1386
1387       rv = vppcom_session_connect (vsock->sid, &ep);
1388     }
1389   return rv;
1390 }
1391
1392 static inline int
1393 vcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1394 {
1395   int rv;
1396   uint32_t size = sizeof (*ep);
1397
1398   rv = vppcom_session_attr (sid, VPPCOM_ATTR_GET_PEER_ADDR, ep, &size);
1399   return rv;
1400 }
1401
1402 int
1403 vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1404                          socklen_t * __restrict __len)
1405 {
1406   int rv = -1;
1407   vcom_socket_main_t *vsm = &vcom_socket_main;
1408   uword *p;
1409   vcom_socket_t *vsock;
1410
1411
1412   p = hash_get (vsm->sockidx_by_fd, __fd);
1413   if (!p)
1414     return -EBADF;
1415
1416   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1417   if (!vsock)
1418     return -ENOTSOCK;
1419
1420   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1421     return -EINVAL;
1422
1423   if (!__addr || !__len)
1424     return -EFAULT;
1425
1426   if (*__len < 0)
1427     {
1428       return -EINVAL;
1429     }
1430
1431   vppcom_endpt_t ep;
1432   ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1433   rv = vcom_session_getpeername (vsock->sid, &ep);
1434   if (rv == 0)
1435     {
1436       if (ep.vrf == VPPCOM_VRF_DEFAULT)
1437         {
1438           __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1439           switch (__addr->sa_family)
1440             {
1441             case AF_INET:
1442               ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1443               *__len = sizeof (struct sockaddr_in);
1444               break;
1445
1446             case AF_INET6:
1447               ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1448               *__len = sizeof (struct sockaddr_in6);
1449               break;
1450
1451             default:
1452               break;
1453             }
1454         }
1455     }
1456
1457   return rv;
1458 }
1459
1460 ssize_t
1461 vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1462 {
1463   return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1464 }
1465
1466 ssize_t
1467 vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1468 {
1469   int rv = -1;
1470   rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1471   return rv;
1472 }
1473
1474 /*
1475  * RETURN   1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1476  * 0 otherwise
1477  * */
1478 int
1479 vcom_socket_is_connection_mode_socket (int __fd)
1480 {
1481   int rv = -1;
1482   /* TBD define new vppcom api */
1483   vcom_socket_main_t *vsm = &vcom_socket_main;
1484   uword *p;
1485   vcom_socket_t *vsock;
1486
1487   int type;
1488   socklen_t optlen;
1489
1490   p = hash_get (vsm->sockidx_by_fd, __fd);
1491
1492   if (p)
1493     {
1494       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1495       if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1496         {
1497           optlen = sizeof (type);
1498           rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1499           if (rv != 0)
1500             {
1501               return 0;
1502             }
1503           /* get socket type */
1504           switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1505             {
1506             case SOCK_STREAM:
1507             case SOCK_SEQPACKET:
1508               return 1;
1509               break;
1510
1511             default:
1512               return 0;
1513               break;
1514             }
1515         }
1516     }
1517   return 0;
1518 }
1519
1520 static inline ssize_t
1521 vcom_session_sendto (int __sid, void *__buf, size_t __n,
1522                      int __flags, __CONST_SOCKADDR_ARG __addr,
1523                      socklen_t __addr_len)
1524 {
1525   int rv = -1;
1526   /* TBD add new vpp api  */
1527   /* TBD add flags parameter */
1528   rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1529   return rv;
1530 }
1531
1532 ssize_t
1533 vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1534                     int __flags, __CONST_SOCKADDR_ARG __addr,
1535                     socklen_t __addr_len)
1536 {
1537   int rv = -1;
1538   vcom_socket_main_t *vsm = &vcom_socket_main;
1539   uword *p;
1540   vcom_socket_t *vsock;
1541
1542   p = hash_get (vsm->sockidx_by_fd, __fd);
1543   if (!p)
1544     return -EBADF;
1545
1546   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1547   if (!vsock)
1548     return -ENOTSOCK;
1549
1550   if ((vsock->type != SOCKET_TYPE_VPPCOM_BOUND) || !__buf || __n < 0)
1551     {
1552       return -EINVAL;
1553     }
1554
1555   if (vcom_socket_is_connection_mode_socket (__fd))
1556     {
1557       /* ignore __addr and _addr_len */
1558       /* and EISCONN may be returned when they are not NULL and 0 */
1559       if ((__addr != NULL) || (__addr_len != 0))
1560         {
1561           return -EISCONN;
1562         }
1563     }
1564   else
1565     {
1566       if (!__addr || __addr_len < 0)
1567         {
1568           return -EDESTADDRREQ;
1569         }
1570       /* not a vppcom supported address family */
1571       if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1572         {
1573           return -EINVAL;
1574         }
1575     }
1576
1577   rv = vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1578                             __flags, __addr, __addr_len);
1579   return rv;
1580 }
1581
1582 static inline ssize_t
1583 vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1584                        int __flags, __SOCKADDR_ARG __addr,
1585                        socklen_t * __restrict __addr_len)
1586 {
1587   int rv = -1;
1588
1589   /* TBD add flags parameter */
1590   rv = vppcom_session_read (__sid, __buf, __n);
1591   return rv;
1592 }
1593
1594 ssize_t
1595 vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1596                       int __flags, __SOCKADDR_ARG __addr,
1597                       socklen_t * __restrict __addr_len)
1598 {
1599   int rv = -1;
1600   vcom_socket_main_t *vsm = &vcom_socket_main;
1601   uword *p;
1602   vcom_socket_t *vsock;
1603
1604   p = hash_get (vsm->sockidx_by_fd, __fd);
1605   if (!p)
1606     return -EBADF;
1607
1608   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1609   if (!vsock)
1610     return -ENOTSOCK;
1611
1612   if ((vsock->type != SOCKET_TYPE_VPPCOM_BOUND) ||
1613       !__buf || __n < 0 || !__addr || !__addr_len || (__addr_len < 0))
1614     {
1615       return -EINVAL;
1616     }
1617
1618   rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1619                               __flags, __addr, __addr_len);
1620   return rv;
1621 }
1622
1623 /* TBD: move it to vppcom */
1624 static inline ssize_t
1625 vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1626 {
1627   int rv = -1;
1628   /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1629      (int)__n); */
1630   return rv;
1631 }
1632
1633 ssize_t
1634 vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1635 {
1636   int rv = -1;
1637   vcom_socket_main_t *vsm = &vcom_socket_main;
1638   uword *p;
1639   vcom_socket_t *vsock;
1640
1641   p = hash_get (vsm->sockidx_by_fd, __fd);
1642   if (!p)
1643     return -EBADF;
1644
1645   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1646   if (!vsock)
1647     return -ENOTSOCK;
1648
1649   if (vcom_socket_is_connection_mode_socket (__fd))
1650     {
1651       /* ignore __addr and _addr_len */
1652       /* and EISCONN may be returned when they are not NULL and 0 */
1653       if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1654         {
1655           return -EISCONN;
1656         }
1657     }
1658   else
1659     {
1660       /* TBD: validate __message->msg_name and __message->msg_namelen
1661        * and return -EINVAL on validation error
1662        * */
1663       ;
1664     }
1665
1666   rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
1667
1668   return rv;
1669 }
1670
1671 #ifdef __USE_GNU
1672 int
1673 vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1674                       unsigned int __vlen, int __flags)
1675 {
1676
1677   /* TBD: define a new vppcom api */
1678   return 0;
1679 }
1680 #endif
1681
1682 /* TBD: move it to vppcom */
1683 static inline ssize_t
1684 vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
1685 {
1686   int rv = -1;
1687   /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1688      (int)__n); */
1689   rv = -EOPNOTSUPP;
1690   return rv;
1691 }
1692
1693 ssize_t
1694 vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1695 {
1696   int rv = -1;
1697   vcom_socket_main_t *vsm = &vcom_socket_main;
1698   uword *p;
1699   vcom_socket_t *vsock;
1700
1701   p = hash_get (vsm->sockidx_by_fd, __fd);
1702   if (!p)
1703     return -EBADF;
1704
1705   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1706   if (!vsock)
1707     return -ENOTSOCK;
1708
1709   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1710     return -EINVAL;
1711
1712   if (!__message)
1713     {
1714       return -EINVAL;
1715     }
1716
1717   /* validate __flags */
1718
1719   rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
1720   return rv;
1721 }
1722
1723 #ifdef __USE_GNU
1724 int
1725 vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1726                       unsigned int __vlen, int __flags,
1727                       struct timespec *__tmo)
1728 {
1729   /* TBD: define a new vppcom api */
1730   return 0;
1731 }
1732 #endif
1733
1734 /* TBD: move it to vppcom */
1735 static inline int
1736 vcom_session_get_sockopt (int __sid, int __level, int __optname,
1737                           void *__restrict __optval,
1738                           socklen_t * __restrict __optlen)
1739 {
1740   /* 1. for socket level options that are NOT socket attributes
1741    *    and that has corresponding vpp options get from vppcom */
1742   return 0;
1743 }
1744
1745 int
1746 vcom_socket_getsockopt (int __fd, int __level, int __optname,
1747                         void *__restrict __optval,
1748                         socklen_t * __restrict __optlen)
1749 {
1750   int rv = -1;
1751   vcom_socket_main_t *vsm = &vcom_socket_main;
1752   uword *p;
1753   vcom_socket_t *vsock;
1754
1755   p = hash_get (vsm->sockidx_by_fd, __fd);
1756   if (!p)
1757     return -EBADF;
1758
1759   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1760   if (!vsock)
1761     return -ENOTSOCK;
1762
1763   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1764     return -EINVAL;
1765
1766   if (!__optval && !__optlen)
1767     return -EFAULT;
1768
1769   if (*__optlen < 0)
1770     {
1771       return -EINVAL;
1772     }
1773
1774   switch (__level)
1775     {
1776       /* handle options at socket level */
1777     case SOL_SOCKET:
1778       switch (__optname)
1779         {
1780 /*
1781  *  1. for socket level options that are socket attributes,
1782  *     get from libc_getsockopt.
1783  *  2. for socket level options that are NOT socket
1784  *     attributes and that has corresponding vpp options
1785  *     get from vppcom.
1786  *  3. for socket level options unimplemented
1787  *     return -ENOPROTOOPT */
1788         case SO_DEBUG:
1789         case SO_DONTROUTE:
1790         case SO_BROADCAST:
1791         case SO_SNDBUF:
1792         case SO_RCVBUF:
1793         case SO_REUSEADDR:
1794         case SO_REUSEPORT:
1795         case SO_KEEPALIVE:
1796         case SO_TYPE:
1797         case SO_PROTOCOL:
1798         case SO_DOMAIN:
1799         case SO_ERROR:
1800         case SO_OOBINLINE:
1801         case SO_NO_CHECK:
1802         case SO_PRIORITY:
1803         case SO_LINGER:
1804         case SO_BSDCOMPAT:
1805         case SO_TIMESTAMP:
1806         case SO_TIMESTAMPNS:
1807         case SO_TIMESTAMPING:
1808         case SO_RCVTIMEO:
1809         case SO_SNDTIMEO:
1810         case SO_RCVLOWAT:
1811         case SO_SNDLOWAT:
1812         case SO_PASSCRED:
1813         case SO_PEERCRED:
1814         case SO_PEERNAME:
1815         case SO_ACCEPTCONN:
1816         case SO_PASSSEC:
1817         case SO_PEERSEC:
1818         case SO_MARK:
1819         case SO_RXQ_OVFL:
1820         case SO_WIFI_STATUS:
1821         case SO_PEEK_OFF:
1822         case SO_NOFCS:
1823         case SO_BINDTODEVICE:
1824         case SO_GET_FILTER:
1825         case SO_LOCK_FILTER:
1826         case SO_BPF_EXTENSIONS:
1827         case SO_SELECT_ERR_QUEUE:
1828 #ifdef CONFIG_NET_RX_BUSY_POLL
1829         case SO_BUSY_POLL:
1830 #endif
1831         case SO_MAX_PACING_RATE:
1832         case SO_INCOMING_CPU:
1833           rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1834           if (rv != 0)
1835             {
1836               rv = -errno;
1837               return rv;
1838             }
1839           break;
1840
1841         default:
1842           /* We implement the SO_SNDLOWAT etc to not be settable
1843            * (1003.1g 7).
1844            */
1845           return -ENOPROTOOPT;
1846         }
1847
1848       break;
1849
1850     default:
1851       /* 1. handle options that are NOT socket level options,
1852        *    but have corresponding vpp otions. */
1853       rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1854                                      __optval, __optlen);
1855       break;
1856     }
1857
1858   return rv;
1859 }
1860
1861 /* TBD: move it to vppcom */
1862 static inline int
1863 vcom_session_setsockopt (int __sid, int __level, int __optname,
1864                          const void *__optval, socklen_t __optlen)
1865 {
1866   int rv = -EOPNOTSUPP;
1867
1868   switch (__level)
1869     {
1870     case SOL_TCP:
1871       switch (__optname)
1872         {
1873         case TCP_KEEPIDLE:
1874           rv =
1875             vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1876           break;
1877         case TCP_KEEPINTVL:
1878           rv =
1879             vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1880           break;
1881         default:
1882           break;
1883         }
1884       break;
1885     case SOL_IPV6:
1886       switch (__optname)
1887         {
1888         case IPV6_V6ONLY:
1889           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
1890           break;
1891         default:
1892           break;
1893         }
1894       break;
1895     case SOL_SOCKET:
1896       switch (__optname)
1897         {
1898         case SO_KEEPALIVE:
1899           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1900           break;
1901         case SO_REUSEADDR:
1902           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
1903           break;
1904         case SO_BROADCAST:
1905           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
1906           break;
1907         default:
1908           break;
1909         }
1910       break;
1911     default:
1912       break;
1913     }
1914
1915   return rv;
1916 }
1917
1918 int
1919 vcom_socket_setsockopt (int __fd, int __level, int __optname,
1920                         const void *__optval, socklen_t __optlen)
1921 {
1922   int rv = -1;
1923   vcom_socket_main_t *vsm = &vcom_socket_main;
1924   uword *p;
1925   vcom_socket_t *vsock;
1926
1927   p = hash_get (vsm->sockidx_by_fd, __fd);
1928   if (!p)
1929     return -EBADF;
1930
1931   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1932   if (!vsock)
1933     return -ENOTSOCK;
1934
1935   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1936     return -EINVAL;
1937
1938   /*
1939    *      Options without arguments
1940    */
1941
1942   if (__optname == SO_BINDTODEVICE)
1943     {
1944       rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1945       if (rv != 0)
1946         {
1947           rv = -errno;
1948         }
1949       return rv;
1950     }
1951
1952   if (!__optval)
1953     return -EFAULT;
1954
1955   if ((__optlen < 0) || (__optlen < sizeof (int)))
1956     return -EINVAL;
1957
1958   switch (__level)
1959     {
1960     case SOL_IPV6:
1961       switch (__optname)
1962         {
1963         case IPV6_V6ONLY:
1964           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1965                                         __optval, __optlen);
1966           break;
1967         default:
1968           return -EOPNOTSUPP;
1969         }
1970       break;
1971     case SOL_TCP:
1972       switch (__optname)
1973         {
1974         case TCP_NODELAY:
1975           return 0;
1976         case TCP_KEEPIDLE:
1977         case TCP_KEEPINTVL:
1978           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1979                                         __optval, __optlen);
1980           break;
1981         default:
1982           return -EOPNOTSUPP;
1983         }
1984       break;
1985       /* handle options at socket level */
1986     case SOL_SOCKET:
1987       switch (__optname)
1988         {
1989         case SO_REUSEADDR:
1990         case SO_BROADCAST:
1991         case SO_KEEPALIVE:
1992           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
1993                                         __optval, __optlen);
1994           break;
1995
1996           /*
1997            * 1. for socket level options that are socket attributes,
1998            *    set it from libc_getsockopt
1999            * 2. for socket level options that are NOT socket
2000            *    attributes and that has corresponding vpp options
2001            *    set it from vppcom
2002            * 3. for socket level options unimplemented
2003            *    return -ENOPROTOOPT */
2004         case SO_DEBUG:
2005         case SO_DONTROUTE:
2006         case SO_SNDBUF:
2007         case SO_RCVBUF:
2008         case SO_REUSEPORT:
2009         case SO_TYPE:
2010         case SO_PROTOCOL:
2011         case SO_DOMAIN:
2012         case SO_ERROR:
2013         case SO_OOBINLINE:
2014         case SO_NO_CHECK:
2015         case SO_PRIORITY:
2016         case SO_LINGER:
2017         case SO_BSDCOMPAT:
2018         case SO_TIMESTAMP:
2019         case SO_TIMESTAMPNS:
2020         case SO_TIMESTAMPING:
2021         case SO_RCVTIMEO:
2022         case SO_SNDTIMEO:
2023         case SO_RCVLOWAT:
2024         case SO_SNDLOWAT:
2025         case SO_PASSCRED:
2026         case SO_PEERCRED:
2027         case SO_PEERNAME:
2028         case SO_ACCEPTCONN:
2029         case SO_PASSSEC:
2030         case SO_PEERSEC:
2031         case SO_MARK:
2032         case SO_RXQ_OVFL:
2033         case SO_WIFI_STATUS:
2034         case SO_PEEK_OFF:
2035         case SO_NOFCS:
2036           /*
2037            * SO_BINDTODEVICE already handled as
2038            * "Options without arguments" */
2039           /* case SO_BINDTODEVICE: */
2040         case SO_GET_FILTER:
2041         case SO_LOCK_FILTER:
2042         case SO_BPF_EXTENSIONS:
2043         case SO_SELECT_ERR_QUEUE:
2044 #ifdef CONFIG_NET_RX_BUSY_POLL
2045         case SO_BUSY_POLL:
2046 #endif
2047         case SO_MAX_PACING_RATE:
2048         case SO_INCOMING_CPU:
2049           rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2050           if (rv != 0)
2051             {
2052               rv = -errno;
2053               return rv;
2054             }
2055           break;
2056
2057         default:
2058           /* We implement the SO_SNDLOWAT etc to not be settable
2059            * (1003.1g 7).
2060            */
2061           return -ENOPROTOOPT;
2062         }
2063
2064       break;
2065
2066     default:
2067       return -ENOPROTOOPT;
2068     }
2069
2070   return rv;
2071 }
2072
2073 int
2074 vcom_socket_listen (int __fd, int __n)
2075 {
2076   int rv = -1;
2077   vcom_socket_main_t *vsm = &vcom_socket_main;
2078   uword *p;
2079   vcom_socket_t *vsock;
2080
2081   p = hash_get (vsm->sockidx_by_fd, __fd);
2082   if (p)
2083     {
2084       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2085
2086       /* TBD vppcom to accept __n parameter */
2087       rv = vppcom_session_listen (vsock->sid, __n);
2088     }
2089
2090   return rv;
2091 }
2092
2093 static int
2094 vcom_socket_connected_socket (int __fd, int __sid,
2095                               int *__domain,
2096                               int *__type, int *__protocol, int flags)
2097 {
2098   int rv = -1;
2099   vcom_socket_main_t *vsm = &vcom_socket_main;
2100   vcom_socket_t *vsock;
2101
2102   i32 fd;
2103   i32 sockidx;
2104
2105   socklen_t optlen;
2106
2107   optlen = sizeof (*__domain);
2108   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2109   if (rv != 0)
2110     {
2111       rv = -errno;
2112       goto out;
2113     }
2114
2115   optlen = sizeof (*__type);
2116   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2117   if (rv != 0)
2118     {
2119       rv = -errno;
2120       goto out;
2121     }
2122
2123   optlen = sizeof (*__protocol);
2124   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2125   if (rv != 0)
2126     {
2127       rv = -errno;
2128       goto out;
2129     }
2130
2131   fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2132   if (fd < 0)
2133     {
2134       rv = fd;
2135       goto out;
2136     }
2137
2138   pool_get (vsm->vsockets, vsock);
2139   vsocket_init (vsock);
2140
2141   sockidx = vsock - vsm->vsockets;
2142   hash_set (vsm->sockidx_by_fd, fd, sockidx);
2143
2144   vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2145   return fd;
2146
2147 out:
2148   return rv;
2149 }
2150
2151 /* If flag is 0, then accept4() is the same as accept().
2152  * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2153  */
2154 static int
2155 vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2156                           socklen_t * __restrict __addr_len, int flags)
2157 {
2158   int rv = -1;
2159   vcom_socket_main_t *vsm = &vcom_socket_main;
2160   uword *p;
2161   vcom_socket_t *vsock;
2162
2163   int fd;
2164   int sid;
2165   int domain;
2166   int type;
2167   int protocol;
2168
2169   uint8_t addr8[sizeof (struct in6_addr)];
2170   vppcom_endpt_t ep;
2171
2172   ep.ip = addr8;
2173
2174   /* validate flags */
2175
2176   /*
2177    * for documentation
2178    *  switch (flags)
2179    *   {
2180    *   case 0:
2181    *   case SOCK_NONBLOCK:
2182    *   case SOCK_CLOEXEC:
2183    *   case SOCK_NONBLOCK | SOCK_CLOEXEC:
2184    *     break;
2185    *
2186    *   default:
2187    *     return -1;
2188    *   }
2189    */
2190   /* flags can be 0 or can be bitwise OR
2191    * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2192
2193   if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2194     {
2195       /* TBD: return proper error code */
2196       return -1;
2197     }
2198
2199   /* TBD: return proper error code */
2200
2201   if (!vcom_socket_is_connection_mode_socket (__fd))
2202     {
2203       return -EOPNOTSUPP;
2204     }
2205
2206   p = hash_get (vsm->sockidx_by_fd, __fd);
2207   if (p)
2208     {
2209       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2210
2211
2212       rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2213       if (rv < 0)
2214         {
2215           return rv;
2216         }
2217
2218       /* is blocking */
2219       if (!(rv & O_NONBLOCK))
2220         {
2221           /* socket is not marked as nonblocking
2222            * and no pending connections are present
2223            * on the queue, accept () blocks the caller
2224            * until a connection is present.
2225            */
2226           rv = vppcom_session_accept (vsock->sid, &ep,
2227                                       -1.0 /* wait forever */ );
2228         }
2229       else
2230         {
2231           /* The file descriptor refers to a socket and has been
2232            * marked nonblocking(O_NONBLOCK) and the accept would
2233            * block.
2234            * */
2235           /* is non blocking */
2236           rv = vppcom_session_accept (vsock->sid, &ep, 0);
2237           /* If the socket is marked nonblocking and
2238            * no pending connections are present on the
2239            * queue, accept fails with the error
2240            * EAGAIN or EWOULDBLOCK
2241            */
2242           if (rv == VPPCOM_ETIMEDOUT)
2243             {
2244               rv = VPPCOM_EAGAIN;
2245             }
2246         }
2247       if (rv < 0)
2248         {
2249           return rv;
2250         }
2251
2252       sid = rv;
2253
2254       /* create a new connected socket resource and set flags
2255        * on the new file descriptor.
2256        * update vsockets and sockidx_by_fd table
2257        * */
2258       fd = vcom_socket_connected_socket (__fd, sid,
2259                                          &domain, &type, &protocol, flags);
2260       if (fd < 0)
2261         {
2262           return fd;
2263         }
2264
2265       rv = fd;
2266
2267       /* TBD populate __addr and __addr_len */
2268       /* TBD: The returned address is truncated if the buffer
2269        * provided is too small, in this case, __addr_len will
2270        * return a value greater than was supplied to the call.*/
2271       if (__addr)
2272         {
2273           if (ep.is_cut_thru)
2274             {
2275               /* TBD populate __addr and __addr_len */
2276               switch (domain)
2277                 {
2278                 case AF_INET:
2279                   ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2280                   ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2281                   memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2282                           addr8, sizeof (struct in_addr));
2283                   /* TBD: populate __addr_len */
2284                   if (__addr_len)
2285                     {
2286                       *__addr_len = sizeof (struct sockaddr_in);
2287                     }
2288                   break;
2289
2290                 case AF_INET6:
2291                   ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2292                   ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2293                   memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2294                           __in6_u.__u6_addr8, addr8,
2295                           sizeof (struct in6_addr));
2296                   /* TBD: populate __addr_len */
2297                   if (__addr_len)
2298                     {
2299                       *__addr_len = sizeof (struct sockaddr_in6);
2300                     }
2301                   break;
2302
2303                 default:
2304                   return -EAFNOSUPPORT;
2305                 }
2306             }
2307           else
2308             {
2309               switch (ep.is_ip4)
2310                 {
2311                 case VPPCOM_IS_IP4:
2312                   ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2313                   ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2314                   memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2315                           addr8, sizeof (struct in_addr));
2316                   /* TBD: populate __addr_len */
2317                   if (__addr_len)
2318                     {
2319                       *__addr_len = sizeof (struct sockaddr_in);
2320                     }
2321                   break;
2322
2323                 case VPPCOM_IS_IP6:
2324                   ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2325                   ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2326                   memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2327                           __in6_u.__u6_addr8, addr8,
2328                           sizeof (struct in6_addr));
2329                   /* TBD: populate __addr_len */
2330                   if (__addr_len)
2331                     {
2332                       *__addr_len = sizeof (struct sockaddr_in6);
2333                     }
2334                   break;
2335
2336                 default:
2337                   return -EAFNOSUPPORT;
2338                 }
2339             }
2340         }
2341       else
2342         {
2343           /* when __addr is NULL, nothing is filled in,
2344            * in this case, __addr_len is not used,
2345            * and should also be null
2346            * */
2347           if (__addr_len)
2348             {
2349               /* TBD: return proper error code */
2350               return -1;
2351             }
2352         }
2353     }
2354
2355   return rv;
2356 }
2357
2358 int
2359 vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2360                     socklen_t * __restrict __addr_len)
2361 {
2362   /* set flags to 0 for accept() */
2363   return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2364 }
2365
2366 #ifdef __USE_GNU
2367 int
2368 vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2369                      socklen_t * __restrict __addr_len, int __flags)
2370 {
2371   /*  SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2372   return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2373 }
2374 #endif
2375
2376 /* TBD: move it to vppcom */
2377 static inline int
2378 vcom_session_shutdown (int __fd, int __how)
2379 {
2380   return 0;
2381 }
2382
2383 int
2384 vcom_socket_shutdown (int __fd, int __how)
2385 {
2386   int rv = -1;
2387   vcom_socket_main_t *vsm = &vcom_socket_main;
2388   uword *p;
2389   vcom_socket_t *vsock;
2390
2391   p = hash_get (vsm->sockidx_by_fd, __fd);
2392   if (p)
2393     {
2394       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2395       switch (__how)
2396         {
2397         case SHUT_RD:
2398         case SHUT_WR:
2399         case SHUT_RDWR:
2400           rv = vcom_session_shutdown (vsock->sid, __how);
2401           return rv;
2402           break;
2403
2404         default:
2405           return -EINVAL;
2406           break;
2407         }
2408     }
2409
2410   return rv;
2411 }
2412
2413 int
2414 vcom_socket_epoll_create1 (int __flags)
2415 {
2416   int rv = -1;
2417   vcom_socket_main_t *vsm = &vcom_socket_main;
2418   vcom_epoll_t *vepoll;
2419
2420   i32 epfd;
2421   i32 vep_idx;
2422   i32 epollidx;
2423
2424   epfd = vcom_socket_open_epoll (__flags);
2425   if (epfd < 0)
2426     {
2427       rv = epfd;
2428       goto out;
2429     }
2430
2431   vep_idx = vppcom_epoll_create ();
2432   if (vep_idx < 0)
2433     {
2434       rv = vep_idx;
2435       goto out_close_epoll;
2436     }
2437
2438   pool_get (vsm->vepolls, vepoll);
2439   vepoll_init (vepoll);
2440
2441   epollidx = vepoll - vsm->vepolls;
2442   hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2443
2444   vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2445
2446   return epfd;
2447
2448 out_close_epoll:
2449   vcom_socket_close_epoll (epfd);
2450 out:
2451   return rv;
2452 }
2453
2454 /*
2455  * PRE: vppcom_epoll_ctl() is successful
2456  * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2457  */
2458 int
2459 vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2460                          struct epoll_event *__event,
2461                          i32 vep_idx, vcom_epoll_t * vepoll,
2462                          i32 vfd_id, void *vfd, vcom_fd_type_t type,
2463                          int free_vepitem_on_del)
2464 {
2465   int rv = -1;
2466   vcom_socket_main_t *vsm = &vcom_socket_main;
2467   vcom_epitem_t *vepitem;
2468
2469   vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2470   uword *p;
2471   i32 vepitemidx;
2472
2473   i32 *vepitemidxs = 0;
2474
2475   struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2476
2477   i32 vec_idx;
2478
2479   /* perform control operations on the epoll instance */
2480   switch (__op)
2481     {
2482     case EPOLL_CTL_ADD:
2483       /*
2484        * supplied file descriptor is already
2485        * registered with this epoll instance
2486        * */
2487       /* vepitem exists */
2488       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2489       if (p)
2490         {
2491           rv = -EEXIST;
2492           goto out;
2493         }
2494
2495       /* add a new vepitem */
2496       pool_get (vsm->vepitems, vepitem);
2497       vepitem_init (vepitem);
2498
2499       vepitemidx = vepitem - vsm->vepitems;
2500       hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2501       vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2502
2503       /* update epitemidxs */
2504       /* by_epfd */
2505       p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2506       if (!p)                   /*  not exist */
2507         {
2508           vepitemidxs = 0;
2509           vec_add1 (vepitemidxs, vepitemidx);
2510           hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2511         }
2512       else                      /*  exists */
2513         {
2514           vepitemidxs = *(i32 **) p;
2515           vec_add1 (vepitemidxs, vepitemidx);
2516           hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2517         }
2518       /* update epitemidxs */
2519       /* by_fd */
2520       p = hash_get (vsm->epitemidxs_by_fd, __fd);
2521       if (!p)                   /*  not exist */
2522         {
2523           vepitemidxs = 0;
2524           vec_add1 (vepitemidxs, vepitemidx);
2525           hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2526         }
2527       else                      /*  exists */
2528         {
2529           vepitemidxs = *(i32 **) p;
2530           vec_add1 (vepitemidxs, vepitemidx);
2531           hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2532         }
2533
2534       /* increment vepoll fd count by 1 */
2535       vepoll->count += 1;
2536
2537       rv = 0;
2538       goto out;
2539       break;
2540
2541     case EPOLL_CTL_MOD:
2542       /*
2543        * supplied file descriptor is not
2544        * registered with this epoll instance
2545        * */
2546       /* vepitem not exist */
2547       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2548       if (!p)
2549         {
2550           rv = -ENOENT;
2551           goto out;
2552         }
2553       vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2554       if (vepitem)
2555         {
2556           vepitem->event = *__event;
2557           vepitem->revent = revent;
2558         }
2559
2560       rv = 0;
2561       goto out;
2562       break;
2563
2564     case EPOLL_CTL_DEL:
2565       /*
2566        * supplied file descriptor is not
2567        * registered with this epoll instance
2568        * */
2569       /* vepitem not exist */
2570       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2571       if (!p)
2572         {
2573           rv = -ENOENT;
2574           goto out;
2575         }
2576       vepitemidx = *(i32 *) p;
2577       hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2578
2579       /* update epitemidxs */
2580       /* by_epfd */
2581       p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2582       if (!p)                   /*  not exist */
2583         {
2584           rv = -ENOENT;
2585           goto out;
2586         }
2587       else                      /*  exists */
2588         {
2589           vepitemidxs = *(i32 **) p;
2590           vec_idx = vec_search (vepitemidxs, vepitemidx);
2591           if (vec_idx != ~0)
2592             {
2593               vec_del1 (vepitemidxs, vec_idx);
2594               if (!vec_len (vepitemidxs))
2595                 {
2596                   vec_free (vepitemidxs);
2597                   hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2598                 }
2599             }
2600         }
2601
2602       /* update epitemidxs */
2603       /* by_fd */
2604       p = hash_get (vsm->epitemidxs_by_fd, __fd);
2605       if (!p)                   /*  not exist */
2606         {
2607           rv = -ENOENT;
2608           goto out;
2609         }
2610       else                      /*  exists */
2611         {
2612           vepitemidxs = *(i32 **) p;
2613           vec_idx = vec_search (vepitemidxs, vepitemidx);
2614           if (vec_idx != ~0)
2615             {
2616               vec_del1 (vepitemidxs, vec_idx);
2617               if (!vec_len (vepitemidxs))
2618                 {
2619                   vec_free (vepitemidxs);
2620                   hash_unset (vsm->epitemidxs_by_fd, __fd);
2621                 }
2622             }
2623         }
2624
2625       /* pool put vepitem */
2626       vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2627       if (free_vepitem_on_del)
2628         {
2629           if (!vepitem)
2630             {
2631               rv = -ENOENT;
2632               goto out;
2633             }
2634           vepitem_init (vepitem);
2635           pool_put (vsm->vepitems, vepitem);
2636         }
2637       else
2638         {
2639           if (!vepitem)
2640             {
2641               vepitem_init (vepitem);
2642             }
2643         }
2644
2645       /* decrement vepoll fd count by 1 */
2646       vepoll->count -= 1;
2647
2648       rv = 0;
2649       goto out;
2650       break;
2651
2652     default:
2653       rv = -EINVAL;
2654       goto out;
2655       break;
2656     }
2657
2658 out:
2659   return rv;
2660 }
2661
2662 /*
2663  * PRE: 00. null pointer check on __event
2664  *      01. all other parameters are validated
2665  */
2666
2667 static int
2668 vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2669                                 struct epoll_event *__event,
2670                                 int free_vepitem_on_del)
2671 {
2672   int rv = -1;
2673
2674   /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2675   vcom_epoll_t *vepoll;
2676
2677   /*__fd could could be vcom socket or vcom epoll or kernel fd */
2678   void *vfd;
2679   vcom_epoll_t *vfd_vepoll;
2680   vcom_socket_t *vfd_vsock;
2681
2682   i32 vep_idx;
2683   i32 vfd_id;
2684
2685   vcom_fd_type_t type = FD_TYPE_INVALID;
2686
2687   /* validate __event */
2688
2689   /* get vep_idx and vepoll */
2690   vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2691   if (vep_idx == INVALID_VEP_IDX)
2692     {
2693       return -EBADF;
2694     }
2695
2696   /* get vcom fd type, vfd_id and vfd */
2697   vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2698   if (vfd_id != INVALID_SESSION_ID)
2699     {
2700       type = FD_TYPE_VCOM_SOCKET;
2701       vfd = vfd_vsock;
2702     }
2703   else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll))
2704            != INVALID_VEP_IDX)
2705     {
2706       type = FD_TYPE_EPOLL;
2707       vfd = vfd_vepoll;
2708     }
2709   else
2710     {
2711       /* FD_TYPE_KERNEL not supported by epoll instance */
2712       type = FD_TYPE_INVALID;
2713       return -EBADF;
2714     }
2715
2716
2717   /* vepoll and vsock are now valid */
2718   rv = vppcom_epoll_ctl (vep_idx, __op, vfd_id, __event);
2719   if (rv < 0)
2720     {
2721       return rv;
2722     }
2723
2724   rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2725                                 __event,
2726                                 vep_idx, vepoll,
2727                                 vfd_id, vfd, type, free_vepitem_on_del);
2728   return rv;
2729 }
2730
2731 int
2732 vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2733                        struct epoll_event *__event)
2734 {
2735   int rv = -1;
2736
2737   rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2738   return rv;
2739 }
2740
2741 static int
2742 vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2743                         struct epoll_event *__event)
2744 {
2745   int rv = -1;
2746
2747   rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2748   return rv;
2749 }
2750
2751 int
2752 vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2753                          int __maxevents, int __timeout,
2754                          const __sigset_t * __ss)
2755 {
2756   int rv = -EBADF;
2757
2758   /* in seconds eg. 3.123456789 seconds */
2759   double time_to_wait = (double) 0;
2760
2761   i32 vep_idx;
2762
2763   /* validate __event */
2764   if (!__events)
2765     {
2766       rv = -EFAULT;
2767       goto out;
2768     }
2769
2770   /* validate __timeout */
2771   if (__timeout > 0)
2772     {
2773       time_to_wait = (double) __timeout / (double) 1000;
2774     }
2775   else if (__timeout == 0)
2776     {
2777       time_to_wait = (double) 0;
2778     }
2779   else if (__timeout == -1)
2780     {
2781       time_to_wait = ~0;
2782     }
2783   else
2784     {
2785       rv = -EBADF;
2786       goto out;
2787     }
2788
2789   /* get vep_idx */
2790   vep_idx = vcom_socket_get_vep_idx (__epfd);
2791   if (vep_idx != INVALID_VEP_IDX)
2792     {
2793       rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2794     }
2795 out:
2796   return rv;
2797 }
2798
2799 static inline void
2800 vcom_pollfds_2_selectfds (
2801                            /* src */
2802                            struct pollfd *__fds, nfds_t __nfds,
2803                            /* dest */
2804                            int vcom_nfds,
2805                            fd_set * __restrict vcom_readfds,
2806                            fd_set * __restrict vcom_writefds,
2807                            fd_set * __restrict vcom_exceptfds)
2808 {
2809   nfds_t fds_idx = 0;
2810
2811   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2812     {
2813       /* ignore negative fds */
2814       if (__fds[fds_idx].fd < 0)
2815         {
2816           continue;
2817         }
2818
2819       /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
2820       FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2821
2822       /* requested events */
2823       if (__fds[fds_idx].events)
2824         {
2825           if (__fds[fds_idx].events & POLLIN)
2826             {
2827               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2828             }
2829           if (__fds[fds_idx].events & POLLPRI)
2830             {
2831               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2832             }
2833           if (__fds[fds_idx].events & POLLOUT)
2834             {
2835               FD_SET (__fds[fds_idx].fd, vcom_writefds);
2836             }
2837 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2838           if (__fds[fds_idx].events & POLLRDNORM)
2839             {
2840               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2841             }
2842           if (__fds[fds_idx].events & POLLRDBAND)
2843             {
2844               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2845             }
2846           if (__fds[fds_idx].events & POLLWRNORM)
2847             {
2848               FD_SET (__fds[fds_idx].fd, vcom_writefds);
2849             }
2850           if (__fds[fds_idx].events & POLLWRBAND)
2851             {
2852               FD_SET (__fds[fds_idx].fd, vcom_writefds);
2853             }
2854 #endif
2855         }
2856     }                           /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2857 }
2858
2859 static inline void
2860 vcom_selectfds_2_pollfds (
2861                            /* dest */
2862                            struct pollfd *__fds, nfds_t __nfds, int *nfd,
2863                            /* src */
2864                            int vcom_nfds,
2865                            fd_set * __restrict vcom_readfds,
2866                            fd_set * __restrict vcom_writefds,
2867                            fd_set * __restrict vcom_exceptfds)
2868 {
2869   nfds_t fds_idx = 0;
2870
2871
2872   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2873     {
2874       /* ignore negative fds */
2875       if (__fds[fds_idx].fd < 0)
2876         {
2877           __fds[fds_idx].revents = 0;
2878         }
2879
2880       /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
2881       if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
2882         {
2883           /*
2884            * TBD: for now any select exception
2885            *      is flagged as POLLERR
2886            * */
2887           __fds[fds_idx].revents |= POLLERR;
2888         }
2889
2890       /* requested events */
2891       if (__fds[fds_idx].events & POLLIN)
2892         {
2893           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2894             {
2895               __fds[fds_idx].revents |= POLLIN;
2896             }
2897         }
2898       if (__fds[fds_idx].events & POLLPRI)
2899         {
2900           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2901             {
2902               __fds[fds_idx].revents |= POLLIN;
2903             }
2904         }
2905       if (__fds[fds_idx].events & POLLOUT)
2906         {
2907           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2908             {
2909               __fds[fds_idx].revents |= POLLOUT;
2910             }
2911         }
2912 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2913       if (__fds[fds_idx].events & POLLRDNORM)
2914         {
2915           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2916             {
2917               __fds[fds_idx].revents |= POLLRDNORM;
2918             }
2919         }
2920       if (__fds[fds_idx].events & POLLRDBAND)
2921         {
2922           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
2923             {
2924               __fds[fds_idx].revents |= POLLRDBAND;
2925             }
2926         }
2927       if (__fds[fds_idx].events & POLLWRNORM)
2928         {
2929           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2930             {
2931               __fds[fds_idx].revents |= POLLWRNORM;
2932             }
2933         }
2934       if (__fds[fds_idx].events & POLLWRBAND)
2935         {
2936           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
2937             {
2938               __fds[fds_idx].revents |= POLLWRBAND;
2939             }
2940         }
2941 #endif
2942     }                           /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
2943
2944   /*
2945    * nfd:
2946    * the number of structures which have nonzero revents  fields
2947    * (in  other  words,  those  descriptors  with events or
2948    * errors reported)
2949    * */
2950   *nfd = 0;
2951   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2952     {
2953       /* ignore negative fds */
2954       if (__fds[fds_idx].fd < 0)
2955         {
2956           continue;
2957         }
2958
2959       if (__fds[fds_idx].revents)
2960         {
2961           (*nfd)++;
2962         }
2963     }
2964 }
2965
2966 /*
2967  * PRE: parameters are validated,
2968  *      vcom_socket_poll is always called with __timeout set to zero
2969  *      hence returns immediately
2970  *
2971  * ACTION: handle non negative validated vcom fds and ignore rest
2972  */
2973
2974 /*
2975  * implements vcom_socket_poll () interface
2976  *
2977  * internally uses vcom_socket_select ()
2978  * to realize the behavior
2979  * */
2980 int
2981 vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
2982                               int __timeout)
2983 {
2984   int rv;
2985   pid_t pid = getpid ();
2986
2987   nfds_t fds_idx = 0;
2988   int nfd = 0;
2989
2990   /* vcom */
2991   int vcom_nfds = 0;
2992   fd_set vcom_readfds;
2993   fd_set vcom_writefds;
2994   fd_set vcom_exceptfds;
2995   int vcom_nfd = -1;
2996   /* invalid max_vcom_fd is -1 */
2997   int max_vcom_fd = -1;
2998
2999   /* __timeout is zero to get ready events and return immediately */
3000   struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3001
3002   /* validate __nfds from select perspective */
3003   if (__nfds < 0 || __nfds > FD_SETSIZE)
3004     {
3005       rv = -EINVAL;
3006       goto poll_done;
3007     }
3008
3009   /* zero vcom fd sets */
3010   /*
3011    * V vcom fd set
3012    */
3013 #define _(V)      \
3014     FD_ZERO ((V))
3015
3016   _(&vcom_readfds);
3017   _(&vcom_writefds);
3018   _(&vcom_exceptfds);
3019 #undef _
3020
3021   vcom_nfds = 0;
3022   vcom_nfd = -1;
3023
3024
3025   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3026     {
3027       /* ignore negative fds */
3028       if (__fds[fds_idx].fd < 0)
3029         {
3030           continue;
3031         }
3032
3033       /* non negative validated vcom fds */
3034       if (__fds[fds_idx].fd > FD_SETSIZE)
3035         {
3036           rv = -EINVAL;
3037           goto poll_done;
3038         }
3039
3040       /* max_vcom_fd and vcom_nfd */
3041       if (__fds[fds_idx].fd > max_vcom_fd)
3042         {
3043           /* requested events */
3044           if (__fds[fds_idx].events)
3045             {
3046               max_vcom_fd = __fds[fds_idx].fd;
3047             }
3048         }
3049       ++vcom_nfd;
3050     }
3051
3052   vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3053
3054   if (!vcom_nfds)
3055     {
3056       rv = vcom_nfds;
3057       goto poll_done;
3058     }
3059
3060   vcom_pollfds_2_selectfds (
3061                              /* src */
3062                              __fds, __nfds,
3063                              /* dest */
3064                              vcom_nfds,
3065                              &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3066
3067   /* select on vcom fds */
3068   vcom_nfd = vcom_socket_select (vcom_nfds,
3069                                  &vcom_readfds,
3070                                  &vcom_writefds, &vcom_exceptfds, &tv);
3071   if (VCOM_DEBUG > 2)
3072     fprintf (stderr,
3073              "[%d] vcom_socket_select: "
3074              "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
3075
3076   if (vcom_nfd < 0)
3077     {
3078       rv = vcom_nfd;
3079       goto poll_done;
3080     }
3081
3082   vcom_selectfds_2_pollfds (
3083                              /* dest */
3084                              __fds, __nfds, &nfd,
3085                              /* src */
3086                              vcom_nfds,
3087                              &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3088
3089   rv = nfd;
3090
3091 poll_done:
3092   return rv;
3093 }
3094
3095 /*
3096  * TBD: remove this static function once vppcom
3097  *      has an implementation in place
3098  *
3099  * ACTION:
3100  */
3101 static int
3102 vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3103 {
3104   return -EOPNOTSUPP;
3105 }
3106
3107 int
3108 vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3109                               int __timeout)
3110 {
3111   nfds_t fds_idx = 0;
3112
3113   /* in seconds eg. 3.123456789 seconds */
3114   double time_to_wait = (double) 0;
3115
3116   i32 sid;
3117   i32 vep_idx;
3118
3119   /* replace vcom fd with session idx */
3120   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3121     {
3122       /* ignore negative fds */
3123       if (__fds[fds_idx].fd < 0)
3124         {
3125           continue;
3126         }
3127
3128       /* non negative validated vcom fds */
3129       sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3130       if (sid != INVALID_SESSION_ID)
3131         {
3132           __fds[fds_idx].fd = sid;
3133         }
3134       else
3135         {
3136           /* get vep_idx */
3137           vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3138           if (vep_idx != INVALID_VEP_IDX)
3139             {
3140               __fds[fds_idx].fd = vep_idx;
3141             }
3142           else
3143             {
3144               return -EBADF;
3145             }
3146         }
3147     }
3148
3149   /* validate __timeout */
3150   if (__timeout > 0)
3151     {
3152       time_to_wait = (double) __timeout / (double) 1000;
3153     }
3154   else if (__timeout == 0)
3155     {
3156       time_to_wait = (double) 0;
3157     }
3158   else if (__timeout < 0)
3159     {
3160       time_to_wait = ~0;
3161     }
3162   else
3163     {
3164       return -EBADF;
3165     }
3166
3167   return vppcom_poll (__fds, __nfds, time_to_wait);
3168 }
3169
3170 int
3171 vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3172 {
3173   /* select an implementation */
3174
3175   /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3176   return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3177 }
3178
3179 #ifdef __USE_GNU
3180 int
3181 vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3182                    const struct timespec *__timeout, const __sigset_t * __ss)
3183 {
3184   return -EOPNOTSUPP;
3185 }
3186 #endif
3187
3188 int
3189 vcom_socket_main_init (void)
3190 {
3191   vcom_socket_main_t *vsm = &vcom_socket_main;
3192
3193   if (VCOM_DEBUG > 0)
3194     printf ("vcom_socket_main_init\n");
3195
3196   if (!vsm->init)
3197     {
3198       /* TBD: define FD_MAXSIZE and use it here */
3199       pool_alloc (vsm->vsockets, FD_SETSIZE);
3200       vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3201
3202       pool_alloc (vsm->vepolls, FD_SETSIZE);
3203       vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3204
3205       pool_alloc (vsm->vepitems, FD_SETSIZE);
3206       vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3207
3208       vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3209       vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3210
3211       vsm->init = 1;
3212     }
3213
3214   return 0;
3215 }
3216
3217
3218 void
3219 vcom_socket_main_show (void)
3220 {
3221   vcom_socket_main_t *vsm = &vcom_socket_main;
3222   vcom_socket_t *vsock;
3223
3224   vcom_epoll_t *vepoll;
3225
3226   vcom_epitem_t *vepitem;
3227
3228   i32 epfd;
3229   i32 fd;
3230   i32 *vepitemidxs, *vepitemidxs_var;
3231
3232   if (vsm->init)
3233     {
3234       /* from active list of vsockets show vsock */
3235
3236       /* *INDENT-OFF* */
3237       pool_foreach (vsock, vsm->vsockets,
3238         ({
3239           printf(
3240                  "fd='%04d', sid='%08x',type='%-30s'\n",
3241                  vsock->fd, vsock->sid,
3242                  vcom_socket_type_str (vsock->type));
3243         }));
3244       /* *INDENT-ON* */
3245
3246       /* from active list of vepolls, show vepoll */
3247
3248       /* *INDENT-OFF* */
3249       pool_foreach (vepoll, vsm->vepolls,
3250         ({
3251           printf(
3252                  "epfd='%04d', vep_idx='%08x', "
3253                  "type='%-30s', "
3254                  "flags='%d', count='%d', close='%d'\n",
3255                  vepoll->epfd, vepoll->vep_idx,
3256                  vcom_socket_epoll_type_str (vepoll->type),
3257                  vepoll->flags, vepoll->count, vepoll->close);
3258         }));
3259       /* *INDENT-ON* */
3260
3261       /* from active list of vepitems, show vepitem */
3262
3263       /* *INDENT-OFF* */
3264       pool_foreach (vepitem, vsm->vepitems,
3265         ({
3266           printf(
3267                  "epfd='%04d', fd='%04d', "
3268                  "next_fd='%04d', prev_fd='%04d', "
3269                  "type='%-30s', "
3270                  "events='%04x', revents='%04x'\n",
3271                  vepitem->epfd, vepitem->fd,
3272                  vepitem->next_fd, vepitem->prev_fd,
3273                  vcom_socket_vcom_fd_type_str (vepitem->type),
3274                  vepitem->event.events, vepitem->revent.events);
3275         }));
3276
3277       /* *INDENT-ON* */
3278
3279       /* show epitemidxs for epfd */
3280       /* *INDENT-OFF* */
3281       hash_foreach (epfd, vepitemidxs,
3282                     vsm->epitemidxs_by_epfd,
3283       ({
3284         printf("\n[ '%04d': ", epfd);
3285         vec_foreach (vepitemidxs_var,vepitemidxs)
3286         {
3287           printf("'%04d' ", (int)vepitemidxs_var[0]);
3288         }
3289         printf("]\n");
3290       }));
3291       /* *INDENT-ON* */
3292
3293       /* show epitemidxs for fd */
3294       /* *INDENT-OFF* */
3295       hash_foreach (fd, vepitemidxs,
3296                     vsm->epitemidxs_by_fd,
3297       ({
3298         printf("\n{ '%04d': ", fd);
3299         vec_foreach (vepitemidxs_var,vepitemidxs)
3300         {
3301           printf("'%04d' ", (int)vepitemidxs_var[0]);
3302         }
3303         printf("}\n");
3304       }));
3305       /* *INDENT-ON* */
3306
3307     }
3308 }
3309
3310 void
3311 vcom_socket_main_destroy (void)
3312 {
3313   vcom_socket_main_t *vsm = &vcom_socket_main;
3314   vcom_socket_t *vsock;
3315
3316   vcom_epoll_t *vepoll;
3317
3318   vcom_epitem_t *vepitem;
3319
3320   i32 epfd;
3321   i32 fd;
3322   i32 *vepitemidxs;
3323
3324
3325   if (VCOM_DEBUG > 0)
3326     printf ("vcom_socket_main_destroy\n");
3327
3328   if (vsm->init)
3329     {
3330
3331       /*
3332        * from active list of vepitems,
3333        * remove all "vepitem" elements from the pool in a safe way
3334        * */
3335
3336       /* *INDENT-OFF* */
3337       pool_flush (vepitem, vsm->vepitems,
3338         ({
3339           if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
3340           {
3341               vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3342                                      vepitem->fd, NULL);
3343              vepitem_init (vepitem);
3344           }
3345         }));
3346       /* *INDENT-ON* */
3347
3348       pool_free (vsm->vepitems);
3349       hash_free (vsm->epitemidx_by_epfdfd);
3350
3351       /* free vepitemidxs for each epfd */
3352       /* *INDENT-OFF* */
3353       hash_foreach (epfd, vepitemidxs,
3354                     vsm->epitemidxs_by_epfd,
3355       ({
3356         vec_free (vepitemidxs);
3357       }));
3358       /* *INDENT-ON* */
3359       hash_free (vsm->epitemidxs_by_epfd);
3360
3361       /* free vepitemidxs for each fd */
3362       /* *INDENT-OFF* */
3363       hash_foreach (fd, vepitemidxs,
3364                     vsm->epitemidxs_by_fd,
3365       ({
3366         vec_free (vepitemidxs);
3367       }));
3368       /* *INDENT-ON* */
3369       hash_free (vsm->epitemidxs_by_fd);
3370
3371
3372       /*
3373        * from active list of vsockets,
3374        * close socket and vppcom session
3375        * */
3376
3377       /* *INDENT-OFF* */
3378       pool_foreach (vsock, vsm->vsockets,
3379         ({
3380           if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3381             {
3382               vppcom_session_close (vsock->sid);
3383               vcom_socket_close_socket (vsock->fd);
3384               vsocket_init (vsock);
3385             }
3386         }));
3387       /* *INDENT-ON* */
3388
3389       /*
3390        * return vsocket element to the pool
3391        * */
3392
3393       /* *INDENT-OFF* */
3394       pool_flush (vsock, vsm->vsockets,
3395         ({
3396           // vsocket_init(vsock);
3397           ;
3398         }));
3399       /* *INDENT-ON* */
3400
3401       pool_free (vsm->vsockets);
3402       hash_free (vsm->sockidx_by_fd);
3403
3404       /*
3405        * from active list of vepolls,
3406        * close epoll and vppcom_epoll
3407        * */
3408
3409       /* *INDENT-OFF* */
3410       pool_foreach (vepoll, vsm->vepolls,
3411         ({
3412           if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3413             {
3414               vppcom_session_close (vepoll->vep_idx);
3415               vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3416               vepoll_init (vepoll);
3417             }
3418         }));
3419       /* *INDENT-ON* */
3420
3421       /*
3422        * return vepoll element to the pool
3423        * */
3424
3425       /* *INDENT-OFF* */
3426       pool_flush (vepoll, vsm->vepolls,
3427         ({
3428           // vepoll_init(vepoll);
3429           ;
3430         }));
3431       /* *INDENT-ON* */
3432
3433       pool_free (vsm->vepolls);
3434       hash_free (vsm->epollidx_by_epfd);
3435
3436       vsm->init = 0;
3437     }
3438 }
3439
3440
3441 /*
3442  * fd.io coding-style-patch-verification: ON
3443  *
3444  * Local Variables:
3445  * eval: (c-set-style "gnu")
3446  * End:
3447  */