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