vcom_socket.c revision bea87a67
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
22#include <vppinfra/types.h>
23#include <vppinfra/hash.h>
24#include <vppinfra/pool.h>
25
26#include <libvcl-ldpreload/vcom_socket.h>
27#include <libvcl-ldpreload/vcom_socket_wrapper.h>
28#include <libvcl-ldpreload/vcom.h>
29
30#include <uri/vppcom.h>
31
32
33/*
34 * VCOM_SOCKET Private definitions and functions.
35 */
36
37typedef struct vcom_socket_main_t_
38{
39  u8 init;
40
41  /* vcom_socket pool */
42  vcom_socket_t *vsockets;
43
44  /* Hash table for socketidx to fd mapping */
45  uword *sockidx_by_fd;
46
47  /* vcom_epoll pool */
48  vcom_epoll_t *vepolls;
49
50  /* Hash table for epollidx to epfd mapping */
51  uword *epollidx_by_epfd;
52
53
54  /* common epitem poll for all epfd */
55  /* TBD: epitem poll per epfd */
56  /* vcom_epitem pool */
57  vcom_epitem_t *vepitems;
58
59  /* Hash table for epitemidx to epfdfd mapping */
60  uword *epollidx_by_epfdfd;
61
62  /* Hash table - key:epfd, value:vec of epitemidx */
63  uword *epitemidxs_by_epfd;
64  /* Hash table - key:fd, value:vec of epitemidx */
65  uword *epitemidxs_by_fd;
66
67} vcom_socket_main_t;
68
69vcom_socket_main_t vcom_socket_main;
70
71
72static int
73vcom_socket_open_socket (int domain, int type, int protocol)
74{
75  int rv = -1;
76
77  /* handle domains implemented by vpp */
78  switch (domain)
79    {
80    case AF_INET:
81    case AF_INET6:
82      /* get socket type and
83       * handle the socket types supported by vpp */
84      switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
85        {
86        case SOCK_STREAM:
87        case SOCK_DGRAM:
88          /* the type argument serves a second purpose,
89           * in addition to specifying a socket type,
90           * it may include the bitwise OR of any of
91           * SOCK_NONBLOCK and SOCK_CLOEXEC, to modify
92           * the behavior of socket. */
93          rv = libc_socket (domain, type, protocol);
94          if (rv == -1)
95            rv = -errno;
96          break;
97
98        default:
99          break;
100        }
101
102      break;
103
104    default:
105      break;
106    }
107
108  return rv;
109}
110
111static int
112vcom_socket_open_epoll (int flags)
113{
114  int rv = -1;
115
116  if (flags < 0)
117    {
118      return -EINVAL;
119    }
120  if (flags && (flags & ~EPOLL_CLOEXEC))
121    {
122      return -EINVAL;
123    }
124
125  /* flags can be either zero or EPOLL_CLOEXEC */
126  rv = libc_epoll_create1 (flags);
127  if (rv == -1)
128    rv = -errno;
129
130  return rv;
131}
132
133static int
134vcom_socket_close_socket (int fd)
135{
136  int rv;
137
138  rv = libc_close (fd);
139  if (rv == -1)
140    rv = -errno;
141
142  return rv;
143}
144
145static int
146vcom_socket_close_epoll (int epfd)
147{
148  int rv;
149
150  rv = libc_close (epfd);
151  if (rv == -1)
152    rv = -errno;
153
154  return rv;
155}
156
157/*
158 * Public API functions
159 */
160
161int
162vcom_socket_main_init (void)
163{
164  vcom_socket_main_t *vsm = &vcom_socket_main;
165
166  if (VCOM_DEBUG > 0)
167    printf ("vcom_socket_main_init\n");
168
169  if (!vsm->init)
170    {
171      /* TBD: define FD_MAXSIZE and use it here */
172      pool_alloc (vsm->vsockets, FD_SETSIZE);
173      vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
174
175      pool_alloc (vsm->vepolls, FD_SETSIZE);
176      vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
177
178      pool_alloc (vsm->vepitems, FD_SETSIZE);
179      vsm->epitemidxs_by_epfd = hash_create (0, sizeof (uword *));
180      vsm->epitemidxs_by_fd = hash_create (0, sizeof (uword *));
181
182      vsm->init = 1;
183    }
184
185  return 0;
186}
187
188void
189vcom_socket_main_destroy (void)
190{
191  vcom_socket_main_t *vsm = &vcom_socket_main;
192  vcom_socket_t *vsock;
193
194  vcom_epoll_t *vepoll;
195
196  if (VCOM_DEBUG > 0)
197    printf ("vcom_socket_main_destroy\n");
198
199  if (vsm->init)
200    {
201      /*
202       * from active list of vsockets,
203       * close socket and vppcom session
204       * */
205
206      /* *INDENT-OFF* */
207      pool_foreach (vsock, vsm->vsockets,
208        ({
209          if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
210            {
211              vppcom_session_close (vsock->sid);
212              vcom_socket_close_socket (vsock->fd);
213              vsocket_init (vsock);
214            }
215        }));
216      /* *INDENT-ON* */
217
218      /*
219       * return vsocket element to the pool
220       * */
221
222      /* *INDENT-OFF* */
223      pool_flush (vsock, vsm->vsockets,
224        ({
225          // vsocket_init(vsock);
226          ;
227        }));
228      /* *INDENT-ON* */
229
230      pool_free (vsm->vsockets);
231      hash_free (vsm->sockidx_by_fd);
232
233      /*
234       * from active list of vepolls,
235       * close epoll and vppcom_epoll
236       * */
237
238      /* *INDENT-OFF* */
239      pool_foreach (vepoll, vsm->vepolls,
240        ({
241          if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
242            {
243              vppcom_session_close (vepoll->vep_idx);
244              vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
245              vepoll_init (vepoll);
246            }
247        }));
248      /* *INDENT-ON* */
249
250      /*
251       * return vepoll element to the pool
252       * */
253
254      /* *INDENT-OFF* */
255      pool_flush (vepoll, vsm->vepolls,
256        ({
257          // vepoll_init(vepoll);
258          ;
259        }));
260      /* *INDENT-ON* */
261
262      pool_free (vsm->vepolls);
263      hash_free (vsm->epollidx_by_epfd);
264
265
266      vsm->init = 0;
267    }
268}
269
270void
271vcom_socket_main_show (void)
272{
273  vcom_socket_main_t *vsm = &vcom_socket_main;
274  vcom_socket_t *vsock;
275
276  vcom_epoll_t *vepoll;
277  vcom_epitem_t *vepitem;
278
279  if (vsm->init)
280    {
281      /* from active list of vsockets show vsock */
282
283      /* *INDENT-OFF* */
284      pool_foreach (vsock, vsm->vsockets,
285        ({
286          printf(
287                 "fd='%04d', sid='%08x',type='%-30s'\n",
288                 vsock->fd, vsock->sid,
289                 vcom_socket_type_str (vsock->type));
290        }));
291      /* *INDENT-ON* */
292
293      /* from active list of vepolls, show vepoll */
294
295      /* *INDENT-OFF* */
296      pool_foreach (vepoll, vsm->vepolls,
297        ({
298          printf(
299                 "epfd='%04d', vep_idx='%08x', "
300                 "type='%-30s', "
301                 "flags='%d', count='%d', close='%d'\n",
302                 vepoll->epfd, vepoll->vep_idx,
303                 vcom_socket_epoll_type_str (vepoll->type),
304                 vepoll->flags, vepoll->count, vepoll->close);
305        }));
306      /* *INDENT-ON* */
307
308      /* from active list of vepitems, show vepitem */
309
310      /* *INDENT-OFF* */
311      pool_foreach (vepitem, vsm->vepitems,
312        ({
313          printf(
314                 "epfd='%04d', fd='%04d', "
315                 "next_fd='%04d', prev_fd='%04d', "
316                 "type='%-30s', "
317                 "events='%04x', revents='%04x'\n",
318                 vepitem->epfd, vepitem->fd,
319                 vepitem->next_fd, vepitem->prev_fd,
320                 vcom_socket_vcom_fd_type_str (vepitem->type),
321                 vepitem->event.events, vepitem->revent.events);
322        }));
323      /* *INDENT-ON* */
324    }
325}
326
327int
328vcom_socket_is_vcom_fd (int fd)
329{
330  vcom_socket_main_t *vsm = &vcom_socket_main;
331  uword *p;
332  vcom_socket_t *vsock;
333
334  p = hash_get (vsm->sockidx_by_fd, fd);
335
336  if (p)
337    {
338      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
339      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
340        return 1;
341    }
342  return 0;
343}
344
345int
346vcom_socket_is_vcom_epfd (int epfd)
347{
348  vcom_socket_main_t *vsm = &vcom_socket_main;
349  uword *p;
350  vcom_epoll_t *vepoll;
351
352  p = hash_get (vsm->epollidx_by_epfd, epfd);
353
354  if (p)
355    {
356      vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
357      if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
358        return 1;
359    }
360  return 0;
361}
362
363static inline int
364vcom_socket_get_sid (int fd)
365{
366  vcom_socket_main_t *vsm = &vcom_socket_main;
367  uword *p;
368  vcom_socket_t *vsock;
369
370  p = hash_get (vsm->sockidx_by_fd, fd);
371
372  if (p)
373    {
374      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
375      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
376        return vsock->sid;
377    }
378  return INVALID_SESSION_ID;
379}
380
381static inline int
382vcom_socket_get_vep_idx (int epfd)
383{
384  vcom_socket_main_t *vsm = &vcom_socket_main;
385  uword *p;
386  vcom_epoll_t *vepoll;
387
388  p = hash_get (vsm->epollidx_by_epfd, epfd);
389
390  if (p)
391    {
392      vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
393      if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
394        return vepoll->vep_idx;
395    }
396  return INVALID_VEP_IDX;
397}
398
399static int
400vcom_socket_close_vsock (int fd)
401{
402  int rv = -1;
403  vcom_socket_main_t *vsm = &vcom_socket_main;
404  uword *p;
405  vcom_socket_t *vsock;
406
407  p = hash_get (vsm->sockidx_by_fd, fd);
408  if (!p)
409    return -EBADF;
410
411  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
412  if (!vsock)
413    return -ENOTSOCK;
414
415  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
416    return -EINVAL;
417
418  rv = vppcom_session_close (vsock->sid);
419  rv = vcom_socket_close_socket (vsock->fd);
420
421  vsocket_init (vsock);
422  hash_unset (vsm->sockidx_by_fd, fd);
423  pool_put (vsm->vsockets, vsock);
424
425  /*
426   * TBD:
427   * close all epoll instances that are marked as "close"
428   * of which this fd is the last remaining member
429   * */
430
431  return rv;
432}
433
434int
435vcom_socket_close_vepoll (int epfd)
436{
437  int rv = -1;
438  vcom_socket_main_t *vsm = &vcom_socket_main;
439  uword *p;
440  vcom_epoll_t *vepoll;
441
442  p = hash_get (vsm->epollidx_by_epfd, epfd);
443  if (!p)
444    return -EBADF;
445
446  vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
447  if (!vepoll)
448    return -EBADF;
449
450  if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
451    return -EINVAL;
452
453  if (vepoll->count)
454    {
455      if (!vepoll->close)
456        {
457          vepoll->close = 1;
458          return 0;
459        }
460      else
461        {
462          return -EBADF;
463        }
464    }
465
466  /* count is zero */
467  rv = vppcom_session_close (vepoll->vep_idx);
468  rv = vcom_socket_close_epoll (vepoll->epfd);
469
470  vepoll_init (vepoll);
471  hash_unset (vsm->epollidx_by_epfd, epfd);
472  pool_put (vsm->vepolls, vepoll);
473
474  return rv;
475}
476
477int
478vcom_socket_close (int __fd)
479{
480  int rv;
481
482  if (vcom_socket_is_vcom_fd (__fd))
483    {
484      rv = vcom_socket_close_vsock (__fd);
485    }
486  else if (vcom_socket_is_vcom_epfd (__fd))
487    {
488      rv = vcom_socket_close_vepoll (__fd);
489    }
490  else
491    {
492       rv = -EBADF;
493    }
494
495  return rv;
496}
497
498ssize_t
499vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
500{
501  int rv = -1;
502  vcom_socket_main_t *vsm = &vcom_socket_main;
503  uword *p;
504  vcom_socket_t *vsock;
505
506  p = hash_get (vsm->sockidx_by_fd, __fd);
507  if (!p)
508    return -EBADF;
509
510  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
511  if (!vsock)
512    return -ENOTSOCK;
513
514  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
515    return -EINVAL;
516
517  if (!__buf || __nbytes < 0)
518    {
519      return -EINVAL;
520    }
521
522  rv = vcom_fcntl (__fd, F_GETFL, 0);
523  if (rv < 0)
524    {
525      return rv;
526
527    }
528
529  /* is blocking */
530  if (!(rv & O_NONBLOCK))
531    {
532      do
533        {
534          rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
535        }
536      while (rv == -EAGAIN || rv == -EWOULDBLOCK);
537      return rv;
538    }
539  /* The file descriptor refers to a socket and has been
540   * marked nonblocking(O_NONBLOCK) and the read would
541   * block.
542   * */
543  /* is non blocking */
544  rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
545  return rv;
546}
547
548ssize_t
549vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
550{
551  int rv;
552  vcom_socket_main_t *vsm = &vcom_socket_main;
553  uword *p;
554  vcom_socket_t *vsock;
555  ssize_t total = 0, len = 0;
556
557  p = hash_get (vsm->sockidx_by_fd, __fd);
558  if (!p)
559    return -EBADF;
560
561  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
562  if (!vsock)
563    return -ENOTSOCK;
564
565  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
566    return -EINVAL;
567
568  if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
569    return -EINVAL;
570
571  /* Sanity check */
572  for (int i = 0; i < __iovcnt; ++i)
573    {
574      if (SSIZE_MAX - len < __iov[i].iov_len)
575	return -EINVAL;
576      len += __iov[i].iov_len;
577    }
578
579  rv = vcom_fcntl (__fd, F_GETFL, 0);
580  if (rv < 0)
581    {
582      return rv;
583    }
584
585  /* is blocking */
586  if (!(rv & O_NONBLOCK))
587    {
588      do
589	{
590	  for (int i = 0; i < __iovcnt; ++i)
591	    {
592	      rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
593					__iov[i].iov_len);
594	      if (rv < 0)
595		break;
596	      else
597		{
598		  total += rv;
599		  if (rv < __iov[i].iov_len)
600	            /* Read less than buffer provided, no point to continue */
601		    break;
602		}
603	    }
604	}
605      while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
606      return total;
607    }
608
609  /* is non blocking */
610  for (int i = 0; i < __iovcnt; ++i)
611    {
612      rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
613				__iov[i].iov_len);
614      if (rv < 0)
615	{
616	  if (total > 0)
617	    break;
618	  else
619	    {
620	      errno = rv;
621	      return rv;
622	    }
623	}
624      else
625	{
626	  total += rv;
627	  if (rv < __iov[i].iov_len)
628	    /* Read less than buffer provided, no point to continue */
629	    break;
630	}
631    }
632  return total;
633}
634
635ssize_t
636vcom_socket_write (int __fd, const void *__buf, size_t __n)
637{
638  int rv = -1;
639  vcom_socket_main_t *vsm = &vcom_socket_main;
640  uword *p;
641  vcom_socket_t *vsock;
642
643  p = hash_get (vsm->sockidx_by_fd, __fd);
644  if (!p)
645    return -EBADF;
646
647  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
648  if (!vsock)
649    return -ENOTSOCK;
650
651  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
652    return -EINVAL;
653
654  if (!__buf || __n < 0)
655    {
656      return -EINVAL;
657    }
658
659  rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
660  return rv;
661}
662
663ssize_t
664vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
665{
666  int rv = -1;
667  ssize_t total = 0;
668  vcom_socket_main_t *vsm = &vcom_socket_main;
669  uword *p;
670  vcom_socket_t *vsock;
671
672  p = hash_get (vsm->sockidx_by_fd, __fd);
673  if (!p)
674    return -EBADF;
675
676  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
677  if (!vsock)
678    return -ENOTSOCK;
679
680  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
681    return -EINVAL;
682
683  if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
684    return -EINVAL;
685
686  for (int i = 0; i < __iovcnt; ++i)
687    {
688      rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
689				 __iov[i].iov_len);
690      if (rv < 0)
691	{
692	  if (total > 0)
693	    break;
694	  else
695	    return rv;
696	}
697      else
698	total += rv;
699    }
700  return total;
701}
702
703/*
704 * RETURN:  0 - invalid cmd
705 *          1 - cmd not handled by vcom and vppcom
706 *          2 - cmd handled by vcom socket resource
707 *          3 - cmd handled by vppcom
708 * */
709/* TBD: incomplete list of cmd */
710static int
711vcom_socket_check_fcntl_cmd (int __cmd)
712{
713  switch (__cmd)
714    {
715      /*cmd not handled by vcom and vppcom */
716      /* Fallthrough */
717    case F_DUPFD:
718    case F_DUPFD_CLOEXEC:
719      return 1;
720
721      /* cmd handled by vcom socket resource */
722      /* Fallthrough */
723    case F_GETFD:
724    case F_SETFD:
725    case F_GETFL:
726    case F_SETFL:
727    case F_GETLK:
728    case F_SETLK:
729    case F_SETLKW:
730    case F_GETOWN:
731    case F_SETOWN:
732      return 2;
733
734#if 0
735      /* cmd handled by vppcom */
736    case F_XXXXX:
737      return 3;
738#endif
739      /* invalid cmd */
740    default:
741      return 0;
742    }
743  return 0;
744}
745
746/* TBD: move it to vppcom */
747static int
748vppcom_session_fcntl_va (int __fd, int __cmd, va_list __ap)
749{
750  int rv;
751
752  rv = -EINVAL;
753
754  return rv;
755}
756
757int
758vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
759{
760  int rv = -EBADF;
761  vcom_socket_main_t *vsm = &vcom_socket_main;
762  uword *p;
763  vcom_socket_t *vsock;
764
765  p = hash_get (vsm->sockidx_by_fd, __fd);
766  if (!p)
767    return -EBADF;
768
769  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
770  if (!vsock)
771    return -ENOTSOCK;
772
773  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
774    return -EINVAL;
775
776  switch (vcom_socket_check_fcntl_cmd (__cmd))
777    {
778      /* invalid cmd */
779    case 0:
780      rv = -EBADF;
781      break;
782      /*cmd not handled by vcom and vppcom */
783    case 1:
784      rv = -EBADF;
785      break;
786      /* cmd handled by vcom socket resource */
787    case 2:
788      rv = libc_vfcntl (vsock->fd, __cmd, __ap);
789      break;
790      /* cmd handled by vppcom */
791    case 3:
792      rv = vppcom_session_fcntl_va (vsock->sid, __cmd, __ap);
793      break;
794
795    default:
796      rv = -EINVAL;
797      break;
798    }
799
800  return rv;
801}
802
803static inline int
804vcom_socket_fds_2_sid_fds (
805                            /* dest */
806                            int *vcom_nsid_fds,
807                            fd_set * __restrict vcom_rd_sid_fds,
808                            fd_set * __restrict vcom_wr_sid_fds,
809                            fd_set * __restrict vcom_ex_sid_fds,
810                            /* src */
811                            int vcom_nfds,
812                            fd_set * __restrict vcom_readfds,
813                            fd_set * __restrict vcom_writefds,
814                            fd_set * __restrict vcom_exceptfds)
815{
816  int rv = 0;
817  int fd;
818  int sid;
819  /* invalid max_sid is -1 */
820  int max_sid = -1;
821  int nsid = 0;
822
823  /*
824   *  set sid in sid sets corresponding to fd's in fd sets
825   *  compute nsid and vcom_nsid_fds from sid sets
826   */
827
828  for (fd = 0; fd < vcom_nfds; fd++)
829    {
830      /*
831       * F fd set, src
832       * S sid set, dest
833       */
834#define _(S,F)                              \
835      if ((F) && (S) && FD_ISSET (fd, (F))) \
836        {                                   \
837          sid = vcom_socket_get_sid (fd);   \
838          if (sid != INVALID_SESSION_ID)    \
839            {                               \
840              FD_SET (sid, (S));            \
841              if (sid > max_sid)            \
842                {                           \
843                  max_sid = sid;            \
844                }                           \
845              ++nsid;                       \
846            }                               \
847          else                              \
848            {                               \
849              rv = -EBADFD;                 \
850              goto done;                    \
851            }                               \
852        }
853
854
855      _(vcom_rd_sid_fds, vcom_readfds);
856      _(vcom_wr_sid_fds, vcom_writefds);
857      _(vcom_ex_sid_fds, vcom_exceptfds);
858#undef _
859    }
860
861  *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
862  rv = nsid;
863
864done:
865  return rv;
866}
867
868/*
869 * PRE: 00. sid sets were derived from fd sets
870 *      01. sid sets were updated with sids that actually changed
871 *          status
872 *      02. fd sets still has watched fds
873 *
874 * This function will modify in place fd sets to indicate which fd's
875 * actually changed status(inferred from sid sets)
876 */
877static inline int
878vcom_socket_sid_fds_2_fds (
879                            /* dest */
880                            int *new_vcom_nfds,
881                            int vcom_nfds,
882                            fd_set * __restrict vcom_readfds,
883                            fd_set * __restrict vcom_writefds,
884                            fd_set * __restrict vcom_exceptfds,
885                            /* src */
886                            int vcom_nsid_fds,
887                            fd_set * __restrict vcom_rd_sid_fds,
888                            fd_set * __restrict vcom_wr_sid_fds,
889                            fd_set * __restrict vcom_ex_sid_fds)
890{
891  int rv = 0;
892  int fd;
893  int sid;
894  /* invalid max_fd is -1 */
895  int max_fd = -1;
896  int nfd = 0;
897
898
899  /*
900   *  modify in place fd sets to indicate which fd's
901   * actually changed status(inferred from sid sets)
902   */
903  for (fd = 0; fd < vcom_nfds; fd++)
904    {
905      /*
906       * F fd set, dest
907       * S sid set, src
908       */
909#define _(S,F)                              \
910      if ((F) && (S) && FD_ISSET (fd, (F))) \
911        {                                   \
912          sid = vcom_socket_get_sid (fd);   \
913          if (sid != INVALID_SESSION_ID)    \
914            {                               \
915              if (!FD_ISSET (sid, (S)))     \
916                {                           \
917                   FD_CLR(fd, (F));         \
918                }                           \
919            }                               \
920          else                              \
921            {                               \
922              rv = -EBADFD;                 \
923              goto done;                    \
924            }                               \
925        }
926
927
928      _(vcom_rd_sid_fds, vcom_readfds);
929      _(vcom_wr_sid_fds, vcom_writefds);
930      _(vcom_ex_sid_fds, vcom_exceptfds);
931#undef _
932    }
933
934  /*
935   *  compute nfd and new_vcom_nfds from fd sets
936   */
937  for (fd = 0; fd < vcom_nfds; fd++)
938    {
939
940#define _(F)                                \
941      if ((F) && FD_ISSET (fd, (F)))        \
942        {                                   \
943          if (fd > max_fd)                  \
944            {                               \
945              max_fd = fd;                  \
946            }                               \
947          ++nfd;                            \
948        }
949
950
951      _(vcom_readfds);
952      _(vcom_writefds);
953      _(vcom_exceptfds);
954#undef _
955
956    }
957
958  *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
959  rv = nfd;
960
961done:
962  return rv;
963}
964
965/*
966 * PRE:
967 * vom_socket_select is always called with
968 * timeout->tv_sec and timeout->tv_usec set to zero.
969 * hence vppcom_select return immediately.
970 */
971/*
972 * TBD: do{body;} while(timeout conditional); timeout loop
973 */
974int
975vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
976                    fd_set * __restrict vcom_writefds,
977                    fd_set * __restrict vcom_exceptfds,
978                    struct timeval *__restrict timeout)
979{
980  int rv = -EBADF;
981  pid_t pid = getpid ();
982
983  int new_vcom_nfds = 0;
984  int new_vcom_nfd = 0;
985
986  /* vcom sid fds */
987  fd_set vcom_rd_sid_fds;
988  fd_set vcom_wr_sid_fds;
989  fd_set vcom_ex_sid_fds;
990  unsigned long vcom_nsid_fds = 0;
991  int vcom_nsid = 0;
992
993  /* in seconds eg. 3.123456789 seconds */
994  double time_to_wait = (double) 0;
995
996  /* validate inputs */
997  if (vcom_nfds < 0)
998    {
999      return -EINVAL;
1000    }
1001
1002  /* convert timeval timeout to double time_to_wait */
1003  if (timeout)
1004    {
1005      if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
1006        {
1007          /* polling: vppcom_select returns immediately */
1008          time_to_wait = (double) 0;
1009        }
1010      else
1011        {
1012          /*TBD:  use timeval api */
1013          time_to_wait = (double) timeout->tv_sec +
1014            (double) timeout->tv_usec / (double) 1000000 +
1015            (double) (timeout->tv_usec % 1000000) / (double) 1000000;
1016        }
1017    }
1018  else
1019    {
1020      /*
1021       * no timeout: vppcom_select can block indefinitely
1022       * waiting for a file descriptor to become ready
1023       * */
1024      /* set to a phantom value */
1025      time_to_wait = ~0;
1026    }
1027
1028  /* zero the sid_sets */
1029  /*
1030   * F fd set
1031   * S sid set
1032   */
1033#define _(S,F)                          \
1034  if ((F))                              \
1035    {                                   \
1036      FD_ZERO ((S));                    \
1037    }
1038
1039
1040  _(&vcom_rd_sid_fds, vcom_readfds);
1041  _(&vcom_wr_sid_fds, vcom_writefds);
1042  _(&vcom_ex_sid_fds, vcom_exceptfds);
1043#undef _
1044
1045  /* populate read, write and except sid_sets */
1046  vcom_nsid = vcom_socket_fds_2_sid_fds (
1047                                          /* dest */
1048                                          vcom_readfds || vcom_writefds
1049                                          || vcom_exceptfds ? (int *)
1050                                          &vcom_nsid_fds : NULL,
1051                                          vcom_readfds ? &vcom_rd_sid_fds :
1052                                          NULL,
1053                                          vcom_writefds ? &vcom_wr_sid_fds :
1054                                          NULL,
1055                                          vcom_exceptfds ? &vcom_ex_sid_fds :
1056                                          NULL,
1057                                          /* src */
1058                                          vcom_nfds,
1059                                          vcom_readfds,
1060                                          vcom_writefds, vcom_exceptfds);
1061  if (vcom_nsid < 0)
1062    {
1063      return vcom_nsid;
1064    }
1065  if (vcom_nsid_fds < 0)
1066    {
1067      return -EINVAL;
1068    }
1069
1070  rv = vppcom_select (vcom_nsid_fds,
1071                      vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1072                      NULL,
1073                      vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1074                      NULL,
1075                      vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1076                      NULL, time_to_wait);
1077  if (VCOM_DEBUG > 0)
1078    fprintf (stderr, "[%d] vppcom_select: "
1079             "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1080
1081  /* check if any file descriptors changed status */
1082  if (rv > 0)
1083    {
1084      /*
1085       * on exit, sets are modified in place to indicate which
1086       * file descriptors actually changed status
1087       * */
1088
1089      /*
1090       * comply with pre-condition
1091       * do not clear vcom fd sets befor calling
1092       * vcom_socket_sid_fds_2_fds
1093       */
1094      new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1095                                                 /* dest */
1096                                                 &new_vcom_nfds,
1097                                                 vcom_nfds,
1098                                                 vcom_readfds,
1099                                                 vcom_writefds,
1100                                                 vcom_exceptfds,
1101                                                 /* src */
1102                                                 vcom_nsid_fds,
1103                                                 vcom_readfds ?
1104                                                 &vcom_rd_sid_fds : NULL,
1105                                                 vcom_writefds ?
1106                                                 &vcom_wr_sid_fds : NULL,
1107                                                 vcom_exceptfds ?
1108                                                 &vcom_ex_sid_fds : NULL);
1109      if (new_vcom_nfd < 0)
1110        {
1111          return new_vcom_nfd;
1112        }
1113      if (new_vcom_nfds < 0)
1114        {
1115          return -EINVAL;
1116        }
1117      rv = new_vcom_nfd;
1118    }
1119  return rv;
1120}
1121
1122
1123int
1124vcom_socket_socket (int __domain, int __type, int __protocol)
1125{
1126  int rv = -1;
1127  vcom_socket_main_t *vsm = &vcom_socket_main;
1128  vcom_socket_t *vsock;
1129
1130  i32 fd;
1131  i32 sid;
1132  i32 sockidx;
1133  u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1134  int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1135
1136  fd = vcom_socket_open_socket (__domain, __type, __protocol);
1137  if (fd < 0)
1138    {
1139      rv = fd;
1140      goto out;
1141    }
1142
1143  sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1144                               (type == SOCK_DGRAM) ?
1145                               VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1146                               is_nonblocking);
1147  if (sid < 0)
1148    {
1149      rv = sid;
1150      goto out_close_socket;
1151    }
1152
1153  pool_get (vsm->vsockets, vsock);
1154  vsocket_init (vsock);
1155
1156  sockidx = vsock - vsm->vsockets;
1157  hash_set (vsm->sockidx_by_fd, fd, sockidx);
1158
1159  vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1160  return fd;
1161
1162out_close_socket:
1163  vcom_socket_close_socket (fd);
1164out:
1165  return rv;
1166}
1167
1168int
1169vcom_socket_socketpair (int __domain, int __type, int __protocol,
1170                        int __fds[2])
1171{
1172/* TBD: */
1173  return 0;
1174}
1175
1176int
1177vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1178{
1179  int rv = -1;
1180  vcom_socket_main_t *vsm = &vcom_socket_main;
1181  uword *p;
1182  vcom_socket_t *vsock;
1183
1184  vppcom_endpt_t ep;
1185
1186  p = hash_get (vsm->sockidx_by_fd, __fd);
1187  if (!p)
1188    return -EBADF;
1189
1190  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1191  if (!vsock)
1192    return -ENOTSOCK;
1193
1194  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1195    return -EINVAL;
1196
1197  if (!__addr)
1198    {
1199      return -EINVAL;
1200    }
1201
1202  ep.vrf = VPPCOM_VRF_DEFAULT;
1203  switch (__addr->sa_family)
1204    {
1205    case AF_INET:
1206      if (__len != sizeof (struct sockaddr_in))
1207        {
1208          return -EINVAL;
1209        }
1210      ep.is_ip4 = VPPCOM_IS_IP4;
1211      ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1212      ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1213      break;
1214
1215    case AF_INET6:
1216      if (__len != sizeof (struct sockaddr_in6))
1217        {
1218          return -EINVAL;
1219        }
1220      ep.is_ip4 = VPPCOM_IS_IP6;
1221      ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1222      ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1223      break;
1224
1225    default:
1226      return -1;
1227      break;
1228    }
1229
1230  rv = vppcom_session_bind (vsock->sid, &ep);
1231  /* TBD: remove libc_bind code snippet
1232   * once vppcom implements vppcom_session_getsockname */
1233  if (rv == 0)
1234    {
1235      rv = libc_bind (__fd, __addr, __len);
1236      if (rv != 0)
1237        {
1238          rv = -errno;
1239        }
1240    }
1241  return rv;
1242}
1243
1244int
1245vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1246{
1247  /* TBD: move it to vppcom */
1248  return 0;
1249}
1250
1251int
1252vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1253                         socklen_t * __restrict __len)
1254{
1255  int rv = -1;
1256  vcom_socket_main_t *vsm = &vcom_socket_main;
1257  uword *p;
1258  vcom_socket_t *vsock;
1259
1260
1261  p = hash_get (vsm->sockidx_by_fd, __fd);
1262  if (!p)
1263    return -EBADF;
1264
1265  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1266  if (!vsock)
1267    return -ENOTSOCK;
1268
1269  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1270    return -EINVAL;
1271
1272  if (!__addr || !__len)
1273    return -EFAULT;
1274
1275  if (*__len < 0)
1276    {
1277      return -EINVAL;
1278    }
1279
1280  /* TBD: remove libc_getsockname code snippet
1281   * once vppcom implements vppcom_session_getsockname */
1282  rv = libc_getsockname (__fd, __addr, __len);
1283  if (rv != 0)
1284    {
1285      rv = -errno;
1286      return rv;
1287    }
1288
1289  /* TBD: use the below code snippet when vppcom
1290   * implements vppcom_session_getsockname */
1291#if 0
1292  vppcom_endpt_t ep;
1293  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1294  rv = vppcom_session_getsockname (vsock->sid, &ep);
1295  if (rv == 0)
1296    {
1297      if (ep.vrf == VPPCOM_VRF_DEFAULT)
1298        {
1299          __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1300          switch (__addr->sa_family)
1301            {
1302            case AF_INET:
1303              ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1304              *__len = sizeof (struct sockaddr_in);
1305              break;
1306
1307            case AF_INET6:
1308              ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1309              *__len = sizeof (struct sockaddr_in6);
1310              break;
1311
1312            default:
1313              break;
1314            }
1315        }
1316    }
1317#endif
1318
1319  return rv;
1320}
1321
1322int
1323vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1324{
1325  int rv = -1;
1326  vcom_socket_main_t *vsm = &vcom_socket_main;
1327  uword *p;
1328  vcom_socket_t *vsock;
1329
1330  vppcom_endpt_t ep;
1331
1332  p = hash_get (vsm->sockidx_by_fd, __fd);
1333  if (p)
1334    {
1335      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1336
1337      ep.vrf = VPPCOM_VRF_DEFAULT;
1338      switch (__addr->sa_family)
1339        {
1340        case AF_INET:
1341          ep.is_ip4 = VPPCOM_IS_IP4;
1342          ep.ip =
1343            (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1344          ep.port =
1345            (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1346          break;
1347
1348        case AF_INET6:
1349          ep.is_ip4 = VPPCOM_IS_IP6;
1350          ep.ip =
1351            (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1352          ep.port =
1353            (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1354          break;
1355
1356        default:
1357          return -1;
1358          break;
1359        }
1360
1361      rv = vppcom_session_connect (vsock->sid, &ep);
1362    }
1363  return rv;
1364}
1365
1366int
1367vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1368{
1369  /* TBD: move it to vppcom */
1370  return 0;
1371}
1372
1373int
1374vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1375                         socklen_t * __restrict __len)
1376{
1377  int rv = -1;
1378  vcom_socket_main_t *vsm = &vcom_socket_main;
1379  uword *p;
1380  vcom_socket_t *vsock;
1381
1382
1383  p = hash_get (vsm->sockidx_by_fd, __fd);
1384  if (!p)
1385    return -EBADF;
1386
1387  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1388  if (!vsock)
1389    return -ENOTSOCK;
1390
1391  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1392    return -EINVAL;
1393
1394  if (!__addr || !__len)
1395    return -EFAULT;
1396
1397  if (*__len < 0)
1398    {
1399      return -EINVAL;
1400    }
1401
1402  /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
1403  {
1404    uint8_t *a;
1405    ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1406    ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
1407    a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
1408    a[0] = 0x7f;
1409    a[1] = 0x00;
1410    a[2] = 0x00;
1411    a[3] = 0x01;
1412    *__len = sizeof (struct sockaddr_in);
1413    return 0;
1414  }
1415
1416  /* TBD: remove libc_getpeername code snippet
1417   * once vppcom implements vppcom_session_getpeername */
1418  rv = libc_getpeername (__fd, __addr, __len);
1419  if (rv != 0)
1420    {
1421      rv = -errno;
1422      return rv;
1423    }
1424
1425  /* TBD: use the below code snippet when vppcom
1426   * implements vppcom_session_getpeername */
1427#if 0
1428  vppcom_endpt_t ep;
1429  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1430  rv = vppcom_session_getpeername (vsock->sid, &ep);
1431  if (rv == 0)
1432    {
1433      if (ep.vrf == VPPCOM_VRF_DEFAULT)
1434        {
1435          __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1436          switch (__addr->sa_family)
1437            {
1438            case AF_INET:
1439              ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1440              *__len = sizeof (struct sockaddr_in);
1441              break;
1442
1443            case AF_INET6:
1444              ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1445              *__len = sizeof (struct sockaddr_in6);
1446              break;
1447
1448            default:
1449              break;
1450            }
1451        }
1452    }
1453#endif
1454
1455  return rv;
1456}
1457
1458ssize_t
1459vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1460{
1461  return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1462}
1463
1464ssize_t
1465vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1466{
1467  int rv = -1;
1468  rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1469  return rv;
1470}
1471
1472/*
1473 * RETURN   1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1474 * 0 otherwise
1475 * */
1476int
1477vcom_socket_is_connection_mode_socket (int __fd)
1478{
1479  int rv = -1;
1480  /* TBD define new vppcom api */
1481  vcom_socket_main_t *vsm = &vcom_socket_main;
1482  uword *p;
1483  vcom_socket_t *vsock;
1484
1485  int type;
1486  socklen_t optlen;
1487
1488  p = hash_get (vsm->sockidx_by_fd, __fd);
1489
1490  if (p)
1491    {
1492      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1493      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1494        {
1495          optlen = sizeof (type);
1496          rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1497          if (rv != 0)
1498            {
1499              return 0;
1500            }
1501          /* get socket type */
1502          switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1503            {
1504            case SOCK_STREAM:
1505            case SOCK_SEQPACKET:
1506              return 1;
1507              break;
1508
1509            default:
1510              return 0;
1511              break;
1512            }
1513        }
1514    }
1515  return 0;
1516}
1517
1518ssize_t
1519vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1520                        int __flags, __CONST_SOCKADDR_ARG __addr,
1521                        socklen_t __addr_len)
1522{
1523  int rv = -1;
1524  /* TBD add new vpp api  */
1525  /* TBD add flags parameter */
1526  rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1527  return rv;
1528}
1529
1530ssize_t
1531vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1532                    int __flags, __CONST_SOCKADDR_ARG __addr,
1533                    socklen_t __addr_len)
1534{
1535  int rv = -1;
1536  vcom_socket_main_t *vsm = &vcom_socket_main;
1537  uword *p;
1538  vcom_socket_t *vsock;
1539
1540  p = hash_get (vsm->sockidx_by_fd, __fd);
1541  if (!p)
1542    return -EBADF;
1543
1544  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1545  if (!vsock)
1546    return -ENOTSOCK;
1547
1548  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1549    return -EINVAL;
1550
1551  if (!__buf || __n < 0)
1552    {
1553      return -EINVAL;
1554    }
1555
1556  if (vcom_socket_is_connection_mode_socket (__fd))
1557    {
1558      /* ignore __addr and _addr_len */
1559      /* and EISCONN may be returned when they are not NULL and 0 */
1560      if ((__addr != NULL) || (__addr_len != 0))
1561        {
1562          return -EISCONN;
1563        }
1564    }
1565  else
1566    {
1567      if (!__addr || __addr_len < 0)
1568        {
1569          return -EDESTADDRREQ;
1570        }
1571      /* not a vppcom supported address family */
1572      if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1573        {
1574          return -EINVAL;
1575        }
1576    }
1577
1578  rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1579                               __flags, __addr, __addr_len);
1580  return rv;
1581}
1582
1583/* TBD: move it to vppcom */
1584static ssize_t
1585vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1586                         int __flags, __SOCKADDR_ARG __addr,
1587                         socklen_t * __restrict __addr_len)
1588{
1589  int rv = -1;
1590
1591  /* TBD add flags parameter */
1592  rv = vppcom_session_read (__sid, __buf, __n);
1593  return rv;
1594}
1595
1596ssize_t
1597vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1598                      int __flags, __SOCKADDR_ARG __addr,
1599                      socklen_t * __restrict __addr_len)
1600{
1601  int rv = -1;
1602  vcom_socket_main_t *vsm = &vcom_socket_main;
1603  uword *p;
1604  vcom_socket_t *vsock;
1605
1606  p = hash_get (vsm->sockidx_by_fd, __fd);
1607  if (!p)
1608    return -EBADF;
1609
1610  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1611  if (!vsock)
1612    return -ENOTSOCK;
1613
1614  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1615    return -EINVAL;
1616
1617  if (!__buf || __n < 0)
1618    {
1619      return -EINVAL;
1620    }
1621
1622  if (__addr || __addr_len < 0)
1623    {
1624      return -EINVAL;
1625    }
1626
1627  rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1628                                __flags, __addr, __addr_len);
1629  return rv;
1630}
1631
1632/* TBD: move it to vppcom */
1633static ssize_t
1634vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1635{
1636  int rv = -1;
1637  /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1638     (int)__n); */
1639  return rv;
1640}
1641
1642ssize_t
1643vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1644{
1645  int rv = -1;
1646  vcom_socket_main_t *vsm = &vcom_socket_main;
1647  uword *p;
1648  vcom_socket_t *vsock;
1649
1650  p = hash_get (vsm->sockidx_by_fd, __fd);
1651  if (!p)
1652    return -EBADF;
1653
1654  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1655  if (!vsock)
1656    return -ENOTSOCK;
1657
1658  if (vcom_socket_is_connection_mode_socket (__fd))
1659    {
1660      /* ignore __addr and _addr_len */
1661      /* and EISCONN may be returned when they are not NULL and 0 */
1662      if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1663        {
1664          return -EISCONN;
1665        }
1666    }
1667  else
1668    {
1669      /* TBD: validate __message->msg_name and __message->msg_namelen
1670       * and return -EINVAL on validation error
1671       * */
1672      ;
1673    }
1674
1675  rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1676
1677  return rv;
1678}
1679
1680#ifdef __USE_GNU
1681int
1682vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1683                      unsigned int __vlen, int __flags)
1684{
1685
1686  /* TBD: define a new vppcom api */
1687  return 0;
1688}
1689#endif
1690
1691/* TBD: move it to vppcom */
1692static ssize_t
1693vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1694{
1695  int rv = -1;
1696  /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1697     (int)__n); */
1698  return rv;
1699}
1700
1701ssize_t
1702vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1703{
1704  int rv = -1;
1705  vcom_socket_main_t *vsm = &vcom_socket_main;
1706  uword *p;
1707  vcom_socket_t *vsock;
1708
1709  p = hash_get (vsm->sockidx_by_fd, __fd);
1710  if (!p)
1711    return -EBADF;
1712
1713  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1714  if (!vsock)
1715    return -ENOTSOCK;
1716
1717  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1718    return -EINVAL;
1719
1720  if (!__message)
1721    {
1722      return -EINVAL;
1723    }
1724
1725  /* validate __flags */
1726
1727  rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1728  return rv;
1729}
1730
1731#ifdef __USE_GNU
1732int
1733vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1734                      unsigned int __vlen, int __flags,
1735                      struct timespec *__tmo)
1736{
1737  /* TBD: define a new vppcom api */
1738  return 0;
1739}
1740#endif
1741
1742/* TBD: move it to vppcom */
1743static int
1744vppcom_getsockopt (int __sid, int __level, int __optname,
1745                   void *__restrict __optval, socklen_t * __restrict __optlen)
1746{
1747  /* 1. for socket level options that are NOT socket attributes
1748   *    and that has corresponding vpp options get from vppcom */
1749#if 0
1750  return 0;
1751#endif
1752
1753  /* 2. unhandled options */
1754  return -ENOPROTOOPT;
1755}
1756
1757int
1758vcom_socket_getsockopt (int __fd, int __level, int __optname,
1759                        void *__restrict __optval,
1760                        socklen_t * __restrict __optlen)
1761{
1762  int rv = -1;
1763  vcom_socket_main_t *vsm = &vcom_socket_main;
1764  uword *p;
1765  vcom_socket_t *vsock;
1766
1767  p = hash_get (vsm->sockidx_by_fd, __fd);
1768  if (!p)
1769    return -EBADF;
1770
1771  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1772  if (!vsock)
1773    return -ENOTSOCK;
1774
1775  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1776    return -EINVAL;
1777
1778  if (!__optval && !__optlen)
1779    return -EFAULT;
1780
1781  if (*__optlen < 0)
1782    {
1783      return -EINVAL;
1784    }
1785
1786  switch (__level)
1787    {
1788      /* handle options at socket level */
1789    case SOL_SOCKET:
1790      switch (__optname)
1791        {
1792/*
1793 *  1. for socket level options that are socket attributes,
1794 *     get from libc_getsockopt.
1795 *  2. for socket level options that are NOT socket
1796 *     attributes and that has corresponding vpp options
1797 *     get from vppcom.
1798 *  3. for socket level options unimplemented
1799 *     return -ENOPROTOOPT */
1800        case SO_DEBUG:
1801        case SO_DONTROUTE:
1802        case SO_BROADCAST:
1803        case SO_SNDBUF:
1804        case SO_RCVBUF:
1805        case SO_REUSEADDR:
1806        case SO_REUSEPORT:
1807        case SO_KEEPALIVE:
1808        case SO_TYPE:
1809        case SO_PROTOCOL:
1810        case SO_DOMAIN:
1811        case SO_ERROR:
1812        case SO_OOBINLINE:
1813        case SO_NO_CHECK:
1814        case SO_PRIORITY:
1815        case SO_LINGER:
1816        case SO_BSDCOMPAT:
1817        case SO_TIMESTAMP:
1818        case SO_TIMESTAMPNS:
1819        case SO_TIMESTAMPING:
1820        case SO_RCVTIMEO:
1821        case SO_SNDTIMEO:
1822        case SO_RCVLOWAT:
1823        case SO_SNDLOWAT:
1824        case SO_PASSCRED:
1825        case SO_PEERCRED:
1826        case SO_PEERNAME:
1827        case SO_ACCEPTCONN:
1828        case SO_PASSSEC:
1829        case SO_PEERSEC:
1830        case SO_MARK:
1831        case SO_RXQ_OVFL:
1832        case SO_WIFI_STATUS:
1833        case SO_PEEK_OFF:
1834        case SO_NOFCS:
1835        case SO_BINDTODEVICE:
1836        case SO_GET_FILTER:
1837        case SO_LOCK_FILTER:
1838        case SO_BPF_EXTENSIONS:
1839        case SO_SELECT_ERR_QUEUE:
1840#ifdef CONFIG_NET_RX_BUSY_POLL
1841        case SO_BUSY_POLL:
1842#endif
1843        case SO_MAX_PACING_RATE:
1844        case SO_INCOMING_CPU:
1845          rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1846          if (rv != 0)
1847            {
1848              rv = -errno;
1849              return rv;
1850            }
1851          break;
1852
1853        default:
1854          /* We implement the SO_SNDLOWAT etc to not be settable
1855           * (1003.1g 7).
1856           */
1857          return -ENOPROTOOPT;
1858        }
1859
1860      break;
1861
1862    default:
1863      /* 1. handle options that are NOT socket level options,
1864       *    but have corresponding vpp otions. */
1865      rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1866                              __optval, __optlen);
1867
1868      return rv;
1869#if 0
1870      /* 2. unhandled options */
1871      return -ENOPROTOOPT;
1872#endif
1873    }
1874
1875  return rv;
1876}
1877
1878/* TBD: move it to vppcom */
1879int
1880vppcom_setsockopt (int __fd, int __level, int __optname,
1881                   const void *__optval, socklen_t __optlen)
1882{
1883  /* 1. for socket level options that are NOT socket attributes
1884   *    and that has corresponding vpp options set it from vppcom */
1885#if 0
1886  return 0;
1887#endif
1888
1889  /* 2. unhandled options */
1890  return -ENOPROTOOPT;
1891}
1892
1893int
1894vcom_socket_setsockopt (int __fd, int __level, int __optname,
1895                        const void *__optval, socklen_t __optlen)
1896{
1897  int rv = -1;
1898  vcom_socket_main_t *vsm = &vcom_socket_main;
1899  uword *p;
1900  vcom_socket_t *vsock;
1901
1902  p = hash_get (vsm->sockidx_by_fd, __fd);
1903  if (!p)
1904    return -EBADF;
1905
1906  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1907  if (!vsock)
1908    return -ENOTSOCK;
1909
1910  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1911    return -EINVAL;
1912
1913  /*
1914   *      Options without arguments
1915   */
1916
1917  if (__optname == SO_BINDTODEVICE)
1918    {
1919      rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1920      if (rv != 0)
1921        {
1922          rv = -errno;
1923        }
1924      return rv;
1925    }
1926
1927  if (!__optval)
1928    return -EFAULT;
1929
1930  if ((__optlen < 0) || (__optlen < sizeof (int)))
1931    return -EINVAL;
1932
1933  switch (__level)
1934    {
1935      /* handle options at socket level */
1936    case SOL_SOCKET:
1937      switch (__optname)
1938        {
1939          /*
1940           * 1. for socket level options that are socket attributes,
1941           *    set it from libc_getsockopt
1942           * 2. for socket level options that are NOT socket
1943           *    attributes and that has corresponding vpp options
1944           *    set it from vppcom
1945           * 3. for socket level options unimplemented
1946           *    return -ENOPROTOOPT */
1947        case SO_DEBUG:
1948        case SO_DONTROUTE:
1949        case SO_BROADCAST:
1950        case SO_SNDBUF:
1951        case SO_RCVBUF:
1952        case SO_REUSEADDR:
1953        case SO_REUSEPORT:
1954        case SO_KEEPALIVE:
1955        case SO_TYPE:
1956        case SO_PROTOCOL:
1957        case SO_DOMAIN:
1958        case SO_ERROR:
1959        case SO_OOBINLINE:
1960        case SO_NO_CHECK:
1961        case SO_PRIORITY:
1962        case SO_LINGER:
1963        case SO_BSDCOMPAT:
1964        case SO_TIMESTAMP:
1965        case SO_TIMESTAMPNS:
1966        case SO_TIMESTAMPING:
1967        case SO_RCVTIMEO:
1968        case SO_SNDTIMEO:
1969        case SO_RCVLOWAT:
1970        case SO_SNDLOWAT:
1971        case SO_PASSCRED:
1972        case SO_PEERCRED:
1973        case SO_PEERNAME:
1974        case SO_ACCEPTCONN:
1975        case SO_PASSSEC:
1976        case SO_PEERSEC:
1977        case SO_MARK:
1978        case SO_RXQ_OVFL:
1979        case SO_WIFI_STATUS:
1980        case SO_PEEK_OFF:
1981        case SO_NOFCS:
1982          /*
1983           * SO_BINDTODEVICE already handled as
1984           * "Options without arguments" */
1985          /* case SO_BINDTODEVICE: */
1986        case SO_GET_FILTER:
1987        case SO_LOCK_FILTER:
1988        case SO_BPF_EXTENSIONS:
1989        case SO_SELECT_ERR_QUEUE:
1990#ifdef CONFIG_NET_RX_BUSY_POLL
1991        case SO_BUSY_POLL:
1992#endif
1993        case SO_MAX_PACING_RATE:
1994        case SO_INCOMING_CPU:
1995          rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1996          if (rv != 0)
1997            {
1998              rv = -errno;
1999              return rv;
2000            }
2001          break;
2002
2003        default:
2004          /* We implement the SO_SNDLOWAT etc to not be settable
2005           * (1003.1g 7).
2006           */
2007          return -ENOPROTOOPT;
2008        }
2009
2010      break;
2011
2012    default:
2013      /* 1. handle options that are NOT socket level options,
2014       *    but have corresponding vpp otions. */
2015      rv = vppcom_setsockopt (vsock->sid, __level, __optname,
2016                              __optval, __optlen);
2017      return rv;
2018#if 0
2019      /* 2. unhandled options */
2020      return -ENOPROTOOPT;
2021#endif
2022    }
2023
2024  return rv;
2025}
2026
2027int
2028vcom_socket_listen (int __fd, int __n)
2029{
2030  int rv = -1;
2031  vcom_socket_main_t *vsm = &vcom_socket_main;
2032  uword *p;
2033  vcom_socket_t *vsock;
2034
2035  p = hash_get (vsm->sockidx_by_fd, __fd);
2036  if (p)
2037    {
2038      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2039
2040      /* TBD vppcom to accept __n parameter */
2041      rv = vppcom_session_listen (vsock->sid, __n);
2042    }
2043
2044  return rv;
2045}
2046
2047static int
2048vcom_socket_connected_socket (int __fd, int __sid,
2049                              int *__domain,
2050                              int *__type, int *__protocol, int flags)
2051{
2052  int rv = -1;
2053  vcom_socket_main_t *vsm = &vcom_socket_main;
2054  vcom_socket_t *vsock;
2055
2056  i32 fd;
2057  i32 sockidx;
2058
2059  socklen_t optlen;
2060
2061  optlen = sizeof (*__domain);
2062  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
2063  if (rv != 0)
2064    {
2065      rv = -errno;
2066      goto out;
2067    }
2068
2069  optlen = sizeof (*__type);
2070  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2071  if (rv != 0)
2072    {
2073      rv = -errno;
2074      goto out;
2075    }
2076
2077  optlen = sizeof (*__protocol);
2078  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2079  if (rv != 0)
2080    {
2081      rv = -errno;
2082      goto out;
2083    }
2084
2085  fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2086  if (fd < 0)
2087    {
2088      rv = fd;
2089      goto out;
2090    }
2091
2092  pool_get (vsm->vsockets, vsock);
2093  vsocket_init (vsock);
2094
2095  sockidx = vsock - vsm->vsockets;
2096  hash_set (vsm->sockidx_by_fd, fd, sockidx);
2097
2098  vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2099  return fd;
2100
2101out:
2102  return rv;
2103}
2104
2105/* If flag is 0, then accept4() is the same as accept().
2106 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2107 */
2108static int
2109vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2110                          socklen_t * __restrict __addr_len, int flags)
2111{
2112  int rv = -1;
2113  vcom_socket_main_t *vsm = &vcom_socket_main;
2114  uword *p;
2115  vcom_socket_t *vsock;
2116
2117  int fd;
2118  int sid;
2119  int domain;
2120  int type;
2121  int protocol;
2122
2123  uint8_t addr8[sizeof (struct in6_addr)];
2124  vppcom_endpt_t ep;
2125
2126  ep.ip = addr8;
2127
2128  /* validate flags */
2129
2130  /*
2131   * for documentation
2132   *  switch (flags)
2133   *   {
2134   *   case 0:
2135   *   case SOCK_NONBLOCK:
2136   *   case SOCK_CLOEXEC:
2137   *   case SOCK_NONBLOCK | SOCK_CLOEXEC:
2138   *     break;
2139   *
2140   *   default:
2141   *     return -1;
2142   *   }
2143   */
2144  /* flags can be 0 or can be bitwise OR
2145   * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2146
2147  if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2148    {
2149      /* TBD: return proper error code */
2150      return -1;
2151    }
2152
2153  /* TBD: return proper error code */
2154
2155  if (!vcom_socket_is_connection_mode_socket (__fd))
2156    {
2157      return -EOPNOTSUPP;
2158    }
2159
2160  p = hash_get (vsm->sockidx_by_fd, __fd);
2161  if (p)
2162    {
2163      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2164
2165
2166      rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2167      if (rv < 0)
2168        {
2169          return rv;
2170        }
2171
2172      /* is blocking */
2173      if (!(rv & O_NONBLOCK))
2174        {
2175          /* socket is not marked as nonblocking
2176           * and no pending connections are present
2177           * on the queue, accept () blocks the caller
2178           * until a connection is present.
2179           */
2180          rv = vppcom_session_accept (vsock->sid, &ep,
2181                                      -1.0 /* wait forever */ );
2182        }
2183      else
2184        {
2185          /* The file descriptor refers to a socket and has been
2186           * marked nonblocking(O_NONBLOCK) and the accept would
2187           * block.
2188           * */
2189          /* is non blocking */
2190          rv = vppcom_session_accept (vsock->sid, &ep, 0);
2191          /* If the socket is marked nonblocking and
2192           * no pending connections are present on the
2193           * queue, accept fails with the error
2194           * EAGAIN or EWOULDBLOCK
2195           */
2196          if (rv == VPPCOM_ETIMEDOUT)
2197            {
2198              rv = VPPCOM_EAGAIN;
2199            }
2200        }
2201      if (rv < 0)
2202        {
2203          return rv;
2204        }
2205
2206      sid = rv;
2207
2208      /* create a new connected socket resource and set flags
2209       * on the new file descriptor.
2210       * update vsockets and sockidx_by_fd table
2211       * */
2212      fd = vcom_socket_connected_socket (__fd, sid,
2213                                         &domain, &type, &protocol, flags);
2214      if (fd < 0)
2215        {
2216          return fd;
2217        }
2218
2219      rv = fd;
2220
2221      /* TBD populate __addr and __addr_len */
2222      /* TBD: The returned address is truncated if the buffer
2223       * provided is too small, in this case, __addr_len will
2224       * return a value greater than was supplied to the call.*/
2225      if (__addr)
2226        {
2227          if (ep.is_cut_thru)
2228            {
2229              /* TBD populate __addr and __addr_len */
2230              switch (domain)
2231                {
2232                case AF_INET:
2233                  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2234                  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2235                  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2236                          addr8, sizeof (struct in_addr));
2237                  /* TBD: populate __addr_len */
2238                  if (__addr_len)
2239                    {
2240                      *__addr_len = sizeof (struct sockaddr_in);
2241                    }
2242                  break;
2243
2244                case AF_INET6:
2245                  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2246                  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2247                  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2248                          __in6_u.__u6_addr8, addr8,
2249                          sizeof (struct in6_addr));
2250                  /* TBD: populate __addr_len */
2251                  if (__addr_len)
2252                    {
2253                      *__addr_len = sizeof (struct sockaddr_in6);
2254                    }
2255                  break;
2256
2257                default:
2258                  return -EAFNOSUPPORT;
2259                }
2260            }
2261          else
2262            {
2263              switch (ep.is_ip4)
2264                {
2265                case VPPCOM_IS_IP4:
2266                  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2267                  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2268                  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2269                          addr8, sizeof (struct in_addr));
2270                  /* TBD: populate __addr_len */
2271                  if (__addr_len)
2272                    {
2273                      *__addr_len = sizeof (struct sockaddr_in);
2274                    }
2275                  break;
2276
2277                case VPPCOM_IS_IP6:
2278                  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2279                  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2280                  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2281                          __in6_u.__u6_addr8, addr8,
2282                          sizeof (struct in6_addr));
2283                  /* TBD: populate __addr_len */
2284                  if (__addr_len)
2285                    {
2286                      *__addr_len = sizeof (struct sockaddr_in6);
2287                    }
2288                  break;
2289
2290                default:
2291                  return -EAFNOSUPPORT;
2292                }
2293            }
2294        }
2295      else
2296        {
2297          /* when __addr is NULL, nothing is filled in,
2298           * in this case, __addr_len is not used,
2299           * and should also be null
2300           * */
2301          if (__addr_len)
2302            {
2303              /* TBD: return proper error code */
2304              return -1;
2305            }
2306        }
2307    }
2308
2309  return rv;
2310}
2311
2312int
2313vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2314                    socklen_t * __restrict __addr_len)
2315{
2316  /* set flags to 0 for accept() */
2317  return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2318}
2319
2320#ifdef __USE_GNU
2321int
2322vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2323                     socklen_t * __restrict __addr_len, int __flags)
2324{
2325  /*  SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2326  return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2327}
2328#endif
2329
2330/* TBD: move it to vppcom */
2331int
2332vppcom_session_shutdown (int __fd, int __how)
2333{
2334  return 0;
2335}
2336
2337int
2338vcom_socket_shutdown (int __fd, int __how)
2339{
2340  int rv = -1;
2341  vcom_socket_main_t *vsm = &vcom_socket_main;
2342  uword *p;
2343  vcom_socket_t *vsock;
2344
2345  p = hash_get (vsm->sockidx_by_fd, __fd);
2346  if (p)
2347    {
2348      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2349      switch (__how)
2350        {
2351        case SHUT_RD:
2352        case SHUT_WR:
2353        case SHUT_RDWR:
2354          rv = vppcom_session_shutdown (vsock->sid, __how);
2355          return rv;
2356          break;
2357
2358        default:
2359          return -EINVAL;
2360          break;
2361        }
2362    }
2363
2364  return rv;
2365}
2366
2367/*
2368 * TBD: remove it once vppvom.h is committed.
2369 */
2370int vppcom_epoll_create (void)
2371{
2372  return -ENOSYS;
2373}
2374int
2375vcom_socket_epoll_create1 (int __flags)
2376{
2377  int rv = -1;
2378  vcom_socket_main_t *vsm = &vcom_socket_main;
2379  vcom_epoll_t *vepoll;
2380
2381  i32 epfd;
2382  i32 vep_idx;
2383  i32 epollidx;
2384
2385  epfd = vcom_socket_open_epoll (__flags);
2386  if (epfd < 0)
2387    {
2388      rv = epfd;
2389      goto out;
2390    }
2391
2392  vep_idx = vppcom_epoll_create ( );
2393  if (vep_idx < 0)
2394    {
2395      rv = vep_idx;
2396      goto out_close_epoll;
2397    }
2398
2399  pool_get (vsm->vepolls, vepoll);
2400  vepoll_init (vepoll);
2401
2402  epollidx = vepoll - vsm->vepolls;
2403  hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2404
2405  vepoll_set (vepoll, epfd, vep_idx,
2406              EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2407
2408  return epfd;
2409
2410out_close_epoll:
2411  vcom_socket_close_epoll (epfd);
2412out:
2413  return rv;
2414}
2415
2416int
2417vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2418                       struct epoll_event *__event)
2419{
2420  return -ENOSYS;
2421}
2422
2423int
2424vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2425                         int __maxevents, int __timeout,
2426                         const __sigset_t *__ss)
2427{
2428    return -ENOSYS;
2429}
2430
2431/*
2432 * fd.io coding-style-patch-verification: ON
2433 *
2434 * Local Variables:
2435 * eval: (c-set-style "gnu")
2436 * End:
2437 */
2438