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:
parent
7eb36102a9
commit
5be8ff27d5
6 changed files with 312 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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
|
||||
...
|
||||
```
|
|
@ -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;
|
||||
}
|
|
@ -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),
|
||||
};
|
Loading…
Add table
Reference in a new issue