+ if (wait && clib_time_now (&scm->clib_time) >= timeout)
+ return -1;
+ }
+ return 0;
+}
+
+int
+vl_socket_client_read (int wait)
+{
+ return vl_socket_client_read_internal (socket_client_ctx, wait);
+}
+
+int
+vl_socket_client_read2 (socket_client_main_t * scm, int wait)
+{
+ socket_client_main_t *old_ctx;
+ int rv;
+
+ old_ctx = vl_socket_client_ctx_push (scm);
+ rv = vl_socket_client_read_internal (scm, wait);
+ vl_socket_client_ctx_pop (old_ctx);
+ return rv;
+}
+
+static int
+vl_socket_client_write_internal (socket_client_main_t * scm)
+{
+ int n;
+
+ msgbuf_t msgbuf = {
+ .q = 0,
+ .gc_mark_timestamp = 0,
+ .data_len = htonl (scm->socket_tx_nbytes),
+ };
+
+ n = write (scm->socket_fd, &msgbuf, sizeof (msgbuf));
+ if (n < sizeof (msgbuf))
+ {
+ clib_unix_warning ("socket write (msgbuf)");
+ return -1;
+ }
+
+ n = write (scm->socket_fd, scm->socket_tx_buffer, scm->socket_tx_nbytes);
+ if (n < scm->socket_tx_nbytes)
+ {
+ clib_unix_warning ("socket write (msg)");
+ return -1;
+ }
+
+ return n;
+}
+
+int
+vl_socket_client_write (void)
+{
+ return vl_socket_client_write_internal (socket_client_ctx);
+}
+
+int
+vl_socket_client_write2 (socket_client_main_t * scm)
+{
+ socket_client_main_t *old_ctx;
+ int rv;
+
+ old_ctx = vl_socket_client_ctx_push (scm);
+ rv = vl_socket_client_write_internal (scm);
+ vl_socket_client_ctx_pop (old_ctx);
+ return rv;
+}
+
+void *
+vl_socket_client_msg_alloc2 (socket_client_main_t * scm, int nbytes)
+{
+ scm->socket_tx_nbytes = nbytes;
+ return ((void *) scm->socket_tx_buffer);
+}
+
+void *
+vl_socket_client_msg_alloc (int nbytes)
+{
+ return vl_socket_client_msg_alloc2 (socket_client_ctx, nbytes);
+}
+
+void
+vl_socket_client_disconnect2 (socket_client_main_t * scm)
+{
+ if (vl_mem_client_is_connected ())
+ {
+ vl_client_disconnect_from_vlib_no_unmap ();
+ ssvm_delete_memfd (&scm->memfd_segment);
+ }
+ if (scm->socket_fd && (close (scm->socket_fd) < 0))
+ clib_unix_warning ("close");
+ scm->socket_fd = 0;
+}
+
+void
+vl_socket_client_disconnect (void)
+{
+ vl_socket_client_disconnect2 (socket_client_ctx);
+}
+
+void
+vl_socket_client_enable_disable2 (socket_client_main_t * scm, int enable)
+{
+ scm->socket_enable = enable;
+}
+
+void
+vl_socket_client_enable_disable (int enable)
+{
+ vl_socket_client_enable_disable2 (socket_client_ctx, enable);
+}
+
+static clib_error_t *
+vl_sock_api_recv_fd_msg_internal (socket_client_main_t * scm, int fds[],
+ int n_fds, u32 wait)
+{
+ char msgbuf[16];
+ char ctl[CMSG_SPACE (sizeof (int) * n_fds)
+ + CMSG_SPACE (sizeof (struct ucred))];
+ struct msghdr mh = { 0 };
+ struct iovec iov[1];
+ ssize_t size = 0;
+ struct ucred *cr = 0;
+ struct cmsghdr *cmsg;
+ pid_t pid __attribute__ ((unused));
+ uid_t uid __attribute__ ((unused));
+ gid_t gid __attribute__ ((unused));
+ int socket_fd;
+ f64 timeout;
+
+ socket_fd = scm->client_socket.fd;
+
+ iov[0].iov_base = msgbuf;
+ iov[0].iov_len = 5;
+ mh.msg_iov = iov;
+ mh.msg_iovlen = 1;
+ mh.msg_control = ctl;
+ mh.msg_controllen = sizeof (ctl);
+
+ clib_memset (ctl, 0, sizeof (ctl));
+
+ if (wait != ~0)
+ {
+ timeout = clib_time_now (&scm->clib_time) + wait;
+ while (size != 5 && clib_time_now (&scm->clib_time) < timeout)
+ size = recvmsg (socket_fd, &mh, MSG_DONTWAIT);
+ }
+ else
+ size = recvmsg (socket_fd, &mh, 0);
+
+ if (size != 5)
+ {
+ return (size == 0) ? clib_error_return (0, "disconnected") :
+ clib_error_return_unix (0, "recvmsg: malformed message (fd %d)",
+ socket_fd);
+ }
+
+ cmsg = CMSG_FIRSTHDR (&mh);
+ while (cmsg)
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET)
+ {
+ if (cmsg->cmsg_type == SCM_CREDENTIALS)
+ {
+ cr = (struct ucred *) CMSG_DATA (cmsg);
+ uid = cr->uid;
+ gid = cr->gid;
+ pid = cr->pid;
+ }
+ else if (cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ clib_memcpy_fast (fds, CMSG_DATA (cmsg), sizeof (int) * n_fds);
+ }
+ }
+ cmsg = CMSG_NXTHDR (&mh, cmsg);
+ }
+ return 0;
+}
+
+clib_error_t *
+vl_sock_api_recv_fd_msg (int socket_fd, int fds[], int n_fds, u32 wait)
+{
+ return vl_sock_api_recv_fd_msg_internal (socket_client_ctx, fds, n_fds,
+ wait);
+}
+
+clib_error_t *
+vl_sock_api_recv_fd_msg2 (socket_client_main_t * scm, int socket_fd,
+ int fds[], int n_fds, u32 wait)
+{
+ socket_client_main_t *old_ctx;
+ clib_error_t *error;
+
+ old_ctx = vl_socket_client_ctx_push (scm);
+ error = vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait);
+ vl_socket_client_ctx_pop (old_ctx);
+ return error;
+}
+
+static void vl_api_sock_init_shm_reply_t_handler
+ (vl_api_sock_init_shm_reply_t * mp)
+{
+ socket_client_main_t *scm = socket_client_ctx;
+ ssvm_private_t *memfd = &scm->memfd_segment;
+ i32 retval = ntohl (mp->retval);
+ api_main_t *am = vlibapi_get_main ();
+ clib_error_t *error;
+ int my_fd = -1;
+ u8 *new_name;
+
+ if (retval)
+ {
+ clib_warning ("failed to init shmem");
+ return;
+ }
+
+ /*
+ * Check the socket for the magic fd
+ */
+ error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 1, 5);
+ if (error)
+ {
+ clib_error_report (error);
+ retval = -99;
+ return;
+ }
+
+ clib_memset (memfd, 0, sizeof (*memfd));
+ memfd->fd = my_fd;
+
+ /* Note: this closes memfd.fd */
+ retval = ssvm_client_init_memfd (memfd);
+ if (retval)
+ clib_warning ("WARNING: segment map returned %d", retval);
+
+ /*
+ * Pivot to the memory client segment that vpp just created
+ */
+ am->vlib_rp = (void *) (memfd->requested_va + MMAP_PAGESIZE);
+ am->shmem_hdr = (void *) am->vlib_rp->user_ctx;
+
+ new_name = format (0, "%v[shm]%c", scm->name, 0);
+ vl_client_install_client_message_handlers ();
+ if (scm->want_shm_pthread)
+ {
+ vl_client_connect_to_vlib_no_map ("pvt", (char *) new_name,
+ 32 /* input_queue_length */ );
+ }
+ else
+ {
+ vl_client_connect_to_vlib_no_rx_pthread_no_map ("pvt",
+ (char *) new_name, 32
+ /* input_queue_length */
+ );