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