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