Dave Barach | 59b2565 | 2017-09-10 15:04:27 -0400 | [diff] [blame^] | 1 | /* |
| 2 | *------------------------------------------------------------------ |
| 3 | * socket_client.c - API message handling over sockets, client code. |
| 4 | * |
| 5 | * Copyright (c) 2017 Cisco and/or its affiliates. |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at: |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | *------------------------------------------------------------------ |
| 18 | */ |
| 19 | |
| 20 | #include <stdio.h> |
| 21 | #include <stdlib.h> |
| 22 | #include <setjmp.h> |
| 23 | #include <sys/types.h> |
| 24 | #include <sys/mman.h> |
| 25 | #include <sys/stat.h> |
| 26 | #include <netinet/in.h> |
| 27 | #include <signal.h> |
| 28 | #include <pthread.h> |
| 29 | #include <unistd.h> |
| 30 | #include <time.h> |
| 31 | #include <fcntl.h> |
| 32 | #include <string.h> |
| 33 | #include <vppinfra/clib.h> |
| 34 | #include <vppinfra/vec.h> |
| 35 | #include <vppinfra/hash.h> |
| 36 | #include <vppinfra/bitmap.h> |
| 37 | #include <vppinfra/fifo.h> |
| 38 | #include <vppinfra/time.h> |
| 39 | #include <vppinfra/mheap.h> |
| 40 | #include <vppinfra/heap.h> |
| 41 | #include <vppinfra/pool.h> |
| 42 | #include <vppinfra/format.h> |
| 43 | |
| 44 | #include <vlib/vlib.h> |
| 45 | #include <vlib/unix/unix.h> |
| 46 | #include <vlibmemory/api.h> |
| 47 | |
| 48 | #include <vlibmemory/vl_memory_msg_enum.h> |
| 49 | |
| 50 | #define vl_typedefs /* define message structures */ |
| 51 | #include <vlibmemory/vl_memory_api_h.h> |
| 52 | #undef vl_typedefs |
| 53 | |
| 54 | #define vl_endianfun /* define message structures */ |
| 55 | #include <vlibmemory/vl_memory_api_h.h> |
| 56 | #undef vl_endianfun |
| 57 | |
| 58 | /* instantiate all the print functions we know about */ |
| 59 | #define vl_print(handle, ...) clib_warning (__VA_ARGS__) |
| 60 | #define vl_printfun |
| 61 | #include <vlibmemory/vl_memory_api_h.h> |
| 62 | #undef vl_printfun |
| 63 | |
| 64 | socket_client_main_t socket_client_main; |
| 65 | |
| 66 | /* Debug aid */ |
| 67 | u32 vl (void *p) __attribute__ ((weak)); |
| 68 | u32 |
| 69 | vl (void *p) |
| 70 | { |
| 71 | return vec_len (p); |
| 72 | } |
| 73 | |
| 74 | void |
| 75 | vl_socket_client_read_reply (socket_client_main_t * scm) |
| 76 | { |
| 77 | int n, current_rx_index; |
| 78 | msgbuf_t *mbp; |
| 79 | |
| 80 | if (scm->socket_fd == 0 || scm->socket_enable == 0) |
| 81 | return; |
| 82 | |
| 83 | mbp = 0; |
| 84 | |
| 85 | while (1) |
| 86 | { |
| 87 | current_rx_index = vec_len (scm->socket_rx_buffer); |
| 88 | while (vec_len (scm->socket_rx_buffer) < |
| 89 | sizeof (*mbp) + 2 /* msg id */ ) |
| 90 | { |
| 91 | vec_validate (scm->socket_rx_buffer, current_rx_index |
| 92 | + scm->socket_buffer_size - 1); |
| 93 | _vec_len (scm->socket_rx_buffer) = current_rx_index; |
| 94 | n = read (scm->socket_fd, scm->socket_rx_buffer + current_rx_index, |
| 95 | scm->socket_buffer_size); |
| 96 | if (n < 0) |
| 97 | { |
| 98 | clib_unix_warning ("socket_read"); |
| 99 | return; |
| 100 | } |
| 101 | _vec_len (scm->socket_rx_buffer) += n; |
| 102 | } |
| 103 | |
| 104 | #if CLIB_DEBUG > 1 |
| 105 | if (n > 0) |
| 106 | clib_warning ("read %d bytes", n); |
| 107 | #endif |
| 108 | |
| 109 | if (mbp == 0) |
| 110 | mbp = (msgbuf_t *) (scm->socket_rx_buffer); |
| 111 | |
| 112 | if (vec_len (scm->socket_rx_buffer) >= ntohl (mbp->data_len) |
| 113 | + sizeof (*mbp)) |
| 114 | { |
| 115 | vl_msg_api_socket_handler ((void *) (mbp->data)); |
| 116 | |
| 117 | if (vec_len (scm->socket_rx_buffer) == ntohl (mbp->data_len) |
| 118 | + sizeof (*mbp)) |
| 119 | _vec_len (scm->socket_rx_buffer) = 0; |
| 120 | else |
| 121 | vec_delete (scm->socket_rx_buffer, ntohl (mbp->data_len) |
| 122 | + sizeof (*mbp), 0); |
| 123 | mbp = 0; |
| 124 | |
| 125 | /* Quit if we're out of data, and not expecting a ping reply */ |
| 126 | if (vec_len (scm->socket_rx_buffer) == 0 |
| 127 | && scm->control_pings_outstanding == 0) |
| 128 | break; |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | int |
| 134 | vl_socket_client_connect (socket_client_main_t * scm, char *socket_path, |
| 135 | char *client_name, u32 socket_buffer_size) |
| 136 | { |
| 137 | char buffer[256]; |
| 138 | char *rdptr; |
| 139 | int n, total_bytes; |
| 140 | vl_api_sockclnt_create_reply_t *rp; |
| 141 | vl_api_sockclnt_create_t *mp; |
| 142 | clib_socket_t *sock = &scm->client_socket; |
| 143 | msgbuf_t *mbp; |
| 144 | clib_error_t *error; |
| 145 | |
| 146 | /* Already connected? */ |
| 147 | if (scm->socket_fd) |
| 148 | return (-2); |
| 149 | |
| 150 | /* bogus call? */ |
| 151 | if (socket_path == 0 || client_name == 0) |
| 152 | return (-3); |
| 153 | |
| 154 | sock->config = socket_path; |
| 155 | sock->flags = CLIB_SOCKET_F_IS_CLIENT | CLIB_SOCKET_F_SEQPACKET; |
| 156 | |
| 157 | error = clib_socket_init (sock); |
| 158 | |
| 159 | if (error) |
| 160 | { |
| 161 | clib_error_report (error); |
| 162 | return (-1); |
| 163 | } |
| 164 | |
| 165 | scm->socket_fd = sock->fd; |
| 166 | |
| 167 | mbp = (msgbuf_t *) buffer; |
| 168 | mbp->q = 0; |
| 169 | mbp->data_len = ntohl (sizeof (*mp)); |
| 170 | mbp->gc_mark_timestamp = 0; |
| 171 | |
| 172 | mp = (vl_api_sockclnt_create_t *) mbp->data; |
| 173 | mp->_vl_msg_id = ntohs (VL_API_SOCKCLNT_CREATE); |
| 174 | strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1); |
| 175 | mp->name[sizeof (mp->name) - 1] = 0; |
| 176 | mp->context = 0xfeedface; |
| 177 | |
| 178 | n = write (scm->socket_fd, mbp, sizeof (*mbp) + ntohl (mbp->data_len)); |
| 179 | if (n < 0) |
| 180 | { |
| 181 | clib_unix_warning ("socket write (msg)"); |
| 182 | return (-1); |
| 183 | } |
| 184 | |
| 185 | memset (buffer, 0, sizeof (buffer)); |
| 186 | |
| 187 | total_bytes = 0; |
| 188 | rdptr = buffer; |
| 189 | do |
| 190 | { |
| 191 | n = read (scm->socket_fd, rdptr, sizeof (buffer) - (rdptr - buffer)); |
| 192 | if (n < 0) |
| 193 | { |
| 194 | clib_unix_warning ("socket read"); |
| 195 | } |
| 196 | total_bytes += n; |
| 197 | rdptr += n; |
| 198 | } |
| 199 | while (total_bytes < sizeof (vl_api_sockclnt_create_reply_t) |
| 200 | + sizeof (msgbuf_t)); |
| 201 | |
| 202 | rp = (vl_api_sockclnt_create_reply_t *) (buffer + sizeof (msgbuf_t)); |
| 203 | if (ntohs (rp->_vl_msg_id) != VL_API_SOCKCLNT_CREATE_REPLY) |
| 204 | { |
| 205 | clib_warning ("connect reply got msg id %d\n", ntohs (rp->_vl_msg_id)); |
| 206 | return (-1); |
| 207 | } |
| 208 | |
| 209 | /* allocate tx, rx buffers */ |
| 210 | scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size : |
| 211 | SOCKET_CLIENT_DEFAULT_BUFFER_SIZE; |
| 212 | vec_validate (scm->socket_tx_buffer, scm->socket_buffer_size - 1); |
| 213 | vec_validate (scm->socket_rx_buffer, scm->socket_buffer_size - 1); |
| 214 | _vec_len (scm->socket_rx_buffer) = 0; |
| 215 | scm->socket_enable = 1; |
| 216 | |
| 217 | return (0); |
| 218 | } |
| 219 | |
| 220 | void |
| 221 | vl_socket_client_disconnect (socket_client_main_t * scm) |
| 222 | { |
| 223 | if (scm->socket_fd && (close (scm->socket_fd) < 0)) |
| 224 | clib_unix_warning ("close"); |
| 225 | scm->socket_fd = 0; |
| 226 | } |
| 227 | |
| 228 | void |
| 229 | vl_socket_client_enable_disable (socket_client_main_t * scm, int enable) |
| 230 | { |
| 231 | scm->socket_enable = enable; |
| 232 | } |
| 233 | |
| 234 | /* |
| 235 | * fd.io coding-style-patch-verification: ON |
| 236 | * |
| 237 | * Local Variables: |
| 238 | * eval: (c-set-style "gnu") |
| 239 | * End: |
| 240 | */ |