LCOV - code coverage report
Current view: top level - plugins/hs_apps - http_client_cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 7 247 2.8 %
Date: 2023-07-05 22:20:52 Functions: 5 24 20.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2022 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             : 
      16             : #include <vnet/session/application.h>
      17             : #include <vnet/session/application_interface.h>
      18             : #include <vnet/session/session.h>
      19             : #include <http/http.h>
      20             : #include <hs_apps/http_cli.h>
      21             : 
      22             : typedef struct
      23             : {
      24             :   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
      25             :   u32 session_index;
      26             :   u32 thread_index;
      27             :   u32 rx_offset;
      28             :   u32 vpp_session_index;
      29             :   u32 to_recv;
      30             :   u8 is_closed;
      31             : } hcc_session_t;
      32             : 
      33             : typedef struct
      34             : {
      35             :   hcc_session_t *sessions;
      36             :   u8 *rx_buf;
      37             :   u32 thread_index;
      38             : } hcc_worker_t;
      39             : 
      40             : typedef struct
      41             : {
      42             :   hcc_worker_t *wrk;
      43             :   u32 app_index;
      44             : 
      45             :   u32 prealloc_fifos;
      46             :   u32 private_segment_size;
      47             :   u32 fifo_size;
      48             :   u8 *uri;
      49             :   u8 *http_query;
      50             :   session_endpoint_cfg_t connect_sep;
      51             : 
      52             :   u8 test_client_attached;
      53             :   vlib_main_t *vlib_main;
      54             :   u32 cli_node_index;
      55             :   u8 *http_response;
      56             :   u8 *appns_id;
      57             :   u64 appns_secret;
      58             : } hcc_main_t;
      59             : 
      60             : typedef enum
      61             : {
      62             :   HCC_REPLY_RECEIVED = 100,
      63             : } hcc_cli_signal_t;
      64             : 
      65             : static hcc_main_t hcc_main;
      66             : 
      67             : static hcc_worker_t *
      68           0 : hcc_worker_get (u32 thread_index)
      69             : {
      70           0 :   return vec_elt_at_index (hcc_main.wrk, thread_index);
      71             : }
      72             : 
      73             : static hcc_session_t *
      74           0 : hcc_session_alloc (hcc_worker_t *wrk)
      75             : {
      76             :   hcc_session_t *hs;
      77           0 :   pool_get_zero (wrk->sessions, hs);
      78           0 :   hs->session_index = hs - wrk->sessions;
      79           0 :   hs->thread_index = wrk->thread_index;
      80           0 :   return hs;
      81             : }
      82             : 
      83             : static hcc_session_t *
      84           0 : hcc_session_get (u32 hs_index, u32 thread_index)
      85             : {
      86           0 :   hcc_worker_t *wrk = hcc_worker_get (thread_index);
      87           0 :   return pool_elt_at_index (wrk->sessions, hs_index);
      88             : }
      89             : 
      90             : static void
      91           0 : hcc_session_free (u32 thread_index, hcc_session_t *hs)
      92             : {
      93           0 :   hcc_worker_t *wrk = hcc_worker_get (thread_index);
      94           0 :   pool_put (wrk->sessions, hs);
      95           0 : }
      96             : 
      97             : static int
      98           0 : hcc_ts_accept_callback (session_t *ts)
      99             : {
     100           0 :   clib_warning ("bug");
     101           0 :   return -1;
     102             : }
     103             : 
     104             : static void
     105           0 : hcc_ts_disconnect_callback (session_t *s)
     106             : {
     107           0 :   hcc_main_t *hcm = &hcc_main;
     108           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     109             : 
     110           0 :   a->handle = session_handle (s);
     111           0 :   a->app_index = hcm->app_index;
     112           0 :   vnet_disconnect_session (a);
     113           0 : }
     114             : 
     115             : static int
     116           0 : hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
     117             :                            session_error_t err)
     118             : {
     119           0 :   hcc_main_t *hcm = &hcc_main;
     120             :   hcc_session_t *hs, *new_hs;
     121             :   hcc_worker_t *wrk;
     122             :   http_msg_t msg;
     123             :   int rv;
     124             : 
     125           0 :   if (err)
     126             :     {
     127           0 :       clib_warning ("connected error: hc_index(%d): %U", hc_index,
     128             :                     format_session_error, err);
     129           0 :       return -1;
     130             :     }
     131             : 
     132             :   /* TODO delete half open session once the support is added in http layer */
     133           0 :   hs = hcc_session_get (hc_index, 0);
     134           0 :   wrk = hcc_worker_get (as->thread_index);
     135           0 :   new_hs = hcc_session_alloc (wrk);
     136           0 :   clib_memcpy_fast (new_hs, hs, sizeof (*hs));
     137             : 
     138           0 :   hs->vpp_session_index = as->session_index;
     139             : 
     140           0 :   msg.type = HTTP_MSG_REQUEST;
     141           0 :   msg.method_type = HTTP_REQ_GET;
     142           0 :   msg.content_type = HTTP_CONTENT_TEXT_HTML;
     143           0 :   msg.data.type = HTTP_MSG_DATA_INLINE;
     144           0 :   msg.data.len = vec_len (hcm->http_query);
     145             : 
     146           0 :   svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
     147           0 :                              { hcm->http_query, vec_len (hcm->http_query) } };
     148             : 
     149           0 :   rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 2, 0 /* allow partial */);
     150           0 :   if (rv < 0 || rv != sizeof (msg) + vec_len (hcm->http_query))
     151             :     {
     152           0 :       clib_warning ("failed app enqueue");
     153           0 :       return -1;
     154             :     }
     155             : 
     156           0 :   if (svm_fifo_set_event (as->tx_fifo))
     157           0 :     session_send_io_evt_to_thread (as->tx_fifo, SESSION_IO_EVT_TX);
     158             : 
     159           0 :   return 0;
     160             : }
     161             : 
     162             : static void
     163           0 : hcc_ts_reset_callback (session_t *s)
     164             : {
     165           0 :   hcc_main_t *hcm = &hcc_main;
     166             :   hcc_session_t *hs;
     167           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     168             : 
     169           0 :   hs = hcc_session_get (s->opaque, s->thread_index);
     170           0 :   hs->is_closed = 1;
     171             : 
     172           0 :   a->handle = session_handle (s);
     173           0 :   a->app_index = hcm->app_index;
     174           0 :   vnet_disconnect_session (a);
     175           0 : }
     176             : 
     177             : static int
     178           0 : hcc_ts_tx_callback (session_t *ts)
     179             : {
     180           0 :   clib_warning ("bug");
     181           0 :   return -1;
     182             : }
     183             : 
     184             : static void
     185           0 : hcc_session_disconnect (session_t *s)
     186             : {
     187           0 :   hcc_main_t *hcm = &hcc_main;
     188           0 :   vnet_disconnect_args_t _a = { 0 }, *a = &_a;
     189           0 :   a->handle = session_handle (s);
     190           0 :   a->app_index = hcm->app_index;
     191           0 :   vnet_disconnect_session (a);
     192           0 : }
     193             : 
     194             : static int
     195           0 : hcc_ts_rx_callback (session_t *ts)
     196             : {
     197           0 :   hcc_main_t *hcm = &hcc_main;
     198             :   hcc_session_t *hs;
     199             :   http_msg_t msg;
     200             :   int rv;
     201             : 
     202           0 :   hs = hcc_session_get (ts->opaque, ts->thread_index);
     203             : 
     204           0 :   if (hs->is_closed)
     205             :     {
     206           0 :       clib_warning ("session is closed");
     207           0 :       return 0;
     208             :     }
     209             : 
     210           0 :   if (!hs->to_recv)
     211             :     {
     212           0 :       rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
     213           0 :       ASSERT (rv == sizeof (msg));
     214             : 
     215           0 :       if (msg.type != HTTP_MSG_REPLY || msg.code != HTTP_STATUS_OK)
     216             :         {
     217           0 :           clib_warning ("unexpected msg type %d", msg.type);
     218           0 :           return 0;
     219             :         }
     220           0 :       vec_validate (hcm->http_response, msg.data.len - 1);
     221           0 :       vec_reset_length (hcm->http_response);
     222           0 :       hs->to_recv = msg.data.len;
     223             :     }
     224             : 
     225           0 :   u32 max_deq = svm_fifo_max_dequeue (ts->rx_fifo);
     226             : 
     227           0 :   u32 n_deq = clib_min (hs->to_recv, max_deq);
     228           0 :   u32 curr = vec_len (hcm->http_response);
     229           0 :   rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, hcm->http_response + curr);
     230           0 :   if (rv < 0)
     231             :     {
     232           0 :       clib_warning ("app dequeue failed");
     233           0 :       return -1;
     234             :     }
     235             : 
     236           0 :   if (rv != n_deq)
     237           0 :     return -1;
     238             : 
     239           0 :   vec_set_len (hcm->http_response, curr + n_deq);
     240           0 :   ASSERT (hs->to_recv >= rv);
     241           0 :   hs->to_recv -= rv;
     242             : 
     243           0 :   if (hs->to_recv == 0)
     244             :     {
     245           0 :       hcc_session_disconnect (ts);
     246           0 :       vlib_process_signal_event_mt (hcm->vlib_main, hcm->cli_node_index,
     247             :                                     HCC_REPLY_RECEIVED, 0);
     248             :     }
     249             : 
     250           0 :   return 0;
     251             : }
     252             : 
     253             : static void
     254           0 : hcc_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf)
     255             : {
     256             :   hcc_session_t *hs;
     257             : 
     258           0 :   hs = hcc_session_get (s->thread_index, s->opaque);
     259           0 :   if (!hs)
     260           0 :     return;
     261             : 
     262           0 :   hcc_session_free (s->thread_index, hs);
     263             : }
     264             : 
     265             : static session_cb_vft_t hcc_session_cb_vft = {
     266             :   .session_accept_callback = hcc_ts_accept_callback,
     267             :   .session_disconnect_callback = hcc_ts_disconnect_callback,
     268             :   .session_connected_callback = hcc_ts_connected_callback,
     269             :   .builtin_app_rx_callback = hcc_ts_rx_callback,
     270             :   .builtin_app_tx_callback = hcc_ts_tx_callback,
     271             :   .session_reset_callback = hcc_ts_reset_callback,
     272             :   .session_cleanup_callback = hcc_ts_cleanup_callback,
     273             : };
     274             : 
     275             : static clib_error_t *
     276           0 : hcc_attach ()
     277             : {
     278           0 :   hcc_main_t *hcm = &hcc_main;
     279           0 :   vnet_app_attach_args_t _a, *a = &_a;
     280             :   u64 options[18];
     281           0 :   u32 segment_size = 128 << 20;
     282             :   int rv;
     283             : 
     284           0 :   if (hcm->private_segment_size)
     285           0 :     segment_size = hcm->private_segment_size;
     286             : 
     287           0 :   clib_memset (a, 0, sizeof (*a));
     288           0 :   clib_memset (options, 0, sizeof (options));
     289             : 
     290           0 :   a->api_client_index = ~0;
     291           0 :   a->name = format (0, "http_cli_client");
     292           0 :   a->session_cb_vft = &hcc_session_cb_vft;
     293           0 :   a->options = options;
     294           0 :   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
     295           0 :   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
     296           0 :   a->options[APP_OPTIONS_RX_FIFO_SIZE] =
     297           0 :     hcm->fifo_size ? hcm->fifo_size : 8 << 10;
     298           0 :   a->options[APP_OPTIONS_TX_FIFO_SIZE] =
     299           0 :     hcm->fifo_size ? hcm->fifo_size : 32 << 10;
     300           0 :   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
     301           0 :   a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hcm->prealloc_fifos;
     302           0 :   if (hcm->appns_id)
     303             :     {
     304           0 :       a->namespace_id = hcm->appns_id;
     305           0 :       a->options[APP_OPTIONS_NAMESPACE_SECRET] = hcm->appns_secret;
     306             :     }
     307             : 
     308           0 :   if ((rv = vnet_application_attach (a)))
     309           0 :     return clib_error_return (0, "attach returned %d", rv);
     310             : 
     311           0 :   hcm->app_index = a->app_index;
     312           0 :   vec_free (a->name);
     313           0 :   hcm->test_client_attached = 1;
     314           0 :   return 0;
     315             : }
     316             : 
     317             : static int
     318           0 : hcc_connect_rpc (void *rpc_args)
     319             : {
     320           0 :   vnet_connect_args_t *a = rpc_args;
     321             :   int rv;
     322             : 
     323           0 :   rv = vnet_connect (a);
     324           0 :   if (rv)
     325           0 :     clib_warning (0, "connect returned: %U", format_session_error, rv);
     326             : 
     327           0 :   vec_free (a);
     328           0 :   return rv;
     329             : }
     330             : 
     331             : static void
     332           0 : hcc_program_connect (vnet_connect_args_t *a)
     333             : {
     334           0 :   session_send_rpc_evt_to_thread_force (transport_cl_thread (),
     335             :                                         hcc_connect_rpc, a);
     336           0 : }
     337             : 
     338             : static clib_error_t *
     339           0 : hcc_connect ()
     340             : {
     341           0 :   vnet_connect_args_t *a = 0;
     342           0 :   hcc_main_t *hcm = &hcc_main;
     343             :   hcc_worker_t *wrk;
     344             :   hcc_session_t *hs;
     345             : 
     346           0 :   vec_validate (a, 0);
     347           0 :   clib_memset (a, 0, sizeof (a[0]));
     348             : 
     349           0 :   clib_memcpy (&a->sep_ext, &hcm->connect_sep, sizeof (hcm->connect_sep));
     350           0 :   a->app_index = hcm->app_index;
     351             : 
     352             :   /* allocate http session on main thread */
     353           0 :   wrk = hcc_worker_get (0);
     354           0 :   hs = hcc_session_alloc (wrk);
     355           0 :   a->api_context = hs->session_index;
     356             : 
     357           0 :   hcc_program_connect (a);
     358           0 :   return 0;
     359             : }
     360             : 
     361             : static clib_error_t *
     362           0 : hcc_run (vlib_main_t *vm)
     363             : {
     364           0 :   vlib_thread_main_t *vtm = vlib_get_thread_main ();
     365           0 :   hcc_main_t *hcm = &hcc_main;
     366           0 :   uword event_type, *event_data = 0;
     367             :   u32 num_threads;
     368           0 :   clib_error_t *err = 0;
     369             :   hcc_worker_t *wrk;
     370             : 
     371           0 :   num_threads = 1 /* main thread */ + vtm->n_threads;
     372           0 :   vec_validate (hcm->wrk, num_threads);
     373           0 :   vec_foreach (wrk, hcm->wrk)
     374             :     {
     375           0 :       wrk->thread_index = wrk - hcm->wrk;
     376             :     }
     377             : 
     378           0 :   if ((err = hcc_attach ()))
     379             :     {
     380           0 :       return clib_error_return (0, "http client attach: %U", format_clib_error,
     381             :                                 err);
     382             :     }
     383             : 
     384           0 :   if ((err = hcc_connect ()))
     385             :     {
     386           0 :       return clib_error_return (0, "http client connect: %U",
     387             :                                 format_clib_error, err);
     388             :     }
     389             : 
     390           0 :   vlib_process_wait_for_event_or_clock (vm, 10);
     391           0 :   event_type = vlib_process_get_events (vm, &event_data);
     392           0 :   switch (event_type)
     393             :     {
     394           0 :     case ~0:
     395           0 :       err = clib_error_return (0, "timeout");
     396           0 :       goto cleanup;
     397             : 
     398           0 :     case HCC_REPLY_RECEIVED:
     399           0 :       vlib_cli_output (vm, "%v", hcm->http_response);
     400           0 :       vec_free (hcm->http_response);
     401           0 :       break;
     402           0 :     default:
     403           0 :       clib_error_return (0, "unexpected event %d", event_type);
     404           0 :       break;
     405             :     }
     406             : 
     407           0 : cleanup:
     408           0 :   vec_free (event_data);
     409           0 :   return err;
     410             : }
     411             : 
     412             : static int
     413           0 : hcc_detach ()
     414             : {
     415           0 :   hcc_main_t *hcm = &hcc_main;
     416           0 :   vnet_app_detach_args_t _da, *da = &_da;
     417             :   int rv;
     418             : 
     419           0 :   if (!hcm->test_client_attached)
     420           0 :     return 0;
     421             : 
     422           0 :   da->app_index = hcm->app_index;
     423           0 :   da->api_client_index = ~0;
     424           0 :   rv = vnet_application_detach (da);
     425           0 :   hcm->test_client_attached = 0;
     426           0 :   hcm->app_index = ~0;
     427             : 
     428           0 :   return rv;
     429             : }
     430             : 
     431             : static clib_error_t *
     432           0 : hcc_command_fn (vlib_main_t *vm, unformat_input_t *input,
     433             :                 vlib_cli_command_t *cmd)
     434             : {
     435           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     436           0 :   hcc_main_t *hcm = &hcc_main;
     437             :   u64 seg_size;
     438           0 :   u8 *appns_id = 0;
     439           0 :   clib_error_t *err = 0;
     440             :   int rv;
     441             : 
     442           0 :   hcm->prealloc_fifos = 0;
     443           0 :   hcm->private_segment_size = 0;
     444           0 :   hcm->fifo_size = 0;
     445             : 
     446           0 :   if (hcm->test_client_attached)
     447           0 :     return clib_error_return (0, "failed: already running!");
     448             : 
     449             :   /* Get a line of input. */
     450           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     451           0 :     return clib_error_return (0, "expected URI");
     452             : 
     453           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     454             :     {
     455           0 :       if (unformat (line_input, "prealloc-fifos %d", &hcm->prealloc_fifos))
     456             :         ;
     457           0 :       else if (unformat (line_input, "private-segment-size %U",
     458             :                          unformat_memory_size, &seg_size))
     459           0 :         hcm->private_segment_size = seg_size;
     460           0 :       else if (unformat (line_input, "fifo-size %d", &hcm->fifo_size))
     461           0 :         hcm->fifo_size <<= 10;
     462           0 :       else if (unformat (line_input, "uri %s", &hcm->uri))
     463             :         ;
     464           0 :       else if (unformat (line_input, "appns %_%v%_", &appns_id))
     465             :         ;
     466           0 :       else if (unformat (line_input, "secret %lu", &hcm->appns_secret))
     467             :         ;
     468           0 :       else if (unformat (line_input, "query %s", &hcm->http_query))
     469             :         ;
     470             :       else
     471             :         {
     472           0 :           err = clib_error_return (0, "unknown input `%U'",
     473             :                                    format_unformat_error, line_input);
     474           0 :           goto done;
     475             :         }
     476             :     }
     477             : 
     478           0 :   vec_free (hcm->appns_id);
     479           0 :   hcm->appns_id = appns_id;
     480           0 :   hcm->cli_node_index = vlib_get_current_process (vm)->node_runtime.node_index;
     481             : 
     482           0 :   if (!hcm->uri)
     483             :     {
     484           0 :       err = clib_error_return (0, "URI not defined");
     485           0 :       goto done;
     486             :     }
     487             : 
     488           0 :   if ((rv = parse_uri ((char *) hcm->uri, &hcm->connect_sep)))
     489             :     {
     490           0 :       err = clib_error_return (0, "Uri parse error: %d", rv);
     491           0 :       goto done;
     492             :     }
     493             : 
     494           0 :   vlib_worker_thread_barrier_sync (vm);
     495           0 :   vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */);
     496           0 :   vlib_worker_thread_barrier_release (vm);
     497             : 
     498           0 :   err = hcc_run (vm);
     499             : 
     500           0 :   if (hcc_detach ())
     501             :     {
     502             :       /* don't override last error */
     503           0 :       if (!err)
     504           0 :         err = clib_error_return (0, "failed: app detach");
     505           0 :       clib_warning ("WARNING: app detach failed...");
     506             :     }
     507             : 
     508           0 : done:
     509           0 :   vec_free (hcm->uri);
     510           0 :   vec_free (hcm->http_query);
     511           0 :   unformat_free (line_input);
     512           0 :   return err;
     513             : }
     514             : 
     515      203447 : VLIB_CLI_COMMAND (hcc_command, static) = {
     516             :   .path = "http cli client",
     517             :   .short_help = "[appns <app-ns> secret <appns-secret>] uri http://<ip-addr> "
     518             :                 "query <query-string>",
     519             :   .function = hcc_command_fn,
     520             :   .is_mp_safe = 1,
     521             : };
     522             : 
     523             : static clib_error_t *
     524         559 : hcc_main_init (vlib_main_t *vm)
     525             : {
     526         559 :   hcc_main_t *hcm = &hcc_main;
     527             : 
     528         559 :   hcm->app_index = ~0;
     529         559 :   hcm->vlib_main = vm;
     530         559 :   return 0;
     531             : }
     532             : 
     533        2239 : VLIB_INIT_FUNCTION (hcc_main_init);
     534             : 
     535             : /*
     536             :  * fd.io coding-style-patch-verification: ON
     537             :  *
     538             :  * Local Variables:
     539             :  * eval: (c-set-style "gnu")
     540             :  * End:
     541             :  */

Generated by: LCOV version 1.14