1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

ss-server-raw

Add an example and some small changes for secure streams
serving raw data over a listening tcp socket
This commit is contained in:
Andy Green 2020-07-28 09:21:45 +01:00
parent 7eb36102a9
commit 5be8ff27d5
6 changed files with 312 additions and 1 deletions

View file

@ -907,6 +907,15 @@ rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name)
return 1;
}
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS)
if (wsi->a.vhost->ss_handle &&
wsi->a.vhost->ss_handle->policy->protocol == LWSSSP_RAW) {
lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ?
LRS_SSL_INIT : LRS_ESTABLISHED, &role_ops_raw_skt);
return 1;
}
#endif
/* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */
#if defined(LWS_WITH_HTTP2)

View file

@ -58,6 +58,9 @@ secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user,
h->policy ? h->policy->streamtype : "no policy");
h->wsi = NULL;
if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
#if defined(LWS_WITH_SERVER)
!(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
#endif
!h->txn_ok && !wsi->a.context->being_destroyed)
if (lws_ss_backoff(h))
/* has been destroyed */
@ -77,6 +80,10 @@ secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user,
lws_validity_confirmed(wsi);
break;
case LWS_CALLBACK_RAW_ADOPT:
lwsl_info("%s: RAW_ADOPT\n", __func__);
break;
/* chunks of chunked content, with header removed */
case LWS_CALLBACK_RAW_RX:
if (!h || !h->info.rx)
@ -131,7 +138,7 @@ secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user,
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
return 0;
}
static int

View file

@ -0,0 +1,26 @@
project(lws-minimal-secure-streams-server-raw C)
cmake_minimum_required(VERSION 2.8)
find_package(libwebsockets CONFIG REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR})
include(CheckCSourceCompiles)
include(LwsCheckRequirements)
set(SAMP lws-minimal-secure-streams-server-raw)
set(SRCS main.c ss-server.c)
set(requirements 1)
require_lws_config(LWS_ROLE_H1 1 requirements)
require_lws_config(LWS_WITH_SERVER 1 requirements)
require_lws_config(LWS_WITH_SECURE_STREAMS 1 requirements)
require_lws_config(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY 0 requirements)
if (requirements)
add_executable(${SAMP} ${SRCS})
if (websockets_shared)
target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS})
add_dependencies(${SAMP} websockets_shared)
else()
target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS})
endif()
endif()

View file

@ -0,0 +1,54 @@
# lws minimal secure streams server raw
The application sets up a raw tcp server on localhost:7681
It does it using Secure Streams... information about how the server should
operate is held in JSON policy in main.c
Connecting to the server using `echo "hello" | nc --no-shutdown 127.0.0.1 7681`
will send "hello" which is hexdumped to console by the rx function, then
will receive an incrementing message at 100ms intervals.
Note there are two incomaptible versions of netcat around, this is from Fedora's
nmap-ncat, the --no-shutdown is needed to stop it hanging up itself after it
has sent its stdin.
## build
```
$ cmake . && make
```
## usage
Commandline option|Meaning
---|---
-d <loglevel>|Debug verbosity in decimal, eg, -d15
```
[2020/07/28 10:25:54:6747] U: LWS Secure Streams Server Raw
[2020/07/28 10:25:54:7194] N: LWS: 4.0.99-v4.0.0-247-g58be599aa, loglevel 1031
[2020/07/28 10:25:54:7198] N: NET CLI SRV H1 H2 WS MQTT SS-JSON-POL SSPROX ASYNC_DNS IPv6-absent
[2020/07/28 10:25:54:9376] N: lws_adopt_descriptor_vhost2: wsi 0x5317d30, vhost system ss_handle (nil)
[2020/07/28 10:25:54:9442] N: lws_adopt_descriptor_vhost2: wsi 0x53182c0, vhost system ss_handle (nil)
[2020/07/28 10:25:54:9920] N: smd_cb: creating server stream
[2020/07/28 10:25:54:9963] N: lws_ss_create: created server myrawserver
[2020/07/28 10:26:00:1065] N: secstream_raw: RAW_ADOPT
[2020/07/28 10:26:00:1068] N: lws_adopt_descriptor_vhost2: wsi 0x531a6b0, vhost myrawserver ss_handle 0x5319ac0
[2020/07/28 10:26:00:1088] U: myss_raw_state: 0x531aad0 LWSSSCS_CREATING, ord 0x0
[2020/07/28 10:26:00:1094] U: myss_raw_state: 0x531aad0 LWSSSCS_CONNECTING, ord 0x0
[2020/07/28 10:26:00:1096] U: myss_raw_state: 0x531aad0 LWSSSCS_CONNECTED, ord 0x0
[2020/07/28 10:26:00:1172] U: myss_raw_rx: len 6, flags: 0
[2020/07/28 10:26:02:8516] U: myss_raw_state: 0x531aad0 LWSSSCS_DISCONNECTED, ord 0x0
[2020/07/28 10:26:02:8545] U: myss_raw_state: 0x531aad0 LWSSSCS_DESTROYING, ord 0x0
^C[2020/07/28 10:26:04:9608] U: myss_raw_state: 0x5319ac0 LWSSSCS_DESTROYING, ord 0x0
[2020/07/28 10:26:04:9723] U: Completed: OK
```
```
$ echo "hello" | nc --no-shutdown 127.0.0.1 7681
hello from raw 0
hello from raw 1
hello from raw 2
...
```

