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