X-Git-Url: https://gerrit.fd.io/r/gitweb?p=vpp.git;a=blobdiff_plain;f=src%2Fvlibmemory%2Fsocket_client.c;h=2fb6b8a0c4e9ac43c92f7e259f30ecfc99e40ccd;hp=8519e7f5f7c82d1c248e14d1edc20dfc9c31f786;hb=36217e3ca;hpb=59b2565cd91a67ced650739f36129650830211ac diff --git a/src/vlibmemory/socket_client.c b/src/vlibmemory/socket_client.c index 8519e7f5f7c..2fb6b8a0c4e 100644 --- a/src/vlibmemory/socket_client.c +++ b/src/vlibmemory/socket_client.c @@ -18,32 +18,13 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include +#define __USE_GNU +#define _GNU_SOURCE +#include + +#include +#include +#include #include @@ -62,32 +43,50 @@ #undef vl_printfun socket_client_main_t socket_client_main; +__thread socket_client_main_t *socket_client_ctx = &socket_client_main; /* Debug aid */ u32 vl (void *p) __attribute__ ((weak)); + u32 vl (void *p) { return vec_len (p); } -void -vl_socket_client_read_reply (socket_client_main_t * scm) +static socket_client_main_t * +vl_socket_client_ctx_push (socket_client_main_t * ctx) +{ + socket_client_main_t *old = socket_client_ctx; + socket_client_ctx = ctx; + return old; +} + +static void +vl_socket_client_ctx_pop (socket_client_main_t * old_ctx) { + socket_client_ctx = old_ctx; +} + +static int +vl_socket_client_read_internal (socket_client_main_t * scm, int wait) +{ + u32 data_len = 0, msg_size; int n, current_rx_index; - msgbuf_t *mbp; + msgbuf_t *mbp = 0; + f64 timeout; - if (scm->socket_fd == 0 || scm->socket_enable == 0) - return; + if (scm->socket_fd == 0) + return -1; - mbp = 0; + if (wait) + timeout = clib_time_now (&scm->clib_time) + wait; while (1) { - current_rx_index = vec_len (scm->socket_rx_buffer); - while (vec_len (scm->socket_rx_buffer) < - sizeof (*mbp) + 2 /* msg id */ ) + while (vec_len (scm->socket_rx_buffer) < sizeof (*mbp)) { + current_rx_index = vec_len (scm->socket_rx_buffer); vec_validate (scm->socket_rx_buffer, current_rx_index + scm->socket_buffer_size - 1); _vec_len (scm->socket_rx_buffer) = current_rx_index; @@ -95,8 +94,11 @@ vl_socket_client_read_reply (socket_client_main_t * scm) scm->socket_buffer_size); if (n < 0) { + if (errno == EAGAIN) + continue; + clib_unix_warning ("socket_read"); - return; + return -1; } _vec_len (scm->socket_rx_buffer) += n; } @@ -106,20 +108,38 @@ vl_socket_client_read_reply (socket_client_main_t * scm) clib_warning ("read %d bytes", n); #endif - if (mbp == 0) - mbp = (msgbuf_t *) (scm->socket_rx_buffer); + mbp = (msgbuf_t *) (scm->socket_rx_buffer); + data_len = ntohl (mbp->data_len); + current_rx_index = vec_len (scm->socket_rx_buffer); + vec_validate (scm->socket_rx_buffer, current_rx_index + data_len); + _vec_len (scm->socket_rx_buffer) = current_rx_index; + mbp = (msgbuf_t *) (scm->socket_rx_buffer); + msg_size = data_len + sizeof (*mbp); + + while (vec_len (scm->socket_rx_buffer) < msg_size) + { + n = read (scm->socket_fd, + scm->socket_rx_buffer + vec_len (scm->socket_rx_buffer), + msg_size - vec_len (scm->socket_rx_buffer)); + if (n < 0) + { + if (errno == EAGAIN) + continue; + + clib_unix_warning ("socket_read"); + return -1; + } + _vec_len (scm->socket_rx_buffer) += n; + } - if (vec_len (scm->socket_rx_buffer) >= ntohl (mbp->data_len) - + sizeof (*mbp)) + if (vec_len (scm->socket_rx_buffer) >= data_len + sizeof (*mbp)) { vl_msg_api_socket_handler ((void *) (mbp->data)); - if (vec_len (scm->socket_rx_buffer) == ntohl (mbp->data_len) - + sizeof (*mbp)) + if (vec_len (scm->socket_rx_buffer) == data_len + sizeof (*mbp)) _vec_len (scm->socket_rx_buffer) = 0; else - vec_delete (scm->socket_rx_buffer, ntohl (mbp->data_len) - + sizeof (*mbp), 0); + vec_delete (scm->socket_rx_buffer, data_len + sizeof (*mbp), 0); mbp = 0; /* Quit if we're out of data, and not expecting a ping reply */ @@ -127,20 +147,308 @@ vl_socket_client_read_reply (socket_client_main_t * scm) && scm->control_pings_outstanding == 0) break; } + 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 */ + ); + } + vl_socket_client_enable_disable (0); + vec_free (new_name); +} + +static void +vl_api_sockclnt_create_reply_t_handler (vl_api_sockclnt_create_reply_t * mp) +{ + socket_client_main_t *scm = socket_client_ctx; + if (!mp->response) + { + scm->socket_enable = 1; + scm->client_index = clib_net_to_host_u32 (mp->index); } } +#define foreach_sock_client_api_msg \ +_(SOCKCLNT_CREATE_REPLY, sockclnt_create_reply) \ +_(SOCK_INIT_SHM_REPLY, sock_init_shm_reply) \ + +static void +noop_handler (void *notused) +{ +} + +void +vl_sock_client_install_message_handlers (void) +{ + +#define _(N, n) \ + vl_msg_api_set_handlers (VL_API_##N, #n, vl_api_##n##_t_handler, \ + noop_handler, vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, sizeof (vl_api_##n##_t), 0, \ + vl_api_##n##_t_print_json, vl_api_##n##_t_tojson, \ + vl_api_##n##_t_fromjson); + foreach_sock_client_api_msg; +#undef _ +} + int -vl_socket_client_connect (socket_client_main_t * scm, char *socket_path, - char *client_name, u32 socket_buffer_size) +vl_socket_client_connect_internal (socket_client_main_t * scm, + char *socket_path, char *client_name, + u32 socket_buffer_size) { - char buffer[256]; - char *rdptr; - int n, total_bytes; - vl_api_sockclnt_create_reply_t *rp; vl_api_sockclnt_create_t *mp; - clib_socket_t *sock = &scm->client_socket; - msgbuf_t *mbp; + clib_socket_t *sock; clib_error_t *error; /* Already connected? */ @@ -151,84 +459,139 @@ vl_socket_client_connect (socket_client_main_t * scm, char *socket_path, if (socket_path == 0 || client_name == 0) return (-3); + sock = &scm->client_socket; sock->config = socket_path; - sock->flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET; - - error = clib_socket_init (sock); + sock->flags = CLIB_SOCKET_F_IS_CLIENT; - if (error) + if ((error = clib_socket_init (sock))) { clib_error_report (error); return (-1); } - scm->socket_fd = sock->fd; + vl_sock_client_install_message_handlers (); - mbp = (msgbuf_t *) buffer; - mbp->q = 0; - mbp->data_len = ntohl (sizeof (*mp)); - mbp->gc_mark_timestamp = 0; + scm->socket_fd = sock->fd; + scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size : + SOCKET_CLIENT_DEFAULT_BUFFER_SIZE; + vec_validate (scm->socket_tx_buffer, scm->socket_buffer_size - 1); + vec_validate (scm->socket_rx_buffer, scm->socket_buffer_size - 1); + _vec_len (scm->socket_rx_buffer) = 0; + _vec_len (scm->socket_tx_buffer) = 0; + scm->name = format (0, "%s", client_name); - mp = (vl_api_sockclnt_create_t *) mbp->data; - mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_CREATE); + mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp)); + mp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE); strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1); mp->name[sizeof (mp->name) - 1] = 0; mp->context = 0xfeedface; - n = write (scm->socket_fd, mbp, sizeof (*mbp) + ntohl (mbp->data_len)); - if (n < 0) - { - clib_unix_warning ("socket write (msg)"); - return (-1); - } + clib_time_init (&scm->clib_time); + + if (vl_socket_client_write_internal (scm) <= 0) + return (-1); + + if (vl_socket_client_read_internal (scm, 5)) + return (-1); + + return (0); +} + +int +vl_socket_client_connect (char *socket_path, char *client_name, + u32 socket_buffer_size) +{ + return vl_socket_client_connect_internal (socket_client_ctx, socket_path, + client_name, socket_buffer_size); +} + +int +vl_socket_client_connect2 (socket_client_main_t * scm, char *socket_path, + char *client_name, u32 socket_buffer_size) +{ + socket_client_main_t *old_ctx; + int rv; + + old_ctx = vl_socket_client_ctx_push (scm); + rv = vl_socket_client_connect_internal (socket_client_ctx, socket_path, + client_name, socket_buffer_size); + vl_socket_client_ctx_pop (old_ctx); + return rv; +} + +int +vl_socket_client_init_shm_internal (socket_client_main_t * scm, + vl_api_shm_elem_config_t * config, + int want_pthread) +{ + vl_api_sock_init_shm_t *mp; + int rv, i; + u64 *cfg; - memset (buffer, 0, sizeof (buffer)); + scm->want_shm_pthread = want_pthread; - total_bytes = 0; - rdptr = buffer; - do + mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp) + + vec_len (config) * sizeof (u64)); + clib_memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SOCK_INIT_SHM); + mp->client_index = clib_host_to_net_u32 (scm->client_index); + mp->requested_size = 64 << 20; + + if (config) { - n = read (scm->socket_fd, rdptr, sizeof (buffer) - (rdptr - buffer)); - if (n < 0) + for (i = 0; i < vec_len (config); i++) { - clib_unix_warning ("socket read"); + cfg = (u64 *) & config[i]; + mp->configs[i] = *cfg; } - total_bytes += n; - rdptr += n; + mp->nitems = vec_len (config); } - while (total_bytes < sizeof (vl_api_sockclnt_create_reply_t) - + sizeof (msgbuf_t)); + rv = vl_socket_client_write_internal (scm); + if (rv <= 0) + return rv; - rp = (vl_api_sockclnt_create_reply_t *) (buffer + sizeof (msgbuf_t)); - if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY) - { - clib_warning ("connect reply got msg id %d\n", ntohs (rp->_vl_msg_id)); - return (-1); - } + if (vl_socket_client_read_internal (scm, 1)) + return -1; - /* allocate tx, rx buffers */ - scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size : - SOCKET_CLIENT_DEFAULT_BUFFER_SIZE; - vec_validate (scm->socket_tx_buffer, scm->socket_buffer_size - 1); - vec_validate (scm->socket_rx_buffer, scm->socket_buffer_size - 1); - _vec_len (scm->socket_rx_buffer) = 0; - scm->socket_enable = 1; + return 0; +} - return (0); +int +vl_socket_client_init_shm (vl_api_shm_elem_config_t * config, + int want_pthread) +{ + return vl_socket_client_init_shm_internal (socket_client_ctx, config, + want_pthread); } -void -vl_socket_client_disconnect (socket_client_main_t * scm) +int +vl_socket_client_init_shm2 (socket_client_main_t * scm, + vl_api_shm_elem_config_t * config, + int want_pthread) { - if (scm->socket_fd && (close (scm->socket_fd) < 0)) - clib_unix_warning ("close"); - scm->socket_fd = 0; + socket_client_main_t *old_ctx; + int rv; + + old_ctx = vl_socket_client_ctx_push (scm); + rv = vl_socket_client_init_shm_internal (socket_client_ctx, config, + want_pthread); + vl_socket_client_ctx_pop (old_ctx); + return rv; } -void -vl_socket_client_enable_disable (socket_client_main_t * scm, int enable) +clib_error_t * +vl_socket_client_recv_fd_msg2 (socket_client_main_t * scm, int fds[], + int n_fds, u32 wait) { - scm->socket_enable = enable; + if (!scm->socket_fd) + return clib_error_return (0, "no socket"); + return vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait); +} + +clib_error_t * +vl_socket_client_recv_fd_msg (int fds[], int n_fds, u32 wait) +{ + return vl_socket_client_recv_fd_msg2 (socket_client_ctx, fds, n_fds, wait); } /*