LCOV - code coverage report
Current view: top level - vlibmemory - socket_api.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 334 388 86.1 %
Date: 2023-10-26 01:39:38 Functions: 27 30 90.0 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * socket_api.c
       4             :  *
       5             :  * Copyright (c) 2009 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 <sys/types.h>
      21             : #include <sys/socket.h>
      22             : #include <netinet/in.h>
      23             : #include <sys/ioctl.h>
      24             : #include <fcntl.h>
      25             : #include <sys/stat.h>
      26             : 
      27             : #include <vppinfra/byte_order.h>
      28             : #include <svm/ssvm.h>
      29             : #include <vlibmemory/api.h>
      30             : 
      31             : #include <vlibmemory/vl_memory_msg_enum.h>
      32             : 
      33             : #define vl_typedefs             /* define message structures */
      34             : #include <vlibmemory/vl_memory_api_h.h>
      35             : #undef vl_typedefs
      36             : 
      37             : /* instantiate all the print functions we know about */
      38             : #define vl_printfun
      39             : #include <vlibmemory/vl_memory_api_h.h>
      40             : #undef vl_printfun
      41             : 
      42             : /* instantiate all the endian swap functions we know about */
      43             : #define vl_endianfun
      44             : #include <vlibmemory/vl_memory_api_h.h>
      45             : #undef vl_endianfun
      46             : 
      47             : #define vl_calcsizefun
      48             : #include <vlibmemory/vl_memory_api_h.h>
      49             : #undef vl_calcsizefun
      50             : 
      51             : socket_main_t socket_main;
      52             : 
      53             : #define SOCK_API_REG_HANDLE_BIT (1<<31)
      54             : 
      55             : static u32
      56        1811 : sock_api_registration_handle (vl_api_registration_t * regp)
      57             : {
      58        1811 :   ASSERT (regp->vl_api_registration_pool_index < SOCK_API_REG_HANDLE_BIT);
      59        1811 :   return regp->vl_api_registration_pool_index | SOCK_API_REG_HANDLE_BIT;
      60             : }
      61             : 
      62             : static u32
      63      442436 : socket_api_registration_handle_to_index (u32 reg_index)
      64             : {
      65      442436 :   return (reg_index & ~SOCK_API_REG_HANDLE_BIT);
      66             : }
      67             : 
      68             : u8
      69      442599 : vl_socket_api_registration_handle_is_valid (u32 reg_handle)
      70             : {
      71      442599 :   return ((reg_handle & SOCK_API_REG_HANDLE_BIT) != 0);
      72             : }
      73             : 
      74             : void
      75           0 : vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
      76             : {
      77             :   vl_api_registration_t *reg;
      78           0 :   socket_main_t *sm = &socket_main;
      79             :   clib_file_t *f;
      80             : 
      81             :   /*
      82             :    * Must have at least one active client, not counting the
      83             :    * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
      84             :    */
      85           0 :   if (pool_elts (sm->registration_pool) < 2)
      86           0 :     return;
      87             : 
      88           0 :   vlib_cli_output (vm, "Socket clients");
      89           0 :   vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
      90             :     /* *INDENT-OFF* */
      91           0 :     pool_foreach (reg, sm->registration_pool)
      92             :      {
      93           0 :         if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
      94           0 :             f = vl_api_registration_file (reg);
      95           0 :             vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
      96             :         }
      97             :     }
      98             : /* *INDENT-ON* */
      99             : }
     100             : 
     101             : vl_api_registration_t *
     102      441861 : vl_socket_api_client_handle_to_registration (u32 handle)
     103             : {
     104      441861 :   socket_main_t *sm = &socket_main;
     105      441861 :   u32 index = socket_api_registration_handle_to_index (handle);
     106      441861 :   if (pool_is_free_index (sm->registration_pool, index))
     107             :     {
     108             : #if DEBUG > 2
     109             :       clib_warning ("Invalid index %d\n", index);
     110             : #endif
     111           0 :       return 0;
     112             :     }
     113      441861 :   return pool_elt_at_index (sm->registration_pool, index);
     114             : }
     115             : 
     116             : void
     117      699099 : vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
     118             : {
     119             : #if CLIB_DEBUG > 1
     120             :   u32 output_length;
     121             : #endif
     122      699099 :   socket_main_t *sm = &socket_main;
     123      699099 :   u16 msg_id = ntohs (*(u16 *) elem);
     124      699099 :   api_main_t *am = vlibapi_get_main ();
     125      699099 :   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
     126             :   vl_api_registration_t *sock_rp;
     127      699099 :   clib_file_main_t *fm = &file_main;
     128             :   clib_error_t *error;
     129             :   clib_file_t *cf;
     130             : 
     131      699099 :   cf = vl_api_registration_file (rp);
     132      699099 :   ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
     133             : 
     134      699099 :   if (msg_id >= vec_len (am->msg_data))
     135             :     {
     136           0 :       clib_warning ("id out of range: %d", msg_id);
     137           0 :       vl_msg_api_free ((void *) elem);
     138           0 :       return;
     139             :     }
     140             : 
     141      699099 :   sock_rp = pool_elt_at_index (sm->registration_pool,
     142             :                                rp->vl_api_registration_pool_index);
     143      699099 :   ASSERT (sock_rp);
     144             : 
     145             :   /* Add the msgbuf_t to the output vector */
     146      699099 :   vec_add (sock_rp->output_vector, (u8 *) mb, sizeof (*mb));
     147             : 
     148             :   /* Try to send the message and save any error like
     149             :    * we do in the input epoll loop */
     150      699099 :   vec_add (sock_rp->output_vector, elem, ntohl (mb->data_len));
     151      699099 :   error = clib_file_write (cf);
     152      699099 :   unix_save_error (&unix_main, error);
     153             : 
     154             :   /* If we didn't finish sending everything, wait for tx space */
     155      699099 :   if (vec_len (sock_rp->output_vector) > 0
     156       10336 :       && !(cf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
     157             :     {
     158         646 :       cf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
     159         646 :       fm->file_update (cf, UNIX_FILE_UPDATE_MODIFY);
     160             :     }
     161             : 
     162             : #if CLIB_DEBUG > 1
     163             :   output_length = sizeof (*mb) + ntohl (mb->data_len);
     164             :   clib_warning ("wrote %u bytes to fd %d", output_length,
     165             :                 cf->file_descriptor);
     166             : #endif
     167             : 
     168      699099 :   vl_msg_api_free ((void *) elem);
     169             : }
     170             : 
     171             : void
     172        1193 : vl_socket_free_registration_index (u32 pool_index)
     173             : {
     174             :   int i;
     175             :   vl_api_registration_t *rp;
     176             :   void vl_api_call_reaper_functions (u32 client_index);
     177             : 
     178        1193 :   if (pool_is_free_index (socket_main.registration_pool, pool_index))
     179             :     {
     180           0 :       clib_warning ("main pool index %d already free", pool_index);
     181           0 :       return;
     182             :     }
     183        1193 :   rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
     184             : 
     185        1193 :   vl_api_call_reaper_functions (
     186             :     clib_host_to_net_u32 (sock_api_registration_handle (rp)));
     187             : 
     188        1193 :   ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
     189        1236 :   for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
     190          43 :     if (close (rp->additional_fds_to_close[i]) < 0)
     191           0 :       clib_unix_warning ("close");
     192        1193 :   vec_free (rp->additional_fds_to_close);
     193        1193 :   vec_free (rp->name);
     194        1193 :   vec_free (rp->unprocessed_input);
     195        1193 :   vec_free (rp->output_vector);
     196        1193 :   rp->registration_type = REGISTRATION_TYPE_FREE;
     197        1193 :   pool_put (socket_main.registration_pool, rp);
     198             : }
     199             : 
     200             : void
     201      441860 : vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
     202             : {
     203      441860 :   msgbuf_t *mbp = (msgbuf_t *) input_v;
     204             : 
     205      441860 :   u8 *the_msg = (u8 *) (mbp->data);
     206      441860 :   socket_main.current_rp = rp;
     207      441860 :   vl_msg_api_socket_handler (the_msg, ntohl (mbp->data_len));
     208      441860 :   socket_main.current_rp = 0;
     209      441860 : }
     210             : 
     211             : int
     212     1135370 : is_being_removed_reg_index (u32 reg_index)
     213             : {
     214     1135370 :   vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
     215     1135370 :   ALWAYS_ASSERT (rp != 0);
     216     1135370 :   return (rp->is_being_removed);
     217             : }
     218             : 
     219             : static void
     220          43 : socket_cleanup_pending_remove_registration_cb (u32 *preg_index)
     221             : {
     222          43 :   vl_api_registration_t *rp = vl_socket_get_registration (*preg_index);
     223          43 :   if (!rp)
     224             :     {
     225             :       /* Might already have gone */
     226           0 :       return;
     227             :     }
     228             : 
     229          43 :   clib_file_main_t *fm = &file_main;
     230          43 :   u32 pending_remove_file_index = vl_api_registration_file_index (rp);
     231             : 
     232          43 :   clib_file_t *zf = fm->file_pool + pending_remove_file_index;
     233             : 
     234          43 :   clib_file_del (fm, zf);
     235          43 :   vl_socket_free_registration_index (rp - socket_main.registration_pool);
     236             : }
     237             : 
     238             : static void
     239          43 : vl_socket_request_remove_reg_index (u32 reg_index)
     240             : {
     241          43 :   vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
     242          43 :   ALWAYS_ASSERT (rp != 0);
     243          43 :   if (rp->is_being_removed)
     244             :     {
     245           0 :       return;
     246             :     }
     247          43 :   rp->is_being_removed = 1;
     248          43 :   vl_api_force_rpc_call_main_thread (
     249             :     socket_cleanup_pending_remove_registration_cb, (void *) &reg_index,
     250             :     sizeof (u32));
     251             : }
     252             : 
     253             : /*
     254             :  * Read function for API socket.
     255             :  *
     256             :  * Read data from socket, invoke SOCKET_READ_EVENT
     257             :  * for each fully read API message, return 0.
     258             :  * Store incomplete data for next invocation to continue.
     259             :  *
     260             :  * On severe read error, the file is closed.
     261             :  *
     262             :  * As reading is single threaded,
     263             :  * socket_main.input_buffer is used temporarily.
     264             :  * Even its length is modified, but always restored before return.
     265             :  *
     266             :  * Incomplete data is copied into a vector,
     267             :  * pointer saved in registration's unprocessed_input.
     268             :  */
     269             : clib_error_t *
     270      435506 : vl_socket_read_ready (clib_file_t * uf)
     271             : {
     272      435506 :   vlib_main_t *vm = vlib_get_main ();
     273             :   vl_api_registration_t *rp;
     274             :   /* n is the size of data read to input_buffer */
     275             :   int n;
     276             :   /* msg_buffer vector can point to input_buffer or unprocessed_input */
     277      435506 :   i8 *msg_buffer = 0;
     278             :   /* data_for_process is a vector containing one full message, incl msgbuf_t */
     279             :   u8 *data_for_process;
     280             :   /* msgbuf_len is the size of one message, including sizeof (msgbuf_t) */
     281             :   u32 msgbuf_len;
     282      435506 :   u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
     283             :   vl_socket_args_for_process_t *a;
     284      435506 :   u32 reg_index = uf->private_data;
     285      435506 :   if (is_being_removed_reg_index (reg_index))
     286             :     {
     287           0 :       return 0;
     288             :     }
     289             : 
     290      435506 :   rp = vl_socket_get_registration (reg_index);
     291      435506 :   if (!rp)
     292             :     {
     293           0 :       return 0;
     294             :     }
     295             : 
     296             :   /* Ignore unprocessed_input for now, n describes input_buffer for now. */
     297      435506 :   n = read (uf->file_descriptor, socket_main.input_buffer,
     298      435506 :             vec_len (socket_main.input_buffer));
     299             : 
     300      435506 :   if (n <= 0)
     301             :     {
     302          43 :       if (errno != EAGAIN)
     303             :         {
     304             :           /* Severe error, close the file. */
     305          43 :           vl_socket_request_remove_reg_index (reg_index);
     306             :         }
     307             :       /* EAGAIN means we do not close the file, but no data to process anyway. */
     308          43 :       return 0;
     309             :     }
     310             : 
     311             :   /* Fake smaller length teporarily, so input_buffer can be used as msg_buffer. */
     312      435463 :   vec_set_len (socket_main.input_buffer, n);
     313             : 
     314             :   /*
     315             :    * Look for bugs here. This code is tricky because
     316             :    * data read from a stream socket does not honor message
     317             :    * boundaries. In the case of a long message (>4K bytes)
     318             :    * we have to do (at least) 2 reads, etc.
     319             :    */
     320             :   /* Determine msg_buffer. */
     321      435463 :   if (vec_len (rp->unprocessed_input))
     322             :     {
     323        6508 :       vec_append (rp->unprocessed_input, socket_main.input_buffer);
     324        6508 :       msg_buffer = rp->unprocessed_input;
     325             :     }
     326             :   else
     327             :     {
     328      428955 :       msg_buffer = socket_main.input_buffer;
     329             :     }
     330             :   /* Loop to process any full messages. */
     331      435463 :   ASSERT (vec_len (msg_buffer) > 0);
     332             :   do
     333             :     {
     334             :       /* Here, we are not sure how big a chunk of message we have left. */
     335             :       /* Do we at least know how big the full message will be? */
     336      448368 :       if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
     337             :         /* No, so fragment is not a full message. */
     338        6458 :         goto save_and_split;
     339             : 
     340             :       /* Now we know how big the full message will be. */
     341      441910 :       msgbuf_len =
     342      441910 :         ntohl (((msgbuf_t *) msg_buffer)->data_len) + sizeof (msgbuf_t);
     343             : 
     344             :       /* But do we have a full message? */
     345      441910 :       if (msgbuf_len > vec_len (msg_buffer))
     346             :         {
     347          50 :         save_and_split:
     348             :           /* We don't have the entire message yet. */
     349             :           /* If msg_buffer is unprocessed_input, nothing needs to be done. */
     350        6508 :           if (msg_buffer == socket_main.input_buffer)
     351             :             /* But if we were using the input buffer, save the fragment. */
     352             :             {
     353        6457 :               ASSERT (vec_len (rp->unprocessed_input) == 0);
     354        6457 :               vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
     355       12914 :               clib_memcpy_fast (rp->unprocessed_input, msg_buffer,
     356        6457 :                                 vec_len (msg_buffer));
     357        6457 :               vec_set_len (rp->unprocessed_input, vec_len (msg_buffer));
     358             :             }
     359             :           /* No more full messages, restore original input_buffer length. */
     360        6508 :           vec_set_len (socket_main.input_buffer, save_input_buffer_length);
     361        6508 :           return 0;
     362             :         }
     363             : 
     364             :       /*
     365             :        * We have at least one full message.
     366             :        * But msg_buffer can contain more data, so copy one message data
     367             :        * so we can overwrite its length to what single message has.
     368             :        */
     369      441860 :       data_for_process = (u8 *) vec_dup (msg_buffer);
     370      441860 :       vec_set_len (data_for_process, msgbuf_len);
     371             :       /* Everything is ready to signal the SOCKET_READ_EVENT. */
     372      441860 :       pool_get (socket_main.process_args, a);
     373      441860 :       a->reg_index = reg_index;
     374      441860 :       a->data = data_for_process;
     375             : 
     376      441860 :       vlib_process_signal_event (vm, vl_api_clnt_node.index,
     377             :                                  SOCKET_READ_EVENT,
     378      441860 :                                  a - socket_main.process_args);
     379      441860 :       if (vec_len (msg_buffer) > msgbuf_len)
     380             :         /* There are some fragments left. Shrink the msg_buffer to simplify logic. */
     381       12905 :         vec_delete (msg_buffer, msgbuf_len, 0);
     382             :       else
     383             :         /* We are done with msg_buffer. */
     384      428955 :         vec_set_len (msg_buffer, 0);
     385             :     }
     386      441860 :   while (vec_len (msg_buffer) > 0);
     387             : 
     388             :   /* Restore input_buffer, it could have been msg_buffer. */
     389      428955 :   vec_set_len (socket_main.input_buffer, save_input_buffer_length);
     390      428955 :   return 0;
     391             : }
     392             : 
     393             : clib_error_t *
     394      699860 : vl_socket_write_ready (clib_file_t * uf)
     395             : {
     396      699860 :   clib_file_main_t *fm = &file_main;
     397             :   vl_api_registration_t *rp;
     398             :   int n;
     399             : 
     400      699860 :   u32 reg_index = uf->private_data;
     401      699860 :   if (is_being_removed_reg_index (reg_index))
     402             :     {
     403           0 :       return 0;
     404             :     }
     405             : 
     406      699860 :   rp = pool_elt_at_index (socket_main.registration_pool, reg_index);
     407             : 
     408             :   /* Flush output vector. */
     409      699860 :   size_t total_bytes = vec_len (rp->output_vector);
     410      699860 :   size_t bytes_to_send, remaining_bytes = total_bytes;
     411      699860 :   void *p = rp->output_vector;
     412     1645110 :   while (remaining_bytes > 0)
     413             :     {
     414      955765 :       bytes_to_send = remaining_bytes > 4096 ? 4096 : remaining_bytes;
     415      955765 :       n = send (uf->file_descriptor, p, bytes_to_send, MSG_NOSIGNAL);
     416      955765 :       if (n < 0)
     417             :         {
     418       10515 :           if (errno == EAGAIN)
     419             :             {
     420       10515 :               break;
     421             :             }
     422             : #if DEBUG > 2
     423             :           clib_warning ("write error, close the file...\n");
     424             : #endif
     425           0 :           vl_socket_request_remove_reg_index (reg_index);
     426           0 :           return 0;
     427             :         }
     428      945250 :       remaining_bytes -= bytes_to_send;
     429      945250 :       p += bytes_to_send;
     430             :     }
     431             : 
     432      699860 :   vec_delete (rp->output_vector, total_bytes - remaining_bytes, 0);
     433      699860 :   if (vec_len (rp->output_vector) <= 0
     434      689345 :       && (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
     435             :     {
     436         646 :       uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
     437         646 :       fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
     438             :     }
     439             : 
     440      699860 :   return 0;
     441             : }
     442             : 
     443             : clib_error_t *
     444           0 : vl_socket_error_ready (clib_file_t * uf)
     445             : {
     446           0 :   u32 reg_index = uf->private_data;
     447           0 :   vl_socket_request_remove_reg_index (reg_index);
     448           0 :   return 0;
     449             : }
     450             : 
     451             : void
     452         618 : socksvr_file_add (clib_file_main_t * fm, int fd)
     453             : {
     454             :   vl_api_registration_t *rp;
     455         618 :   clib_file_t template = { 0 };
     456             : 
     457         618 :   pool_get (socket_main.registration_pool, rp);
     458         618 :   clib_memset (rp, 0, sizeof (*rp));
     459             : 
     460         618 :   template.read_function = vl_socket_read_ready;
     461         618 :   template.write_function = vl_socket_write_ready;
     462         618 :   template.error_function = vl_socket_error_ready;
     463         618 :   template.file_descriptor = fd;
     464         618 :   template.description = format (0, "socksrv");
     465         618 :   template.private_data = rp - socket_main.registration_pool;
     466             : 
     467         618 :   rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
     468         618 :   rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
     469         618 :   rp->clib_file_index = clib_file_add (fm, &template);
     470         618 : }
     471             : 
     472             : static clib_error_t *
     473         618 : socksvr_accept_ready (clib_file_t * uf)
     474             : {
     475         618 :   clib_file_main_t *fm = &file_main;
     476         618 :   socket_main_t *sm = &socket_main;
     477         618 :   clib_socket_t *sock = &sm->socksvr_listen_socket;
     478             :   clib_socket_t client;
     479             :   clib_error_t *error;
     480             : 
     481         618 :   error = clib_socket_accept (sock, &client);
     482         618 :   if (error)
     483           0 :     return error;
     484             : 
     485         618 :   socksvr_file_add (fm, client.fd);
     486         618 :   return 0;
     487             : }
     488             : 
     489             : static clib_error_t *
     490           0 : socksvr_bogus_write (clib_file_t * uf)
     491             : {
     492           0 :   clib_warning ("why am I here?");
     493           0 :   return 0;
     494             : }
     495             : 
     496             : /*
     497             :  * vl_api_sockclnt_create_t_handler
     498             :  */
     499             : void
     500         618 : vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
     501             : {
     502             :   vl_api_registration_t *regp;
     503             :   vl_api_sockclnt_create_reply_t *rp;
     504         618 :   api_main_t *am = vlibapi_get_main ();
     505             :   hash_pair_t *hp;
     506         618 :   int rv = 0;
     507         618 :   u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
     508         618 :   u32 i = 0;
     509             : 
     510         618 :   regp = socket_main.current_rp;
     511             : 
     512             :   /* client already connected through shared memory? */
     513         618 :   if (!regp || regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
     514             :     {
     515           0 :       clib_warning (
     516             :         "unsupported API call: already connected though shared memory?");
     517           0 :       return;
     518             :     }
     519             : 
     520         618 :   regp->name = format (0, "%s%c", mp->name, 0);
     521             : 
     522         618 :   u32 size = sizeof (*rp) + (nmsg * sizeof (vl_api_message_table_entry_t));
     523         618 :   rp = vl_msg_api_alloc_zero (size);
     524         618 :   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
     525         618 :   rp->index = htonl (sock_api_registration_handle (regp));
     526         618 :   rp->context = mp->context;
     527         618 :   rp->response = htonl (rv);
     528         618 :   rp->count = htons (nmsg);
     529             : 
     530             :   /* *INDENT-OFF* */
     531     3620890 :   hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
     532             :   ({
     533             :     rp->message_table[i].index = htons(hp->value[0]);
     534             :     (void) strncpy_s((char *)rp->message_table[i].name,
     535             :                      64 /* bytes of space at dst */,
     536             :                      (char *)hp->key,
     537             :                      64-1 /* chars to copy, without zero byte. */);
     538             :     i++;
     539             :   }));
     540             :   /* *INDENT-ON* */
     541         618 :   vl_api_send_msg (regp, (u8 *) rp);
     542             : }
     543             : 
     544             : /*
     545             :  * vl_api_sockclnt_delete_t_handler
     546             :  */
     547             : void
     548         575 : vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
     549             : {
     550             :   vl_api_registration_t *regp;
     551             :   vl_api_sockclnt_delete_reply_t *rp;
     552             : 
     553         575 :   regp = vl_api_client_index_to_registration (mp->client_index);
     554         575 :   if (!regp)
     555           0 :     return;
     556             : 
     557         575 :   u32 reg_index = socket_api_registration_handle_to_index (ntohl (mp->index));
     558         575 :   rp = vl_msg_api_alloc (sizeof (*rp));
     559         575 :   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
     560         575 :   rp->context = mp->context;
     561             : 
     562         575 :   if (!pool_is_free_index (socket_main.registration_pool, reg_index))
     563             :     {
     564         575 :       rp->response = htonl (1);
     565         575 :       vl_api_send_msg (regp, (u8 *) rp);
     566             : 
     567         575 :       vl_api_registration_del_file (regp);
     568         575 :       vl_socket_free_registration_index (reg_index);
     569             :     }
     570             :   else
     571             :     {
     572           0 :       clib_warning ("unknown client ID %d", reg_index);
     573           0 :       rp->response = htonl (-1);
     574           0 :       vl_api_send_msg (regp, (u8 *) rp);
     575             :     }
     576             : }
     577             : 
     578             : clib_error_t *
     579         116 : vl_sock_api_send_fd_msg (int socket_fd, int fds[], int n_fds)
     580         116 : {
     581         116 :   struct msghdr mh = { 0 };
     582             :   struct iovec iov[1];
     583         116 :   char ctl[CMSG_SPACE (sizeof (int) * n_fds)];
     584             :   struct cmsghdr *cmsg;
     585         116 :   char *msg = "fdmsg";
     586             :   int rv;
     587             : 
     588         116 :   iov[0].iov_base = msg;
     589         116 :   iov[0].iov_len = strlen (msg);
     590         116 :   mh.msg_iov = iov;
     591         116 :   mh.msg_iovlen = 1;
     592             : 
     593         116 :   clib_memset (&ctl, 0, sizeof (ctl));
     594         116 :   mh.msg_control = ctl;
     595         116 :   mh.msg_controllen = sizeof (ctl);
     596         116 :   cmsg = CMSG_FIRSTHDR (&mh);
     597         116 :   cmsg->cmsg_len = CMSG_LEN (sizeof (int) * n_fds);
     598         116 :   cmsg->cmsg_level = SOL_SOCKET;
     599         116 :   cmsg->cmsg_type = SCM_RIGHTS;
     600         116 :   clib_memcpy_fast (CMSG_DATA (cmsg), fds, sizeof (int) * n_fds);
     601             : 
     602         116 :   while ((rv = sendmsg (socket_fd, &mh, 0)) < 0 && errno == EAGAIN)
     603             :     ;
     604         116 :   if (rv < 0)
     605           0 :     return clib_error_return_unix (0, "sendmsg");
     606         116 :   return 0;
     607             : }
     608             : 
     609             : vl_api_shm_elem_config_t *
     610          43 : vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
     611             : {
     612          43 :   vl_api_shm_elem_config_t *config = 0, *c;
     613             :   u64 cfg;
     614             :   int i;
     615             : 
     616          43 :   if (!mp->nitems)
     617             :     {
     618          42 :       vec_validate (config, 6);
     619          42 :       config[0].type = VL_API_VLIB_RING;
     620          42 :       config[0].size = 256;
     621          42 :       config[0].count = 32;
     622             : 
     623          42 :       config[1].type = VL_API_VLIB_RING;
     624          42 :       config[1].size = 1024;
     625          42 :       config[1].count = 16;
     626             : 
     627          42 :       config[2].type = VL_API_VLIB_RING;
     628          42 :       config[2].size = 4096;
     629          42 :       config[2].count = 2;
     630             : 
     631          42 :       config[3].type = VL_API_CLIENT_RING;
     632          42 :       config[3].size = 256;
     633          42 :       config[3].count = 32;
     634             : 
     635          42 :       config[4].type = VL_API_CLIENT_RING;
     636          42 :       config[4].size = 1024;
     637          42 :       config[4].count = 16;
     638             : 
     639          42 :       config[5].type = VL_API_CLIENT_RING;
     640          42 :       config[5].size = 4096;
     641          42 :       config[5].count = 2;
     642             : 
     643          42 :       config[6].type = VL_API_QUEUE;
     644          42 :       config[6].count = 128;
     645          42 :       config[6].size = sizeof (uword);
     646             :     }
     647             :   else
     648             :     {
     649           1 :       vec_validate (config, mp->nitems - 1);
     650           8 :       for (i = 0; i < mp->nitems; i++)
     651             :         {
     652           7 :           cfg = mp->configs[i];
     653             :           /* Pretty much a hack but it avoids defining our own api type
     654             :            * in memclnt.api */
     655           7 :           c = (vl_api_shm_elem_config_t *) & cfg;
     656           7 :           config[i].type = c->type;
     657           7 :           config[i].count = c->count;
     658           7 :           config[i].size = c->size;
     659             :         }
     660             :     }
     661          43 :   return config;
     662             : }
     663             : 
     664             : /*
     665             :  * Bootstrap shm api using the socket api
     666             :  */
     667             : void
     668          43 : vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
     669             : {
     670             :   vl_api_sock_init_shm_reply_t *rmp;
     671          43 :   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
     672          43 :   svm_map_region_args_t _args, *a = &_args;
     673             :   vl_api_registration_t *regp;
     674          43 :   api_main_t *am = vlibapi_get_main ();
     675             :   svm_region_t *vlib_rp;
     676             :   clib_file_t *cf;
     677          43 :   vl_api_shm_elem_config_t *config = 0;
     678             :   vl_shmem_hdr_t *shmem_hdr;
     679          43 :   int rv, tries = 1000;
     680             : 
     681          43 :   regp = vl_api_client_index_to_registration (mp->client_index);
     682          43 :   if (regp == 0)
     683             :     {
     684           0 :       clib_warning ("API client disconnected");
     685           0 :       return;
     686             :     }
     687          43 :   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
     688             :     {
     689           0 :       clib_warning ("Invalid registration");
     690           0 :       return;
     691             :     }
     692             : 
     693             :   /*
     694             :    * Set up a memfd segment of the requested size wherein the
     695             :    * shmem data structures will be initialized
     696             :    */
     697          43 :   clib_memset (memfd, 0, sizeof (*memfd));
     698          43 :   memfd->ssvm_size = mp->requested_size;
     699          43 :   memfd->requested_va = 0ULL;
     700          43 :   memfd->is_server = 1;
     701          43 :   memfd->name = format (0, "%s%c", regp->name, 0);
     702             : 
     703          43 :   if ((rv = ssvm_server_init_memfd (memfd)))
     704           0 :     goto reply;
     705             : 
     706             :   /* delete the unused heap created in ssvm_server_init_memfd and mark it
     707             :    * accessible again for ASAN */
     708          43 :   clib_mem_destroy_heap (memfd->sh->heap);
     709          43 :   clib_mem_unpoison ((void *) memfd->sh->ssvm_va, memfd->ssvm_size);
     710             : 
     711             :   /* Remember to close this fd when the socket connection goes away */
     712          43 :   vec_add1 (regp->additional_fds_to_close, memfd->fd);
     713             : 
     714             :   /*
     715             :    * Create a plausible svm_region in the memfd backed segment
     716             :    */
     717          43 :   clib_memset (a, 0, sizeof (*a));
     718          43 :   a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
     719          43 :   a->size = memfd->ssvm_size - MMAP_PAGESIZE;
     720             :   /* $$$$ might want a different config parameter */
     721          43 :   a->pvt_heap_size = am->api_pvt_heap_size;
     722          43 :   a->flags = SVM_FLAGS_MHEAP;
     723          43 :   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
     724             : 
     725             :   /*
     726             :    * Part deux, initialize the svm_region_t shared-memory header
     727             :    * api allocation rings, and so on.
     728             :    */
     729          43 :   config = vl_api_make_shm_config (mp);
     730          43 :   vlib_rp = (svm_region_t *) a->baseva;
     731          43 :   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
     732             :                  1 /* is_private */ );
     733             : 
     734             :   /* Remember who created this. Needs to be post vl_init_shmem */
     735          43 :   shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
     736          43 :   shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
     737             : 
     738          43 :   vec_add1 (am->vlib_private_rps, vlib_rp);
     739          43 :   memfd->sh->ready = 1;
     740          43 :   vec_free (config);
     741             : 
     742             :   /* Recompute the set of input queues to poll in memclnt_process */
     743          43 :   vec_reset_length (vl_api_queue_cursizes);
     744             : 
     745           0 : reply:
     746             : 
     747          43 :   rmp = vl_msg_api_alloc (sizeof (*rmp));
     748          43 :   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
     749          43 :   rmp->context = mp->context;
     750          43 :   rmp->retval = htonl (rv);
     751             : 
     752             :   /*
     753             :    * Note: The reply message needs to make it out the back door
     754             :    * before we send the magic fd message. That's taken care of by
     755             :    * the send function.
     756             :    */
     757          43 :   vl_socket_api_send (regp, (u8 *) rmp);
     758             : 
     759          43 :   if (rv != 0)
     760           0 :     return;
     761             : 
     762             :   /* Send the magic "here's your sign (aka fd)" socket message */
     763          43 :   cf = vl_api_registration_file (regp);
     764          43 :   if (!cf)
     765             :     {
     766           0 :       clib_warning ("cf removed");
     767           0 :       return;
     768             :     }
     769             : 
     770             :   /* Wait for reply to be consumed before sending the fd */
     771          46 :   while (tries-- > 0)
     772             :     {
     773             :       int bytes;
     774          46 :       rv = ioctl (cf->file_descriptor, TIOCOUTQ, &bytes);
     775          46 :       if (rv < 0)
     776             :         {
     777           0 :           clib_unix_warning ("ioctl returned");
     778          43 :           break;
     779             :         }
     780          46 :       if (bytes == 0)
     781          43 :         break;
     782           3 :       usleep (1e3);
     783             :     }
     784             : 
     785          43 :   vl_sock_api_send_fd_msg (cf->file_descriptor, &memfd->fd, 1);
     786             : }
     787             : 
     788             : #define foreach_vlib_api_msg                                                  \
     789             :   _ (SOCKCLNT_CREATE, sockclnt_create, 0)                                     \
     790             :   _ (SOCKCLNT_DELETE, sockclnt_delete, 0)                                     \
     791             :   _ (SOCK_INIT_SHM, sock_init_shm, 0)
     792             : 
     793             : clib_error_t *
     794         575 : vl_sock_api_init (vlib_main_t * vm)
     795             : {
     796         575 :   api_main_t *am = vlibapi_get_main ();
     797         575 :   clib_file_main_t *fm = &file_main;
     798         575 :   clib_file_t template = { 0 };
     799             :   vl_api_registration_t *rp;
     800         575 :   socket_main_t *sm = &socket_main;
     801         575 :   clib_socket_t *sock = &sm->socksvr_listen_socket;
     802             :   clib_error_t *error;
     803             : 
     804             :   /* If not explicitly configured, do not bind/enable, etc. */
     805         575 :   if (sm->socket_name == 0)
     806           0 :     return 0;
     807             : 
     808             : #define _(N, n, t)                                                            \
     809             :   vl_msg_api_config (&(vl_msg_api_msg_config_t){                              \
     810             :     .id = VL_API_##N,                                                         \
     811             :     .name = #n,                                                               \
     812             :     .handler = vl_api_##n##_t_handler,                                        \
     813             :     .endian = vl_api_##n##_t_endian,                                          \
     814             :     .format_fn = vl_api_##n##_t_format,                                       \
     815             :     .size = sizeof (vl_api_##n##_t),                                          \
     816             :     .traced = t,                                                              \
     817             :     .tojson = vl_api_##n##_t_tojson,                                          \
     818             :     .fromjson = vl_api_##n##_t_fromjson,                                      \
     819             :     .calc_size = vl_api_##n##_t_calc_size,                                    \
     820             :   });                                                                         \
     821             :   am->msg_data[VL_API_##N].replay_allowed = 0;
     822         575 :   foreach_vlib_api_msg;
     823             : #undef _
     824             : 
     825         575 :   vec_resize (sm->input_buffer, 4096);
     826             : 
     827         575 :   sock->config = (char *) sm->socket_name;
     828         575 :   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
     829         575 :   error = clib_socket_init (sock);
     830         575 :   if (error)
     831           0 :     return error;
     832             : 
     833         575 :   pool_get (sm->registration_pool, rp);
     834         575 :   clib_memset (rp, 0, sizeof (*rp));
     835             : 
     836         575 :   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
     837             : 
     838         575 :   template.read_function = socksvr_accept_ready;
     839         575 :   template.write_function = socksvr_bogus_write;
     840         575 :   template.file_descriptor = sock->fd;
     841         575 :   template.description = format (0, "socksvr %s", sock->config);
     842         575 :   template.private_data = rp - sm->registration_pool;
     843             : 
     844         575 :   rp->clib_file_index = clib_file_add (fm, &template);
     845         575 :   return 0;
     846             : }
     847             : 
     848             : static clib_error_t *
     849         575 : socket_exit (vlib_main_t * vm)
     850             : {
     851         575 :   socket_main_t *sm = &socket_main;
     852             :   vl_api_registration_t *rp;
     853             : 
     854             :   /* Defensive driving in case something wipes out early */
     855         575 :   if (sm->registration_pool)
     856             :     {
     857             :       u32 index;
     858             :         /* *INDENT-OFF* */
     859        1150 :         pool_foreach (rp, sm->registration_pool)  {
     860         575 :           vl_api_registration_del_file (rp);
     861         575 :           index = rp->vl_api_registration_pool_index;
     862         575 :           vl_socket_free_registration_index (index);
     863             :         }
     864             : /* *INDENT-ON* */
     865             :     }
     866             : 
     867         575 :   return 0;
     868             : }
     869             : 
     870        3451 : VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
     871             : 
     872             : static clib_error_t *
     873         575 : socksvr_config (vlib_main_t * vm, unformat_input_t * input)
     874             : {
     875         575 :   socket_main_t *sm = &socket_main;
     876             : 
     877        1150 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     878             :     {
     879         575 :       if (unformat (input, "socket-name %s", &sm->socket_name))
     880             :         ;
     881             :       /* DEPRECATE: default keyword is ignored */
     882           0 :       else if (unformat (input, "default"))
     883             :         ;
     884             :       else
     885             :         {
     886           0 :           return clib_error_return (0, "unknown input '%U'",
     887             :                                     format_unformat_error, input);
     888             :         }
     889             :     }
     890             : 
     891         575 :   if (!vec_len (sm->socket_name))
     892           0 :     sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
     893             :                               API_SOCKET_FILENAME);
     894         575 :   vec_terminate_c_string (sm->socket_name);
     895             : 
     896         575 :   return 0;
     897             : }
     898             : 
     899        7514 : VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
     900             : 
     901             : void
     902         575 : vlibsocket_reference ()
     903             : {
     904         575 : }
     905             : 
     906             : /*
     907             :  * fd.io coding-style-patch-verification: ON
     908             :  *
     909             :  * Local Variables:
     910             :  * eval: (c-set-style "gnu")
     911             :  * End:
     912             :  */

Generated by: LCOV version 1.14