View file

@ -0,0 +1,104 @@
/*
* lws-minimal-secure-streams-server
*
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*/
#include <libwebsockets.h>
#include <string.h>
#include <signal.h>
extern const lws_ss_info_t ssi_client, ssi_server;
static struct lws_context *context;
int interrupted, bad = 1;
static const char * const default_ss_policy =
"{"
"\"release\":" "\"01234567\","
"\"product\":" "\"myproduct\","
"\"schema-version\":" "1,"
"\"s\": ["
/*
* This streamtype represents a raw server listening on :7681,
* without tls
*/
"{\"myrawserver\": {"
/* if given, "endpoint" is network if to bind to */
"\"server\":" "true,"
"\"port\":" "7681,"
"\"protocol\":" "\"raw\""
"}}"
"]"
"}"
;
static int
smd_cb(void *opaque, lws_smd_class_t c, lws_usec_t ts, void *buf, size_t len)
{
if ((c & LWSSMDCL_SYSTEM_STATE) &&
!lws_json_simple_strcmp(buf, len, "\"state\":", "OPERATIONAL")) {
/* create the secure streams */
lwsl_notice("%s: creating server stream\n", __func__);
if (lws_ss_create(context, 0, &ssi_server, NULL, NULL,
NULL, NULL)) {
lwsl_err("%s: failed to create secure stream\n",
__func__);
return -1;
}
}
return 0;
}
static void
sigint_handler(int sig)
{
interrupted = 1;
}
int main(int argc, const char **argv)
{
struct lws_context_creation_info info;
int n = 0;
signal(SIGINT, sigint_handler);
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
lws_cmdline_option_handle_builtin(argc, argv, &info);
lwsl_user("LWS Secure Streams Server Raw\n");
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.fd_limit_per_thread = 1 + 6 + 1;
info.pss_policies_json = default_ss_policy;
info.port = CONTEXT_PORT_NO_LISTEN;
info.early_smd_cb = smd_cb;
info.early_smd_class_filter = LWSSMDCL_SYSTEM_STATE;
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
/* the event loop */
while (n >= 0 && !interrupted)
n = lws_service(context, 0);
bad = 0;
lws_context_destroy(context);
lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
return bad;
}

View file

@ -0,0 +1,111 @@
/*
* lws-minimal-secure-streams-server
*
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*/
#include <libwebsockets.h>
#include <assert.h>
extern int interrupted, bad;
typedef struct myss {
struct lws_ss_handle *ss;
void *opaque_data;
/* ... application specific state ... */
lws_sorted_usec_list_t sul;
int count;
char upgraded;
} myss_srv_t;
/*
* This is the Secure Streams Server RX and TX
*/
static int
myss_raw_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
{
// myss_srv_t *m = (myss_srv_t *)userobj;
lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
lwsl_hexdump_info(buf, len);
/*
* If we received the whole message, for our example it means
* we are done.
*/
if (flags & LWSSS_FLAG_EOM) {
bad = 0;
interrupted = 1;
}
return 0;
}
/* this is the callback that mediates sending the incrementing number */
static void
spam_sul_cb(struct lws_sorted_usec_list *sul)
{
myss_srv_t *m = lws_container_of(sul, myss_srv_t, sul);
lws_ss_request_tx(m->ss);
lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
100 * LWS_US_PER_MS);
}
static int
myss_raw_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
int *flags)
{
myss_srv_t *m = (myss_srv_t *)userobj;
*flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
*len = lws_snprintf((char *)buf, *len, "hello from raw %d\n", m->count++);
lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
100 * LWS_US_PER_MS);
return 0;
}
static int
myss_raw_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
myss_srv_t *m = (myss_srv_t *)userobj;
lwsl_user("%s: %p %s, ord 0x%x\n", __func__, m->ss,
lws_ss_state_name(state), (unsigned int)ack);
switch (state) {
case LWSSSCS_DISCONNECTED:
lws_sul_cancel(&m->sul);
break;
case LWSSSCS_CONNECTED:
lws_ss_request_tx(m->ss);
break;
default:
break;
}
return 0;
}
const lws_ss_info_t ssi_server = {
.handle_offset = offsetof(myss_srv_t, ss),
.opaque_user_data_offset = offsetof(myss_srv_t, opaque_data),
.streamtype = "myrawserver",
.rx = myss_raw_rx,
.tx = myss_raw_tx,
.state = myss_raw_state,
.user_alloc = sizeof(myss_srv_t),
};