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