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