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