vcom_socket.c revision 20574915
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 *epitemidx_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
161
162int
163vcom_socket_is_vcom_fd (int fd)
164{
165  vcom_socket_main_t *vsm = &vcom_socket_main;
166  uword *p;
167  vcom_socket_t *vsock;
168
169  p = hash_get (vsm->sockidx_by_fd, fd);
170
171  if (p)
172    {
173      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
174      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
175        return 1;
176    }
177  return 0;
178}
179
180int
181vcom_socket_is_vcom_epfd (int epfd)
182{
183  vcom_socket_main_t *vsm = &vcom_socket_main;
184  uword *p;
185  vcom_epoll_t *vepoll;
186
187  p = hash_get (vsm->epollidx_by_epfd, epfd);
188
189  if (p)
190    {
191      vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
192      if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
193        return 1;
194    }
195  return 0;
196}
197
198static inline int
199vcom_socket_get_sid (int fd)
200{
201  vcom_socket_main_t *vsm = &vcom_socket_main;
202  uword *p;
203  vcom_socket_t *vsock;
204
205  p = hash_get (vsm->sockidx_by_fd, fd);
206
207  if (p)
208    {
209      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
210      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
211        return vsock->sid;
212    }
213  return INVALID_SESSION_ID;
214}
215
216static inline int
217vcom_socket_get_vep_idx (int epfd)
218{
219  vcom_socket_main_t *vsm = &vcom_socket_main;
220  uword *p;
221  vcom_epoll_t *vepoll;
222
223  p = hash_get (vsm->epollidx_by_epfd, epfd);
224
225  if (p)
226    {
227      vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
228      if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
229        return vepoll->vep_idx;
230    }
231  return INVALID_VEP_IDX;
232}
233
234static inline int
235vcom_socket_get_sid_and_vsock (int fd, vcom_socket_t **vsockp)
236{
237  vcom_socket_main_t *vsm = &vcom_socket_main;
238  uword *p;
239  vcom_socket_t *vsock;
240
241  p = hash_get (vsm->sockidx_by_fd, fd);
242
243  if (p)
244    {
245      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
246      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
247        {
248          *vsockp = vsock;
249          return vsock->sid;
250        }
251    }
252  return INVALID_SESSION_ID;
253}
254
255static inline int
256vcom_socket_get_vep_idx_and_vepoll (int epfd, vcom_epoll_t **vepollp)
257{
258  vcom_socket_main_t *vsm = &vcom_socket_main;
259  uword *p;
260  vcom_epoll_t *vepoll;
261
262  p = hash_get (vsm->epollidx_by_epfd, epfd);
263
264  if (p)
265    {
266      vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
267      if (vepoll && vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
268        {
269          *vepollp = vepoll;
270          return vepoll->vep_idx;
271        }
272    }
273  return INVALID_VEP_IDX;
274}
275
276
277static int
278vcom_socket_close_vepoll (int epfd)
279{
280  int rv = -1;
281  vcom_socket_main_t *vsm = &vcom_socket_main;
282  uword *p;
283  vcom_epoll_t *vepoll;
284
285  p = hash_get (vsm->epollidx_by_epfd, epfd);
286  if (!p)
287    return -EBADF;
288
289  vepoll = pool_elt_at_index (vsm->vepolls, p[0]);
290  if (!vepoll)
291    return -EBADF;
292
293  if (vepoll->type != EPOLL_TYPE_VPPCOM_BOUND)
294    return -EINVAL;
295
296  if (vepoll->count)
297    {
298      if (!vepoll->close)
299        {
300          vepoll->close = 1;
301          return 0;
302        }
303      else
304        {
305          return -EBADF;
306        }
307    }
308
309  /* count is zero */
310  rv = vppcom_session_close (vepoll->vep_idx);
311  rv = vcom_socket_close_epoll (vepoll->epfd);
312
313  vepoll_init (vepoll);
314  hash_unset (vsm->epollidx_by_epfd, epfd);
315  pool_put (vsm->vepolls, vepoll);
316
317  return rv;
318}
319
320static int
321vcom_socket_close_vsock (int fd)
322{
323  int rv = -1;
324  vcom_socket_main_t *vsm = &vcom_socket_main;
325  uword *p;
326  vcom_socket_t *vsock;
327
328  vcom_epitem_t *vepitem;
329
330  i32 *vepitemidxs = 0;
331  i32 *vepitemidxs_var = 0;
332
333  p = hash_get (vsm->sockidx_by_fd, fd);
334  if (!p)
335    return -EBADF;
336
337  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
338  if (!vsock)
339    return -ENOTSOCK;
340
341  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
342    return -EINVAL;
343
344  rv = vppcom_session_close (vsock->sid);
345  rv = vcom_socket_close_socket (vsock->fd);
346
347  vsocket_init (vsock);
348  hash_unset (vsm->sockidx_by_fd, fd);
349  pool_put (vsm->vsockets, vsock);
350
351  /*
352   * NOTE:
353   * Before calling close(), user should remove
354   * this fd from the epoll-set of all epoll instances,
355   * otherwise resource(epitems) leaks ensues.
356   */
357
358  /*
359   * 00. close all epoll instances that are marked as "close"
360   *     of which this fd is the "last" remaining member.
361   * 01. epitems associated with this fd are intentionally
362   *     not removed, see NOTE: above.
363   * */
364
365  /* does this fd participate in epoll */
366  p = hash_get (vsm->epitemidxs_by_fd, fd);
367  if (p)
368    {
369      vepitemidxs = *(i32 **)p;
370      vec_foreach (vepitemidxs_var, vepitemidxs)
371      {
372        vepitem = pool_elt_at_index (vsm->vepitems, vepitemidxs_var[0]);
373        if (vepitem && vepitem->fd == fd &&
374            vepitem->type == FD_TYPE_VCOM_SOCKET)
375          {
376            i32 vep_idx;
377            vcom_epoll_t *vepoll;
378            if ((vep_idx =
379                 vcom_socket_get_vep_idx_and_vepoll (vepitem->epfd, &vepoll)) != INVALID_VEP_IDX)
380            {
381              if (vepoll->close)
382                {
383                  if (vepoll->count == 1)
384                    {
385                      /*
386                       * force count to zero and
387                       * close this epoll instance
388                       * */
389                      vepoll->count = 0;
390                      vcom_socket_close_vepoll (vepoll->epfd);
391                    }
392                  else
393                    {
394                      vepoll->count -= 1;
395                    }
396                }
397            }
398          }
399
400      }
401    }
402
403  return rv;
404}
405
406int
407vcom_socket_close (int __fd)
408{
409  int rv;
410
411  if (vcom_socket_is_vcom_fd (__fd))
412    {
413      rv = vcom_socket_close_vsock (__fd);
414    }
415  else if (vcom_socket_is_vcom_epfd (__fd))
416    {
417      rv = vcom_socket_close_vepoll (__fd);
418    }
419  else
420    {
421       rv = -EBADF;
422    }
423
424  return rv;
425}
426
427ssize_t
428vcom_socket_read (int __fd, void *__buf, size_t __nbytes)
429{
430  int rv = -1;
431  vcom_socket_main_t *vsm = &vcom_socket_main;
432  uword *p;
433  vcom_socket_t *vsock;
434
435  p = hash_get (vsm->sockidx_by_fd, __fd);
436  if (!p)
437    return -EBADF;
438
439  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
440  if (!vsock)
441    return -ENOTSOCK;
442
443  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
444    return -EINVAL;
445
446  if (!__buf || __nbytes < 0)
447    {
448      return -EINVAL;
449    }
450
451  rv = vcom_fcntl (__fd, F_GETFL, 0);
452  if (rv < 0)
453    {
454      return rv;
455
456    }
457
458  /* is blocking */
459  if (!(rv & O_NONBLOCK))
460    {
461      do
462        {
463          rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
464        }
465      while (rv == -EAGAIN || rv == -EWOULDBLOCK);
466      return rv;
467    }
468  /* The file descriptor refers to a socket and has been
469   * marked nonblocking(O_NONBLOCK) and the read would
470   * block.
471   * */
472  /* is non blocking */
473  rv = vppcom_session_read (vsock->sid, __buf, __nbytes);
474  return rv;
475}
476
477ssize_t
478vcom_socket_readv (int __fd, const struct iovec * __iov, int __iovcnt)
479{
480  int rv;
481  vcom_socket_main_t *vsm = &vcom_socket_main;
482  uword *p;
483  vcom_socket_t *vsock;
484  ssize_t total = 0, len = 0;
485
486  p = hash_get (vsm->sockidx_by_fd, __fd);
487  if (!p)
488    return -EBADF;
489
490  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
491  if (!vsock)
492    return -ENOTSOCK;
493
494  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
495    return -EINVAL;
496
497  if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
498    return -EINVAL;
499
500  /* Sanity check */
501  for (int i = 0; i < __iovcnt; ++i)
502    {
503      if (SSIZE_MAX - len < __iov[i].iov_len)
504	return -EINVAL;
505      len += __iov[i].iov_len;
506    }
507
508  rv = vcom_fcntl (__fd, F_GETFL, 0);
509  if (rv < 0)
510    {
511      return rv;
512    }
513
514  /* is blocking */
515  if (!(rv & O_NONBLOCK))
516    {
517      do
518	{
519	  for (int i = 0; i < __iovcnt; ++i)
520	    {
521	      rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
522					__iov[i].iov_len);
523	      if (rv < 0)
524		break;
525	      else
526		{
527		  total += rv;
528		  if (rv < __iov[i].iov_len)
529	            /* Read less than buffer provided, no point to continue */
530		    break;
531		}
532	    }
533	}
534      while ((rv == -EAGAIN || rv == -EWOULDBLOCK) && total == 0);
535      return total;
536    }
537
538  /* is non blocking */
539  for (int i = 0; i < __iovcnt; ++i)
540    {
541      rv = vppcom_session_read (vsock->sid, __iov[i].iov_base,
542				__iov[i].iov_len);
543      if (rv < 0)
544	{
545	  if (total > 0)
546	    break;
547	  else
548	    {
549	      errno = rv;
550	      return rv;
551	    }
552	}
553      else
554	{
555	  total += rv;
556	  if (rv < __iov[i].iov_len)
557	    /* Read less than buffer provided, no point to continue */
558	    break;
559	}
560    }
561  return total;
562}
563
564ssize_t
565vcom_socket_write (int __fd, const void *__buf, size_t __n)
566{
567  int rv = -1;
568  vcom_socket_main_t *vsm = &vcom_socket_main;
569  uword *p;
570  vcom_socket_t *vsock;
571
572  p = hash_get (vsm->sockidx_by_fd, __fd);
573  if (!p)
574    return -EBADF;
575
576  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
577  if (!vsock)
578    return -ENOTSOCK;
579
580  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
581    return -EINVAL;
582
583  if (!__buf || __n < 0)
584    {
585      return -EINVAL;
586    }
587
588  rv = vppcom_session_write (vsock->sid, (void *) __buf, __n);
589  return rv;
590}
591
592ssize_t
593vcom_socket_writev (int __fd, const struct iovec * __iov, int __iovcnt)
594{
595  int rv = -1;
596  ssize_t total = 0;
597  vcom_socket_main_t *vsm = &vcom_socket_main;
598  uword *p;
599  vcom_socket_t *vsock;
600
601  p = hash_get (vsm->sockidx_by_fd, __fd);
602  if (!p)
603    return -EBADF;
604
605  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
606  if (!vsock)
607    return -ENOTSOCK;
608
609  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
610    return -EINVAL;
611
612  if (__iov == 0 || __iovcnt == 0 || __iovcnt > IOV_MAX)
613    return -EINVAL;
614
615  for (int i = 0; i < __iovcnt; ++i)
616    {
617      rv = vppcom_session_write (vsock->sid, __iov[i].iov_base,
618				 __iov[i].iov_len);
619      if (rv < 0)
620	{
621	  if (total > 0)
622	    break;
623	  else
624	    return rv;
625	}
626      else
627	total += rv;
628    }
629  return total;
630}
631
632/*
633 * RETURN:  0 - invalid cmd
634 *          1 - cmd not handled by vcom and vppcom
635 *          2 - cmd handled by vcom socket resource
636 *          3 - cmd handled by vppcom
637 * */
638/* TBD: incomplete list of cmd */
639static int
640vcom_socket_check_fcntl_cmd (int __cmd)
641{
642  switch (__cmd)
643    {
644      /*cmd not handled by vcom and vppcom */
645      /* Fallthrough */
646    case F_DUPFD:
647    case F_DUPFD_CLOEXEC:
648      return 1;
649
650      /* cmd handled by vcom socket resource */
651      /* Fallthrough */
652    case F_GETFD:
653    case F_SETFD:
654    case F_GETFL:
655    case F_SETFL:
656    case F_GETLK:
657    case F_SETLK:
658    case F_SETLKW:
659    case F_GETOWN:
660    case F_SETOWN:
661      return 2;
662
663#if 0
664      /* cmd handled by vppcom */
665    case F_XXXXX:
666      return 3;
667#endif
668      /* invalid cmd */
669    default:
670      return 0;
671    }
672  return 0;
673}
674
675/* TBD: move it to vppcom */
676static int
677vppcom_session_fcntl_va (int __fd, int __cmd, va_list __ap)
678{
679  int rv;
680
681  rv = -EINVAL;
682
683  return rv;
684}
685
686int
687vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
688{
689  int rv = -EBADF;
690  vcom_socket_main_t *vsm = &vcom_socket_main;
691  uword *p;
692  vcom_socket_t *vsock;
693
694  p = hash_get (vsm->sockidx_by_fd, __fd);
695  if (!p)
696    return -EBADF;
697
698  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
699  if (!vsock)
700    return -ENOTSOCK;
701
702  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
703    return -EINVAL;
704
705  switch (vcom_socket_check_fcntl_cmd (__cmd))
706    {
707      /* invalid cmd */
708    case 0:
709      rv = -EBADF;
710      break;
711      /*cmd not handled by vcom and vppcom */
712    case 1:
713      rv = -EBADF;
714      break;
715      /* cmd handled by vcom socket resource */
716    case 2:
717      rv = libc_vfcntl (vsock->fd, __cmd, __ap);
718      break;
719      /* cmd handled by vppcom */
720    case 3:
721      rv = vppcom_session_fcntl_va (vsock->sid, __cmd, __ap);
722      break;
723
724    default:
725      rv = -EINVAL;
726      break;
727    }
728
729  return rv;
730}
731
732static inline int
733vcom_socket_fds_2_sid_fds (
734                            /* dest */
735                            int *vcom_nsid_fds,
736                            fd_set * __restrict vcom_rd_sid_fds,
737                            fd_set * __restrict vcom_wr_sid_fds,
738                            fd_set * __restrict vcom_ex_sid_fds,
739                            /* src */
740                            int vcom_nfds,
741                            fd_set * __restrict vcom_readfds,
742                            fd_set * __restrict vcom_writefds,
743                            fd_set * __restrict vcom_exceptfds)
744{
745  int rv = 0;
746  int fd;
747  int sid;
748  /* invalid max_sid is -1 */
749  int max_sid = -1;
750  int nsid = 0;
751
752  /*
753   *  set sid in sid sets corresponding to fd's in fd sets
754   *  compute nsid and vcom_nsid_fds from sid sets
755   */
756
757  for (fd = 0; fd < vcom_nfds; fd++)
758    {
759      /*
760       * F fd set, src
761       * S sid set, dest
762       */
763#define _(S,F)                              \
764      if ((F) && (S) && FD_ISSET (fd, (F))) \
765        {                                   \
766          sid = vcom_socket_get_sid (fd);   \
767          if (sid != INVALID_SESSION_ID)    \
768            {                               \
769              FD_SET (sid, (S));            \
770              if (sid > max_sid)            \
771                {                           \
772                  max_sid = sid;            \
773                }                           \
774              ++nsid;                       \
775            }                               \
776          else                              \
777            {                               \
778              rv = -EBADFD;                 \
779              goto done;                    \
780            }                               \
781        }
782
783
784      _(vcom_rd_sid_fds, vcom_readfds);
785      _(vcom_wr_sid_fds, vcom_writefds);
786      _(vcom_ex_sid_fds, vcom_exceptfds);
787#undef _
788    }
789
790  *vcom_nsid_fds = max_sid != -1 ? max_sid + 1 : 0;
791  rv = nsid;
792
793done:
794  return rv;
795}
796
797/*
798 * PRE: 00. sid sets were derived from fd sets
799 *      01. sid sets were updated with sids that actually changed
800 *          status
801 *      02. fd sets still has watched fds
802 *
803 * This function will modify in place fd sets to indicate which fd's
804 * actually changed status(inferred from sid sets)
805 */
806static inline int
807vcom_socket_sid_fds_2_fds (
808                            /* dest */
809                            int *new_vcom_nfds,
810                            int vcom_nfds,
811                            fd_set * __restrict vcom_readfds,
812                            fd_set * __restrict vcom_writefds,
813                            fd_set * __restrict vcom_exceptfds,
814                            /* src */
815                            int vcom_nsid_fds,
816                            fd_set * __restrict vcom_rd_sid_fds,
817                            fd_set * __restrict vcom_wr_sid_fds,
818                            fd_set * __restrict vcom_ex_sid_fds)
819{
820  int rv = 0;
821  int fd;
822  int sid;
823  /* invalid max_fd is -1 */
824  int max_fd = -1;
825  int nfd = 0;
826
827
828  /*
829   *  modify in place fd sets to indicate which fd's
830   * actually changed status(inferred from sid sets)
831   */
832  for (fd = 0; fd < vcom_nfds; fd++)
833    {
834      /*
835       * F fd set, dest
836       * S sid set, src
837       */
838#define _(S,F)                              \
839      if ((F) && (S) && FD_ISSET (fd, (F))) \
840        {                                   \
841          sid = vcom_socket_get_sid (fd);   \
842          if (sid != INVALID_SESSION_ID)    \
843            {                               \
844              if (!FD_ISSET (sid, (S)))     \
845                {                           \
846                   FD_CLR(fd, (F));         \
847                }                           \
848            }                               \
849          else                              \
850            {                               \
851              rv = -EBADFD;                 \
852              goto done;                    \
853            }                               \
854        }
855
856
857      _(vcom_rd_sid_fds, vcom_readfds);
858      _(vcom_wr_sid_fds, vcom_writefds);
859      _(vcom_ex_sid_fds, vcom_exceptfds);
860#undef _
861    }
862
863  /*
864   *  compute nfd and new_vcom_nfds from fd sets
865   */
866  for (fd = 0; fd < vcom_nfds; fd++)
867    {
868
869#define _(F)                                \
870      if ((F) && FD_ISSET (fd, (F)))        \
871        {                                   \
872          if (fd > max_fd)                  \
873            {                               \
874              max_fd = fd;                  \
875            }                               \
876          ++nfd;                            \
877        }
878
879
880      _(vcom_readfds);
881      _(vcom_writefds);
882      _(vcom_exceptfds);
883#undef _
884
885    }
886
887  *new_vcom_nfds = max_fd != -1 ? max_fd + 1 : 0;
888  rv = nfd;
889
890done:
891  return rv;
892}
893
894/*
895 * PRE:
896 * vom_socket_select is always called with
897 * timeout->tv_sec and timeout->tv_usec set to zero.
898 * hence vppcom_select return immediately.
899 */
900/*
901 * TBD: do{body;} while(timeout conditional); timeout loop
902 */
903int
904vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
905                    fd_set * __restrict vcom_writefds,
906                    fd_set * __restrict vcom_exceptfds,
907                    struct timeval *__restrict timeout)
908{
909  int rv = -EBADF;
910  pid_t pid = getpid ();
911
912  int new_vcom_nfds = 0;
913  int new_vcom_nfd = 0;
914
915  /* vcom sid fds */
916  fd_set vcom_rd_sid_fds;
917  fd_set vcom_wr_sid_fds;
918  fd_set vcom_ex_sid_fds;
919  unsigned long vcom_nsid_fds = 0;
920  int vcom_nsid = 0;
921
922  /* in seconds eg. 3.123456789 seconds */
923  double time_to_wait = (double) 0;
924
925  /* validate inputs */
926  if (vcom_nfds < 0)
927    {
928      return -EINVAL;
929    }
930
931  /* convert timeval timeout to double time_to_wait */
932  if (timeout)
933    {
934      if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
935        {
936          /* polling: vppcom_select returns immediately */
937          time_to_wait = (double) 0;
938        }
939      else
940        {
941          /*TBD:  use timeval api */
942          time_to_wait = (double) timeout->tv_sec +
943            (double) timeout->tv_usec / (double) 1000000 +
944            (double) (timeout->tv_usec % 1000000) / (double) 1000000;
945        }
946    }
947  else
948    {
949      /*
950       * no timeout: vppcom_select can block indefinitely
951       * waiting for a file descriptor to become ready
952       * */
953      /* set to a phantom value */
954      time_to_wait = ~0;
955    }
956
957  /* zero the sid_sets */
958  /*
959   * F fd set
960   * S sid set
961   */
962#define _(S,F)                          \
963  if ((F))                              \
964    {                                   \
965      FD_ZERO ((S));                    \
966    }
967
968
969  _(&vcom_rd_sid_fds, vcom_readfds);
970  _(&vcom_wr_sid_fds, vcom_writefds);
971  _(&vcom_ex_sid_fds, vcom_exceptfds);
972#undef _
973
974  /* populate read, write and except sid_sets */
975  vcom_nsid = vcom_socket_fds_2_sid_fds (
976                                          /* dest */
977                                          vcom_readfds || vcom_writefds
978                                          || vcom_exceptfds ? (int *)
979                                          &vcom_nsid_fds : NULL,
980                                          vcom_readfds ? &vcom_rd_sid_fds :
981                                          NULL,
982                                          vcom_writefds ? &vcom_wr_sid_fds :
983                                          NULL,
984                                          vcom_exceptfds ? &vcom_ex_sid_fds :
985                                          NULL,
986                                          /* src */
987                                          vcom_nfds,
988                                          vcom_readfds,
989                                          vcom_writefds, vcom_exceptfds);
990  if (vcom_nsid < 0)
991    {
992      return vcom_nsid;
993    }
994  if (vcom_nsid_fds < 0)
995    {
996      return -EINVAL;
997    }
998
999  rv = vppcom_select (vcom_nsid_fds,
1000                      vcom_readfds ? (unsigned long *) &vcom_rd_sid_fds :
1001                      NULL,
1002                      vcom_writefds ? (unsigned long *) &vcom_wr_sid_fds :
1003                      NULL,
1004                      vcom_exceptfds ? (unsigned long *) &vcom_ex_sid_fds :
1005                      NULL, time_to_wait);
1006  if (VCOM_DEBUG > 0)
1007    fprintf (stderr, "[%d] vppcom_select: "
1008             "'%04d'='%04d'\n", pid, rv, (int) vcom_nsid_fds);
1009
1010  /* check if any file descriptors changed status */
1011  if (rv > 0)
1012    {
1013      /*
1014       * on exit, sets are modified in place to indicate which
1015       * file descriptors actually changed status
1016       * */
1017
1018      /*
1019       * comply with pre-condition
1020       * do not clear vcom fd sets befor calling
1021       * vcom_socket_sid_fds_2_fds
1022       */
1023      new_vcom_nfd = vcom_socket_sid_fds_2_fds (
1024                                                 /* dest */
1025                                                 &new_vcom_nfds,
1026                                                 vcom_nfds,
1027                                                 vcom_readfds,
1028                                                 vcom_writefds,
1029                                                 vcom_exceptfds,
1030                                                 /* src */
1031                                                 vcom_nsid_fds,
1032                                                 vcom_readfds ?
1033                                                 &vcom_rd_sid_fds : NULL,
1034                                                 vcom_writefds ?
1035                                                 &vcom_wr_sid_fds : NULL,
1036                                                 vcom_exceptfds ?
1037                                                 &vcom_ex_sid_fds : NULL);
1038      if (new_vcom_nfd < 0)
1039        {
1040          return new_vcom_nfd;
1041        }
1042      if (new_vcom_nfds < 0)
1043        {
1044          return -EINVAL;
1045        }
1046      rv = new_vcom_nfd;
1047    }
1048  return rv;
1049}
1050
1051
1052int
1053vcom_socket_socket (int __domain, int __type, int __protocol)
1054{
1055  int rv = -1;
1056  vcom_socket_main_t *vsm = &vcom_socket_main;
1057  vcom_socket_t *vsock;
1058
1059  i32 fd;
1060  i32 sid;
1061  i32 sockidx;
1062  u8 is_nonblocking = __type & SOCK_NONBLOCK ? 1 : 0;
1063  int type = __type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC);
1064
1065  fd = vcom_socket_open_socket (__domain, __type, __protocol);
1066  if (fd < 0)
1067    {
1068      rv = fd;
1069      goto out;
1070    }
1071
1072  sid = vppcom_session_create (VPPCOM_VRF_DEFAULT,
1073                               (type == SOCK_DGRAM) ?
1074                               VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP,
1075                               is_nonblocking);
1076  if (sid < 0)
1077    {
1078      rv = sid;
1079      goto out_close_socket;
1080    }
1081
1082  pool_get (vsm->vsockets, vsock);
1083  vsocket_init (vsock);
1084
1085  sockidx = vsock - vsm->vsockets;
1086  hash_set (vsm->sockidx_by_fd, fd, sockidx);
1087
1088  vsocket_set (vsock, fd, sid, SOCKET_TYPE_VPPCOM_BOUND);
1089  return fd;
1090
1091out_close_socket:
1092  vcom_socket_close_socket (fd);
1093out:
1094  return rv;
1095}
1096
1097int
1098vcom_socket_socketpair (int __domain, int __type, int __protocol,
1099                        int __fds[2])
1100{
1101/* TBD: */
1102  return 0;
1103}
1104
1105int
1106vcom_socket_bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1107{
1108  int rv = -1;
1109  vcom_socket_main_t *vsm = &vcom_socket_main;
1110  uword *p;
1111  vcom_socket_t *vsock;
1112
1113  vppcom_endpt_t ep;
1114
1115  p = hash_get (vsm->sockidx_by_fd, __fd);
1116  if (!p)
1117    return -EBADF;
1118
1119  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1120  if (!vsock)
1121    return -ENOTSOCK;
1122
1123  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1124    return -EINVAL;
1125
1126  if (!__addr)
1127    {
1128      return -EINVAL;
1129    }
1130
1131  ep.vrf = VPPCOM_VRF_DEFAULT;
1132  switch (__addr->sa_family)
1133    {
1134    case AF_INET:
1135      if (__len != sizeof (struct sockaddr_in))
1136        {
1137          return -EINVAL;
1138        }
1139      ep.is_ip4 = VPPCOM_IS_IP4;
1140      ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1141      ep.port = (u16) ((const struct sockaddr_in *) __addr)->sin_port;
1142      break;
1143
1144    case AF_INET6:
1145      if (__len != sizeof (struct sockaddr_in6))
1146        {
1147          return -EINVAL;
1148        }
1149      ep.is_ip4 = VPPCOM_IS_IP6;
1150      ep.ip = (u8 *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1151      ep.port = (u16) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1152      break;
1153
1154    default:
1155      return -1;
1156      break;
1157    }
1158
1159  rv = vppcom_session_bind (vsock->sid, &ep);
1160  /* TBD: remove libc_bind code snippet
1161   * once vppcom implements vppcom_session_getsockname */
1162  if (rv == 0)
1163    {
1164      rv = libc_bind (__fd, __addr, __len);
1165      if (rv != 0)
1166        {
1167          rv = -errno;
1168        }
1169    }
1170  return rv;
1171}
1172
1173int
1174vppcom_session_getsockname (int sid, vppcom_endpt_t * ep)
1175{
1176  /* TBD: move it to vppcom */
1177  return 0;
1178}
1179
1180int
1181vcom_socket_getsockname (int __fd, __SOCKADDR_ARG __addr,
1182                         socklen_t * __restrict __len)
1183{
1184  int rv = -1;
1185  vcom_socket_main_t *vsm = &vcom_socket_main;
1186  uword *p;
1187  vcom_socket_t *vsock;
1188
1189
1190  p = hash_get (vsm->sockidx_by_fd, __fd);
1191  if (!p)
1192    return -EBADF;
1193
1194  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1195  if (!vsock)
1196    return -ENOTSOCK;
1197
1198  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1199    return -EINVAL;
1200
1201  if (!__addr || !__len)
1202    return -EFAULT;
1203
1204  if (*__len < 0)
1205    {
1206      return -EINVAL;
1207    }
1208
1209  /* TBD: remove libc_getsockname code snippet
1210   * once vppcom implements vppcom_session_getsockname */
1211  rv = libc_getsockname (__fd, __addr, __len);
1212  if (rv != 0)
1213    {
1214      rv = -errno;
1215      return rv;
1216    }
1217
1218  /* TBD: use the below code snippet when vppcom
1219   * implements vppcom_session_getsockname */
1220#if 0
1221  vppcom_endpt_t ep;
1222  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1223  rv = vppcom_session_getsockname (vsock->sid, &ep);
1224  if (rv == 0)
1225    {
1226      if (ep.vrf == VPPCOM_VRF_DEFAULT)
1227        {
1228          __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1229          switch (__addr->sa_family)
1230            {
1231            case AF_INET:
1232              ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1233              *__len = sizeof (struct sockaddr_in);
1234              break;
1235
1236            case AF_INET6:
1237              ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1238              *__len = sizeof (struct sockaddr_in6);
1239              break;
1240
1241            default:
1242              break;
1243            }
1244        }
1245    }
1246#endif
1247
1248  return rv;
1249}
1250
1251int
1252vcom_socket_connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
1253{
1254  int rv = -1;
1255  vcom_socket_main_t *vsm = &vcom_socket_main;
1256  uword *p;
1257  vcom_socket_t *vsock;
1258
1259  vppcom_endpt_t ep;
1260
1261  p = hash_get (vsm->sockidx_by_fd, __fd);
1262  if (p)
1263    {
1264      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1265
1266      ep.vrf = VPPCOM_VRF_DEFAULT;
1267      switch (__addr->sa_family)
1268        {
1269        case AF_INET:
1270          ep.is_ip4 = VPPCOM_IS_IP4;
1271          ep.ip =
1272            (uint8_t *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1273          ep.port =
1274            (uint16_t) ((const struct sockaddr_in *) __addr)->sin_port;
1275          break;
1276
1277        case AF_INET6:
1278          ep.is_ip4 = VPPCOM_IS_IP6;
1279          ep.ip =
1280            (uint8_t *) & ((const struct sockaddr_in6 *) __addr)->sin6_addr;
1281          ep.port =
1282            (uint16_t) ((const struct sockaddr_in6 *) __addr)->sin6_port;
1283          break;
1284
1285        default:
1286          return -1;
1287          break;
1288        }
1289
1290      rv = vppcom_session_connect (vsock->sid, &ep);
1291    }
1292  return rv;
1293}
1294
1295int
1296vppcom_session_getpeername (int sid, vppcom_endpt_t * ep)
1297{
1298  /* TBD: move it to vppcom */
1299  return 0;
1300}
1301
1302int
1303vcom_socket_getpeername (int __fd, __SOCKADDR_ARG __addr,
1304                         socklen_t * __restrict __len)
1305{
1306  int rv = -1;
1307  vcom_socket_main_t *vsm = &vcom_socket_main;
1308  uword *p;
1309  vcom_socket_t *vsock;
1310
1311
1312  p = hash_get (vsm->sockidx_by_fd, __fd);
1313  if (!p)
1314    return -EBADF;
1315
1316  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1317  if (!vsock)
1318    return -ENOTSOCK;
1319
1320  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1321    return -EINVAL;
1322
1323  if (!__addr || !__len)
1324    return -EFAULT;
1325
1326  if (*__len < 0)
1327    {
1328      return -EINVAL;
1329    }
1330
1331  /* DAW: hack to allow iperf3 to be happy w/ getpeername output */
1332  {
1333    uint8_t *a;
1334    ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
1335    ((struct sockaddr_in *) __addr)->sin_port = 0x1000;
1336    a = (uint8_t *) & ((struct sockaddr_in *) __addr)->sin_addr;
1337    a[0] = 0x7f;
1338    a[1] = 0x00;
1339    a[2] = 0x00;
1340    a[3] = 0x01;
1341    *__len = sizeof (struct sockaddr_in);
1342    return 0;
1343  }
1344
1345  /* TBD: remove libc_getpeername code snippet
1346   * once vppcom implements vppcom_session_getpeername */
1347  rv = libc_getpeername (__fd, __addr, __len);
1348  if (rv != 0)
1349    {
1350      rv = -errno;
1351      return rv;
1352    }
1353
1354  /* TBD: use the below code snippet when vppcom
1355   * implements vppcom_session_getpeername */
1356#if 0
1357  vppcom_endpt_t ep;
1358  ep.ip = (u8 *) & ((const struct sockaddr_in *) __addr)->sin_addr;
1359  rv = vppcom_session_getpeername (vsock->sid, &ep);
1360  if (rv == 0)
1361    {
1362      if (ep.vrf == VPPCOM_VRF_DEFAULT)
1363        {
1364          __addr->sa_family = ep.is_ip4 == VPPCOM_IS_IP4 ? AF_INET : AF_INET6;
1365          switch (__addr->sa_family)
1366            {
1367            case AF_INET:
1368              ((struct sockaddr_in *) __addr)->sin_port = ep.port;
1369              *__len = sizeof (struct sockaddr_in);
1370              break;
1371
1372            case AF_INET6:
1373              ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
1374              *__len = sizeof (struct sockaddr_in6);
1375              break;
1376
1377            default:
1378              break;
1379            }
1380        }
1381    }
1382#endif
1383
1384  return rv;
1385}
1386
1387ssize_t
1388vcom_socket_send (int __fd, const void *__buf, size_t __n, int __flags)
1389{
1390  return vcom_socket_sendto (__fd, __buf, __n, __flags, NULL, 0);
1391}
1392
1393ssize_t
1394vcom_socket_recv (int __fd, void *__buf, size_t __n, int __flags)
1395{
1396  int rv = -1;
1397  rv = vcom_socket_recvfrom (__fd, __buf, __n, __flags, NULL, 0);
1398  return rv;
1399}
1400
1401/*
1402 * RETURN   1 if __fd is (SOCK_STREAM, SOCK_SEQPACKET),
1403 * 0 otherwise
1404 * */
1405int
1406vcom_socket_is_connection_mode_socket (int __fd)
1407{
1408  int rv = -1;
1409  /* TBD define new vppcom api */
1410  vcom_socket_main_t *vsm = &vcom_socket_main;
1411  uword *p;
1412  vcom_socket_t *vsock;
1413
1414  int type;
1415  socklen_t optlen;
1416
1417  p = hash_get (vsm->sockidx_by_fd, __fd);
1418
1419  if (p)
1420    {
1421      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1422      if (vsock && vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
1423        {
1424          optlen = sizeof (type);
1425          rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, &type, &optlen);
1426          if (rv != 0)
1427            {
1428              return 0;
1429            }
1430          /* get socket type */
1431          switch (type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1432            {
1433            case SOCK_STREAM:
1434            case SOCK_SEQPACKET:
1435              return 1;
1436              break;
1437
1438            default:
1439              return 0;
1440              break;
1441            }
1442        }
1443    }
1444  return 0;
1445}
1446
1447ssize_t
1448vvppcom_session_sendto (int __sid, const void *__buf, size_t __n,
1449                        int __flags, __CONST_SOCKADDR_ARG __addr,
1450                        socklen_t __addr_len)
1451{
1452  int rv = -1;
1453  /* TBD add new vpp api  */
1454  /* TBD add flags parameter */
1455  rv = vppcom_session_write (__sid, (void *) __buf, (int) __n);
1456  return rv;
1457}
1458
1459ssize_t
1460vcom_socket_sendto (int __fd, const void *__buf, size_t __n,
1461                    int __flags, __CONST_SOCKADDR_ARG __addr,
1462                    socklen_t __addr_len)
1463{
1464  int rv = -1;
1465  vcom_socket_main_t *vsm = &vcom_socket_main;
1466  uword *p;
1467  vcom_socket_t *vsock;
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 (!__buf || __n < 0)
1481    {
1482      return -EINVAL;
1483    }
1484
1485  if (vcom_socket_is_connection_mode_socket (__fd))
1486    {
1487      /* ignore __addr and _addr_len */
1488      /* and EISCONN may be returned when they are not NULL and 0 */
1489      if ((__addr != NULL) || (__addr_len != 0))
1490        {
1491          return -EISCONN;
1492        }
1493    }
1494  else
1495    {
1496      if (!__addr || __addr_len < 0)
1497        {
1498          return -EDESTADDRREQ;
1499        }
1500      /* not a vppcom supported address family */
1501      if ((__addr->sa_family != AF_INET) || (__addr->sa_family != AF_INET6))
1502        {
1503          return -EINVAL;
1504        }
1505    }
1506
1507  rv = vvppcom_session_sendto (vsock->sid, (void *) __buf, (int) __n,
1508                               __flags, __addr, __addr_len);
1509  return rv;
1510}
1511
1512/* TBD: move it to vppcom */
1513static ssize_t
1514vppcom_session_recvfrom (int __sid, void *__restrict __buf, size_t __n,
1515                         int __flags, __SOCKADDR_ARG __addr,
1516                         socklen_t * __restrict __addr_len)
1517{
1518  int rv = -1;
1519
1520  /* TBD add flags parameter */
1521  rv = vppcom_session_read (__sid, __buf, __n);
1522  return rv;
1523}
1524
1525ssize_t
1526vcom_socket_recvfrom (int __fd, void *__restrict __buf, size_t __n,
1527                      int __flags, __SOCKADDR_ARG __addr,
1528                      socklen_t * __restrict __addr_len)
1529{
1530  int rv = -1;
1531  vcom_socket_main_t *vsm = &vcom_socket_main;
1532  uword *p;
1533  vcom_socket_t *vsock;
1534
1535  p = hash_get (vsm->sockidx_by_fd, __fd);
1536  if (!p)
1537    return -EBADF;
1538
1539  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1540  if (!vsock)
1541    return -ENOTSOCK;
1542
1543  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1544    return -EINVAL;
1545
1546  if (!__buf || __n < 0)
1547    {
1548      return -EINVAL;
1549    }
1550
1551  if (__addr || __addr_len < 0)
1552    {
1553      return -EINVAL;
1554    }
1555
1556  rv = vppcom_session_recvfrom (vsock->sid, __buf, __n,
1557                                __flags, __addr, __addr_len);
1558  return rv;
1559}
1560
1561/* TBD: move it to vppcom */
1562static ssize_t
1563vppcom_sendmsg (int __sid, const struct msghdr *__message, int __flags)
1564{
1565  int rv = -1;
1566  /* rv = vppcom_session_write (__sid, (void *) __message->__buf,
1567     (int)__n); */
1568  return rv;
1569}
1570
1571ssize_t
1572vcom_socket_sendmsg (int __fd, const struct msghdr * __message, int __flags)
1573{
1574  int rv = -1;
1575  vcom_socket_main_t *vsm = &vcom_socket_main;
1576  uword *p;
1577  vcom_socket_t *vsock;
1578
1579  p = hash_get (vsm->sockidx_by_fd, __fd);
1580  if (!p)
1581    return -EBADF;
1582
1583  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1584  if (!vsock)
1585    return -ENOTSOCK;
1586
1587  if (vcom_socket_is_connection_mode_socket (__fd))
1588    {
1589      /* ignore __addr and _addr_len */
1590      /* and EISCONN may be returned when they are not NULL and 0 */
1591      if ((__message->msg_name != NULL) || (__message->msg_namelen != 0))
1592        {
1593          return -EISCONN;
1594        }
1595    }
1596  else
1597    {
1598      /* TBD: validate __message->msg_name and __message->msg_namelen
1599       * and return -EINVAL on validation error
1600       * */
1601      ;
1602    }
1603
1604  rv = vppcom_sendmsg (vsock->sid, __message, __flags);
1605
1606  return rv;
1607}
1608
1609#ifdef __USE_GNU
1610int
1611vcom_socket_sendmmsg (int __fd, struct mmsghdr *__vmessages,
1612                      unsigned int __vlen, int __flags)
1613{
1614
1615  /* TBD: define a new vppcom api */
1616  return 0;
1617}
1618#endif
1619
1620/* TBD: move it to vppcom */
1621static ssize_t
1622vppcom_recvmsg (int __sid, struct msghdr *__message, int __flags)
1623{
1624  int rv = -1;
1625  /* rv = vppcom_session_read (__sid, (void *) __message->__buf,
1626     (int)__n); */
1627  rv = -EOPNOTSUPP;
1628  return rv;
1629}
1630
1631ssize_t
1632vcom_socket_recvmsg (int __fd, struct msghdr * __message, int __flags)
1633{
1634  int rv = -1;
1635  vcom_socket_main_t *vsm = &vcom_socket_main;
1636  uword *p;
1637  vcom_socket_t *vsock;
1638
1639  p = hash_get (vsm->sockidx_by_fd, __fd);
1640  if (!p)
1641    return -EBADF;
1642
1643  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1644  if (!vsock)
1645    return -ENOTSOCK;
1646
1647  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1648    return -EINVAL;
1649
1650  if (!__message)
1651    {
1652      return -EINVAL;
1653    }
1654
1655  /* validate __flags */
1656
1657  rv = vppcom_recvmsg (vsock->sid, __message, __flags);
1658  return rv;
1659}
1660
1661#ifdef __USE_GNU
1662int
1663vcom_socket_recvmmsg (int __fd, struct mmsghdr *__vmessages,
1664                      unsigned int __vlen, int __flags,
1665                      struct timespec *__tmo)
1666{
1667  /* TBD: define a new vppcom api */
1668  return 0;
1669}
1670#endif
1671
1672/* TBD: move it to vppcom */
1673static int
1674vppcom_getsockopt (int __sid, int __level, int __optname,
1675                   void *__restrict __optval, socklen_t * __restrict __optlen)
1676{
1677  /* 1. for socket level options that are NOT socket attributes
1678   *    and that has corresponding vpp options get from vppcom */
1679#if 0
1680  return 0;
1681#endif
1682
1683  /* 2. unhandled options */
1684  return -ENOPROTOOPT;
1685}
1686
1687int
1688vcom_socket_getsockopt (int __fd, int __level, int __optname,
1689                        void *__restrict __optval,
1690                        socklen_t * __restrict __optlen)
1691{
1692  int rv = -1;
1693  vcom_socket_main_t *vsm = &vcom_socket_main;
1694  uword *p;
1695  vcom_socket_t *vsock;
1696
1697  p = hash_get (vsm->sockidx_by_fd, __fd);
1698  if (!p)
1699    return -EBADF;
1700
1701  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1702  if (!vsock)
1703    return -ENOTSOCK;
1704
1705  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1706    return -EINVAL;
1707
1708  if (!__optval && !__optlen)
1709    return -EFAULT;
1710
1711  if (*__optlen < 0)
1712    {
1713      return -EINVAL;
1714    }
1715
1716  switch (__level)
1717    {
1718      /* handle options at socket level */
1719    case SOL_SOCKET:
1720      switch (__optname)
1721        {
1722/*
1723 *  1. for socket level options that are socket attributes,
1724 *     get from libc_getsockopt.
1725 *  2. for socket level options that are NOT socket
1726 *     attributes and that has corresponding vpp options
1727 *     get from vppcom.
1728 *  3. for socket level options unimplemented
1729 *     return -ENOPROTOOPT */
1730        case SO_DEBUG:
1731        case SO_DONTROUTE:
1732        case SO_BROADCAST:
1733        case SO_SNDBUF:
1734        case SO_RCVBUF:
1735        case SO_REUSEADDR:
1736        case SO_REUSEPORT:
1737        case SO_KEEPALIVE:
1738        case SO_TYPE:
1739        case SO_PROTOCOL:
1740        case SO_DOMAIN:
1741        case SO_ERROR:
1742        case SO_OOBINLINE:
1743        case SO_NO_CHECK:
1744        case SO_PRIORITY:
1745        case SO_LINGER:
1746        case SO_BSDCOMPAT:
1747        case SO_TIMESTAMP:
1748        case SO_TIMESTAMPNS:
1749        case SO_TIMESTAMPING:
1750        case SO_RCVTIMEO:
1751        case SO_SNDTIMEO:
1752        case SO_RCVLOWAT:
1753        case SO_SNDLOWAT:
1754        case SO_PASSCRED:
1755        case SO_PEERCRED:
1756        case SO_PEERNAME:
1757        case SO_ACCEPTCONN:
1758        case SO_PASSSEC:
1759        case SO_PEERSEC:
1760        case SO_MARK:
1761        case SO_RXQ_OVFL:
1762        case SO_WIFI_STATUS:
1763        case SO_PEEK_OFF:
1764        case SO_NOFCS:
1765        case SO_BINDTODEVICE:
1766        case SO_GET_FILTER:
1767        case SO_LOCK_FILTER:
1768        case SO_BPF_EXTENSIONS:
1769        case SO_SELECT_ERR_QUEUE:
1770#ifdef CONFIG_NET_RX_BUSY_POLL
1771        case SO_BUSY_POLL:
1772#endif
1773        case SO_MAX_PACING_RATE:
1774        case SO_INCOMING_CPU:
1775          rv = libc_getsockopt (__fd, __level, __optname, __optval, __optlen);
1776          if (rv != 0)
1777            {
1778              rv = -errno;
1779              return rv;
1780            }
1781          break;
1782
1783        default:
1784          /* We implement the SO_SNDLOWAT etc to not be settable
1785           * (1003.1g 7).
1786           */
1787          return -ENOPROTOOPT;
1788        }
1789
1790      break;
1791
1792    default:
1793      /* 1. handle options that are NOT socket level options,
1794       *    but have corresponding vpp otions. */
1795      rv = vppcom_getsockopt (vsock->sid, __level, __optname,
1796                              __optval, __optlen);
1797
1798      return rv;
1799#if 0
1800      /* 2. unhandled options */
1801      return -ENOPROTOOPT;
1802#endif
1803    }
1804
1805  return rv;
1806}
1807
1808/* TBD: move it to vppcom */
1809int
1810vppcom_setsockopt (int __fd, int __level, int __optname,
1811                   const void *__optval, socklen_t __optlen)
1812{
1813  /* 1. for socket level options that are NOT socket attributes
1814   *    and that has corresponding vpp options set it from vppcom */
1815#if 0
1816  return 0;
1817#endif
1818
1819  /* 2. unhandled options */
1820  return -ENOPROTOOPT;
1821}
1822
1823int
1824vcom_socket_setsockopt (int __fd, int __level, int __optname,
1825                        const void *__optval, socklen_t __optlen)
1826{
1827  int rv = -1;
1828  vcom_socket_main_t *vsm = &vcom_socket_main;
1829  uword *p;
1830  vcom_socket_t *vsock;
1831
1832  p = hash_get (vsm->sockidx_by_fd, __fd);
1833  if (!p)
1834    return -EBADF;
1835
1836  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1837  if (!vsock)
1838    return -ENOTSOCK;
1839
1840  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
1841    return -EINVAL;
1842
1843  /*
1844   *      Options without arguments
1845   */
1846
1847  if (__optname == SO_BINDTODEVICE)
1848    {
1849      rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1850      if (rv != 0)
1851        {
1852          rv = -errno;
1853        }
1854      return rv;
1855    }
1856
1857  if (!__optval)
1858    return -EFAULT;
1859
1860  if ((__optlen < 0) || (__optlen < sizeof (int)))
1861    return -EINVAL;
1862
1863  switch (__level)
1864    {
1865      /* handle options at socket level */
1866    case SOL_SOCKET:
1867      switch (__optname)
1868        {
1869          /*
1870           * 1. for socket level options that are socket attributes,
1871           *    set it from libc_getsockopt
1872           * 2. for socket level options that are NOT socket
1873           *    attributes and that has corresponding vpp options
1874           *    set it from vppcom
1875           * 3. for socket level options unimplemented
1876           *    return -ENOPROTOOPT */
1877        case SO_DEBUG:
1878        case SO_DONTROUTE:
1879        case SO_BROADCAST:
1880        case SO_SNDBUF:
1881        case SO_RCVBUF:
1882        case SO_REUSEADDR:
1883        case SO_REUSEPORT:
1884        case SO_KEEPALIVE:
1885        case SO_TYPE:
1886        case SO_PROTOCOL:
1887        case SO_DOMAIN:
1888        case SO_ERROR:
1889        case SO_OOBINLINE:
1890        case SO_NO_CHECK:
1891        case SO_PRIORITY:
1892        case SO_LINGER:
1893        case SO_BSDCOMPAT:
1894        case SO_TIMESTAMP:
1895        case SO_TIMESTAMPNS:
1896        case SO_TIMESTAMPING:
1897        case SO_RCVTIMEO:
1898        case SO_SNDTIMEO:
1899        case SO_RCVLOWAT:
1900        case SO_SNDLOWAT:
1901        case SO_PASSCRED:
1902        case SO_PEERCRED:
1903        case SO_PEERNAME:
1904        case SO_ACCEPTCONN:
1905        case SO_PASSSEC:
1906        case SO_PEERSEC:
1907        case SO_MARK:
1908        case SO_RXQ_OVFL:
1909        case SO_WIFI_STATUS:
1910        case SO_PEEK_OFF:
1911        case SO_NOFCS:
1912          /*
1913           * SO_BINDTODEVICE already handled as
1914           * "Options without arguments" */
1915          /* case SO_BINDTODEVICE: */
1916        case SO_GET_FILTER:
1917        case SO_LOCK_FILTER:
1918        case SO_BPF_EXTENSIONS:
1919        case SO_SELECT_ERR_QUEUE:
1920#ifdef CONFIG_NET_RX_BUSY_POLL
1921        case SO_BUSY_POLL:
1922#endif
1923        case SO_MAX_PACING_RATE:
1924        case SO_INCOMING_CPU:
1925          rv = libc_setsockopt (__fd, __level, __optname, __optval, __optlen);
1926          if (rv != 0)
1927            {
1928              rv = -errno;
1929              return rv;
1930            }
1931          break;
1932
1933        default:
1934          /* We implement the SO_SNDLOWAT etc to not be settable
1935           * (1003.1g 7).
1936           */
1937          return -ENOPROTOOPT;
1938        }
1939
1940      break;
1941
1942    default:
1943      /* 1. handle options that are NOT socket level options,
1944       *    but have corresponding vpp otions. */
1945      rv = vppcom_setsockopt (vsock->sid, __level, __optname,
1946                              __optval, __optlen);
1947      return rv;
1948#if 0
1949      /* 2. unhandled options */
1950      return -ENOPROTOOPT;
1951#endif
1952    }
1953
1954  return rv;
1955}
1956
1957int
1958vcom_socket_listen (int __fd, int __n)
1959{
1960  int rv = -1;
1961  vcom_socket_main_t *vsm = &vcom_socket_main;
1962  uword *p;
1963  vcom_socket_t *vsock;
1964
1965  p = hash_get (vsm->sockidx_by_fd, __fd);
1966  if (p)
1967    {
1968      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
1969
1970      /* TBD vppcom to accept __n parameter */
1971      rv = vppcom_session_listen (vsock->sid, __n);
1972    }
1973
1974  return rv;
1975}
1976
1977static int
1978vcom_socket_connected_socket (int __fd, int __sid,
1979                              int *__domain,
1980                              int *__type, int *__protocol, int flags)
1981{
1982  int rv = -1;
1983  vcom_socket_main_t *vsm = &vcom_socket_main;
1984  vcom_socket_t *vsock;
1985
1986  i32 fd;
1987  i32 sockidx;
1988
1989  socklen_t optlen;
1990
1991  optlen = sizeof (*__domain);
1992  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_DOMAIN, __domain, &optlen);
1993  if (rv != 0)
1994    {
1995      rv = -errno;
1996      goto out;
1997    }
1998
1999  optlen = sizeof (*__type);
2000  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_TYPE, __type, &optlen);
2001  if (rv != 0)
2002    {
2003      rv = -errno;
2004      goto out;
2005    }
2006
2007  optlen = sizeof (*__protocol);
2008  rv = libc_getsockopt (__fd, SOL_SOCKET, SO_PROTOCOL, __protocol, &optlen);
2009  if (rv != 0)
2010    {
2011      rv = -errno;
2012      goto out;
2013    }
2014
2015  fd = vcom_socket_open_socket (*__domain, *__type | flags, *__protocol);
2016  if (fd < 0)
2017    {
2018      rv = fd;
2019      goto out;
2020    }
2021
2022  pool_get (vsm->vsockets, vsock);
2023  vsocket_init (vsock);
2024
2025  sockidx = vsock - vsm->vsockets;
2026  hash_set (vsm->sockidx_by_fd, fd, sockidx);
2027
2028  vsocket_set (vsock, fd, __sid, SOCKET_TYPE_VPPCOM_BOUND);
2029  return fd;
2030
2031out:
2032  return rv;
2033}
2034
2035/* If flag is 0, then accept4() is the same as accept().
2036 * SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags
2037 */
2038static int
2039vcom_socket_accept_flags (int __fd, __SOCKADDR_ARG __addr,
2040                          socklen_t * __restrict __addr_len, int flags)
2041{
2042  int rv = -1;
2043  vcom_socket_main_t *vsm = &vcom_socket_main;
2044  uword *p;
2045  vcom_socket_t *vsock;
2046
2047  int fd;
2048  int sid;
2049  int domain;
2050  int type;
2051  int protocol;
2052
2053  uint8_t addr8[sizeof (struct in6_addr)];
2054  vppcom_endpt_t ep;
2055
2056  ep.ip = addr8;
2057
2058  /* validate flags */
2059
2060  /*
2061   * for documentation
2062   *  switch (flags)
2063   *   {
2064   *   case 0:
2065   *   case SOCK_NONBLOCK:
2066   *   case SOCK_CLOEXEC:
2067   *   case SOCK_NONBLOCK | SOCK_CLOEXEC:
2068   *     break;
2069   *
2070   *   default:
2071   *     return -1;
2072   *   }
2073   */
2074  /* flags can be 0 or can be bitwise OR
2075   * of any of SOCK_NONBLOCK and SOCK_CLOEXEC */
2076
2077  if (!(!flags || (flags & (SOCK_NONBLOCK | SOCK_CLOEXEC))))
2078    {
2079      /* TBD: return proper error code */
2080      return -1;
2081    }
2082
2083  /* TBD: return proper error code */
2084
2085  if (!vcom_socket_is_connection_mode_socket (__fd))
2086    {
2087      return -EOPNOTSUPP;
2088    }
2089
2090  p = hash_get (vsm->sockidx_by_fd, __fd);
2091  if (p)
2092    {
2093      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2094
2095
2096      rv = vcom_fcntl (vsock->fd, F_GETFL, 0);
2097      if (rv < 0)
2098        {
2099          return rv;
2100        }
2101
2102      /* is blocking */
2103      if (!(rv & O_NONBLOCK))
2104        {
2105          /* socket is not marked as nonblocking
2106           * and no pending connections are present
2107           * on the queue, accept () blocks the caller
2108           * until a connection is present.
2109           */
2110          rv = vppcom_session_accept (vsock->sid, &ep,
2111                                      -1.0 /* wait forever */ );
2112        }
2113      else
2114        {
2115          /* The file descriptor refers to a socket and has been
2116           * marked nonblocking(O_NONBLOCK) and the accept would
2117           * block.
2118           * */
2119          /* is non blocking */
2120          rv = vppcom_session_accept (vsock->sid, &ep, 0);
2121          /* If the socket is marked nonblocking and
2122           * no pending connections are present on the
2123           * queue, accept fails with the error
2124           * EAGAIN or EWOULDBLOCK
2125           */
2126          if (rv == VPPCOM_ETIMEDOUT)
2127            {
2128              rv = VPPCOM_EAGAIN;
2129            }
2130        }
2131      if (rv < 0)
2132        {
2133          return rv;
2134        }
2135
2136      sid = rv;
2137
2138      /* create a new connected socket resource and set flags
2139       * on the new file descriptor.
2140       * update vsockets and sockidx_by_fd table
2141       * */
2142      fd = vcom_socket_connected_socket (__fd, sid,
2143                                         &domain, &type, &protocol, flags);
2144      if (fd < 0)
2145        {
2146          return fd;
2147        }
2148
2149      rv = fd;
2150
2151      /* TBD populate __addr and __addr_len */
2152      /* TBD: The returned address is truncated if the buffer
2153       * provided is too small, in this case, __addr_len will
2154       * return a value greater than was supplied to the call.*/
2155      if (__addr)
2156        {
2157          if (ep.is_cut_thru)
2158            {
2159              /* TBD populate __addr and __addr_len */
2160              switch (domain)
2161                {
2162                case AF_INET:
2163                  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2164                  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2165                  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2166                          addr8, sizeof (struct in_addr));
2167                  /* TBD: populate __addr_len */
2168                  if (__addr_len)
2169                    {
2170                      *__addr_len = sizeof (struct sockaddr_in);
2171                    }
2172                  break;
2173
2174                case AF_INET6:
2175                  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2176                  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2177                  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2178                          __in6_u.__u6_addr8, addr8,
2179                          sizeof (struct in6_addr));
2180                  /* TBD: populate __addr_len */
2181                  if (__addr_len)
2182                    {
2183                      *__addr_len = sizeof (struct sockaddr_in6);
2184                    }
2185                  break;
2186
2187                default:
2188                  return -EAFNOSUPPORT;
2189                }
2190            }
2191          else
2192            {
2193              switch (ep.is_ip4)
2194                {
2195                case VPPCOM_IS_IP4:
2196                  ((struct sockaddr_in *) __addr)->sin_family = AF_INET;
2197                  ((struct sockaddr_in *) __addr)->sin_port = ep.port;
2198                  memcpy (&((struct sockaddr_in *) __addr)->sin_addr,
2199                          addr8, sizeof (struct in_addr));
2200                  /* TBD: populate __addr_len */
2201                  if (__addr_len)
2202                    {
2203                      *__addr_len = sizeof (struct sockaddr_in);
2204                    }
2205                  break;
2206
2207                case VPPCOM_IS_IP6:
2208                  ((struct sockaddr_in6 *) __addr)->sin6_family = AF_INET6;
2209                  ((struct sockaddr_in6 *) __addr)->sin6_port = ep.port;
2210                  memcpy (((struct sockaddr_in6 *) __addr)->sin6_addr.
2211                          __in6_u.__u6_addr8, addr8,
2212                          sizeof (struct in6_addr));
2213                  /* TBD: populate __addr_len */
2214                  if (__addr_len)
2215                    {
2216                      *__addr_len = sizeof (struct sockaddr_in6);
2217                    }
2218                  break;
2219
2220                default:
2221                  return -EAFNOSUPPORT;
2222                }
2223            }
2224        }
2225      else
2226        {
2227          /* when __addr is NULL, nothing is filled in,
2228           * in this case, __addr_len is not used,
2229           * and should also be null
2230           * */
2231          if (__addr_len)
2232            {
2233              /* TBD: return proper error code */
2234              return -1;
2235            }
2236        }
2237    }
2238
2239  return rv;
2240}
2241
2242int
2243vcom_socket_accept (int __fd, __SOCKADDR_ARG __addr,
2244                    socklen_t * __restrict __addr_len)
2245{
2246  /* set flags to 0 for accept() */
2247  return vcom_socket_accept_flags (__fd, __addr, __addr_len, 0);
2248}
2249
2250#ifdef __USE_GNU
2251int
2252vcom_socket_accept4 (int __fd, __SOCKADDR_ARG __addr,
2253                     socklen_t * __restrict __addr_len, int __flags)
2254{
2255  /*  SOCK_NONBLOCK and SOCK_CLOEXEC can be bitwise ORed in flags */
2256  return vcom_socket_accept_flags (__fd, __addr, __addr_len, __flags);
2257}
2258#endif
2259
2260/* TBD: move it to vppcom */
2261int
2262vppcom_session_shutdown (int __fd, int __how)
2263{
2264  return 0;
2265}
2266
2267int
2268vcom_socket_shutdown (int __fd, int __how)
2269{
2270  int rv = -1;
2271  vcom_socket_main_t *vsm = &vcom_socket_main;
2272  uword *p;
2273  vcom_socket_t *vsock;
2274
2275  p = hash_get (vsm->sockidx_by_fd, __fd);
2276  if (p)
2277    {
2278      vsock = pool_elt_at_index (vsm->vsockets, p[0]);
2279      switch (__how)
2280        {
2281        case SHUT_RD:
2282        case SHUT_WR:
2283        case SHUT_RDWR:
2284          rv = vppcom_session_shutdown (vsock->sid, __how);
2285          return rv;
2286          break;
2287
2288        default:
2289          return -EINVAL;
2290          break;
2291        }
2292    }
2293
2294  return rv;
2295}
2296
2297int
2298vcom_socket_epoll_create1 (int __flags)
2299{
2300  int rv = -1;
2301  vcom_socket_main_t *vsm = &vcom_socket_main;
2302  vcom_epoll_t *vepoll;
2303
2304  i32 epfd;
2305  i32 vep_idx;
2306  i32 epollidx;
2307
2308  epfd = vcom_socket_open_epoll (__flags);
2309  if (epfd < 0)
2310    {
2311      rv = epfd;
2312      goto out;
2313    }
2314
2315  vep_idx = vppcom_epoll_create ( );
2316  if (vep_idx < 0)
2317    {
2318      rv = vep_idx;
2319      goto out_close_epoll;
2320    }
2321
2322  pool_get (vsm->vepolls, vepoll);
2323  vepoll_init (vepoll);
2324
2325  epollidx = vepoll - vsm->vepolls;
2326  hash_set (vsm->epollidx_by_epfd, epfd, epollidx);
2327
2328  vepoll_set (vepoll, epfd, vep_idx,
2329              EPOLL_TYPE_VPPCOM_BOUND, __flags, 0, 0);
2330
2331  return epfd;
2332
2333out_close_epoll:
2334  vcom_socket_close_epoll (epfd);
2335out:
2336  return rv;
2337}
2338
2339/*
2340 * PRE: vppcom_epoll_ctl() is successful
2341 * free_vepitem_on_del : 0 - no_pool_put, 1 - pool_put
2342 */
2343int
2344vcom_socket_ctl_vepitem (int __epfd, int __op, int __fd,
2345                         struct epoll_event *__event,
2346                         i32 vep_idx, vcom_epoll_t *vepoll,
2347                         i32 vfd_id, void *vfd, vcom_fd_type_t type,
2348                         int free_vepitem_on_del)
2349{
2350  int rv = -1;
2351  vcom_socket_main_t *vsm = &vcom_socket_main;
2352  vcom_epitem_t *vepitem;
2353
2354  vcom_epitem_key_t epfdfd = {.epfd = __epfd, .fd = __fd};
2355  uword *p;
2356  i32 vepitemidx;
2357
2358  i32 *vepitemidxs = 0;
2359
2360  struct epoll_event revent = {.events = 0, .data.fd = INVALID_FD};
2361
2362  i32 vec_idx ;
2363
2364  /* perform control operations on the epoll instance */
2365  switch (__op)
2366    {
2367    case EPOLL_CTL_ADD:
2368      /*
2369       * supplied file descriptor is already
2370       * registered with this epoll instance
2371       * */
2372      /* vepitem exists */
2373      p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2374      if (p)
2375        {
2376          rv = -EEXIST;
2377          goto out;
2378        }
2379
2380      /* add a new vepitem */
2381      pool_get (vsm->vepitems, vepitem);
2382      vepitem_init (vepitem);
2383
2384      vepitemidx = vepitem - vsm->vepitems;
2385      hash_set (vsm->epitemidx_by_epfdfd, epfdfd.key, vepitemidx);
2386      vepitem_set (vepitem,
2387                   __epfd,
2388                   __fd, __fd, __fd,
2389                   type,
2390                   *__event, revent);
2391
2392      /* update epitemidxs */
2393      /* by_epfd */
2394      p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2395      if (!p)   /*  not exist */
2396        {
2397          vepitemidxs = 0;
2398          vec_add1 (vepitemidxs, vepitemidx);
2399          hash_set (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs);
2400        }
2401      else      /*  exists */
2402        {
2403          vepitemidxs = *(i32 **)p;
2404          vec_add1 (vepitemidxs, vepitemidx);
2405          hash_set3 (vsm->epitemidxs_by_epfd, __epfd, vepitemidxs, 0);
2406        }
2407      /* update epitemidxs */
2408      /* by_fd */
2409      p = hash_get (vsm->epitemidxs_by_fd, __fd);
2410      if (!p)   /*  not exist */
2411        {
2412          vepitemidxs = 0;
2413          vec_add1 (vepitemidxs, vepitemidx);
2414          hash_set (vsm->epitemidxs_by_fd, __fd, vepitemidxs);
2415        }
2416      else      /*  exists */
2417        {
2418          vepitemidxs = *(i32 **)p;
2419          vec_add1 (vepitemidxs, vepitemidx);
2420          hash_set3 (vsm->epitemidxs_by_fd, __fd, vepitemidxs, 0);
2421        }
2422
2423      /* increment vepoll fd count by 1 */
2424      vepoll->count +=1;
2425
2426      rv = 0;
2427      goto out;
2428      break;
2429
2430    case EPOLL_CTL_MOD:
2431      /*
2432       * supplied file descriptor is not
2433       * registered with this epoll instance
2434       * */
2435      /* vepitem not exist */
2436      p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2437      if (!p)
2438        {
2439          rv = -ENOENT;
2440          goto out;
2441        }
2442      vepitem = pool_elt_at_index (vsm->vepitems, p[0]);
2443      if (vepitem)
2444        {
2445          vepitem->event = *__event;
2446          vepitem->revent = revent;
2447        }
2448
2449      rv = 0;
2450      goto out;
2451      break;
2452
2453    case EPOLL_CTL_DEL:
2454      /*
2455       * supplied file descriptor is not
2456       * registered with this epoll instance
2457       * */
2458      /* vepitem not exist */
2459      p = hash_get (vsm->epitemidx_by_epfdfd, epfdfd.key);
2460      if (!p)
2461        {
2462          rv = -ENOENT;
2463          goto out;
2464        }
2465      vepitemidx = *(i32 *)p;
2466      hash_unset (vsm->epitemidx_by_epfdfd, epfdfd.key);
2467
2468      /* update epitemidxs */
2469      /* by_epfd */
2470      p = hash_get (vsm->epitemidxs_by_epfd, __epfd);
2471      if (!p)   /*  not exist */
2472        {
2473          rv = -ENOENT;
2474          goto out;
2475        }
2476      else      /*  exists */
2477        {
2478          vepitemidxs = *(i32 **)p;
2479          vec_idx = vec_search (vepitemidxs, vepitemidx);
2480          if(vec_idx != ~0)
2481            {
2482              vec_del1 (vepitemidxs, vec_idx);
2483              if(!vec_len (vepitemidxs))
2484                {
2485                  vec_free (vepitemidxs);
2486                  hash_unset (vsm->epitemidxs_by_epfd, __epfd);
2487                }
2488            }
2489        }
2490
2491      /* update epitemidxs */
2492      /* by_fd */
2493      p = hash_get (vsm->epitemidxs_by_fd, __fd);
2494      if (!p)   /*  not exist */
2495        {
2496          rv = -ENOENT;
2497          goto out;
2498        }
2499      else      /*  exists */
2500        {
2501          vepitemidxs = *(i32 **)p;
2502          vec_idx = vec_search (vepitemidxs, vepitemidx);
2503          if(vec_idx != ~0)
2504            {
2505              vec_del1 (vepitemidxs, vec_idx);
2506              if(!vec_len (vepitemidxs))
2507                {
2508                  vec_free (vepitemidxs);
2509                  hash_unset (vsm->epitemidxs_by_fd, __fd);
2510                }
2511            }
2512        }
2513
2514      /* pool put vepitem */
2515      vepitem = pool_elt_at_index (vsm->vepitems, vepitemidx);
2516      if (free_vepitem_on_del)
2517      {
2518        if(!vepitem)
2519          {
2520            rv = -ENOENT;
2521            goto out;
2522          }
2523        vepitem_init(vepitem);
2524        pool_put (vsm->vepitems, vepitem);
2525      }
2526      else
2527        {
2528          if(!vepitem)
2529            {
2530              vepitem_init(vepitem);
2531            }
2532        }
2533
2534      /* decrement vepoll fd count by 1 */
2535      vepoll->count -=1;
2536
2537      rv = 0;
2538      goto out;
2539      break;
2540
2541    default:
2542      rv = -EINVAL;
2543      goto out;
2544      break;
2545    }
2546
2547out:
2548  return rv;
2549}
2550
2551/*
2552 * PRE: 00. null pointer check on __event
2553 *      01. all other parameters are validated
2554 */
2555
2556static int
2557vcom_socket_epoll_ctl_internal (int __epfd, int __op, int __fd,
2558                                struct epoll_event *__event,
2559                                int free_vepitem_on_del)
2560{
2561  int rv = -1;
2562
2563  /* vcom_socket_main_t *vsm = &vcom_socket_main; */
2564  vcom_epoll_t *vepoll;
2565
2566  /*__fd could could be vcom socket or vcom epoll or kernel fd */
2567  void *vfd;
2568  vcom_epoll_t *vfd_vepoll;
2569  vcom_socket_t *vfd_vsock;
2570
2571  i32 vep_idx;
2572  i32 vfd_id;
2573
2574  vcom_fd_type_t type = FD_TYPE_INVALID;
2575
2576  /* validate __event */
2577
2578  /* get vep_idx and vepoll */
2579  vep_idx = vcom_socket_get_vep_idx_and_vepoll (__epfd, &vepoll);
2580  if (vep_idx == INVALID_VEP_IDX)
2581    {
2582      return -EBADF;
2583    }
2584
2585  /* get vcom fd type, vfd_id and vfd */
2586  vfd_id = vcom_socket_get_sid_and_vsock (__fd, &vfd_vsock);
2587  if (vfd_id != INVALID_SESSION_ID)
2588    {
2589      type = FD_TYPE_VCOM_SOCKET;
2590      vfd = vfd_vsock;
2591    }
2592  else if ((vfd_id = vcom_socket_get_vep_idx_and_vepoll (__fd, &vfd_vepoll)) != INVALID_VEP_IDX)
2593    {
2594      type = FD_TYPE_EPOLL;
2595      vfd = vfd_vepoll;
2596    }
2597  else
2598    {
2599      /* FD_TYPE_KERNEL not supported by epoll instance */
2600      type = FD_TYPE_INVALID;
2601      return -EBADF;
2602    }
2603
2604
2605  /* vepoll and vsock are now valid */
2606  rv = vppcom_epoll_ctl ( vep_idx, __op, vfd_id, __event);
2607  if (rv < 0)
2608    {
2609      return rv;
2610    }
2611
2612  rv = vcom_socket_ctl_vepitem (__epfd, __op, __fd,
2613                                __event,
2614                                vep_idx, vepoll,
2615                                vfd_id, vfd, type,
2616                                free_vepitem_on_del);
2617  return rv;
2618}
2619
2620int
2621vcom_socket_epoll_ctl (int __epfd, int __op, int __fd,
2622                       struct epoll_event *__event)
2623{
2624  int rv = -1;
2625
2626  rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd,
2627                                       __event, 1);
2628  return rv;
2629}
2630
2631static int
2632vcom_socket_epoll_ctl1 (int __epfd, int __op, int __fd,
2633                       struct epoll_event *__event)
2634{
2635  int rv = -1;
2636
2637  rv = vcom_socket_epoll_ctl_internal (__epfd, __op, __fd,
2638                                       __event, 0);
2639  return rv;
2640}
2641
2642int
2643vcom_socket_epoll_pwait (int __epfd, struct epoll_event *__events,
2644                         int __maxevents, int __timeout,
2645                         const __sigset_t *__ss)
2646{
2647  int rv = -EBADF;
2648
2649  /* in seconds eg. 3.123456789 seconds */
2650  double time_to_wait = (double) 0;
2651
2652  i32 vep_idx;
2653
2654  /* validate __event */
2655  if (!__events)
2656    {
2657      rv = -EFAULT;
2658      goto out;
2659    }
2660
2661  /* validate __timeout */
2662  if (__timeout > 0)
2663    {
2664      time_to_wait = (double) __timeout / (double) 1000;
2665    }
2666  else if (__timeout == 0)
2667    {
2668      time_to_wait = (double) 0;
2669    }
2670  else if (__timeout == -1)
2671    {
2672      time_to_wait = ~0;
2673    }
2674  else
2675    {
2676      rv = -EBADF;
2677      goto out;
2678    }
2679
2680  /* get vep_idx */
2681  vep_idx = vcom_socket_get_vep_idx (__epfd);
2682  if (vep_idx != INVALID_VEP_IDX)
2683    {
2684      rv = vppcom_epoll_wait (vep_idx, __events,
2685                              __maxevents, time_to_wait);
2686    }
2687out:
2688    return rv;
2689}
2690
2691int
2692vcom_socket_main_init (void)
2693{
2694  vcom_socket_main_t *vsm = &vcom_socket_main;
2695
2696  if (VCOM_DEBUG > 0)
2697    printf ("vcom_socket_main_init\n");
2698
2699  if (!vsm->init)
2700    {
2701      /* TBD: define FD_MAXSIZE and use it here */
2702      pool_alloc (vsm->vsockets, FD_SETSIZE);
2703      vsm->sockidx_by_fd = hash_create (0, sizeof (i32));
2704
2705      pool_alloc (vsm->vepolls, FD_SETSIZE);
2706      vsm->epollidx_by_epfd = hash_create (0, sizeof (i32));
2707
2708      pool_alloc (vsm->vepitems, FD_SETSIZE);
2709      vsm->epitemidx_by_epfdfd = hash_create (0, sizeof (i32));
2710
2711      vsm->epitemidxs_by_epfd = hash_create (0, sizeof (i32 *));
2712      vsm->epitemidxs_by_fd = hash_create (0, sizeof (i32 *));
2713
2714      vsm->init = 1;
2715    }
2716
2717  return 0;
2718}
2719
2720
2721void
2722vcom_socket_main_show (void)
2723{
2724  vcom_socket_main_t *vsm = &vcom_socket_main;
2725  vcom_socket_t *vsock;
2726
2727  vcom_epoll_t *vepoll;
2728
2729  vcom_epitem_t *vepitem;
2730
2731  i32 epfd;
2732  i32 fd;
2733  i32 *vepitemidxs, *vepitemidxs_var;
2734
2735  if (vsm->init)
2736    {
2737      /* from active list of vsockets show vsock */
2738
2739      /* *INDENT-OFF* */
2740      pool_foreach (vsock, vsm->vsockets,
2741        ({
2742          printf(
2743                 "fd='%04d', sid='%08x',type='%-30s'\n",
2744                 vsock->fd, vsock->sid,
2745                 vcom_socket_type_str (vsock->type));
2746        }));
2747      /* *INDENT-ON* */
2748
2749      /* from active list of vepolls, show vepoll */
2750
2751      /* *INDENT-OFF* */
2752      pool_foreach (vepoll, vsm->vepolls,
2753        ({
2754          printf(
2755                 "epfd='%04d', vep_idx='%08x', "
2756                 "type='%-30s', "
2757                 "flags='%d', count='%d', close='%d'\n",
2758                 vepoll->epfd, vepoll->vep_idx,
2759                 vcom_socket_epoll_type_str (vepoll->type),
2760                 vepoll->flags, vepoll->count, vepoll->close);
2761        }));
2762      /* *INDENT-ON* */
2763
2764      /* from active list of vepitems, show vepitem */
2765
2766      /* *INDENT-OFF* */
2767      pool_foreach (vepitem, vsm->vepitems,
2768        ({
2769          printf(
2770                 "epfd='%04d', fd='%04d', "
2771                 "next_fd='%04d', prev_fd='%04d', "
2772                 "type='%-30s', "
2773                 "events='%04x', revents='%04x'\n",
2774                 vepitem->epfd, vepitem->fd,
2775                 vepitem->next_fd, vepitem->prev_fd,
2776                 vcom_socket_vcom_fd_type_str (vepitem->type),
2777                 vepitem->event.events, vepitem->revent.events);
2778        }));
2779
2780      /* *INDENT-ON* */
2781
2782      /* show epitemidxs for epfd */
2783      /* *INDENT-OFF* */
2784      hash_foreach (epfd, vepitemidxs,
2785                    vsm->epitemidxs_by_epfd,
2786      ({
2787        printf("\n[ '%04d': ", epfd);
2788        vec_foreach (vepitemidxs_var,vepitemidxs)
2789        {
2790          printf("'%04d' ", (int)vepitemidxs_var[0]);
2791        }
2792        printf("]\n");
2793      }));
2794      /* *INDENT-ON* */
2795
2796      /* show epitemidxs for fd */
2797      /* *INDENT-OFF* */
2798      hash_foreach (fd, vepitemidxs,
2799                    vsm->epitemidxs_by_fd,
2800      ({
2801        printf("\n{ '%04d': ", fd);
2802        vec_foreach (vepitemidxs_var,vepitemidxs)
2803        {
2804          printf("'%04d' ", (int)vepitemidxs_var[0]);
2805        }
2806        printf("}\n");
2807      }));
2808      /* *INDENT-ON* */
2809
2810    }
2811}
2812
2813void
2814vcom_socket_main_destroy (void)
2815{
2816  vcom_socket_main_t *vsm = &vcom_socket_main;
2817  vcom_socket_t *vsock;
2818
2819  vcom_epoll_t *vepoll;
2820
2821  vcom_epitem_t *vepitem;
2822
2823  i32 epfd;
2824  i32 fd;
2825  i32 *vepitemidxs;
2826
2827
2828  if (VCOM_DEBUG > 0)
2829    printf ("vcom_socket_main_destroy\n");
2830
2831  if (vsm->init)
2832    {
2833
2834      /*
2835       * from active list of vepitems,
2836       * remove all "vepitem" elements from the pool in a safe way
2837       * */
2838
2839      /* *INDENT-OFF* */
2840      pool_flush (vepitem, vsm->vepitems,
2841        ({
2842          if (vepitem->type == FD_TYPE_EPOLL || FD_TYPE_VCOM_SOCKET)
2843          {
2844              vcom_socket_epoll_ctl1 (vepitem->epfd, EPOLL_CTL_DEL,
2845                                     vepitem->fd, NULL);
2846             vepitem_init (vepitem);
2847          }
2848        }));
2849      /* *INDENT-ON* */
2850
2851      pool_free (vsm->vepitems);
2852      hash_free (vsm->epitemidx_by_epfdfd);
2853
2854      /* free vepitemidxs for each epfd */
2855      /* *INDENT-OFF* */
2856      hash_foreach (epfd, vepitemidxs,
2857                    vsm->epitemidxs_by_epfd,
2858      ({
2859        vec_free (vepitemidxs);
2860      }));
2861      /* *INDENT-ON* */
2862      hash_free (vsm->epitemidxs_by_epfd);
2863
2864      /* free vepitemidxs for each fd */
2865      /* *INDENT-OFF* */
2866      hash_foreach (fd, vepitemidxs,
2867                    vsm->epitemidxs_by_fd,
2868      ({
2869        vec_free (vepitemidxs);
2870      }));
2871      /* *INDENT-ON* */
2872      hash_free (vsm->epitemidxs_by_fd);
2873
2874
2875      /*
2876       * from active list of vsockets,
2877       * close socket and vppcom session
2878       * */
2879
2880      /* *INDENT-OFF* */
2881      pool_foreach (vsock, vsm->vsockets,
2882        ({
2883          if (vsock->type == SOCKET_TYPE_VPPCOM_BOUND)
2884            {
2885              vppcom_session_close (vsock->sid);
2886              vcom_socket_close_socket (vsock->fd);
2887              vsocket_init (vsock);
2888            }
2889        }));
2890      /* *INDENT-ON* */
2891
2892      /*
2893       * return vsocket element to the pool
2894       * */
2895
2896      /* *INDENT-OFF* */
2897      pool_flush (vsock, vsm->vsockets,
2898        ({
2899          // vsocket_init(vsock);
2900          ;
2901        }));
2902      /* *INDENT-ON* */
2903
2904      pool_free (vsm->vsockets);
2905      hash_free (vsm->sockidx_by_fd);
2906
2907      /*
2908       * from active list of vepolls,
2909       * close epoll and vppcom_epoll
2910       * */
2911
2912      /* *INDENT-OFF* */
2913      pool_foreach (vepoll, vsm->vepolls,
2914        ({
2915          if (vepoll->type == EPOLL_TYPE_VPPCOM_BOUND)
2916            {
2917              vppcom_session_close (vepoll->vep_idx);
2918              vcom_socket_close_epoll (vepoll->epfd); /* TBD: */
2919              vepoll_init (vepoll);
2920            }
2921        }));
2922      /* *INDENT-ON* */
2923
2924      /*
2925       * return vepoll element to the pool
2926       * */
2927
2928      /* *INDENT-OFF* */
2929      pool_flush (vepoll, vsm->vepolls,
2930        ({
2931          // vepoll_init(vepoll);
2932          ;
2933        }));
2934      /* *INDENT-ON* */
2935
2936      pool_free (vsm->vepolls);
2937      hash_free (vsm->epollidx_by_epfd);
2938
2939      vsm->init = 0;
2940    }
2941}
2942
2943
2944/*
2945 * fd.io coding-style-patch-verification: ON
2946 *
2947 * Local Variables:
2948 * eval: (c-set-style "gnu")
2949 * End:
2950 */
2951