FD.io VPP  v21.06
Vector Packet Processing
http_server.c
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2017-2019 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/vnet.h>
19 #include <vnet/session/session.h>
21 
22 typedef enum
23 {
26 
27 typedef struct
28 {
33 
34 typedef enum
35 {
40 typedef struct
41 {
42  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
43 #define _(type, name) type name;
45 #undef _
52 
53 typedef struct
54 {
58 
60 
62 
64 
65  /* Sever's event queue */
67 
68  /* API client handle */
70 
72 
73  /* process node index for evnt scheduling */
75 
76  /* Cert key pair for tls */
78 
79  tw_timer_wheel_2t_1w_2048sl_t tw;
81 
85  u8 *uri;
89 
91 
92 static void
94 {
95  clib_rwlock_reader_lock (&http_server_main.sessions_lock);
96 }
97 
98 static void
100 {
101  clib_rwlock_reader_unlock (&http_server_main.sessions_lock);
102 }
103 
104 static void
106 {
107  clib_rwlock_writer_lock (&http_server_main.sessions_lock);
108 }
109 
110 static void
112 {
113  clib_rwlock_writer_unlock (&http_server_main.sessions_lock);
114 }
115 
116 static http_session_t *
118 {
120  http_session_t *hs;
121  pool_get (hsm->sessions[thread_index], hs);
122  memset (hs, 0, sizeof (*hs));
123  hs->session_index = hs - hsm->sessions[thread_index];
125  hs->timer_handle = ~0;
126  return hs;
127 }
128 
129 static http_session_t *
131 {
133  if (pool_is_free_index (hsm->sessions[thread_index], hs_index))
134  return 0;
135  return pool_elt_at_index (hsm->sessions[thread_index], hs_index);
136 }
137 
138 static void
140 {
142  u32 thread = hs->thread_index;
143  if (CLIB_DEBUG)
144  memset (hs, 0xfa, sizeof (*hs));
145  pool_put (hsm->sessions[thread], hs);
146 }
147 
148 static void
150 {
152  vec_validate (hsm->session_to_http_session[thread_index], s_index);
153  hsm->session_to_http_session[thread_index][s_index] = hs_index;
154 }
155 
156 static void
158 {
160  hsm->session_to_http_session[thread_index][s_index] = ~0;
161 }
162 
163 static http_session_t *
165 {
167  u32 hs_index;
168 
169  if (s_index < vec_len (hsm->session_to_http_session[thread_index]))
170  {
171  hs_index = hsm->session_to_http_session[thread_index][s_index];
172  return http_server_session_get (thread_index, hs_index);
173  }
174  return 0;
175 }
176 
177 
178 static void
180 {
181  u32 hs_handle;
182  hs_handle = hs->thread_index << 24 | hs->session_index;
183  clib_spinlock_lock (&http_server_main.tw_lock);
184  hs->timer_handle = tw_timer_start_2t_1w_2048sl (&http_server_main.tw,
185  hs_handle, 0, 60);
186  clib_spinlock_unlock (&http_server_main.tw_lock);
187 }
188 
189 static void
191 {
192  if (hs->timer_handle == ~0)
193  return;
194  clib_spinlock_lock (&http_server_main.tw_lock);
195  tw_timer_stop_2t_1w_2048sl (&http_server_main.tw, hs->timer_handle);
196  clib_spinlock_unlock (&http_server_main.tw_lock);
197 }
198 
199 static void
201 {
202  vnet_disconnect_args_t _a = { 0 }, *a = &_a;
203  a->handle = hs->vpp_session_handle;
204  a->app_index = http_server_main.app_index;
206 }
207 
208 static void
210 {
214  vlib_node_t *n;
215  u32 node_index;
216  http_server_args **save_args;
217 
218  node_index = args->node_index;
219  ASSERT (node_index != 0);
220 
221  n = vlib_get_node (vm, node_index);
222  rt = vlib_node_get_runtime (vm, n->index);
223  save_args = vlib_node_get_runtime_data (vm, n->index);
224 
225  /* Reset process session pointer */
226  clib_mem_free (*save_args);
227  *save_args = 0;
228 
229  /* Turn off the process node */
230  vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED);
231 
232  /* add node index to the freelist */
233  vec_add1 (hsm->free_http_cli_process_node_indices, node_index);
234 }
235 
236 /* *INDENT-OFF* */
237 static const char *http_ok =
238  "HTTP/1.1 200 OK\r\n";
239 
240 static const char *http_response =
241  "Content-Type: text/html\r\n"
242  "Expires: Mon, 11 Jan 1970 10:10:10 GMT\r\n"
243  "Connection: close \r\n"
244  "Pragma: no-cache\r\n"
245  "Content-Length: %d\r\n\r\n%v";
246 
247 static const char *http_error_template =
248  "HTTP/1.1 %s\r\n"
249  "Content-Type: text/html\r\n"
250  "Expires: Mon, 11 Jan 1970 10:10:10 GMT\r\n"
251  "Connection: close\r\n"
252  "Pragma: no-cache\r\n"
253  "Content-Length: 0\r\n\r\n";
254 
255 /* Header, including incantation to suppress favicon.ico requests */
256 static const char *html_header_template =
257  "<html><head><title>%v</title></head>"
258  "<link rel=\"icon\" href=\"data:,\">"
259  "<body><pre>";
260 
261 static const char *html_footer =
262  "</pre></body></html>\r\n";
263 
264 static const char *html_header_static =
265  "<html><head><title>static reply</title></head>"
266  "<link rel=\"icon\" href=\"data:,\">"
267  "<body><pre>hello</pre></body></html>\r\n";
268 /* *INDENT-ON* */
269 
270 static u8 *static_http;
271 static u8 *static_ok;
272 
273 static void
274 http_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
275 {
276  u8 **output_vecp = (u8 **) arg;
277  u8 *output_vec;
278  u32 offset;
279 
280  output_vec = *output_vecp;
281 
282  offset = vec_len (output_vec);
283  vec_validate (output_vec, offset + buffer_bytes - 1);
284  clib_memcpy_fast (output_vec + offset, buffer, buffer_bytes);
285 
286  *output_vecp = output_vec;
287 }
288 
289 void
291 {
293  vnet_disconnect_args_t _a = { 0 }, *a = &_a;
295  f64 last_sent_timer = vlib_time_now (vm);
296  u32 offset, bytes_to_send;
297  f64 delay = 10e-3;
298 
299  bytes_to_send = vec_len (data);
300  offset = 0;
301 
302  while (bytes_to_send > 0)
303  {
304  int actual_transfer;
305 
306  actual_transfer = svm_fifo_enqueue
307  (hs->tx_fifo, bytes_to_send, data + offset);
308 
309  /* Made any progress? */
310  if (actual_transfer <= 0)
311  {
313  vlib_process_suspend (vm, delay);
315 
316  /* 10s deadman timer */
317  if (vlib_time_now (vm) > last_sent_timer + 10.0)
318  {
319  a->handle = hs->vpp_session_handle;
320  a->app_index = hsm->app_index;
322  break;
323  }
324  /* Exponential backoff, within reason */
325  if (delay < 1.0)
326  delay = delay * 2.0;
327  }
328  else
329  {
330  last_sent_timer = vlib_time_now (vm);
331  offset += actual_transfer;
332  bytes_to_send -= actual_transfer;
333 
334  if (svm_fifo_set_event (hs->tx_fifo))
335  session_send_io_evt_to_thread (hs->tx_fifo,
337  delay = 10e-3;
338  }
339  }
340 }
341 
342 static void
343 send_error (http_session_t * hs, char *str)
344 {
345  u8 *data;
346 
347  data = format (0, http_error_template, str);
348  send_data (hs, data);
349  vec_free (data);
350 }
351 
352 static uword
354  vlib_frame_t * f)
355 {
356  u8 *request = 0, *reply = 0, *http = 0, *html = 0;
358  http_server_args **save_args;
359  http_server_args *args;
360  unformat_input_t input;
361  http_session_t *hs;
362  int i;
363 
364  save_args = vlib_node_get_runtime_data (hsm->vlib_main, rt->node_index);
365  args = *save_args;
366 
368 
369  hs = http_server_session_get (args->thread_index, args->hs_index);
370  ASSERT (hs);
371 
372  request = hs->rx_buf;
373  if (vec_len (request) < 7)
374  {
375  send_error (hs, "400 Bad Request");
376  goto out;
377  }
378 
379  for (i = 0; i < vec_len (request) - 4; i++)
380  {
381  if (request[i] == 'G' &&
382  request[i + 1] == 'E' &&
383  request[i + 2] == 'T' && request[i + 3] == ' ')
384  goto found;
385  }
386 bad_request:
387  send_error (hs, "400 Bad Request");
388  goto out;
389 
390 found:
391  /* Lose "GET " */
392  vec_delete (request, i + 5, 0);
393 
394  /* Replace slashes with spaces, stop at the end of the path */
395  i = 0;
396  while (1)
397  {
398  if (request[i] == '/')
399  request[i] = ' ';
400  else if (request[i] == ' ')
401  {
402  /* vlib_cli_input is vector-based, no need for a NULL */
403  _vec_len (request) = i;
404  break;
405  }
406  i++;
407  /* Should never happen */
408  if (i == vec_len (request))
409  goto bad_request;
410  }
411 
412  /* Generate the html header */
413  html = format (0, html_header_template, request /* title */ );
414 
415  /* Run the command */
416  unformat_init_vector (&input, vec_dup (request));
417  vlib_cli_input (vm, &input, http_cli_output, (uword) & reply);
418  unformat_free (&input);
419  request = 0;
420 
421  /* Generate the html page */
422  html = format (html, "%v", reply);
423  html = format (html, html_footer);
424  /* And the http reply */
425  http = format (0, http_ok);
426  http = format (http, http_response, vec_len (html), html);
427 
428  /* Send it */
429  send_data (hs, http);
430 
431 out:
432  /* Cleanup */
434  vec_free (reply);
435  vec_free (html);
436  vec_free (http);
437 
438  http_process_free (args);
439  return (0);
440 }
441 
442 static void
444 {
445  char *name;
446  vlib_node_t *n;
448  vlib_main_t *vm = hsm->vlib_main;
450  http_server_args **save_args;
451 
453  {
455  vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING);
456  _vec_len (hsm->free_http_cli_process_node_indices) = l - 1;
457  }
458  else
459  {
460  static vlib_node_registration_t r = {
461  .function = http_cli_process,
462  .type = VLIB_NODE_TYPE_PROCESS,
463  .process_log2_n_stack_bytes = 16,
464  .runtime_data_bytes = sizeof (void *),
465  };
466 
467  name = (char *) format (0, "http-cli-%d", l);
468  r.name = name;
469  vlib_register_node (vm, &r);
470  vec_free (name);
471 
472  n = vlib_get_node (vm, r.index);
473  }
474 
475  /* Save the node index in the args. It won't be zero. */
476  args->node_index = n->index;
477 
478  /* Save the args (pointer) in the node runtime */
479  save_args = vlib_node_get_runtime_data (vm, n->index);
480  *save_args = clib_mem_alloc (sizeof (*args));
481  clib_memcpy_fast (*save_args, args, sizeof (*args));
482 
484 }
485 
486 static void
488 {
489  alloc_http_process ((http_server_args *) cb_args);
490 }
491 
492 static int
494 {
495  u32 max_dequeue, cursize;
496  int n_read;
497 
498  cursize = vec_len (hs->rx_buf);
499  max_dequeue = svm_fifo_max_dequeue_cons (hs->rx_fifo);
500  if (PREDICT_FALSE (max_dequeue == 0))
501  return -1;
502 
503  vec_validate (hs->rx_buf, cursize + max_dequeue - 1);
504  n_read = app_recv_stream_raw (hs->rx_fifo, hs->rx_buf + cursize,
505  max_dequeue, 0, 0 /* peek */ );
506  ASSERT (n_read == max_dequeue);
507  if (svm_fifo_is_empty_cons (hs->rx_fifo))
508  svm_fifo_unset_event (hs->rx_fifo);
509 
510  _vec_len (hs->rx_buf) = cursize + n_read;
511  return 0;
512 }
513 
514 static int
516 {
517  http_server_args args;
518  http_session_t *hs;
519  int rv;
520 
522 
524  if (!hs || hs->session_state != HTTP_STATE_ESTABLISHED)
525  return -1;
526 
527  rv = session_rx_request (hs);
528  if (rv)
529  return rv;
530 
531  /* send the command to a new/recycled vlib process */
532  args.hs_index = hs->session_index;
533  args.thread_index = hs->thread_index;
534 
536 
537  /* Send RPC request to main thread */
538  if (vlib_get_thread_index () != 0)
540  sizeof (args));
541  else
542  alloc_http_process (&args);
543  return 0;
544 }
545 
546 static int
548 {
549  http_session_t *hs;
550  u32 request_len;
551  u8 *request = 0;
552  int i, rv;
553 
555  if (!hs || hs->session_state == HTTP_STATE_CLOSED)
556  return 0;
557 
558  /* ok 200 was sent */
559  if (hs->session_state == HTTP_STATE_OK_SENT)
560  goto send_data;
561 
562  rv = session_rx_request (hs);
563  if (rv)
564  goto wait_for_data;
565 
566  request = hs->rx_buf;
567  request_len = vec_len (request);
568  if (vec_len (request) < 7)
569  {
570  send_error (hs, "400 Bad Request");
571  goto close_session;
572  }
573 
574  for (i = 0; i < request_len - 4; i++)
575  {
576  if (request[i] == 'G' &&
577  request[i + 1] == 'E' &&
578  request[i + 2] == 'T' && request[i + 3] == ' ')
579  goto find_end;
580  }
581  send_error (hs, "400 Bad Request");
582  goto close_session;
583 
584 find_end:
585 
586  /* check for the end sequence: /r/n/r/n */
587  if (request[request_len - 1] != 0xa || request[request_len - 3] != 0xa
588  || request[request_len - 2] != 0xd || request[request_len - 4] != 0xd)
589  goto wait_for_data;
590 
591  /* send 200 OK first */
592  send_data (hs, static_ok);
593  hs->session_state = HTTP_STATE_OK_SENT;
594  goto postpone;
595 
596 send_data:
597  send_data (hs, static_http);
598 
601  return 0;
602 
603 postpone:
604  (void) svm_fifo_set_event (hs->rx_fifo);
606  return 0;
607 
608 wait_for_data:
609  return 0;
610 }
611 
612 static int
614 {
616  http_session_t *hs;
617 
618  hsm->vpp_queue[s->thread_index] =
620 
621  if (!hsm->is_static)
623 
626  hs->session_index);
627  hs->rx_fifo = s->rx_fifo;
628  hs->tx_fifo = s->tx_fifo;
631  hs->session_state = HTTP_STATE_ESTABLISHED;
633 
634  if (!hsm->is_static)
636 
637  s->session_state = SESSION_STATE_READY;
638  return 0;
639 }
640 
641 static void
643 {
645  vnet_disconnect_args_t _a = { 0 }, *a = &_a;
646 
647  a->handle = session_handle (s);
648  a->app_index = hsm->app_index;
650 }
651 
652 static void
654 {
656  vnet_disconnect_args_t _a = { 0 }, *a = &_a;
657 
658  a->handle = session_handle (s);
659  a->app_index = hsm->app_index;
661 }
662 
663 static int
665  session_t * s, session_error_t err)
666 {
667  clib_warning ("called...");
668  return -1;
669 }
670 
671 static int
672 http_server_add_segment_callback (u32 client_index, u64 segment_handle)
673 {
674  return 0;
675 }
676 
677 static void
679 {
681  http_session_t *hs;
682 
683  if (ntf == SESSION_CLEANUP_TRANSPORT)
684  return;
685 
686  if (!hsm->is_static)
688 
690  if (!hs)
691  goto done;
692 
694  vec_free (hs->rx_buf);
697 
698 done:
699 
700  if (!hsm->is_static)
702 }
703 
704 static session_cb_vft_t http_server_session_cb_vft = {
706  .session_disconnect_callback = http_server_session_disconnect_callback,
707  .session_connected_callback = http_server_session_connected_callback,
708  .add_segment_callback = http_server_add_segment_callback,
709  .builtin_app_rx_callback = http_server_rx_callback,
710  .session_reset_callback = http_server_session_reset_callback,
711  .session_cleanup_callback = http_server_cleanup_callback,
712 };
713 
714 static int
716 {
717  vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
720  vnet_app_attach_args_t _a, *a = &_a;
721  u32 segment_size = 128 << 20;
722 
723  clib_memset (a, 0, sizeof (*a));
724  clib_memset (options, 0, sizeof (options));
725 
726  if (hsm->private_segment_size)
727  segment_size = hsm->private_segment_size;
728 
729  a->api_client_index = ~0;
730  a->name = format (0, "test_http_server");
731  a->session_cb_vft = &http_server_session_cb_vft;
732  a->options = options;
733  a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
734  a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
735  a->options[APP_OPTIONS_RX_FIFO_SIZE] =
736  hsm->fifo_size ? hsm->fifo_size : 8 << 10;
737  a->options[APP_OPTIONS_TX_FIFO_SIZE] =
738  hsm->fifo_size ? hsm->fifo_size : 32 << 10;
739  a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
741 
742  if (vnet_application_attach (a))
743  {
744  vec_free (a->name);
745  clib_warning ("failed to attach server");
746  return -1;
747  }
748  vec_free (a->name);
749  hsm->app_index = a->app_index;
750 
751  clib_memset (ck_pair, 0, sizeof (*ck_pair));
752  ck_pair->cert = (u8 *) test_srv_crt_rsa;
753  ck_pair->key = (u8 *) test_srv_key_rsa;
754  ck_pair->cert_len = test_srv_crt_rsa_len;
755  ck_pair->key_len = test_srv_key_rsa_len;
756  vnet_app_add_cert_key_pair (ck_pair);
757  hsm->ckpair_index = ck_pair->index;
758 
759  return 0;
760 }
761 
762 static int
764 {
765  return proto == TRANSPORT_PROTO_TLS || proto == TRANSPORT_PROTO_DTLS ||
766  proto == TRANSPORT_PROTO_QUIC;
767 }
768 
769 static int
771 {
774  vnet_listen_args_t _a, *a = &_a;
775  char *uri = "tcp://0.0.0.0/80";
776  int rv;
777 
778  clib_memset (a, 0, sizeof (*a));
779  a->app_index = hsm->app_index;
780 
781  if (hsm->uri)
782  uri = (char *) hsm->uri;
783 
784  if (parse_uri (uri, &sep))
785  return -1;
786 
787  clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
788  if (http_transport_needs_crypto (a->sep_ext.transport_proto))
789  {
790  session_endpoint_alloc_ext_cfg (&a->sep_ext,
792  a->sep_ext.ext_cfg->crypto.ckpair_index = hsm->ckpair_index;
793  }
794 
795  rv = vnet_listen (a);
796  if (a->sep_ext.ext_cfg)
797  clib_mem_free (a->sep_ext.ext_cfg);
798  return rv;
799 }
800 
801 static void
803 {
804  http_session_t *hs;
805  uword hs_handle;
806  hs_handle = pointer_to_uword (hs_handlep);
807  hs = http_server_session_get (hs_handle >> 24, hs_handle & 0x00FFFFFF);
808  if (!hs)
809  return;
810  hs->timer_handle = ~0;
812 }
813 
814 static void
816 {
817  u32 hs_handle;
818  int i;
819 
820  for (i = 0; i < vec_len (expired_timers); i++)
821  {
822  /* Get session handle. The first bit is the timer id */
823  hs_handle = expired_timers[i] & 0x7FFFFFFF;
824  session_send_rpc_evt_to_thread (hs_handle >> 24,
826  uword_to_pointer (hs_handle, void *));
827  }
828 }
829 
830 static uword
832  vlib_frame_t * f)
833 {
835  f64 now, timeout = 1.0;
836  uword *event_data = 0;
837  uword __clib_unused event_type;
838 
839  while (1)
840  {
842  now = vlib_time_now (vm);
843  event_type = vlib_process_get_events (vm, (uword **) & event_data);
844 
845  /* expire timers */
846  clib_spinlock_lock (&http_server_main.tw_lock);
847  tw_timer_expire_timers_2t_1w_2048sl (&hsm->tw, now);
848  clib_spinlock_unlock (&http_server_main.tw_lock);
849 
850  vec_reset_length (event_data);
851  }
852  return 0;
853 }
854 
855 /* *INDENT-OFF* */
857 {
858  .function = http_server_process,
859  .type = VLIB_NODE_TYPE_PROCESS,
860  .name = "http-server-process",
861  .state = VLIB_NODE_STATE_DISABLED,
862 };
863 /* *INDENT-ON* */
864 
865 static int
867 {
870  u32 num_threads;
871  vlib_node_t *n;
872 
873  num_threads = 1 /* main thread */ + vtm->n_threads;
874  vec_validate (hsm->vpp_queue, num_threads - 1);
875  vec_validate (hsm->sessions, num_threads - 1);
876  vec_validate (hsm->session_to_http_session, num_threads - 1);
877 
879  clib_spinlock_init (&hsm->tw_lock);
880 
881  if (http_server_attach ())
882  {
883  clib_warning ("failed to attach server");
884  return -1;
885  }
886  if (http_server_listen ())
887  {
888  clib_warning ("failed to start listening");
889  return -1;
890  }
891 
892  /* Init timer wheel and process */
893  tw_timer_wheel_init_2t_1w_2048sl (&hsm->tw, http_expired_timers_dispatch,
894  1 /* timer interval */ , ~0);
896  VLIB_NODE_STATE_POLLING);
897  n = vlib_get_node (vm, http_server_process_node.index);
899 
900  return 0;
901 }
902 
903 static clib_error_t *
905  unformat_input_t * input,
906  vlib_cli_command_t * cmd)
907 {
909  unformat_input_t _line_input, *line_input = &_line_input;
910  u64 seg_size;
911  u8 *html;
912  int rv;
913 
914  hsm->prealloc_fifos = 0;
915  hsm->private_segment_size = 0;
916  hsm->fifo_size = 0;
917  hsm->is_static = 0;
918 
919  /* Get a line of input. */
920  if (!unformat_user (input, unformat_line_input, line_input))
921  goto start_server;
922 
923  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
924  {
925  if (unformat (line_input, "static"))
926  hsm->is_static = 1;
927  else
928  if (unformat (line_input, "prealloc-fifos %d", &hsm->prealloc_fifos))
929  ;
930  else if (unformat (line_input, "private-segment-size %U",
931  unformat_memory_size, &seg_size))
932  {
933  if (seg_size >= 0x100000000ULL)
934  {
935  vlib_cli_output (vm, "private segment size %llu, too large",
936  seg_size);
937  return 0;
938  }
939  hsm->private_segment_size = seg_size;
940  }
941  else if (unformat (line_input, "fifo-size %d", &hsm->fifo_size))
942  hsm->fifo_size <<= 10;
943  else if (unformat (line_input, "uri %s", &hsm->uri))
944  ;
945  else
946  return clib_error_return (0, "unknown input `%U'",
947  format_unformat_error, line_input);
948  }
949  unformat_free (line_input);
950 
951 start_server:
952 
953  if (hsm->my_client_index != (u32) ~ 0)
954  return clib_error_return (0, "test http server is already running");
955 
956  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
957 
958  if (hsm->is_static)
959  {
960  http_server_session_cb_vft.builtin_app_rx_callback =
962  html = format (0, html_header_static);
963  static_http = format (0, http_response, vec_len (html), html);
964  static_ok = format (0, http_ok);
965  }
966  rv = http_server_create (vm);
967  switch (rv)
968  {
969  case 0:
970  break;
971  default:
972  return clib_error_return (0, "server_create returned %d", rv);
973  }
974  return 0;
975 }
976 
977 /* *INDENT-OFF* */
978 VLIB_CLI_COMMAND (http_server_create_command, static) =
979 {
980  .path = "test http server",
981  .short_help = "test http server",
982  .function = http_server_create_command_fn,
983 };
984 /* *INDENT-ON* */
985 
986 static clib_error_t *
988 {
990 
991  hsm->my_client_index = ~0;
992  hsm->vlib_main = vm;
993  return 0;
994 }
995 
997 
998 /*
999 * fd.io coding-style-patch-verification: ON
1000 *
1001 * Local Variables:
1002 * eval: (c-set-style "gnu")
1003 * End:
1004 */
static void http_server_session_timer_start(http_session_t *hs)
Definition: http_server.c:179
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
#define foreach_app_session_field
flag for dgram mode
static void clib_rwlock_reader_lock(clib_rwlock_t *p)
Definition: lock.h:169
static void http_server_sessions_reader_unlock(void)
Definition: http_server.c:99
static int app_recv_stream_raw(svm_fifo_t *f, u8 *buf, u32 len, u8 clear_evt, u8 peek)
#define CLIB_CACHE_LINE_ALIGN_MARK(mark)
Definition: cache.h:60
vnet_interface_output_runtime_t * rt
static uword http_server_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: http_server.c:831
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:121
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:82
static int http_server_create(vlib_main_t *vm)
Definition: http_server.c:866
int vnet_app_add_cert_key_pair(vnet_app_add_cert_key_pair_args_t *a)
Definition: application.c:2017
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:755
a
Definition: bitmap.h:544
static void clib_rwlock_writer_lock(clib_rwlock_t *p)
Definition: lock.h:192
static const char * html_header_template
Definition: http_server.c:256
svm_fifo_t * tx_fifo
vnet_hw_if_output_node_runtime_t * r
svm_queue_t * vl_input_queue
Definition: http_server.c:66
static const char * http_response
Definition: http_server.c:240
u32 thread_index
u32 session_index
Index in thread pool where session was allocated.
unsigned long u64
Definition: types.h:89
static int session_rx_request(http_session_t *hs)
Definition: http_server.c:493
static svm_msg_q_t * session_main_get_vpp_event_queue(u32 thread_index)
Definition: session.h:716
u32 timer_handle
Timeout timer handle.
Definition: http_server.c:50
static void http_server_sessions_writer_unlock(void)
Definition: http_server.c:111
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 index
Definition: node.h:270
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:325
svm_fifo_t * rx_fifo
Pointers to rx/tx buffers.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
u32 vpp_session_index
vpp session index, handle
Definition: http_server.c:48
void session_send_rpc_evt_to_thread(u32 thread_index, void *fp, void *rpc_args)
Definition: session.c:116
static int svm_fifo_is_empty_cons(svm_fifo_t *f)
Check if fifo is empty optimized for consumer.
Definition: svm_fifo.h:554
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
static void http_process_free(http_server_args *args)
Definition: http_server.c:209
static int http_server_rx_callback_static(session_t *s)
Definition: http_server.c:547
string name[64]
Definition: fib.api:25
static void http_server_session_lookup_add(u32 thread_index, u32 s_index, u32 hs_index)
Definition: http_server.c:149
int vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
Definition: cli.c:675
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
unsigned char u8
Definition: types.h:56
u8 data[128]
Definition: ipsec_types.api:92
struct _vnet_bind_args_t vnet_listen_args_t
static void alloc_http_process_callback(void *cb_args)
Definition: http_server.c:487
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
static session_handle_t session_handle(session_t *s)
unsigned int u32
Definition: types.h:88
#define clib_memcpy(d, s, n)
Definition: string.h:197
static void http_server_session_disconnect(http_session_t *hs)
Definition: http_server.c:200
vlib_frame_t * f
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:486
static int http_server_session_accept_callback(session_t *s)
Definition: http_server.c:613
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
http_session_state_t
Definition: http_server.c:34
int(* builtin_app_rx_callback)(session_t *session)
Direct RX callback for built-in application.
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:172
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:583
struct _vnet_disconnect_args_t vnet_disconnect_args_t
static const u32 test_srv_key_rsa_len
Definition: tls_test.h:77
static void http_expired_timers_dispatch(u32 *expired_timers)
Definition: http_server.c:815
static u32 svm_fifo_max_dequeue_cons(svm_fifo_t *f)
Fifo max bytes to dequeue optimized for consumer.
Definition: svm_fifo.h:487
description fragment has unexpected format
Definition: map.api:433
foreach_app_session_field u32 thread_index
rx thread index
Definition: http_server.c:46
static int http_server_rx_callback(session_t *s)
Definition: http_server.c:515
static int http_server_listen()
Definition: http_server.c:770
#define clib_error_return(e, args...)
Definition: error.h:99
static int http_server_session_connected_callback(u32 app_index, u32 api_context, session_t *s, session_error_t err)
Definition: http_server.c:664
svm_msg_q_t ** vpp_queue
Definition: http_server.c:59
pthread_t thread[MAX_CONNS]
Definition: main.c:142
int __clib_unused rv
Definition: application.c:491
int session_send_io_evt_to_thread(svm_fifo_t *f, session_evt_type_t evt_type)
Definition: session.c:84
tw_timer_wheel_2t_1w_2048sl_t tw
Definition: http_server.c:79
static void http_server_sessions_writer_lock(void)
Definition: http_server.c:105
struct _vnet_app_attach_args_t vnet_app_attach_args_t
static void http_server_session_free(http_session_t *hs)
Definition: http_server.c:139
unformat_function_t unformat_line_input
Definition: format.h:275
static void clib_spinlock_init(clib_spinlock_t *p)
Definition: lock.h:65
struct _session_endpoint_cfg session_endpoint_cfg_t
static session_cb_vft_t http_server_session_cb_vft
Definition: http_server.c:704
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
static void clib_rwlock_init(clib_rwlock_t *p)
Definition: lock.h:152
static u8 * static_ok
Definition: http_server.c:271
static void clib_rwlock_reader_unlock(clib_rwlock_t *p)
Definition: lock.h:184
u64 vpp_session_handle
Definition: http_server.c:49
vl_api_ip_proto_t proto
Definition: acl_types.api:51
static const char * html_header_static
Definition: http_server.c:264
static void http_server_session_close_cb(void *hs_handlep)
Definition: http_server.c:802
static u8 * static_http
Definition: http_server.c:270
struct _unformat_input_t unformat_input_t
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
Definition: node.c:519
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
int svm_fifo_enqueue(svm_fifo_t *f, u32 len, const u8 *src)
Enqueue data to fifo.
Definition: svm_fifo.c:847
static void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Get node runtime private data by node index.
Definition: node_funcs.h:137
#define PREDICT_FALSE(x)
Definition: clib.h:124
clib_spinlock_t tw_lock
Definition: http_server.c:80
static void svm_fifo_unset_event(svm_fifo_t *f)
Unset fifo event flag.
Definition: svm_fifo.h:803
static const char * html_footer
Definition: http_server.c:261
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
Application session.
Definition: http_server.c:40
u32 node_index
Node index.
Definition: node.h:479
static const char test_srv_crt_rsa[]
Definition: tls_test.h:23
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
Definition: session.c:1927
static void session_endpoint_alloc_ext_cfg(session_endpoint_cfg_t *sep_ext, transport_endpt_ext_cfg_type_t type)
int vnet_application_attach(vnet_app_attach_args_t *a)
Attach application to vpp.
Definition: application.c:1114
void unformat_init_vector(unformat_input_t *input, u8 *vector_string)
Definition: unformat.c:1037
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
Definition: svm_fifo.h:790
static void clib_rwlock_writer_unlock(clib_rwlock_t *p)
Definition: lock.h:206
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
vlib_main_t * vlib_main
Definition: http_server.c:87
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
u32 runtime_index
Definition: node.h:273
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:208
static int http_server_attach()
Definition: http_server.c:715
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
char * buffer
Definition: cJSON.h:163
vlib_node_registration_t http_server_process_node
(constructor) VLIB_REGISTER_NODE (http_server_process_node)
Definition: http_server.c:856
#define clib_warning(format, args...)
Definition: error.h:59
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:116
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:302
static int http_transport_needs_crypto(transport_proto_t proto)
Definition: http_server.c:763
u32 ** session_to_http_session
Definition: http_server.c:57
static const char test_srv_key_rsa[]
Definition: tls_test.h:49
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
u8 * rx_buf
rx buffer
Definition: http_server.c:47
static vlib_main_t * vlib_get_first_main(void)
Definition: global_funcs.h:44
#define uword_to_pointer(u, type)
Definition: types.h:136
#define ASSERT(truth)
static http_session_t * http_server_session_get(u32 thread_index, u32 hs_index)
Definition: http_server.c:130
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:876
int vnet_listen(vnet_listen_args_t *a)
Definition: application.c:1266
static void clib_mem_free(void *p)
Definition: mem.h:311
enum _transport_proto transport_proto_t
static void http_server_session_lookup_del(u32 thread_index, u32 s_index)
Definition: http_server.c:157
struct _vnet_app_add_cert_key_pair_args_ vnet_app_add_cert_key_pair_args_t
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Definition: node_funcs.h:175
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
static void http_server_session_timer_stop(http_session_t *hs)
Definition: http_server.c:190
static void * clib_mem_alloc(uword size)
Definition: mem.h:253
static uword pointer_to_uword(const void *p)
Definition: types.h:131
static void http_server_cleanup_callback(session_t *s, session_cleanup_ntf_t ntf)
Definition: http_server.c:678
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:38
u8 thread_index
Index of the thread that allocated the session.
uword * handler_by_get_request
Definition: http_server.c:61
static http_session_t * http_server_session_alloc(u32 thread_index)
Definition: http_server.c:117
struct _vlib_node_registration vlib_node_registration_t
static clib_error_t * http_server_main_init(vlib_main_t *vm)
Definition: http_server.c:987
int parse_uri(char *uri, session_endpoint_cfg_t *sep)
http_server_main_t http_server_main
Definition: http_server.c:90
static void alloc_http_process(http_server_args *args)
Definition: http_server.c:443
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
void vlib_rpc_call_main_thread(void *callback, u8 *args, u32 arg_size)
Definition: threads.c:1637
volatile u8 session_state
State in session layer state machine.
static void close_session(http_session_t *hs)
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
static int http_server_add_segment_callback(u32 client_index, u64 segment_handle)
Definition: http_server.c:672
int vnet_disconnect_session(vnet_disconnect_args_t *a)
Definition: application.c:1411
vhost_user_req_t request
Definition: vhost_user.h:123
node node_index
static clib_error_t * http_server_create_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: http_server.c:904
#define SESSION_ENDPOINT_CFG_NULL
Definition: session_types.h:77
session_cleanup_ntf_t
struct _svm_queue svm_queue_t
static const char * http_error_template
Definition: http_server.c:247
unformat_function_t unformat_memory_size
Definition: format.h:288
struct clib_bihash_value offset
template key/value backing page structure
static struct option options[]
Definition: main.c:52
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:56
f64 now
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:86
enum session_error_ session_error_t
static const char * http_ok
Definition: http_server.c:237
int(* session_accept_callback)(session_t *new_session)
Notify server of newly accepted session.
http_session_t ** sessions
Definition: http_server.c:55
http_process_event_t
Definition: http_server.c:22
void vlib_start_process(vlib_main_t *vm, uword process_index)
Definition: main.c:1416
static http_session_t * http_server_session_lookup(u32 thread_index, u32 s_index)
Definition: http_server.c:164
static void http_server_session_reset_callback(session_t *s)
Definition: http_server.c:653
static void http_cli_output(uword arg, u8 *buffer, uword buffer_bytes)
Definition: http_server.c:274
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static const u32 test_srv_crt_rsa_len
Definition: tls_test.h:47
void send_data(http_session_t *hs, u8 *data)
Definition: http_server.c:290
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:163
u32 * free_http_cli_process_node_indices
Definition: http_server.c:63
static void http_server_session_disconnect_callback(session_t *s)
Definition: http_server.c:642
static uword http_cli_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: http_server.c:353
static void http_server_sessions_reader_lock(void)
Definition: http_server.c:93
static void send_error(http_session_t *hs, char *str)
Definition: http_server.c:343
clib_rwlock_t sessions_lock
Definition: http_server.c:56