mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
minimal: minimal raw vhost
This commit is contained in:
parent
03acd5a24d
commit
7aa511d8c5
7 changed files with 274 additions and 12 deletions
|
@ -4644,6 +4644,8 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh,
|
|||
#define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE
|
||||
#define LWS_SEND_BUFFER_POST_PADDING 0
|
||||
|
||||
#define LWS_WRITE_RAW LWS_WRITE_HTTP
|
||||
|
||||
/*
|
||||
* NOTE: These public enums are part of the abi. If you want to add one,
|
||||
* add it at where specified so existing users are unaffected.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|name|demonstrates|
|
||||
---|---
|
||||
minimal-raw-file|Shows how to adopt a file descriptor (device node, fifo, file, etc) into the lws event loop and handle events
|
||||
minimal-raw-vhost|Shows how to set up a vhost that listens and accepts RAW socket connections
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# lws minimal ws server
|
||||
|
||||
This demonstrates adopting a file descriptor into the lws event
|
||||
loop. The filepath is given as an argument to the example app, eg
|
||||
loop. The filepath to open and adopt is given as an argument to the example app, eg
|
||||
|
||||
```
|
||||
$ ./lws-minimal-raw-file <file>
|
||||
```
|
||||
|
||||
On a Linux system, some example files might be
|
||||
On a Linux system, some example files for testing might be
|
||||
|
||||
- /proc/self/fd/0 (stdin)
|
||||
- /dev/ttyUSB0 (a USB <-> serial converter)
|
||||
|
@ -21,7 +21,7 @@ This isn't very useful standalone as shown here for clarity, but you can
|
|||
freely combine raw file descriptor adoption with other lws server
|
||||
and client features.
|
||||
|
||||
Becuase raw file events have their own callback, the handlers can
|
||||
Becuase raw file events have their own callback reasons, the handlers can
|
||||
be integrated in a single protocol that also handles http and ws
|
||||
server and client callbacks without conflict.
|
||||
|
||||
|
|
76
minimal-examples/raw/minimal-raw-vhost/CMakeLists.txt
Normal file
76
minimal-examples/raw/minimal-raw-vhost/CMakeLists.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-minimal-raw-vhost)
|
||||
set(SRCS minimal-raw-vhost.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
#
|
||||
# If we are being built externally, confirm installed lws was configured to
|
||||
# support reqconfig, else error out with a helpful message about the problem.
|
||||
#
|
||||
MACRO(require_lws_config reqconfig _val result)
|
||||
|
||||
if (DEFINED ${reqconfig})
|
||||
if (${reqconfig})
|
||||
set (rq 1)
|
||||
else()
|
||||
set (rq 0)
|
||||
endif()
|
||||
else()
|
||||
set(rq 0)
|
||||
endif()
|
||||
|
||||
if (${_val} EQUAL ${rq})
|
||||
set(SAME 1)
|
||||
else()
|
||||
set(SAME 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
|
||||
if (${_val})
|
||||
message("${SAMP}: skipping as lws being built without ${reqconfig}")
|
||||
else()
|
||||
message("${SAMP}: skipping as lws built with ${reqconfig}")
|
||||
endif()
|
||||
set(${result} 0)
|
||||
else()
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES)
|
||||
set(MET ${SAME})
|
||||
else()
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
|
||||
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
|
||||
set(HAS_${reqconfig} 0)
|
||||
else()
|
||||
set(HAS_${reqconfig} 1)
|
||||
endif()
|
||||
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
|
||||
set(MET 1)
|
||||
else()
|
||||
set(MET 0)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT MET)
|
||||
if (${_val})
|
||||
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
|
||||
else()
|
||||
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
ENDMACRO()
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared)
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
||||
endif()
|
40
minimal-examples/raw/minimal-raw-vhost/README.md
Normal file
40
minimal-examples/raw/minimal-raw-vhost/README.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# lws minimal ws server raw vhost
|
||||
|
||||
This demonstrates setting up a vhost to listen and accept raw sockets.
|
||||
Raw sockets are just sockets... lws does not send anything on them or
|
||||
interpret by itself what it receives on them. So you can implement
|
||||
arbitrary tcp protocols using them.
|
||||
|
||||
This isn't very useful standalone as shown here for clarity, but you can
|
||||
freely combine a raw socket vhost with other lws server
|
||||
and client features and other vhosts handling http or ws.
|
||||
|
||||
Becuase raw socket events have their own callback reasons, the handlers can
|
||||
be integrated in a single protocol that also handles http and ws
|
||||
server and client callbacks without conflict.
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
```
|
||||
$ ./lws-minimal-raw-vhost
|
||||
[2018/03/22 14:49:47:9516] USER: LWS minimal raw vhost
|
||||
[2018/03/22 14:49:47:9673] NOTICE: Creating Vhost 'default' port 7681, 1 protocols, IPv6 off
|
||||
[2018/03/22 14:49:52:3789] USER: LWS_CALLBACK_RAW_ADOPT
|
||||
[2018/03/22 14:49:57:4271] USER: LWS_CALLBACK_RAW_CLOSE
|
||||
```
|
||||
|
||||
```
|
||||
$ nc localhost 7681
|
||||
hello
|
||||
hello
|
||||
```
|
||||
|
||||
Connect one or more sessions to the server using netcat... lines you type
|
||||
into netcat are sent to the server, which echos them to all connected clients.
|
||||
|
148
minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c
Normal file
148
minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* lws-minimal-raw-vhost
|
||||
*
|
||||
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates integrating a raw tcp listener into the lws event loop.
|
||||
*
|
||||
* This demo doesn't have any http or ws support. You can connect to it
|
||||
* using netcat. If you make multiple connections to it, things typed in one
|
||||
* netcat session are broadcast to all netcat connections.
|
||||
*
|
||||
* $ nc localhost 7681
|
||||
*
|
||||
* You can add more vhosts with things like http or ws support, it's as it is
|
||||
* for clarity.
|
||||
*
|
||||
* The main point is the apis and ways of managing raw sockets are almost
|
||||
* identical to http or ws mode sockets in lws. The callback names for raw
|
||||
* wsi are changed to be specific to RAW mode is all.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
struct raw_pss {
|
||||
struct raw_pss *pss_list;
|
||||
struct lws *wsi;
|
||||
};
|
||||
|
||||
/* one of these is created for each vhost our protocol is used with */
|
||||
|
||||
struct raw_vhd {
|
||||
struct raw_pss *pss_list; /* linked-list of live pss*/
|
||||
|
||||
int len;
|
||||
uint8_t buf[4096];
|
||||
};
|
||||
|
||||
static int
|
||||
callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct raw_pss *pss = (struct raw_pss *)user;
|
||||
struct raw_vhd *vhd = (struct raw_vhd *)lws_protocol_vh_priv_get(
|
||||
lws_get_vhost(wsi), lws_get_protocol(wsi));
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi), sizeof(struct raw_vhd));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
break;
|
||||
|
||||
/* callbacks related to raw socket descriptor */
|
||||
|
||||
case LWS_CALLBACK_RAW_ADOPT:
|
||||
lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
|
||||
pss->wsi = wsi;
|
||||
lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_CLOSE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
|
||||
lws_ll_fwd_remove(struct raw_pss, pss_list, pss, vhd->pss_list);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_RX:
|
||||
vhd->len = len;
|
||||
if (vhd->len > (int)sizeof(vhd->buf))
|
||||
vhd->len = sizeof(vhd->buf);
|
||||
memcpy(vhd->buf, in, vhd->len);
|
||||
lws_start_foreach_llp(struct raw_pss **, ppss, vhd->pss_list) {
|
||||
lws_callback_on_writable((*ppss)->wsi);
|
||||
} lws_end_foreach_llp(ppss, pss_list);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_WRITEABLE:
|
||||
if (lws_write(wsi, vhd->buf, vhd->len, LWS_WRITE_RAW) !=
|
||||
vhd->len) {
|
||||
lwsl_notice("%s: raw write failed\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{ "raw-test", callback_raw_test, sizeof(struct raw_pss), 0 },
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
static int interrupted;
|
||||
|
||||
void sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_context *context;
|
||||
int n = 0;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = 7681;
|
||||
info.protocols = protocols;
|
||||
info.options = LWS_SERVER_OPTION_ONLY_RAW; /* vhost accepts RAW */
|
||||
|
||||
lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
* lws must have been configured and built with
|
||||
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
|
||||
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
||||
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
||||
/* | LLL_DEBUG */, NULL);
|
||||
|
||||
lwsl_user("LWS minimal raw vhost\n");
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 1000);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -83,21 +83,15 @@ callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
/* add ourselves to the list of live pss held in the vhd */
|
||||
pss->pss_list = vhd->pss_list;
|
||||
vhd->pss_list = pss;
|
||||
lws_ll_fwd_insert(pss, pss_list, vhd->pss_list);
|
||||
pss->wsi = wsi;
|
||||
pss->last = vhd->current;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
/* remove our closing pss from the list of live pss */
|
||||
lws_start_foreach_llp(struct per_session_data__minimal **,
|
||||
ppss, vhd->pss_list) {
|
||||
if (*ppss == pss) {
|
||||
*ppss = pss->pss_list;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(ppss, pss_list);
|
||||
lws_ll_fwd_remove(struct per_session_data__minimal, pss_list,
|
||||
pss, vhd->pss_list);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
|
|
Loading…
Add table
Reference in a new issue