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