VCL/LDPRELOAD: Fix out-of-bounds access and inequality comparison coverity errors
[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 static inline int
1417 vcom_socket_copy_ep_to_sockaddr (__SOCKADDR_ARG __addr,
1418                                  socklen_t * __restrict __len,
1419                                  vppcom_endpt_t * ep)
1420 {
1421   int rv = 0;
1422   int sa_len, copy_len;
1423
1424   __addr->sa_family = (ep->is_ip4 == VPPCOM_IS_IP4) ? AF_INET : AF_INET6;
1425   switch (__addr->sa_family)
1426     {
1427     case AF_INET:
1428       ((struct sockaddr_in *) __addr)->sin_port = ep->port;
1429       if (*__len > sizeof (struct sockaddr_in))
1430         *__len = sizeof (struct sockaddr_in);
1431       sa_len = sizeof (struct sockaddr_in) - sizeof (struct in_addr);
1432       copy_len = *__len - sa_len;
1433       if (copy_len > 0)
1434         memcpy (&((struct sockaddr_in *) __addr)->sin_addr, ep->ip, copy_len);
1435       break;
1436
1437     case AF_INET6:
1438       ((struct sockaddr_in6 *) __addr)->sin6_port = ep->port;
1439       if (*__len > sizeof (struct sockaddr_in6))
1440         *__len = sizeof (struct sockaddr_in6);
1441       sa_len = sizeof (struct sockaddr_in6) - sizeof (struct in6_addr);
1442       copy_len = *__len - sa_len;
1443       if (copy_len > 0)
1444         memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
1445                 __in6_u.__u6_addr8, ep->ip, copy_len);
1446       break;
1447
1448     default:
1449       /* Not possible */
1450       rv = -EAFNOSUPPORT;
1451       break;
1452     }
1453
1454   return rv;
1455 }
1456
1457 int
1458 vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1459                          socklen_t * __restrict __len)
1460 {
1461   int rv = -1;
1462   vcom_socket_main_t *vsm = &vcom_socket_main;
1463   uword *p;
1464   vcom_socket_t *vsock;
1465   u8 src_addr[sizeof (struct sockaddr_in6)];
1466   vppcom_endpt_t ep;
1467
1468   p = hash_get (vsm->sockidx_by_fd, __fd);
1469   if (!p)
1470     return -EBADF;
1471
1472   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1473   if (!vsock)
1474     return -ENOTSOCK;
1475
1476   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1477     return -EINVAL;
1478
1479   if (!__addr || !__len)
1480     return -EFAULT;
1481
1482   ep.ip = src_addr;
1483   rv = vcom_session_getpeername (vsock->sid, &ep);
1484   if (rv == 0)
1485     rv = vcom_socket_copy_ep_to_sockaddr (__addr, __len, &ep);
1486
1487   return rv;
1488 }
1489
1490 ssize_t
1491 vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1492 {
1493   return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1494 }
1495
1496 ssize_t
1497 vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1498 {
1499   int rv = -1;
1500   rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1501   return rv;
1502 }
1503
1504 /*
1505  * RETURN   1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1506  * 0 otherwise
1507  * */
1508 int
1509 vcom_socket_is_connection_mode_socket (int __fd)
1510 {
1511   int rv = -1;
1512   /* TBD define new vppcom api */
1513   vcom_socket_main_t *vsm = &vcom_socket_main;
1514   uword *p;
1515   vcom_socket_t *vsock;
1516
1517   int type;
1518   socklen_t optlen;
1519
1520   p = hash_get (vsm->sockidx_by_fd, __fd);
1521
1522   if (p)
1523     {
1524       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1525       if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1526         {
1527           optlen = sizeof (type);
1528           rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1529           if (rv != 0)
1530             {
1531               return 0;
1532             }
1533           /* get socket type */
1534           switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1535             {
1536             case SOCK_STREAM:
1537             case SOCK_SEQPACKET:
1538               return 1;
1539               break;
1540
1541             default:
1542               return 0;
1543               break;
1544             }
1545         }
1546     }
1547   return 0;
1548 }
1549
1550 static inline ssize_t
1551 vcom_session_sendto (int __sid, void *__buf, size_t __n,
1552                      int __flags, __CONST_SOCKADDR_ARG __addr,
1553                      socklen_t __addr_len)
1554 {
1555   vppcom_endpt_t *ep = 0;
1556   vppcom_endpt_t _ep;
1557
1558   if (__addr)
1559     {
1560       ep = &_ep;
1561       ep->vrf = VPPCOM_VRF_DEFAULT;
1562       switch (__addr->sa_family)
1563         {
1564         case AF_INET:
1565           ep->is_ip4 = VPPCOM_IS_IP4;
1566           ep->ip =
1567             (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1568           ep->port =
1569             (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1570           break;
1571
1572         case AF_INET6:
1573           ep->is_ip4 = VPPCOM_IS_IP6;
1574           ep->ip =
1575             (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1576           ep->port =
1577             (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1578           break;
1579
1580         default:
1581           return -EAFNOSUPPORT;
1582         }
1583     }
1584
1585   return vppcom_session_sendto (__sid, __buf, __n, __flags, ep);;
1586 }
1587
1588 ssize_t
1589 vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1590                     int __flags, __CONST_SOCKADDR_ARG __addr,
1591                     socklen_t __addr_len)
1592 {
1593   vcom_socket_main_t *vsm = &vcom_socket_main;
1594   uword *p;
1595   vcom_socket_t *vsock;
1596
1597   if (!__buf)
1598     {
1599       return -EINVAL;
1600     }
1601
1602   p = hash_get (vsm->sockidx_by_fd, __fd);
1603   if (!p)
1604     return -EBADF;
1605
1606   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1607   if (!vsock)
1608     return -ENOTSOCK;
1609
1610   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1611     {
1612       return -EINVAL;
1613     }
1614
1615   if (vcom_socket_is_connection_mode_socket (__fd))
1616     {
1617       /* ignore __addr and _addr_len */
1618       /* and EISCONN may be returned when they are not NULL and 0 */
1619       if ((__addr != NULL) || (__addr_len != 0))
1620         {
1621           return -EISCONN;
1622         }
1623     }
1624   else
1625     {
1626       if (!__addr)
1627         {
1628           return -EDESTADDRREQ;
1629         }
1630       /* not a vppcom supported address family */
1631       if (!((__addr->sa_family == AF_INET) ||
1632             (__addr->sa_family == AF_INET6)))
1633         {
1634           return -EINVAL;
1635         }
1636     }
1637
1638   return vcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1639                               __flags, __addr, __addr_len);
1640 }
1641
1642 static inline ssize_t
1643 vcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1644                        int __flags, __SOCKADDR_ARG __addr,
1645                        socklen_t * __restrict __addr_len)
1646 {
1647   int rv;
1648   vppcom_endpt_t ep;
1649   u8 src_addr[sizeof (struct sockaddr_in6)];
1650
1651   if (__addr)
1652     {
1653       ep.ip = src_addr;
1654       rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, &ep);
1655
1656       if (rv > 0)
1657         rv = vcom_socket_copy_ep_to_sockaddr (__addr, __addr_len, &ep);
1658     }
1659   else
1660     rv = vppcom_session_recvfrom (__sid, __buf, __n, __flags, NULL);
1661
1662   return rv;
1663 }
1664
1665 ssize_t
1666 vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1667                       int __flags, __SOCKADDR_ARG __addr,
1668                       socklen_t * __restrict __addr_len)
1669 {
1670   int rv = -1;
1671   vcom_socket_main_t *vsm = &vcom_socket_main;
1672   uword *p;
1673   vcom_socket_t *vsock;
1674
1675   if (__addr && !__addr_len)
1676     return -EINVAL;
1677
1678   p = hash_get (vsm->sockidx_by_fd, __fd);
1679   if (!p)
1680     return -EBADF;
1681
1682   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1683   if (!vsock)
1684     return -ENOTSOCK;
1685
1686   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1687     {
1688       return -EINVAL;
1689     }
1690
1691   rv = vcom_session_recvfrom (vsock->sid, __buf, __n,
1692                               __flags, __addr, __addr_len);
1693   return rv;
1694 }
1695
1696 /* TBD: move it to vppcom */
1697 static inline ssize_t
1698 vcom_session_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1699 {
1700   int rv = -1;
1701   /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1702      (int)__n); */
1703   return rv;
1704 }
1705
1706 ssize_t
1707 vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1708 {
1709   int rv = -1;
1710   vcom_socket_main_t *vsm = &vcom_socket_main;
1711   uword *p;
1712   vcom_socket_t *vsock;
1713
1714   p = hash_get (vsm->sockidx_by_fd, __fd);
1715   if (!p)
1716     return -EBADF;
1717
1718   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1719   if (!vsock)
1720     return -ENOTSOCK;
1721
1722   if (vcom_socket_is_connection_mode_socket (__fd))
1723     {
1724       /* ignore __addr and _addr_len */
1725       /* and EISCONN may be returned when they are not NULL and 0 */
1726       if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1727         {
1728           return -EISCONN;
1729         }
1730     }
1731   else
1732     {
1733       /* TBD: validate __message->msg_name and __message->msg_namelen
1734        * and return -EINVAL on validation error
1735        * */
1736       ;
1737     }
1738
1739   rv = vcom_session_sendmsg (vsock->sid, __message, __flags);
1740
1741   return rv;
1742 }
1743
1744 #ifdef __USE_GNU
1745 int
1746 vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1747                       unsigned int __vlen, int __flags)
1748 {
1749
1750   /* TBD: define a new vppcom api */
1751   return 0;
1752 }
1753 #endif
1754
1755 /* TBD: move it to vppcom */
1756 static inline ssize_t
1757 vcom_session_recvmsg (int __sid, struct msghdr *__message, int __flags)
1758 {
1759   int rv = -1;
1760   /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1761      (int)__n); */
1762   rv = -EOPNOTSUPP;
1763   return rv;
1764 }
1765
1766 ssize_t
1767 vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1768 {
1769   int rv = -1;
1770   vcom_socket_main_t *vsm = &vcom_socket_main;
1771   uword *p;
1772   vcom_socket_t *vsock;
1773
1774   p = hash_get (vsm->sockidx_by_fd, __fd);
1775   if (!p)
1776     return -EBADF;
1777
1778   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1779   if (!vsock)
1780     return -ENOTSOCK;
1781
1782   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1783     return -EINVAL;
1784
1785   if (!__message)
1786     {
1787       return -EINVAL;
1788     }
1789
1790   /* validate __flags */
1791
1792   rv = vcom_session_recvmsg (vsock->sid, __message, __flags);
1793   return rv;
1794 }
1795
1796 #ifdef __USE_GNU
1797 int
1798 vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1799                       unsigned int __vlen, int __flags,
1800                       struct timespec *__tmo)
1801 {
1802   /* TBD: define a new vppcom api */
1803   return 0;
1804 }
1805 #endif
1806
1807 /* TBD: move it to vppcom */
1808 static inline int
1809 vcom_session_get_sockopt (int __sid, int __level, int __optname,
1810                           void *__restrict __optval,
1811                           socklen_t * __restrict __optlen)
1812 {
1813   int rv = 0;
1814
1815   /* 1. for socket level options that are NOT socket attributes
1816    *    and that has corresponding vpp options get from vppcom */
1817   switch (__level)
1818     {
1819     case SOL_SOCKET:
1820       switch (__optname)
1821         {
1822         case SO_ERROR:
1823           *(int *) __optval = 0;
1824           break;
1825         default:
1826           break;
1827         }
1828     default:
1829       break;
1830     }
1831   /* 2. unhandled options */
1832   return rv;
1833 }
1834
1835 int
1836 vcom_socket_getsockopt (int __fd, int __level, int __optname,
1837                         void *__restrict __optval,
1838                         socklen_t * __restrict __optlen)
1839 {
1840   int rv = -1;
1841   vcom_socket_main_t *vsm = &vcom_socket_main;
1842   uword *p;
1843   vcom_socket_t *vsock;
1844
1845   if (!__optval || !__optlen)
1846     return -EINVAL;
1847
1848   p = hash_get (vsm->sockidx_by_fd, __fd);
1849   if (!p)
1850     return -EBADF;
1851
1852   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1853   if (!vsock)
1854     return -ENOTSOCK;
1855
1856   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1857     return -EINVAL;
1858
1859   switch (__level)
1860     {
1861     case SOL_SOCKET:
1862       switch (__optname)
1863         {
1864 /*
1865  *  1. for socket level options that are socket attributes,
1866  *     get from libc_getsockopt.
1867  *  2. for socket level options that are NOT socket
1868  *     attributes and that has corresponding vpp options
1869  *     get from vppcom.
1870  *  3. for socket level options unimplemented
1871  *     return -ENOPROTOOPT */
1872         case SO_DEBUG:
1873         case SO_DONTROUTE:
1874         case SO_BROADCAST:
1875         case SO_SNDBUF:
1876         case SO_RCVBUF:
1877         case SO_REUSEADDR:
1878         case SO_REUSEPORT:
1879         case SO_KEEPALIVE:
1880         case SO_TYPE:
1881         case SO_PROTOCOL:
1882         case SO_DOMAIN:
1883         case SO_OOBINLINE:
1884         case SO_NO_CHECK:
1885         case SO_PRIORITY:
1886         case SO_LINGER:
1887         case SO_BSDCOMPAT:
1888         case SO_TIMESTAMP:
1889         case SO_TIMESTAMPNS:
1890         case SO_TIMESTAMPING:
1891         case SO_RCVTIMEO:
1892         case SO_SNDTIMEO:
1893         case SO_RCVLOWAT:
1894         case SO_SNDLOWAT:
1895         case SO_PASSCRED:
1896         case SO_PEERCRED:
1897         case SO_PEERNAME:
1898         case SO_ACCEPTCONN:
1899         case SO_PASSSEC:
1900         case SO_PEERSEC:
1901         case SO_MARK:
1902         case SO_RXQ_OVFL:
1903         case SO_WIFI_STATUS:
1904         case SO_PEEK_OFF:
1905         case SO_NOFCS:
1906         case SO_BINDTODEVICE:
1907         case SO_GET_FILTER:
1908         case SO_LOCK_FILTER:
1909         case SO_BPF_EXTENSIONS:
1910         case SO_SELECT_ERR_QUEUE:
1911 #ifdef CONFIG_NET_RX_BUSY_POLL
1912         case SO_BUSY_POLL:
1913 #endif
1914         case SO_MAX_PACING_RATE:
1915 #ifdef SO_INCOMING_CPU
1916         case SO_INCOMING_CPU:
1917 #endif
1918           rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1919           if (rv != 0)
1920             {
1921               rv = -errno;
1922               return rv;
1923             }
1924           break;
1925
1926         case SO_ERROR:
1927           rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1928                                          __optval, __optlen);
1929           break;
1930
1931         default:
1932           /* We implement the SO_SNDLOWAT etc to not be settable
1933            * (1003.1g 7).
1934            */
1935           return -ENOPROTOOPT;
1936         }
1937
1938       break;
1939
1940     default:
1941       /* 1. handle options that are NOT socket level options,
1942        *    but have corresponding vpp otions. */
1943       rv = vcom_session_get_sockopt (vsock->sid, __level, __optname,
1944                                      __optval, __optlen);
1945       break;
1946     }
1947
1948   return rv;
1949 }
1950
1951 /* TBD: move it to vppcom */
1952 static inline int
1953 vcom_session_setsockopt (int __sid, int __level, int __optname,
1954                          const void *__optval, socklen_t __optlen)
1955 {
1956   int rv = -EOPNOTSUPP;
1957
1958   switch (__level)
1959     {
1960     case SOL_TCP:
1961       switch (__optname)
1962         {
1963         case TCP_KEEPIDLE:
1964           rv =
1965             vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPIDLE, 0, 0);
1966           break;
1967         case TCP_KEEPINTVL:
1968           rv =
1969             vppcom_session_attr (__sid, VPPCOM_ATTR_SET_TCP_KEEPINTVL, 0, 0);
1970           break;
1971         default:
1972           break;
1973         }
1974       break;
1975     case SOL_IPV6:
1976       switch (__optname)
1977         {
1978         case IPV6_V6ONLY:
1979           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
1980           break;
1981         default:
1982           break;
1983         }
1984       break;
1985     case SOL_SOCKET:
1986       switch (__optname)
1987         {
1988         case SO_KEEPALIVE:
1989           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_KEEPALIVE, 0, 0);
1990           break;
1991         case SO_REUSEADDR:
1992           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
1993           break;
1994         case SO_BROADCAST:
1995           rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
1996           break;
1997         default:
1998           break;
1999         }
2000       break;
2001     default:
2002       break;
2003     }
2004
2005   return rv;
2006 }
2007
2008 int
2009 vcom_socket_setsockopt (int __fd, int __level, int __optname,
2010                         const void *__optval, socklen_t __optlen)
2011 {
2012   int rv = -1;
2013   vcom_socket_main_t *vsm = &vcom_socket_main;
2014   uword *p;
2015   vcom_socket_t *vsock;
2016
2017   p = hash_get (vsm->sockidx_by_fd, __fd);
2018   if (!p)
2019     return -EBADF;
2020
2021   vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2022   if (!vsock)
2023     return -ENOTSOCK;
2024
2025   if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
2026     return -EINVAL;
2027
2028   /*
2029    *      Options without arguments
2030    */
2031
2032   if (__optname == SO_BINDTODEVICE)
2033     {
2034       rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2035       if (rv != 0)
2036         {
2037           rv = -errno;
2038         }
2039       return rv;
2040     }
2041
2042   if (!__optval)
2043     return -EFAULT;
2044
2045   if (__optlen < sizeof (int))
2046     return -EINVAL;
2047
2048   switch (__level)
2049     {
2050     case SOL_IPV6:
2051       switch (__optname)
2052         {
2053         case IPV6_V6ONLY:
2054           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2055                                         __optval, __optlen);
2056           break;
2057         default:
2058           return -EOPNOTSUPP;
2059         }
2060       break;
2061     case SOL_TCP:
2062       switch (__optname)
2063         {
2064         case TCP_NODELAY:
2065           return 0;
2066         case TCP_KEEPIDLE:
2067         case TCP_KEEPINTVL:
2068           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2069                                         __optval, __optlen);
2070           break;
2071         default:
2072           return -EOPNOTSUPP;
2073         }
2074       break;
2075       /* handle options at socket level */
2076     case SOL_SOCKET:
2077       switch (__optname)
2078         {
2079         case SO_REUSEADDR:
2080         case SO_BROADCAST:
2081         case SO_KEEPALIVE:
2082           rv = vcom_session_setsockopt (vsock->sid, __level, __optname,
2083                                         __optval, __optlen);
2084           break;
2085
2086           /*
2087            * 1. for socket level options that are socket attributes,
2088            *    set it from libc_getsockopt
2089            * 2. for socket level options that are NOT socket
2090            *    attributes and that has corresponding vpp options
2091            *    set it from vppcom
2092            * 3. for socket level options unimplemented
2093            *    return -ENOPROTOOPT */
2094         case SO_DEBUG:
2095         case SO_DONTROUTE:
2096         case SO_SNDBUF:
2097         case SO_RCVBUF:
2098         case SO_REUSEPORT:
2099         case SO_TYPE:
2100         case SO_PROTOCOL:
2101         case SO_DOMAIN:
2102         case SO_ERROR:
2103         case SO_OOBINLINE:
2104         case SO_NO_CHECK:
2105         case SO_PRIORITY:
2106         case SO_LINGER:
2107         case SO_BSDCOMPAT:
2108         case SO_TIMESTAMP:
2109         case SO_TIMESTAMPNS:
2110         case SO_TIMESTAMPING:
2111         case SO_RCVTIMEO:
2112         case SO_SNDTIMEO:
2113         case SO_RCVLOWAT:
2114         case SO_SNDLOWAT:
2115         case SO_PASSCRED:
2116         case SO_PEERCRED:
2117         case SO_PEERNAME:
2118         case SO_ACCEPTCONN:
2119         case SO_PASSSEC:
2120         case SO_PEERSEC:
2121         case SO_MARK:
2122         case SO_RXQ_OVFL:
2123         case SO_WIFI_STATUS:
2124         case SO_PEEK_OFF:
2125         case SO_NOFCS:
2126           /*
2127            * SO_BINDTODEVICE already handled as
2128            * "Options without arguments" */
2129           /* case SO_BINDTODEVICE: */
2130         case SO_GET_FILTER:
2131         case SO_LOCK_FILTER:
2132         case SO_BPF_EXTENSIONS:
2133         case SO_SELECT_ERR_QUEUE:
2134 #ifdef CONFIG_NET_RX_BUSY_POLL
2135         case SO_BUSY_POLL:
2136 #endif
2137         case SO_MAX_PACING_RATE:
2138 #ifdef SO_INCOMING_CPU
2139         case SO_INCOMING_CPU:
2140 #endif
2141           rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
2142           if (rv != 0)
2143             {
2144               rv = -errno;
2145               return rv;
2146             }
2147           break;
2148
2149         default:
2150           /* We implement the SO_SNDLOWAT etc to not be settable
2151            * (1003.1g 7).
2152            */
2153           return -ENOPROTOOPT;
2154         }
2155
2156       break;
2157
2158     default:
2159       return -ENOPROTOOPT;
2160     }
2161
2162   return rv;
2163 }
2164
2165 int
2166 vcom_socket_listen (int __fd, int __n)
2167 {
2168   int rv = -1;
2169   vcom_socket_main_t *vsm = &vcom_socket_main;
2170   uword *p;
2171   vcom_socket_t *vsock;
2172
2173   p = hash_get (vsm->sockidx_by_fd, __fd);
2174   if (p)
2175     {
2176       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2177
2178       /* TBD vppcom to accept __n parameter */
2179       rv = vppcom_session_listen (vsock->sid, __n);
2180     }
2181
2182   return rv;
2183 }
2184
2185 static int
2186 vcom_socket_connected_socket (int __fd, int __sid,
2187                               int *__domain,
2188                               int *__type, int *__protocol, int flags)
2189 {
2190   int rv = -1;
2191   vcom_socket_main_t *vsm = &vcom_socket_main;
2192   vcom_socket_t *vsock;
2193
2194   i32 fd;
2195   i32 sockidx;
2196
2197   socklen_t optlen;
2198
2199   optlen = sizeof (*__domain);
2200   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2201   if (rv != 0)
2202     {
2203       rv = -errno;
2204       goto out;
2205     }
2206
2207   optlen = sizeof (*__type);
2208   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2209   if (rv != 0)
2210     {
2211       rv = -errno;
2212       goto out;
2213     }
2214
2215   optlen = sizeof (*__protocol);
2216   rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2217   if (rv != 0)
2218     {
2219       rv = -errno;
2220       goto out;
2221     }
2222
2223   fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2224   if (fd < 0)
2225     {
2226       rv = fd;
2227       goto out;
2228     }
2229
2230   pool_get (vsm->vsockets, vsock);
2231   vsocket_init (vsock);
2232
2233   sockidx = vsock - vsm->vsockets;
2234   hash_set (vsm->sockidx_by_fd, fd, sockidx);
2235
2236   vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2237   return fd;
2238
2239 out:
2240   return rv;
2241 }
2242
2243 /* If flag is 0, then accept4() is the same as accept().
2244  * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2245  */
2246 static int
2247 vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2248                           socklen_t * __restrict __addr_len, int flags)
2249 {
2250   int rv = -1;
2251   vcom_socket_main_t *vsm = &vcom_socket_main;
2252   uword *p;
2253   vcom_socket_t *vsock;
2254
2255   int fd;
2256   int sid;
2257   int domain;
2258   int type;
2259   int protocol;
2260
2261   uint8_t addr8[sizeof (struct in6_addr)];
2262   vppcom_endpt_t ep;
2263
2264   ep.ip = addr8;
2265
2266   /* validate flags */
2267
2268   /*
2269    * for documentation
2270    *  switch (flags)
2271    *   {
2272    *   case 0:
2273    *   case SOCK_NONBLOCK:
2274    *   case SOCK_CLOEXEC:
2275    *   case SOCK_NONBLOCK | SOCK_CLOEXEC:
2276    *     break;
2277    *
2278    *   default:
2279    *     return -1;
2280    *   }
2281    */
2282   /* flags can be 0 or can be bitwise OR
2283    * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2284
2285   if (VCOM_DEBUG > 2)
2286     fprintf (stderr, "[%d] vcom_socket_accept_flags: "
2287              "fd = %d, __addr = %p, __addr_len = %p  flags = %d (0x%x)\n",
2288              getpid (), __fd, __addr, __addr_len, flags, flags);
2289
2290   if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2291     {
2292       /* TBD: return proper error code */
2293       fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2294                "invalid flags = %d (0x%x)\n", getpid (), flags, flags);
2295
2296       return -1;
2297     }
2298
2299   /* TBD: return proper error code */
2300
2301   if (!vcom_socket_is_connection_mode_socket (__fd))
2302     {
2303       fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2304                "connection mode socket support TBD!\n", getpid ());
2305       return -EOPNOTSUPP;
2306     }
2307
2308   p = hash_get (vsm->sockidx_by_fd, __fd);
2309   if (p)
2310     {
2311       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2312
2313
2314       rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2315       if (rv < 0)
2316         {
2317           fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2318                    "vcom_fcnt() returned %d!\n", getpid (), rv);
2319           return rv;
2320         }
2321
2322       /* is blocking */
2323       if (!(rv & O_NONBLOCK))
2324         {
2325           /* socket is not marked as nonblocking
2326            * and no pending connections are present
2327            * on the queue, accept () blocks the caller
2328            * until a connection is present.
2329            */
2330           rv = vppcom_session_accept (vsock->sid, &ep,
2331                                       -1.0 /* wait forever */ );
2332         }
2333       else
2334         {
2335           /* The file descriptor refers to a socket and has been
2336            * marked nonblocking(O_NONBLOCK) and the accept would
2337            * block.
2338            * */
2339           /* is non blocking */
2340           rv = vppcom_session_accept (vsock->sid, &ep, 0);
2341           /* If the socket is marked nonblocking and
2342            * no pending connections are present on the
2343            * queue, accept fails with the error
2344            * EAGAIN or EWOULDBLOCK
2345            */
2346           if (rv == VPPCOM_ETIMEDOUT)
2347             {
2348               rv = VPPCOM_EAGAIN;
2349             }
2350         }
2351       if (rv < 0)
2352         {
2353           if (rv != VPPCOM_EAGAIN)
2354             fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2355                      "vppcom_session_accept() returned %d!", getpid (), rv);
2356           return rv;
2357         }
2358
2359       sid = rv;
2360
2361       /* create a new connected socket resource and set flags
2362        * on the new file descriptor.
2363        * update vsockets and sockidx_by_fd table
2364        * */
2365       fd = vcom_socket_connected_socket (__fd, sid,
2366                                          &domain, &type, &protocol, flags);
2367       if (fd < 0)
2368         {
2369           fprintf (stderr, "[%d] ERROR: vcom_socket_accept_flags: "
2370                    "vcom_socket_connected_socket() returned %d!",
2371                    getpid (), rv);
2372           return fd;
2373         }
2374
2375       rv = fd;
2376
2377       /* TBD populate __addr and __addr_len */
2378       /* TBD: The returned address is truncated if the buffer
2379        * provided is too small, in this case, __addr_len will
2380        * return a value greater than was supplied to the call.*/
2381       if (__addr)
2382         {
2383           if (ep.is_cut_thru)
2384             {
2385               /* TBD populate __addr and __addr_len */
2386               switch (domain)
2387                 {
2388                 case AF_INET:
2389                   ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2390                   ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2391                   memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2392                           addr8, sizeof (struct in_addr));
2393                   /* TBD: populate __addr_len */
2394                   if (__addr_len)
2395                     {
2396                       *__addr_len = sizeof (struct sockaddr_in);
2397                     }
2398                   break;
2399
2400                 case AF_INET6:
2401                   ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2402                   ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2403                   memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2404                           __in6_u.__u6_addr8, addr8,
2405                           sizeof (struct in6_addr));
2406                   /* TBD: populate __addr_len */
2407                   if (__addr_len)
2408                     {
2409                       *__addr_len = sizeof (struct sockaddr_in6);
2410                     }
2411                   break;
2412
2413                 default:
2414                   return -EAFNOSUPPORT;
2415                 }
2416             }
2417           else
2418             {
2419               switch (ep.is_ip4)
2420                 {
2421                 case VPPCOM_IS_IP4:
2422                   ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2423                   ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2424                   memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2425                           addr8, sizeof (struct in_addr));
2426                   /* TBD: populate __addr_len */
2427                   if (__addr_len)
2428                     {
2429                       *__addr_len = sizeof (struct sockaddr_in);
2430                     }
2431                   break;
2432
2433                 case VPPCOM_IS_IP6:
2434                   ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2435                   ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2436                   memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2437                           __in6_u.__u6_addr8, addr8,
2438                           sizeof (struct in6_addr));
2439                   /* TBD: populate __addr_len */
2440                   if (__addr_len)
2441                     {
2442                       *__addr_len = sizeof (struct sockaddr_in6);
2443                     }
2444                   break;
2445
2446                 default:
2447                   return -EAFNOSUPPORT;
2448                 }
2449             }
2450         }
2451     }
2452
2453   return rv;
2454 }
2455
2456 int
2457 vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2458                     socklen_t * __restrict __addr_len)
2459 {
2460   /* set flags to 0 for accept() */
2461   return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2462 }
2463
2464 int
2465 vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2466                      socklen_t * __restrict __addr_len, int __flags)
2467 {
2468   /*  SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2469   return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2470 }
2471
2472 /* TBD: move it to vppcom */
2473 static inline int
2474 vcom_session_shutdown (int __fd, int __how)
2475 {
2476   return 0;
2477 }
2478
2479 int
2480 vcom_socket_shutdown (int __fd, int __how)
2481 {
2482   int rv = -1;
2483   vcom_socket_main_t *vsm = &vcom_socket_main;
2484   uword *p;
2485   vcom_socket_t *vsock;
2486
2487   p = hash_get (vsm->sockidx_by_fd, __fd);
2488   if (p)
2489     {
2490       vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2491       switch (__how)
2492         {
2493         case SHUT_RD:
2494         case SHUT_WR:
2495         case SHUT_RDWR:
2496           rv = vcom_session_shutdown (vsock->sid, __how);
2497           return rv;
2498           break;
2499
2500         default:
2501           return -EINVAL;
2502           break;
2503         }
2504     }
2505
2506   return rv;
2507 }
2508
2509 int
2510 vcom_socket_epoll_create1 (int __flags)
2511 {
2512   int rv = -1;
2513   vcom_socket_main_t *vsm = &vcom_socket_main;
2514   vcom_epoll_t *vepoll;
2515
2516   i32 epfd;
2517   i32 vep_idx;
2518   i32 epollidx;
2519
2520   epfd = vcom_socket_open_epoll (__flags);
2521   if (epfd < 0)
2522     {
2523       rv = epfd;
2524       goto out;
2525     }
2526
2527   vep_idx = vppcom_epoll_create ();
2528   if (vep_idx < 0)
2529     {
2530       rv = vep_idx;
2531       goto out_close_epoll;
2532     }
2533
2534   pool_get (vsm->vepolls, vepoll);
2535   vepoll_init (vepoll);
2536
2537   epollidx = vepoll - vsm->vepolls;
2538   hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2539
2540   vepoll_set (vepoll, epfd, vep_idx, EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2541
2542   return epfd;
2543
2544 out_close_epoll:
2545   vcom_socket_close_epoll (epfd);
2546 out:
2547   return rv;
2548 }
2549
2550 /*
2551  * PRE: vppcom_epoll_ctl() is successful
2552  * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2553  */
2554 int
2555 vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2556                          struct epoll_event *__event,
2557                          i32 vep_idx, vcom_epoll_t * vepoll,
2558                          i32 vfd_id, void *vfd, vcom_fd_type_t type,
2559                          int free_vepitem_on_del)
2560 {
2561   int rv = -1;
2562   vcom_socket_main_t *vsm = &vcom_socket_main;
2563   vcom_epitem_t *vepitem;
2564
2565   vcom_epitem_key_t epfdfd = {.epfd = __epfd,.fd = __fd };
2566   uword *p;
2567   i32 vepitemidx;
2568
2569   i32 *vepitemidxs = 0;
2570
2571   struct epoll_event revent = {.events = 0,.data.fd = INVALID_FD };
2572
2573   i32 vec_idx;
2574
2575   /* perform control operations on the epoll instance */
2576   switch (__op)
2577     {
2578     case EPOLL_CTL_ADD:
2579       /*
2580        * supplied file descriptor is already
2581        * registered with this epoll instance
2582        * */
2583       /* vepitem exists */
2584       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2585       if (p)
2586         {
2587           rv = -EEXIST;
2588           goto out;
2589         }
2590
2591       /* add a new vepitem */
2592       pool_get (vsm->vepitems, vepitem);
2593       vepitem_init (vepitem);
2594
2595       vepitemidx = vepitem - vsm->vepitems;
2596       hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2597       vepitem_set (vepitem, __epfd, __fd, __fd, __fd, type, *__event, revent);
2598
2599       /* update epitemidxs */
2600       /* by_epfd */
2601       p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2602       if (!p)                   /*  not exist */
2603         {
2604           vepitemidxs = 0;
2605           vec_add1 (vepitemidxs, vepitemidx);
2606           hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2607         }
2608       else                      /*  exists */
2609         {
2610           vepitemidxs = *(i32 **) p;
2611           vec_add1 (vepitemidxs, vepitemidx);
2612           hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2613         }
2614       /* update epitemidxs */
2615       /* by_fd */
2616       p = hash_get (vsm->epitemidxs_by_fd, __fd);
2617       if (!p)                   /*  not exist */
2618         {
2619           vepitemidxs = 0;
2620           vec_add1 (vepitemidxs, vepitemidx);
2621           hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2622         }
2623       else                      /*  exists */
2624         {
2625           vepitemidxs = *(i32 **) p;
2626           vec_add1 (vepitemidxs, vepitemidx);
2627           hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2628         }
2629
2630       /* increment vepoll fd count by 1 */
2631       vepoll->count += 1;
2632
2633       rv = 0;
2634       goto out;
2635       break;
2636
2637     case EPOLL_CTL_MOD:
2638       /*
2639        * supplied file descriptor is not
2640        * registered with this epoll instance
2641        * */
2642       /* vepitem not exist */
2643       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2644       if (!p)
2645         {
2646           rv = -ENOENT;
2647           goto out;
2648         }
2649       vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2650       if (vepitem)
2651         {
2652           vepitem->event = *__event;
2653           vepitem->revent = revent;
2654         }
2655
2656       rv = 0;
2657       goto out;
2658       break;
2659
2660     case EPOLL_CTL_DEL:
2661       /*
2662        * supplied file descriptor is not
2663        * registered with this epoll instance
2664        * */
2665       /* vepitem not exist */
2666       p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2667       if (!p)
2668         {
2669           rv = -ENOENT;
2670           goto out;
2671         }
2672       vepitemidx = *(i32 *) p;
2673       hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2674
2675       /* update epitemidxs */
2676       /* by_epfd */
2677       p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2678       if (!p)                   /*  not exist */
2679         {
2680           rv = -ENOENT;
2681           goto out;
2682         }
2683       else                      /*  exists */
2684         {
2685           vepitemidxs = *(i32 **) p;
2686           vec_idx = vec_search (vepitemidxs, vepitemidx);
2687           if (vec_idx != ~0)
2688             {
2689               vec_del1 (vepitemidxs, vec_idx);
2690               if (!vec_len (vepitemidxs))
2691                 {
2692                   vec_free (vepitemidxs);
2693                   hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2694                 }
2695             }
2696         }
2697
2698       /* update epitemidxs */
2699       /* by_fd */
2700       p = hash_get (vsm->epitemidxs_by_fd, __fd);
2701       if (!p)                   /*  not exist */
2702         {
2703           rv = -ENOENT;
2704           goto out;
2705         }
2706       else                      /*  exists */
2707         {
2708           vepitemidxs = *(i32 **) p;
2709           vec_idx = vec_search (vepitemidxs, vepitemidx);
2710           if (vec_idx != ~0)
2711             {
2712               vec_del1 (vepitemidxs, vec_idx);
2713               if (!vec_len (vepitemidxs))
2714                 {
2715                   vec_free (vepitemidxs);
2716                   hash_unset (vsm->epitemidxs_by_fd, __fd);
2717                 }
2718             }
2719         }
2720
2721       /* pool put vepitem */
2722       vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2723       if (free_vepitem_on_del)
2724         {
2725           if (!vepitem)
2726             {
2727               rv = -ENOENT;
2728               goto out;
2729             }
2730           vepitem_init (vepitem);
2731           pool_put (vsm->vepitems, vepitem);
2732         }
2733       else
2734         {
2735           if (!vepitem)
2736             {
2737               vepitem_init (vepitem);
2738             }
2739         }
2740
2741       /* decrement vepoll fd count by 1 */
2742       vepoll->count -= 1;
2743
2744       rv = 0;
2745       goto out;
2746       break;
2747
2748     default:
2749       rv = -EINVAL;
2750       goto out;
2751       break;
2752     }
2753
2754 out:
2755   return rv;
2756 }
2757
2758 /*
2759  * PRE: 00. null pointer check on __event
2760  *      01. all other parameters are validated
2761  */
2762
2763 static int
2764 vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2765                                 struct epoll_event *__event,
2766                                 int free_vepitem_on_del)
2767 {
2768   int rv = -1;
2769   i32 cnt;
2770   vcom_epoll_t *vepoll;
2771   vcom_socket_t *vfd_vsock;
2772   i32 vep_idx;
2773   i32 sid;
2774
2775   /* get vep_idx and vepoll */
2776   vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2777   if (vep_idx == INVALID_VEP_IDX)
2778     {
2779       return -EBADF;
2780     }
2781
2782   /* get vcom fd type, vfd_id and vfd */
2783   sid = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2784   if ((sid != INVALID_SESSION_ID) &&
2785       vcom_socket_type_is_vppcom_bound (vfd_vsock->type))
2786     {
2787       rv = vppcom_epoll_ctl (vep_idx, __op, sid, __event);
2788       if (rv == VPPCOM_OK)
2789         {
2790           cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2791                  (__op == EPOLL_CTL_DEL) ? -1 : 0);
2792           vepoll->count += cnt;
2793           vepoll->vcl_cnt += cnt;
2794         }
2795       if (VCOM_DEBUG > 0)
2796         fprintf (stderr,
2797                  "[%d] vcom_socket_epoll_ctl_i: vppcom_epoll_ctl() "
2798                  "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2799                  "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
2800                  getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
2801                  vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
2802     }
2803   else
2804     {
2805       rv = libc_epoll_ctl (__epfd, __op, __fd, __event);
2806       if (rv == 0)
2807         {
2808           cnt = ((__op == EPOLL_CTL_ADD) ? 1 :
2809                  (__op == EPOLL_CTL_DEL) ? -1 : 0);
2810           vepoll->count += cnt;
2811           vepoll->libc_cnt += cnt;
2812         }
2813       if (VCOM_DEBUG > 0)
2814         fprintf (stderr,
2815                  "[%d] vcom_socket_epoll_ctl_i: libc_epoll_ctl() "
2816                  "returned %d\n\tepfd %d, vep_idx %d, fd %d sid %d op %d"
2817                  "\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
2818                  getpid (), rv, __epfd, vep_idx, __fd, sid, __op,
2819                  vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
2820     }
2821
2822   return rv;
2823 }
2824
2825 int
2826 vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2827                        struct epoll_event *__event)
2828 {
2829   int rv = -1;
2830
2831   rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 1);
2832   return rv;
2833 }
2834
2835 static int
2836 vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2837                         struct epoll_event *__event)
2838 {
2839   int rv = -1;
2840
2841   rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd, __event, 0);
2842   return rv;
2843 }
2844
2845 int
2846 vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2847                          int __maxevents, int __timeout,
2848                          const __sigset_t * __ss)
2849 {
2850   vcom_socket_main_t *vsm = &vcom_socket_main;
2851   int rv = -EBADF;
2852   int rv2;
2853   double time_to_wait = (double) 0;
2854   double timeout, now = 0;
2855   vcom_epoll_t *vepoll;
2856   i32 vep_idx;
2857   static struct epoll_event *libc_ev = 0;
2858
2859   /* validate __event */
2860   if (!__events || (__timeout < -1))
2861     {
2862       fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
2863                "Bad args __events %p, __timeout %d\n", getpid (),
2864                __events, __timeout);
2865       rv = -EFAULT;
2866       goto out;
2867     }
2868
2869   time_to_wait = ((__timeout >= 0) ? (double) __timeout / (double) 1000 : 0);
2870
2871   vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2872   if (vep_idx == INVALID_VEP_IDX)
2873     {
2874       fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: "
2875                "Bad epoll fd %d\n", getpid (), __epfd);
2876       return -EBADF;
2877     }
2878
2879   if (vepoll->count <= 0)
2880     {
2881       fprintf (stderr, "[%d] ERROR: vcom_socket_epoll_pwait: No events"
2882                " in epfd!\n\tcount %d, vcl_cnt %d, libc_cnt %d\n",
2883                getpid (), vepoll->count, vepoll->vcl_cnt, vepoll->libc_cnt);
2884       rv = -EINVAL;
2885       goto out;
2886     }
2887
2888   if (vepoll->libc_cnt == 0)
2889     {
2890       if (VCOM_DEBUG > 2)
2891         fprintf (stderr, "[%d] vcom_socket_epoll_pwait: libc_cnt = 0, "
2892                  "calling vppcom_epoll_wait() time_to_wait = %f\n",
2893                  getpid (), time_to_wait);
2894       rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, time_to_wait);
2895     }
2896   else if (vepoll->vcl_cnt == 0)
2897     {
2898       if (VCOM_DEBUG > 2)
2899         fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = 0, "
2900                  "calling libc_epoll_pwait()\n", getpid ());
2901       rv = libc_epoll_pwait (__epfd, __events, __maxevents, __timeout, __ss);
2902     }
2903   else
2904     {
2905       if (VCOM_DEBUG > 2)
2906         fprintf (stderr, "[%d] vcom_socket_epoll_pwait: vcl_cnt = %d, "
2907                  "libc_cnt = %d -> mixed polling (time_to_wait = %f, "
2908                  "__timeout = %d)\n",
2909                  getpid (), vepoll->vcl_cnt, vepoll->libc_cnt,
2910                  time_to_wait, __timeout);
2911       vec_validate (libc_ev, __maxevents);
2912       timeout = clib_time_now (&vsm->clib_time) + time_to_wait;
2913       do
2914         {
2915           rv = vppcom_epoll_wait (vep_idx, __events, __maxevents, 0);
2916           rv2 = libc_epoll_pwait (__epfd, libc_ev, __maxevents, 1, __ss);
2917           if (VCOM_DEBUG == 666)
2918             fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
2919                      "rv = %d, rv2 = %d, timeout = %f, now = %f\n",
2920                      getpid (), rv, rv2, timeout, now);
2921           if ((rv > 0) || (rv2 > 0))
2922             {
2923               if (VCOM_DEBUG > 2)
2924                 fprintf (stderr, "[%d] vcom_socket_epoll_pwait: "
2925                          "rv = %d, rv2 = %d\n", getpid (), rv, rv2);
2926               int n = __maxevents - rv;
2927               n = rv2 <= n ? rv2 : n;
2928               rv = (rv > 0) ? rv : 0;
2929
2930               clib_memcpy (&__events[rv], libc_ev, n * sizeof (*libc_ev));
2931               rv += rv2;
2932               goto out;
2933             }
2934           else if ((rv < 0) || (rv2 < 0))
2935             {
2936               if (rv < 0)
2937                 fprintf (stderr,
2938                          "[%d] ERROR: vppcom_epoll_wait() returned %d\n",
2939                          getpid (), rv);
2940               if (rv2 < 0)
2941                 {
2942                   fprintf (stderr,
2943                            "[%d] ERROR: libc_epoll_wait() failed, errno %d\n",
2944                            getpid (), errno);
2945                   rv = (rv < 0) ? rv : -errno;
2946                 }
2947               goto out;
2948             }
2949           if (__timeout != -1)
2950             now = clib_time_now (&vsm->clib_time);
2951         }
2952       while (now < timeout);
2953     }
2954
2955 out:
2956   vec_reset_length (libc_ev);
2957   return rv;
2958 }
2959
2960 static inline void
2961 vcom_pollfds_2_selectfds (
2962                            /* src */
2963                            struct pollfd *__fds, nfds_t __nfds,
2964                            /* dest */
2965                            int vcom_nfds,
2966                            fd_set * __restrict vcom_readfds,
2967                            fd_set * __restrict vcom_writefds,
2968                            fd_set * __restrict vcom_exceptfds)
2969 {
2970   nfds_t fds_idx = 0;
2971
2972   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
2973     {
2974       /* ignore negative fds */
2975       if (__fds[fds_idx].fd < 0)
2976         {
2977           continue;
2978         }
2979
2980       /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
2981       FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
2982
2983       /* requested events */
2984       if (__fds[fds_idx].events)
2985         {
2986           if (__fds[fds_idx].events & POLLIN)
2987             {
2988               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2989             }
2990           if (__fds[fds_idx].events & POLLPRI)
2991             {
2992               FD_SET (__fds[fds_idx].fd, vcom_readfds);
2993             }
2994           if (__fds[fds_idx].events & POLLOUT)
2995             {
2996               FD_SET (__fds[fds_idx].fd, vcom_writefds);
2997             }
2998 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
2999           if (__fds[fds_idx].events & POLLRDNORM)
3000             {
3001               FD_SET (__fds[fds_idx].fd, vcom_readfds);
3002             }
3003           if (__fds[fds_idx].events & POLLRDBAND)
3004             {
3005               FD_SET (__fds[fds_idx].fd, vcom_readfds);
3006             }
3007           if (__fds[fds_idx].events & POLLWRNORM)
3008             {
3009               FD_SET (__fds[fds_idx].fd, vcom_writefds);
3010             }
3011           if (__fds[fds_idx].events & POLLWRBAND)
3012             {
3013               FD_SET (__fds[fds_idx].fd, vcom_writefds);
3014             }
3015 #endif
3016         }
3017     }                           /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3018 }
3019
3020 static inline void
3021 vcom_selectfds_2_pollfds (
3022                            /* dest */
3023                            struct pollfd *__fds, nfds_t __nfds, int *nfd,
3024                            /* src */
3025                            int vcom_nfds,
3026                            fd_set * __restrict vcom_readfds,
3027                            fd_set * __restrict vcom_writefds,
3028                            fd_set * __restrict vcom_exceptfds)
3029 {
3030   nfds_t fds_idx = 0;
3031
3032
3033   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3034     {
3035       /* ignore negative fds */
3036       if (__fds[fds_idx].fd < 0)
3037         {
3038           __fds[fds_idx].revents = 0;
3039         }
3040
3041       /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
3042       if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
3043         {
3044           /*
3045            * TBD: for now any select exception
3046            *      is flagged as POLLERR
3047            * */
3048           __fds[fds_idx].revents |= POLLERR;
3049         }
3050
3051       /* requested events */
3052       if (__fds[fds_idx].events & POLLIN)
3053         {
3054           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3055             {
3056               __fds[fds_idx].revents |= POLLIN;
3057             }
3058         }
3059       if (__fds[fds_idx].events & POLLPRI)
3060         {
3061           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3062             {
3063               __fds[fds_idx].revents |= POLLIN;
3064             }
3065         }
3066       if (__fds[fds_idx].events & POLLOUT)
3067         {
3068           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3069             {
3070               __fds[fds_idx].revents |= POLLOUT;
3071             }
3072         }
3073 #if defined __USE_XOPEN || defined __USE_XOPEN2K8
3074       if (__fds[fds_idx].events & POLLRDNORM)
3075         {
3076           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3077             {
3078               __fds[fds_idx].revents |= POLLRDNORM;
3079             }
3080         }
3081       if (__fds[fds_idx].events & POLLRDBAND)
3082         {
3083           if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
3084             {
3085               __fds[fds_idx].revents |= POLLRDBAND;
3086             }
3087         }
3088       if (__fds[fds_idx].events & POLLWRNORM)
3089         {
3090           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3091             {
3092               __fds[fds_idx].revents |= POLLWRNORM;
3093             }
3094         }
3095       if (__fds[fds_idx].events & POLLWRBAND)
3096         {
3097           if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
3098             {
3099               __fds[fds_idx].revents |= POLLWRBAND;
3100             }
3101         }
3102 #endif
3103     }                           /* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
3104
3105   /*
3106    * nfd:
3107    * the number of structures which have nonzero revents  fields
3108    * (in  other  words,  those  descriptors  with events or
3109    * errors reported)
3110    * */
3111   *nfd = 0;
3112   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3113     {
3114       /* ignore negative fds */
3115       if (__fds[fds_idx].fd < 0)
3116         {
3117           continue;
3118         }
3119
3120       if (__fds[fds_idx].revents)
3121         {
3122           (*nfd)++;
3123         }
3124     }
3125 }
3126
3127 /*
3128  * PRE: parameters are validated,
3129  *      vcom_socket_poll is always called with __timeout set to zero
3130  *      hence returns immediately
3131  *
3132  * ACTION: handle non negative validated vcom fds and ignore rest
3133  */
3134
3135 /*
3136  * implements vcom_socket_poll () interface
3137  *
3138  * internally uses vcom_socket_select ()
3139  * to realize the behavior
3140  * */
3141 int
3142 vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
3143                               int __timeout)
3144 {
3145   int rv;
3146
3147   nfds_t fds_idx = 0;
3148   int nfd = 0;
3149
3150   /* vcom */
3151   int vcom_nfds = 0;
3152   fd_set vcom_readfds;
3153   fd_set vcom_writefds;
3154   fd_set vcom_exceptfds;
3155   int vcom_nfd = -1;
3156   /* invalid max_vcom_fd is -1 */
3157   int max_vcom_fd = -1;
3158
3159   /* __timeout is zero to get ready events and return immediately */
3160   struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
3161
3162   /* validate __nfds from select perspective */
3163   if (__nfds > FD_SETSIZE)
3164     {
3165       rv = -EINVAL;
3166       goto poll_done;
3167     }
3168
3169   /* zero vcom fd sets */
3170   /*
3171    * V vcom fd set
3172    */
3173 #define _(V)      \
3174     FD_ZERO ((V))
3175
3176   _(&vcom_readfds);
3177   _(&vcom_writefds);
3178   _(&vcom_exceptfds);
3179 #undef _
3180
3181   vcom_nfds = 0;
3182   vcom_nfd = -1;
3183
3184
3185   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3186     {
3187       /* ignore negative fds */
3188       if (__fds[fds_idx].fd < 0)
3189         {
3190           continue;
3191         }
3192
3193       /* non negative validated vcom fds */
3194       if (__fds[fds_idx].fd > FD_SETSIZE)
3195         {
3196           rv = -EINVAL;
3197           goto poll_done;
3198         }
3199
3200       /* max_vcom_fd and vcom_nfd */
3201       if (__fds[fds_idx].fd > max_vcom_fd)
3202         {
3203           /* requested events */
3204           if (__fds[fds_idx].events)
3205             {
3206               max_vcom_fd = __fds[fds_idx].fd;
3207             }
3208         }
3209       ++vcom_nfd;
3210     }
3211
3212   vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
3213
3214   if (!vcom_nfds)
3215     {
3216       rv = vcom_nfds;
3217       goto poll_done;
3218     }
3219
3220   vcom_pollfds_2_selectfds (
3221                              /* src */
3222                              __fds, __nfds,
3223                              /* dest */
3224                              vcom_nfds,
3225                              &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3226
3227   /* select on vcom fds */
3228   vcom_nfd = vcom_socket_select (vcom_nfds,
3229                                  &vcom_readfds,
3230                                  &vcom_writefds, &vcom_exceptfds, &tv);
3231   if (VCOM_DEBUG > 2)
3232     fprintf (stderr,
3233              "[%d] vcom_socket_select: "
3234              "'%04d'='%04d'\n", getpid (), vcom_nfd, vcom_nfds);
3235
3236   if (vcom_nfd < 0)
3237     {
3238       rv = vcom_nfd;
3239       goto poll_done;
3240     }
3241
3242   vcom_selectfds_2_pollfds (
3243                              /* dest */
3244                              __fds, __nfds, &nfd,
3245                              /* src */
3246                              vcom_nfds,
3247                              &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
3248
3249   rv = nfd;
3250
3251 poll_done:
3252   return rv;
3253 }
3254
3255 /*
3256  * TBD: remove this static function once vppcom
3257  *      has an implementation in place
3258  *
3259  * ACTION:
3260  */
3261 static int
3262 vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
3263 {
3264   return -EOPNOTSUPP;
3265 }
3266
3267 int
3268 vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
3269                               int __timeout)
3270 {
3271   nfds_t fds_idx = 0;
3272
3273   /* in seconds eg. 3.123456789 seconds */
3274   double time_to_wait = (double) 0;
3275
3276   i32 sid;
3277   i32 vep_idx;
3278
3279   /* replace vcom fd with session idx */
3280   for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
3281     {
3282       /* ignore negative fds */
3283       if (__fds[fds_idx].fd < 0)
3284         {
3285           continue;
3286         }
3287
3288       /* non negative validated vcom fds */
3289       sid = vcom_socket_get_sid (__fds[fds_idx].fd);
3290       if (sid != INVALID_SESSION_ID)
3291         {
3292           __fds[fds_idx].fd = sid;
3293         }
3294       else
3295         {
3296           /* get vep_idx */
3297           vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
3298           if (vep_idx != INVALID_VEP_IDX)
3299             {
3300               __fds[fds_idx].fd = vep_idx;
3301             }
3302           else
3303             {
3304               return -EBADF;
3305             }
3306         }
3307     }
3308
3309   /* validate __timeout */
3310   if (__timeout > 0)
3311     {
3312       time_to_wait = (double) __timeout / (double) 1000;
3313     }
3314   else if (__timeout == 0)
3315     {
3316       time_to_wait = (double) 0;
3317     }
3318   else
3319     {
3320       time_to_wait = ~0;
3321     }
3322
3323   return vppcom_poll (__fds, __nfds, time_to_wait);
3324 }
3325
3326 int
3327 vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
3328 {
3329   /* select an implementation */
3330
3331   /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
3332   return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
3333 }
3334
3335 #ifdef __USE_GNU
3336 int
3337 vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
3338                    const struct timespec *__timeout, const __sigset_t * __ss)
3339 {
3340   return -EOPNOTSUPP;
3341 }
3342 #endif
3343
3344 int
3345 vcom_socket_main_init (void)
3346 {
3347   vcom_socket_main_t *vsm = &vcom_socket_main;
3348
3349   if (VCOM_DEBUG > 0)
3350     printf ("vcom_socket_main_init\n");
3351
3352   if (!vsm->init)
3353     {
3354       /* TBD: define FD_MAXSIZE and use it here */
3355       pool_alloc (vsm->vsockets, FD_SETSIZE);
3356       vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
3357
3358       pool_alloc (vsm->vepolls, FD_SETSIZE);
3359       vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
3360
3361       pool_alloc (vsm->vepitems, FD_SETSIZE);
3362       vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
3363
3364       vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
3365       vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
3366
3367       clib_time_init (&vsm->clib_time);
3368
3369       vsm->init = 1;
3370     }
3371
3372   return 0;
3373 }
3374
3375
3376 void
3377 vcom_socket_main_show (void)
3378 {
3379   vcom_socket_main_t *vsm = &vcom_socket_main;
3380   vcom_socket_t *vsock;
3381
3382   vcom_epoll_t *vepoll;
3383
3384   vcom_epitem_t *vepitem;
3385
3386   i32 epfd;
3387   i32 fd;
3388   i32 *vepitemidxs, *vepitemidxs_var;
3389
3390   if (vsm->init)
3391     {
3392       /* from active list of vsockets show vsock */
3393
3394       /* *INDENT-OFF* */
3395       pool_foreach (vsock, vsm->vsockets,
3396         ({
3397           printf(
3398                  "fd='%04d', sid='%08x',type='%-30s'\n",
3399                  vsock->fd, vsock->sid,
3400                  vcom_socket_type_str (vsock->type));
3401         }));
3402       /* *INDENT-ON* */
3403
3404       /* from active list of vepolls, show vepoll */
3405
3406       /* *INDENT-OFF* */
3407       pool_foreach (vepoll, vsm->vepolls,
3408         ({
3409           printf(
3410                  "epfd='%04d', vep_idx='%08x', "
3411                  "type='%-30s', "
3412                  "flags='%d', count='%d', close='%d'\n",
3413                  vepoll->epfd, vepoll->vep_idx,
3414                  vcom_socket_epoll_type_str (vepoll->type),
3415                  vepoll->flags, vepoll->count, vepoll->close);
3416         }));
3417       /* *INDENT-ON* */
3418
3419       /* from active list of vepitems, show vepitem */
3420
3421       /* *INDENT-OFF* */
3422       pool_foreach (vepitem, vsm->vepitems,
3423         ({
3424           printf(
3425                  "epfd='%04d', fd='%04d', "
3426                  "next_fd='%04d', prev_fd='%04d', "
3427                  "type='%-30s', "
3428                  "events='%04x', revents='%04x'\n",
3429                  vepitem->epfd, vepitem->fd,
3430                  vepitem->next_fd, vepitem->prev_fd,
3431                  vcom_socket_vcom_fd_type_str (vepitem->type),
3432                  vepitem->event.events, vepitem->revent.events);
3433         }));
3434
3435       /* *INDENT-ON* */
3436
3437       /* show epitemidxs for epfd */
3438       /* *INDENT-OFF* */
3439       hash_foreach (epfd, vepitemidxs,
3440                     vsm->epitemidxs_by_epfd,
3441       ({
3442         printf("\n[ '%04d': ", epfd);
3443         vec_foreach (vepitemidxs_var,vepitemidxs)
3444         {
3445           printf("'%04d' ", (int)vepitemidxs_var[0]);
3446         }
3447         printf("]\n");
3448       }));
3449       /* *INDENT-ON* */
3450
3451       /* show epitemidxs for fd */
3452       /* *INDENT-OFF* */
3453       hash_foreach (fd, vepitemidxs,
3454                     vsm->epitemidxs_by_fd,
3455       ({
3456         printf("\n{ '%04d': ", fd);
3457         vec_foreach (vepitemidxs_var,vepitemidxs)
3458         {
3459           printf("'%04d' ", (int)vepitemidxs_var[0]);
3460         }
3461         printf("}\n");
3462       }));
3463       /* *INDENT-ON* */
3464
3465     }
3466 }
3467
3468 void
3469 vcom_socket_main_destroy (void)
3470 {
3471   vcom_socket_main_t *vsm = &vcom_socket_main;
3472   vcom_socket_t *vsock;
3473
3474   vcom_epoll_t *vepoll;
3475
3476   vcom_epitem_t *vepitem;
3477
3478   i32 epfd;
3479   i32 fd;
3480   i32 *vepitemidxs;
3481
3482
3483   if (VCOM_DEBUG > 0)
3484     printf ("vcom_socket_main_destroy\n");
3485
3486   if (vsm->init)
3487     {
3488
3489       /*
3490        * from active list of vepitems,
3491        * remove all "vepitem" elements from the pool in a safe way
3492        * */
3493
3494       /* *INDENT-OFF* */
3495       pool_flush (vepitem, vsm->vepitems,
3496         ({
3497           if ((vepitem->type == FD_TYPE_EPOLL) ||
3498               (vepitem->type == FD_TYPE_VCOM_SOCKET))
3499           {
3500              vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
3501                                      vepitem->fd, NULL);
3502              vepitem_init (vepitem);
3503           }
3504         }));
3505       /* *INDENT-ON* */
3506
3507       pool_free (vsm->vepitems);
3508       hash_free (vsm->epitemidx_by_epfdfd);
3509
3510       /* free vepitemidxs for each epfd */
3511       /* *INDENT-OFF* */
3512       hash_foreach (epfd, vepitemidxs,
3513                     vsm->epitemidxs_by_epfd,
3514       ({
3515         vec_free (vepitemidxs);
3516       }));
3517       /* *INDENT-ON* */
3518       hash_free (vsm->epitemidxs_by_epfd);
3519
3520       /* free vepitemidxs for each fd */
3521       /* *INDENT-OFF* */
3522       hash_foreach (fd, vepitemidxs,
3523                     vsm->epitemidxs_by_fd,
3524       ({
3525         vec_free (vepitemidxs);
3526       }));
3527       /* *INDENT-ON* */
3528       hash_free (vsm->epitemidxs_by_fd);
3529
3530
3531       /*
3532        * from active list of vsockets,
3533        * close socket and vppcom session
3534        * */
3535
3536       /* *INDENT-OFF* */
3537       pool_foreach (vsock, vsm->vsockets,
3538         ({
3539           if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
3540             {
3541               vppcom_session_close (vsock->sid);
3542               vcom_socket_close_socket (vsock->fd);
3543               vsocket_init (vsock);
3544             }
3545         }));
3546       /* *INDENT-ON* */
3547
3548       /*
3549        * return vsocket element to the pool
3550        * */
3551
3552       /* *INDENT-OFF* */
3553       pool_flush (vsock, vsm->vsockets,
3554         ({
3555           // vsocket_init(vsock);
3556           ;
3557         }));
3558       /* *INDENT-ON* */
3559
3560       pool_free (vsm->vsockets);
3561       hash_free (vsm->sockidx_by_fd);
3562
3563       /*
3564        * from active list of vepolls,
3565        * close epoll and vppcom_epoll
3566        * */
3567
3568       /* *INDENT-OFF* */
3569       pool_foreach (vepoll, vsm->vepolls,
3570         ({
3571           if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
3572             {
3573               vppcom_session_close (vepoll->vep_idx);
3574               vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
3575               vepoll_init (vepoll);
3576             }
3577         }));
3578       /* *INDENT-ON* */
3579
3580       /*
3581        * return vepoll element to the pool
3582        * */
3583
3584       /* *INDENT-OFF* */
3585       pool_flush (vepoll, vsm->vepolls,
3586         ({
3587           // vepoll_init(vepoll);
3588           ;
3589         }));
3590       /* *INDENT-ON* */
3591
3592       pool_free (vsm->vepolls);
3593       hash_free (vsm->epollidx_by_epfd);
3594
3595       vsm->init = 0;
3596     }
3597 }
3598
3599
3600 /*
3601  * fd.io coding-style-patch-verification: ON
3602  *
3603  * Local Variables:
3604  * eval: (c-set-style "gnu")
3605  * End:
3606  */