22 #include <sys/types.h> 67 #define _(type, name) type name; 75 u32 vpp_session_index;
76 u64 vpp_session_handle;
129 BVT (clib_bihash) name_to_data;
158 tw_timer_wheel_2t_1w_2048sl_t tw;
167 u32 private_segment_size;
183 state_machine_called_from_t cf =
184 va_arg (*args, state_machine_called_from_t);
185 char *which =
"bogus!";
196 which =
"from timer";
203 s =
format (s,
"%s", which);
279 memset (hs, 0,
sizeof (*hs));
280 hs->session_index = hs - hsm->
sessions[thread_index];
311 u32 save_thread_index;
314 memset (hs, 0xfa,
sizeof (*hs));
417 static const char *http_error_template =
420 "Content-Type: text/html\r\n" 421 "Connection: close\r\n" 422 "Pragma: no-cache\r\n" 423 "Content-Length: 0\r\n\r\n";
427 static const char *http_response_template =
429 "Expires: %U GMT\r\n" 430 "Server: VPP Static\r\n" 431 "Content-Type: text/%s\r\n" 432 "Content-Length: %d\r\n\r\n";
449 bytes_to_send = length -
offset;
451 while (bytes_to_send > 0)
456 (hs->tx_fifo, bytes_to_send, data + offset);
459 if (actual_transfer <= 0)
462 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
467 offset += actual_transfer;
468 bytes_to_send -= actual_transfer;
471 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
505 u32 max_dequeue, cursize;
516 ASSERT (n_read == max_dequeue);
520 _vec_len (hs->
rx_buf) = cursize + n_read;
535 last_timestamp = 1e70;
536 for (i = 1, index = hsm->first_index; index != ~0;)
543 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
551 last_timestamp = 0.0;
552 for (i = 1, index = hsm->last_index; index != ~0;)
559 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
582 if (ep_index == hsm->first_index)
584 if (ep_index == hsm->last_index)
619 if (hsm->first_index != ~0)
629 hsm->first_index = ep_index;
632 if (hsm->last_index == ~0)
633 hsm->last_index = ep_index;
662 state_machine_called_from_t cf)
664 clib_warning (
"WARNING: http session %d, called from %U",
680 state_machine_called_from_t cf)
687 struct stat _sb, *sb = &_sb;
699 request_len =
vec_len (request);
708 for (i = 0; i < request_len - 4; i++)
710 if (request[i] ==
'G' &&
711 request[i + 1] ==
'E' &&
712 request[i + 2] ==
'T' && request[i + 3] ==
' ')
728 for (i = 0; i <
vec_len (request); i++)
730 if (request[i] ==
' ' || request[i] ==
'?')
741 if (request[0] ==
'/')
742 path =
format (0,
"%s%s%c", hsm->www_root, request, 0);
744 path =
format (0,
"%s/%s%c", hsm->www_root, request, 0);
750 if (stat ((
char *) path, sb) < 0
752 || (sb->st_mode & S_IFMT) != S_IFREG )
756 _vec_len (path) -= 1;
757 path =
format (path,
"index.html%c", 0);
758 if (stat ((
char *) path, sb) < 0
760 || (sb->st_mode & S_IFMT) != S_IFREG )
762 _vec_len (path) = save_length;
763 path =
format (path,
"/index.html%c", 0);
766 if (stat ((
char *) path, sb) < 0
768 || (sb->st_mode & S_IFMT) != S_IFREG )
789 vec_delete (path, vec_len (hsm->www_root) - 1, 0);
793 local_port = clib_net_to_host_u16 (endpoint.port);
801 port_str =
format (0,
":%u", (
u32) local_port);
804 redirect =
format (0,
"HTTP/1.1 301 Moved Permanently\r\n" 805 "Location: http%s://%U%s%s\r\n\r\n",
809 print_port ? port_str : (
u8 *)
"", path);
829 BVT (clib_bihash_kv) kv;
836 if (BV (clib_bihash_search) (&hsm->name_to_data, &kv, &kv) == 0)
839 clib_warning (
"lookup '%s' returned %lld", kv.key, kv.value);
857 if (hsm->cache_size > hsm->cache_limit)
859 int free_index = hsm->last_index;
861 while (free_index != ~0)
886 hsm->cache_evictions++;
892 if (hsm->cache_size < hsm->cache_limit)
909 memset (dp, 0,
sizeof (*dp));
941 state_machine_called_from_t cf)
967 state_machine_called_from_t cf)
978 while (*suffix !=
'.')
985 http_type =
"javascript";
1001 http_response =
format (0, http_response_template,
1008 if (offset !=
vec_len (http_response))
1034 state_machine_called_from_t cf)
1046 clib_warning (
"No http session for thread %d session_index %d",
1055 fp = state_funcs[hs->session_state];
1056 rv = (*fp) (s, hs, cf);
1058 goto session_closed;
1132 a->app_index = hsm->app_index;
1154 a->app_index = hsm->app_index;
1177 .session_disconnect_callback =
1194 u32 segment_size = 128 << 20;
1199 if (hsm->private_segment_size)
1200 segment_size = hsm->private_segment_size;
1202 a->api_client_index = ~0;
1203 a->name =
format (0,
"test_http_static_server");
1205 a->options = options;
1208 hsm->fifo_size ? hsm->fifo_size : 8 << 10;
1210 hsm->fifo_size ? hsm->fifo_size : 32 << 10;
1222 hsm->app_index = a->app_index;
1225 a_cert->app_index = a->app_index;
1231 a_key->app_index = a->app_index;
1245 a->app_index = hsm->app_index;
1246 a->uri =
"tcp://0.0.0.0/80";
1248 a->uri = (
char *) hsm->uri;
1264 hs_handle >> 24, hs_handle & 0x00FFFFFF, hs);
1280 for (i = 0; i <
vec_len (expired_timers); i++)
1283 hs_handle = expired_timers[
i] & 0x7FFFFFFF;
1297 f64 now, timeout = 1.0;
1298 uword *event_data = 0;
1299 uword __clib_unused event_type;
1309 tw_timer_expire_timers_2t_1w_2048sl (&hsm->tw, now);
1322 .name =
"static-http-server-process",
1323 .state = VLIB_NODE_STATE_DISABLED,
1361 VLIB_NODE_STATE_POLLING);
1362 n =
vlib_get_node (vm, http_static_server_process_node.index);
1373 u32 private_segment_size,
1374 u8 * www_root,
u8 * uri)
1379 hsm->fifo_size = fifo_size;
1380 hsm->cache_limit = cache_limit;
1381 hsm->prealloc_fifos = prealloc_fifos;
1382 hsm->private_segment_size = private_segment_size;
1383 hsm->www_root =
format (0,
"%s%c", www_root, 0);
1384 hsm->uri =
format (0,
"%s%c", uri, 0);
1386 if (
vec_len (hsm->www_root) < 2)
1387 return VNET_API_ERROR_INVALID_VALUE;
1389 if (hsm->my_client_index != ~0)
1390 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
1402 return VNET_API_ERROR_INIT_FAILED;
1418 hsm->prealloc_fifos = 0;
1419 hsm->private_segment_size = 0;
1422 hsm->cache_limit = 10 << 20;
1430 if (
unformat (line_input,
"www-root %s", &www_root))
1433 if (
unformat (line_input,
"prealloc-fifos %d", &hsm->prealloc_fifos))
1435 else if (
unformat (line_input,
"private-segment-size %U",
1438 if (seg_size >= 0x100000000ULL)
1444 hsm->private_segment_size = seg_size;
1446 else if (
unformat (line_input,
"fifo-size %d", &hsm->fifo_size))
1447 hsm->fifo_size <<= 10;
1451 if (hsm->cache_limit < (128 << 10))
1454 "cache-size must be at least 128kb");
1458 else if (
unformat (line_input,
"uri %s", &hsm->uri))
1462 else if (
unformat (line_input,
"debug"))
1476 if (hsm->my_client_index != (
u32) ~ 0)
1482 hsm->www_root = www_root;
1513 .path =
"http static server",
1514 .short_help =
"http static server www-root <path> [prealloc-fifos <nn>]\n" 1515 "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n" 1527 f64 now = va_arg (*args,
f64);
1532 s =
format (s,
"%40s%12s%20s",
"File",
"Size",
"Age");
1543 http_session_state_t
state = va_arg (*args, http_session_state_t);
1544 char *state_string =
"bogus!";
1549 state_string =
"closed";
1552 state_string =
"established";
1555 state_string =
"ok sent";
1558 state_string =
"send more data";
1564 return format (s,
"%s", state_string);
1571 int verbose = va_arg (*args,
int);
1573 s =
format (s,
"[%d]: state %U", hs->session_index,
1577 s =
format (s,
"\n path %s, data length %u, data_offset %u",
1593 int show_sessions = 0;
1597 if (hsm->www_root == 0)
1602 if (
unformat (input,
"verbose %d", &verbose))
1604 else if (
unformat (input,
"verbose"))
1606 else if (
unformat (input,
"cache"))
1608 else if (
unformat (input,
"sessions"))
1614 if ((show_cache + show_sessions) == 0)
1622 (vm,
"www_root %s, cache size %lld bytes, limit %lld bytes, " 1624 hsm->www_root, hsm->cache_size, hsm->cache_limit,
1625 hsm->cache_evictions);
1634 for (index = hsm->first_index; index != ~0;)
1648 u32 *session_indices = 0;
1659 vec_add1 (session_indices, hs - hsm->sessions[i]);
1663 for (j = 0; j <
vec_len (session_indices); j++)
1667 (hsm->
sessions[i], session_indices[j]),
1691 .path =
"show http static server",
1692 .short_help =
"show http static server sessions cache [verbose [<nn>]]",
1702 hsm->my_client_index = ~0;
1703 hsm->vlib_main =
vm;
1704 hsm->first_index = hsm->last_index = ~0;
static int state_sent_ok(session_t *s, http_session_t *hs, state_machine_called_from_t cf)
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
#define foreach_app_session_field
flag for dgram mode
static void clib_rwlock_reader_lock(clib_rwlock_t *p)
Session has sent an OK response.
static int app_recv_stream_raw(svm_fifo_t *f, u8 *buf, u32 len, u8 clear_evt, u8 peek)
u8 * filename
Name of the file.
u8 * format_http_session(u8 *s, va_list *args)
static void lru_remove(http_static_server_main_t *hsm, file_data_cache_t *ep)
Remove a data cache entry from the LRU lists.
#define CLIB_CACHE_LINE_ALIGN_MARK(mark)
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
static http_session_t * http_static_server_session_lookup(u32 thread_index, u32 s_index)
lookup a session in the vpp < – > http session index map
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
session_type_t session_type
Type built from transport and network protocol types.
static void lru_add(http_static_server_main_t *hsm, file_data_cache_t *ep, f64 now)
Add an entry to the LRU lists, tag w/ supplied timestamp.
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...
static void clib_rwlock_writer_lock(clib_rwlock_t *p)
static void http_static_server_session_cleanup(http_session_t *hs)
clean up a session
static const char * http_response
u32 session_index
Index in thread pool where session was allocated.
static svm_msg_q_t * session_main_get_vpp_event_queue(u32 thread_index)
u32 timer_handle
Timeout timer handle.
#define clib_memcpy_fast(a, b, c)
static void http_static_server_sessions_writer_unlock(void)
Drop writer lock on the sessions pools.
static f64 vlib_time_now(vlib_main_t *vm)
svm_fifo_t * rx_fifo
Pointers to rx/tx buffers.
static uword http_static_server_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Timer-wheel expiration process.
u32 data_offset
Current data send offset.
u32 vpp_session_index
vpp session index, handle
void session_send_rpc_evt_to_thread(u32 thread_index, void *fp, void *rpc_args)
int debug_level
Enable debug messages.
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
static void http_static_server_session_disconnect(http_session_t *hs)
Disconnect a session.
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
struct _vnet_application_add_tls_cert_args_t vnet_app_add_tls_cert_args_t
u8 * path
Fully-resolved file path.
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
static void http_static_server_detach_cache_entry(http_session_t *hs)
Detach cache entry from session.
clib_error_t * vnet_app_add_tls_cert(vnet_app_add_tls_cert_args_t *a)
int http_static_server_enable_api(u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, u32 private_segment_size, u8 *www_root, u8 *uri)
API helper function for vl_api_http_static_enable_t messages.
struct _vnet_bind_args_t vnet_listen_args_t
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static session_handle_t session_handle(session_t *s)
static void lru_validate(http_static_server_main_t *hsm)
Sanity-check the forward and reverse LRU lists.
void session_get_endpoint(session_t *s, transport_endpoint_t *tep, u8 is_lcl)
static void http_static_server_session_timer_stop(http_session_t *hs)
stop a session cleanup timer
svm_msg_q_t ** vpp_queue
vpp message/event queue
static int svm_fifo_is_empty(svm_fifo_t *f)
Check if fifo is empty.
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
int clib_bihash_add_del(clib_bihash *h, clib_bihash_kv *add_v, int is_add)
Add or delete a (key,value) pair from a bi-hash table.
#define VLIB_INIT_FUNCTION(x)
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...
struct _vnet_disconnect_args_t vnet_disconnect_args_t
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Fifo max bytes to dequeue.
static int http_static_server_attach()
static const u32 test_srv_key_rsa_len
static f64 clib_timebase_now(clib_timebase_t *tb)
clib_error_t * clib_file_contents(char *file, u8 **result)
static int http_static_server_rx_tx_callback(session_t *s, state_machine_called_from_t cf)
foreach_app_session_field u32 thread_index
rx thread index
#define clib_error_return(e, args...)
u8 * format_http_session_state(u8 *s, va_list *args)
vhost_vring_state_t state
static int http_static_server_session_connected_callback(u32 app_index, u32 api_context, session_t *s, u8 is_fail)
static int session_rx_request(http_session_t *hs)
Retrieve data from the application layer.
state_machine_called_from_t called_from
state machine called from...
int session_send_io_evt_to_thread(svm_fifo_t *f, session_evt_type_t evt_type)
format_function_t format_clib_timebase_time
static int state_send_more_data(session_t *s, http_session_t *hs, state_machine_called_from_t cf)
struct _vnet_app_attach_args_t vnet_app_attach_args_t
static void clib_spinlock_init(clib_spinlock_t *p)
u8 * format_hsm_cache_entry(u8 *s, va_list *args)
format a file cache entry
u8 * data
Contents of the file, as a u8 * vector.
clib_error_t * vnet_app_add_tls_key(vnet_app_add_tls_key_args_t *a)
static void lru_update(http_static_server_main_t *hsm, file_data_cache_t *ep, f64 now)
Remove and re-add a cache entry from/to the LRU lists.
file_data_cache_t * cache_pool
Unified file data cache pool.
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static void clib_rwlock_init(clib_rwlock_t *p)
static int http_static_server_tx_callback(session_t *s)
static u8 * format_state_machine_called_from(u8 *s, va_list *args)
Format the called-from enum.
u8 * data
File data, a vector.
static void clib_rwlock_reader_unlock(clib_rwlock_t *p)
static int http_static_server_session_accept_callback(session_t *s)
Session accept callback.
#define pool_put(P, E)
Free an object E in pool P.
#define vec_dup(V)
Return copy of vector (no header, no alignment)
int svm_fifo_enqueue(svm_fifo_t *f, u32 len, const u8 *src)
Enqueue data to fifo.
static void svm_fifo_unset_event(svm_fifo_t *f)
Unset fifo event flag.
static void http_expired_timers_dispatch(u32 *expired_timers)
Expired session timer-wheel callback.
static const char test_srv_crt_rsa[]
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
static int http_static_server_rx_callback(session_t *s)
static int state_closed(session_t *s, http_session_t *hs, state_machine_called_from_t cf)
Session-layer (main) data rx callback.
int vnet_application_attach(vnet_app_attach_args_t *a)
Attach application to vpp.
static void http_static_server_session_lookup_del(u32 thread_index, u32 s_index)
Remove a session from the vpp < – > http session index map.
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
static void clib_rwlock_writer_unlock(clib_rwlock_t *p)
f64 last_used
Last time the cache entry was used.
#define VLIB_REGISTER_NODE(x,...)
Session has sent an HTML response.
#define vec_free(V)
Free vector's memory (no header).
static clib_error_t * http_static_server_create_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define clib_warning(format, args...)
struct _stream_session_cb_vft session_cb_vft_t
static void http_static_server_session_reset_callback(session_t *s)
Session reset callback.
u32 ** session_to_http_session
vpp session to http session index map
http_session_t ** sessions
Per thread vector of session pools.
static void http_static_server_sessions_reader_unlock(void)
Drop reader lock on the sessions pools.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
static u32 static_send_data(http_session_t *hs, u8 *data, u32 length, u32 offset)
send http data
static transport_proto_t session_type_transport_proto(session_type_t st)
clib_rwlock_t sessions_lock
Session pool reader writer lock.
void clib_timebase_init(clib_timebase_t *tb, i32 timezone_offset_in_hours, clib_timebase_daylight_time_t daylight_type)
static session_cb_vft_t http_static_server_session_cb_vft
Session-layer virtual function table.
static const char test_srv_key_rsa[]
#define VLIB_CLI_COMMAND(x,...)
u32 cache_pool_index
File cache pool index.
#define uword_to_pointer(u, type)
#define vec_delete(V, N, M)
Delete N elements starting at element M.
static void http_static_server_session_disconnect_callback(session_t *s)
Session disconnect callback.
static int http_static_server_create(vlib_main_t *vm)
static int http_static_server_listen()
struct _vnet_application_add_tls_key_args_t vnet_app_add_tls_key_args_t
http_session_state_t
Session States.
enum _transport_proto transport_proto_t
#define clib_error_report(e)
static void svm_fifo_add_want_deq_ntf(svm_fifo_t *f, u8 ntf_type)
Set specific want notification flag.
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
static uword pointer_to_uword(const void *p)
Notify on transition from full.
static http_session_t * http_static_server_session_alloc(u32 thread_index)
Allocate an http session.
u8 thread_index
Index of the thread that allocated the session.
int vlib_main(vlib_main_t *volatile vm, unformat_input_t *input)
static int state_established(session_t *s, http_session_t *hs, state_machine_called_from_t cf)
established state - waiting for GET, POST, etc.
template key/value backing page structure
static void http_static_server_session_lookup_add(u32 thread_index, u32 s_index, u32 hs_index)
add a session to the vpp < – > http session index map
state_machine_called_from_t
u32 next_index
Cache LRU links.
static void http_static_server_sessions_writer_lock(void)
Acquire writer lock on the sessions pools.
static clib_error_t * http_static_server_main_init(vlib_main_t *vm)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static clib_error_t * http_show_static_server_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
volatile u8 session_state
State in session layer state machine.
static void close_session(http_session_t *hs)
static http_session_t * http_static_server_session_get(u32 thread_index, u32 hs_index)
Get an http session by index.
static void http_static_server_session_free(http_session_t *hs)
Free an http session.
static void send_error(http_session_t *hs, char *str)
Send an http error string.
int vnet_bind_uri(vnet_listen_args_t *a)
int inuse
Reference count, so we don't recycle while referenced.
int vnet_disconnect_session(vnet_disconnect_args_t *a)
struct _svm_queue svm_queue_t
struct clib_bihash_value offset
template key/value backing page structure
static vlib_thread_main_t * vlib_get_thread_main()
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
static void http_static_server_session_cleanup_cb(void *hs_handlep)
#define clib_strcmp(s1, s2)
static int http_static_server_add_segment_callback(u32 client_index, u64 segment_handle)
In-memory file data cache entry.
void vlib_start_process(vlib_main_t *vm, uword process_index)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
http_static_server_main_t http_static_server_main
static void http_static_server_sessions_reader_lock(void)
Acquire reader lock on the sessions pools.
static const u32 test_srv_crt_rsa_len
vl_api_fib_path_nh_proto_t proto
static void http_static_server_session_timer_start(http_session_t *hs)
Start a session cleanup timer.