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