1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-16 00:00:07 +01:00
libwebsockets/plugins/protocol_lws_status.c
Andy Green 9a1f184915 rtos diet: http: remove headers at buildtime according to config
Headers related to ws or h2 are now elided if the ws or h2 role
is not enabled for build.  In addition, a new build-time option
LWS_WITH_HTTP_UNCOMMON_HEADERS on by default allows removal of
less-common http headers to shrink the parser footprint.

Minilex is adapted to produce 8 different versions of the lex
table, chosen at build-time according to which headers are
included in the build.

If you don't need the unusual headers, or aren't using h2 or ws,
this chops down the size of the ah and the rodata needed to hold
the parsing table from 87 strings / pointers to 49, and the
parsing table from 1177 to 696 bytes.
2020-03-04 11:00:04 +00:00

273 lines
6.5 KiB
C

/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* The person who associated a work with this deed has dedicated
* the work to the public domain by waiving all of his or her rights
* to the work worldwide under copyright law, including all related
* and neighboring rights, to the extent allowed by law. You can copy,
* modify, distribute and perform the work, even for commercial purposes,
* all without asking permission.
*
* The test apps are intended to be adapted for use in your code, which
* may be proprietary. So unlike the library itself, they are licensed
* Public Domain.
*/
#if !defined (LWS_PLUGIN_STATIC)
#define LWS_DLL
#define LWS_INTERNAL
#include <libwebsockets.h>
#endif
#include <time.h>
#include <string.h>
#ifdef WIN32
#include <io.h>
#include <gettimeofday.h>
#endif
typedef enum {
WALK_NONE,
WALK_INITIAL,
WALK_LIST,
WALK_FINAL
} e_walk;
struct per_session_data__lws_status {
struct per_session_data__lws_status *next;
struct lws *wsi;
time_t time_est;
char user_agent[256];
e_walk walk;
struct per_session_data__lws_status *walk_next;
unsigned char subsequent:1;
unsigned char changed_partway:1;
unsigned char wss_over_h2:1;
};
struct per_vhost_data__lws_status {
struct per_session_data__lws_status *live_pss_list;
struct lws_context *context;
struct lws_vhost *vhost;
const struct lws_protocols *protocol;
int count_live_pss;
};
static void
trigger_resend(struct per_vhost_data__lws_status *vhd)
{
lws_start_foreach_ll(struct per_session_data__lws_status *, pss,
vhd->live_pss_list) {
if (pss->walk == WALK_NONE) {
pss->subsequent = 0;
pss->walk_next = vhd->live_pss_list;
pss->walk = WALK_INITIAL;
} else
pss->changed_partway = 1;
} lws_end_foreach_ll(pss, next);
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
}
/* lws-status protocol */
int
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__lws_status *pss =
(struct per_session_data__lws_status *)user;
struct per_vhost_data__lws_status *vhd =
(struct per_vhost_data__lws_status *)
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
char buf[LWS_PRE + 384], ip[24], *start = buf + LWS_PRE - 1, *p = start,
*end = buf + sizeof(buf) - 1;
int n, m;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT:
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
lws_get_protocol(wsi),
sizeof(struct per_vhost_data__lws_status));
vhd->context = lws_get_context(wsi);
vhd->protocol = lws_get_protocol(wsi);
vhd->vhost = lws_get_vhost(wsi);
break;
case LWS_CALLBACK_ESTABLISHED:
/*
* This shows how to stage sending a single ws message in
* multiple fragments. In this case, it lets us trade off
* memory needed to make the data vs time to send it.
*/
vhd->count_live_pss++;
pss->next = vhd->live_pss_list;
vhd->live_pss_list = pss;
pss->wss_over_h2 = !!len;
time(&pss->time_est);
pss->wsi = wsi;
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)
if (lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
WSI_TOKEN_HTTP_USER_AGENT) < 0) /* too big */
#endif
strcpy(pss->user_agent, "unknown");
trigger_resend(vhd);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
switch (pss->walk) {
case WALK_INITIAL:
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
p += lws_snprintf(p, end - p,
"{ \"version\":\"%s\","
" \"wss_over_h2\":\"%d\","
" \"hostname\":\"%s\","
" \"wsi\":\"%d\", \"conns\":[",
lws_get_library_version(),
pss->wss_over_h2,
lws_canonical_hostname(vhd->context),
vhd->count_live_pss);
pss->walk = WALK_LIST;
pss->walk_next = vhd->live_pss_list;
break;
case WALK_LIST:
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
if (!pss->walk_next)
goto walk_final;
if (pss->subsequent)
*p++ = ',';
pss->subsequent = 1;
m = 0;
lws_start_foreach_ll(struct per_session_data__lws_status *,
pss2, vhd->live_pss_list) {
if (pss2 == pss->walk_next) {
m = 1;
break;
}
} lws_end_foreach_ll(pss2, next);
if (!m) {
/* our next guy went away */
pss->walk = WALK_FINAL;
pss->changed_partway = 1;
break;
}
strcpy(ip, "unknown");
lws_get_peer_simple(pss->walk_next->wsi, ip, sizeof(ip));
p += lws_snprintf(p, end - p,
"{\"peer\":\"%s\",\"time\":\"%ld\","
"\"ua\":\"%s\"}",
ip, (unsigned long)pss->walk_next->time_est,
pss->walk_next->user_agent);
pss->walk_next = pss->walk_next->next;
if (!pss->walk_next)
pss->walk = WALK_FINAL;
break;
case WALK_FINAL:
walk_final:
n = LWS_WRITE_CONTINUATION;
p += lws_snprintf(p, 4, "]}");
if (pss->changed_partway) {
pss->changed_partway = 0;
pss->subsequent = 0;
pss->walk_next = vhd->live_pss_list;
pss->walk = WALK_INITIAL;
} else
pss->walk = WALK_NONE;
break;
default:
return 0;
}
m = lws_write(wsi, (unsigned char *)start, p - start, n);
if (m < 0) {
lwsl_err("ERROR %d writing to di socket\n", m);
return -1;
}
if (pss->walk != WALK_NONE)
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_RECEIVE:
lwsl_notice("pmd test: RX len %d\n", (int)len);
break;
case LWS_CALLBACK_CLOSED:
// lwsl_debug("****** LWS_CALLBACK_CLOSED\n");
lws_start_foreach_llp(struct per_session_data__lws_status **,
ppss, vhd->live_pss_list) {
if (*ppss == pss) {
*ppss = pss->next;
break;
}
} lws_end_foreach_llp(ppss, next);
trigger_resend(vhd);
break;
default:
break;
}
return 0;
}
#define LWS_PLUGIN_PROTOCOL_LWS_STATUS \
{ \
"lws-status", \
callback_lws_status, \
sizeof(struct per_session_data__lws_status), \
512, /* rx buf size must be >= permessage-deflate rx size */ \
0, NULL, 0 \
}
#if !defined (LWS_PLUGIN_STATIC)
static const struct lws_protocols protocols[] = {
LWS_PLUGIN_PROTOCOL_LWS_STATUS
};
LWS_VISIBLE int
init_protocol_lws_status(struct lws_context *context,
struct lws_plugin_capability *c)
{
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
c->api_magic);
return 1;
}
c->protocols = protocols;
c->count_protocols = LWS_ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_VISIBLE int
destroy_protocol_lws_status(struct lws_context *context)
{
return 0;
}
#endif