added more c apis and capi ssl version with capi examples (#1395)
* added more apis and ssl version with most examples * some make files ajusts * set close connection to false (7~10x better performance) in examples, added Async example with abort handler, added var in Makefile for capi library * added better comments and fixed CAPIHelloWorldASync sample * removed ssl and removed allocations * added make file * removed dynamic allocations * add rust example and rename other samples * remove make capi and make capi_examples from the main Makefile * remove capi targets from clean on main Makefile * add buffer solution for get header and some string_view values * added more Rust like sample * add void* user_data in all places with handlers * refactor to eliminate std::strncat * added SSL * added -fPIC to allow dynamic libraries to link (Python and Ruby needs) * removed uws_socket_context_options_t * removed uws_timer_t * fixed async examples * added shared library in makefile for python tests * fixed uws_res_end_without_body and added uws_get_loop_with_native * added libuv build * reverted unintended helloworld and helloworld threaded changes * cork tests * added uws_req_get_full_url, uws_req_for_each_header, uws_req_for_each_header * revert HttpResponse.h log changes * initial add for bun features (Thanks Jarred) * add uws_app_listen_domain, uws_app_listen_domain_with_options, uws_app_domain, and option to pass nullptr to http routes for dynamically removes * added uws_res_state, HttpResponse and WebSocket corkUnsafe + uncorkUnsafe * removing changes in HttpResponse and WebSocket * revert changes outside capi * new lines at the end revert * revert makefiles * revert makefiles last new line * revert makefiles last new line
This commit is contained in:
@@ -1,34 +0,0 @@
|
|||||||
#include "libuwebsockets.h"
|
|
||||||
#include "App.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
uws_app_t *uws_create_app() {
|
|
||||||
return (uws_app_t *) new uWS::App();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uws_app_get(uws_app_t *app, const char *pattern, void (*handler)(uws_res_t *, uws_req_t *)) {
|
|
||||||
uWS::App *uwsApp = (uWS::App *) app;
|
|
||||||
uwsApp->get(pattern, [handler](auto *res, auto *req) {
|
|
||||||
handler((uws_res_t *) res, (uws_req_t *) req);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void uws_app_run(uws_app_t *app) {
|
|
||||||
uWS::App *uwsApp = (uWS::App *) app;
|
|
||||||
uwsApp->run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void uws_res_end(uws_res_t *res, const char *data, size_t length) {
|
|
||||||
uWS::HttpResponse<false> *uwsRes = (uWS::HttpResponse<false> *) res;
|
|
||||||
uwsRes->end(std::string_view(data, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
void uws_app_listen(uws_app_t *app, int port, void (*handler)(void *)) {
|
|
||||||
uWS::App *uwsApp = (uWS::App *) app;
|
|
||||||
uwsApp->listen(port, [handler](struct us_listen_socket_t *listen_socket) {
|
|
||||||
handler((void *) listen_socket);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+37
-6
@@ -1,7 +1,38 @@
|
|||||||
|
CAPI_EXAMPLE_FILES := HelloWorld HelloWorldAsync ServerName UpgradeSync UpgradeAsync EchoServer Broadcast BroadcastEchoServer
|
||||||
|
RUST_EXAMPLE_FILES := RustHelloWorld
|
||||||
|
LIBRARY_NAME := libuwebsockets
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rm -f *.o
|
$(MAKE) capi
|
||||||
make -C ../uSockets
|
$(CXX) -O3 -flto -I ../src -I ../uSockets/src examples/HelloWorld.c *.o -lz -luv -lssl -lcrypto -lstdc++ ../uSockets/uSockets.a -o HelloWorld
|
||||||
g++ -c -O3 -std=c++17 -flto -DUWS_NO_ZLIB -I ../src -I ../uSockets/src App.cpp
|
|
||||||
$(AR) rvs uWebSockets.a App.o ../uSockets/*.o
|
capi:
|
||||||
gcc -O3 -flto example.c *.o -lstdc++ ../uSockets/uSockets.a -o c_example
|
$(MAKE) clean
|
||||||
rustc -C link-arg=uWebSockets.a -C link-arg=-lstdc++ -C opt-level=3 -C lto -L all=. example.rs -o rust_example
|
cd ../uSockets && $(CC) -pthread -DLIBUS_USE_OPENSSL -DLIBUS_USE_LIBUV -std=c11 -Isrc -flto -fPIC -O3 -c src/*.c src/eventing/*.c src/crypto/*.c
|
||||||
|
cd ../uSockets && $(CXX) -std=c++17 -flto -fPIC -O3 -c src/crypto/*.cpp
|
||||||
|
cd ../uSockets && $(AR) rvs uSockets.a *.o
|
||||||
|
|
||||||
|
$(CXX) -c -O3 -std=c++17 -lz -luv -flto -fPIC -I ../src -I ../uSockets/src $(LIBRARY_NAME).cpp
|
||||||
|
$(AR) rvs $(LIBRARY_NAME).a $(LIBRARY_NAME).o ../uSockets/uSockets.a
|
||||||
|
shared:
|
||||||
|
$(MAKE) clean
|
||||||
|
|
||||||
|
cd ../uSockets && $(CC) -pthread -DLIBUS_USE_OPENSSL -DLIBUS_USE_LIBUV -std=c11 -Isrc -flto -fPIC -O3 -c src/*.c src/eventing/*.c src/crypto/*.c
|
||||||
|
cd ../uSockets && $(CXX) -std=c++17 -flto -fPIC -O3 -c src/crypto/*.cpp
|
||||||
|
cd ../uSockets && $(AR) rvs uSockets.a *.o
|
||||||
|
|
||||||
|
$(CXX) -c -O3 -std=c++17 -lz -luv -flto -fPIC -I ../src -I ../uSockets/src $(LIBRARY_NAME).cpp
|
||||||
|
$(CXX) -shared -o $(LIBRARY_NAME).so $(LIBRARY_NAME).o ../uSockets/uSockets.a -fPIC -lz -luv -lssl -lcrypto
|
||||||
|
misc:
|
||||||
|
mkdir -p ../misc && openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -passout pass:1234 -keyout ../misc/key.pem -out ../misc/cert.pem
|
||||||
|
rust:
|
||||||
|
$(MAKE) capi
|
||||||
|
rustc -C link-arg=$(LIBRARY_NAME).a -C link-args="-lstdc++ -luv" -C opt-level=3 -C lto -L all=. examples/RustHelloWorld.rs -o RustHelloWorld
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(CAPI_EXAMPLE_FILES) $(RUST_EXAMPLE_FILES) $(LIBRARY_NAME).a $(LIBRARY_NAME).so
|
||||||
|
|
||||||
|
all:
|
||||||
|
for FILE in $(CAPI_EXAMPLE_FILES); do $(CXX) -O3 -flto -I ../src -I ../uSockets/src examples/$$FILE.c *.o -luv -lstdc++ ../uSockets/uSockets.a -o $$FILE & done; \
|
||||||
|
wait
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
#include "libuwebsockets.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void get_handler(uws_res_t *res, uws_req_t *req) {
|
|
||||||
uws_res_end(res, "Hello CAPI!", 11);
|
|
||||||
}
|
|
||||||
|
|
||||||
void listen_handler(void *listen_socket) {
|
|
||||||
if (listen_socket) {
|
|
||||||
printf("Listening on port now\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
uws_app_t *app = uws_create_app();
|
|
||||||
uws_app_get(app, "/*", get_handler);
|
|
||||||
uws_app_listen(app, 3000, listen_handler);
|
|
||||||
uws_app_run(app);
|
|
||||||
}
|
|
||||||
-112
@@ -1,112 +0,0 @@
|
|||||||
/* automatically generated by rust-bindgen 0.59.2 */
|
|
||||||
|
|
||||||
pub type size_t = ::std::os::raw::c_ulong;
|
|
||||||
pub type wchar_t = ::std::os::raw::c_uint;
|
|
||||||
#[repr(C)]
|
|
||||||
#[repr(align(16))]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct max_align_t {
|
|
||||||
pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
|
|
||||||
pub __bindgen_padding_0: u64,
|
|
||||||
pub __clang_max_align_nonce2: u128,
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn bindgen_test_layout_max_align_t() {
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::size_of::<max_align_t>(),
|
|
||||||
32usize,
|
|
||||||
concat!("Size of: ", stringify!(max_align_t))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
::std::mem::align_of::<max_align_t>(),
|
|
||||||
16usize,
|
|
||||||
concat!("Alignment of ", stringify!(max_align_t))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe {
|
|
||||||
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce1 as *const _ as usize
|
|
||||||
},
|
|
||||||
0usize,
|
|
||||||
concat!(
|
|
||||||
"Offset of field: ",
|
|
||||||
stringify!(max_align_t),
|
|
||||||
"::",
|
|
||||||
stringify!(__clang_max_align_nonce1)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
unsafe {
|
|
||||||
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce2 as *const _ as usize
|
|
||||||
},
|
|
||||||
16usize,
|
|
||||||
concat!(
|
|
||||||
"Offset of field: ",
|
|
||||||
stringify!(max_align_t),
|
|
||||||
"::",
|
|
||||||
stringify!(__clang_max_align_nonce2)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct uws_app_s {
|
|
||||||
_unused: [u8; 0],
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct uws_req_s {
|
|
||||||
_unused: [u8; 0],
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct uws_res_s {
|
|
||||||
_unused: [u8; 0],
|
|
||||||
}
|
|
||||||
pub type uws_app_t = uws_app_s;
|
|
||||||
pub type uws_req_t = uws_req_s;
|
|
||||||
pub type uws_res_t = uws_res_s;
|
|
||||||
extern "C" {
|
|
||||||
pub fn uws_create_app() -> *mut uws_app_t;
|
|
||||||
}
|
|
||||||
extern "C" {
|
|
||||||
pub fn uws_app_get(
|
|
||||||
app: *mut uws_app_t,
|
|
||||||
pattern: *const ::std::os::raw::c_char,
|
|
||||||
handler: ::std::option::Option<
|
|
||||||
unsafe extern "C" fn(arg1: *mut uws_res_t,
|
|
||||||
arg2: *mut uws_req_t),
|
|
||||||
>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
extern "C" {
|
|
||||||
pub fn uws_app_run(arg1: *mut uws_app_t);
|
|
||||||
}
|
|
||||||
extern "C" {
|
|
||||||
pub fn uws_app_listen(
|
|
||||||
app: *mut uws_app_t,
|
|
||||||
port: ::std::os::raw::c_int,
|
|
||||||
handler: ::std::option::Option<unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void)>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
extern "C" {
|
|
||||||
pub fn uws_res_end(res: *mut uws_res_t, data: *const ::std::os::raw::c_char, length: size_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn listen_handler(listen_socket: *mut ::std::os::raw::c_void) {
|
|
||||||
println!("Listening");
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn get_handler(res: *mut uws_res_t, req: *mut uws_req_t) {
|
|
||||||
unsafe {
|
|
||||||
uws_res_end(res, "Hello!".as_bytes().as_ptr(), 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
unsafe {
|
|
||||||
let app = uws_create_app();
|
|
||||||
uws_app_get(app, ::std::ffi::CString::new("/*").expect("").as_ptr(), ::std::option::Option::Some(get_handler));
|
|
||||||
uws_app_listen(app, 3000, ::std::option::Option::Some(listen_handler));
|
|
||||||
uws_app_run(app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
|
||||||
|
//Timer close helper
|
||||||
|
void uws_timer_close(struct us_timer_t *timer)
|
||||||
|
{
|
||||||
|
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
//Timer create helper
|
||||||
|
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||||
|
{
|
||||||
|
struct us_loop_t *loop = uws_get_loop();
|
||||||
|
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||||
|
|
||||||
|
struct timer_handler_data
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
void (*handler)(void *data);
|
||||||
|
bool repeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||||
|
timer_data->data = data;
|
||||||
|
timer_data->handler = handler;
|
||||||
|
timer_data->repeat = repeat_ms > 0;
|
||||||
|
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
us_timer_set(
|
||||||
|
delayTimer, [](struct us_timer_t *t)
|
||||||
|
{
|
||||||
|
/* We wrote the pointer to the timer's extension */
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
data->handler(data->data);
|
||||||
|
|
||||||
|
if (!data->repeat)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ms, repeat_ms);
|
||||||
|
|
||||||
|
return (struct us_timer_t *)delayTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a simple WebSocket "sync" upgrade example.
|
||||||
|
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||||
|
|
||||||
|
/* ws->getUserData returns one of these */
|
||||||
|
struct PerSocketData {
|
||||||
|
/* Fill with user data */
|
||||||
|
};
|
||||||
|
|
||||||
|
int buffer_size(const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int result = vsnprintf(NULL, 0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return result + 1; // safe byte for \0
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket){
|
||||||
|
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_handler(uws_websocket_t* ws){
|
||||||
|
|
||||||
|
/* Open event here, you may access uws_ws_get_user_data(WS) which points to a PerSocketData struct */
|
||||||
|
uws_ws_subscribe(SSL, ws, "broadcast", 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
void message_handler(uws_websocket_t* ws, const char* message, size_t length, uws_opcode_t opcode){
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handler(uws_websocket_t* ws, int code, const char* message, size_t length){
|
||||||
|
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||||
|
* doing any kind of I/O with the socket is not valid. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void drain_handler(uws_websocket_t* ws){
|
||||||
|
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ping_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||||
|
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pong_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||||
|
|
||||||
|
/* You don't need to handle this one either */
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_timer_interval(void* data){
|
||||||
|
|
||||||
|
// broadcast the unix time as millis
|
||||||
|
|
||||||
|
uws_app_t * app = (uws_app_t *)data;
|
||||||
|
struct timespec ts;
|
||||||
|
timespec_get(&ts, TIME_UTC);
|
||||||
|
|
||||||
|
int64_t millis = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||||
|
|
||||||
|
|
||||||
|
char* message = (char*)malloc((size_t)buffer_size("%ld", millis));
|
||||||
|
size_t message_length = sprintf(message, "%ld", millis);
|
||||||
|
|
||||||
|
uws_publish(SSL, app, "broadcast", 9, message, message_length, uws_opcode_t::TEXT, false);
|
||||||
|
free(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||||
|
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||||
|
.maxPayloadLength = 16 * 1024,
|
||||||
|
.idleTimeout = 12,
|
||||||
|
.maxBackpressure = 1 * 1024 * 1024,
|
||||||
|
.upgrade = NULL,
|
||||||
|
.open = open_handler,
|
||||||
|
.message = message_handler,
|
||||||
|
.drain = drain_handler,
|
||||||
|
.ping = ping_handler,
|
||||||
|
.pong = pong_handler,
|
||||||
|
.close = close_handler,
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||||
|
|
||||||
|
// broadcast the unix time as millis every 8 millis
|
||||||
|
uws_create_timer(8, 8, on_timer_interval, app);
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
|
||||||
|
/* This is a simple WebSocket "sync" upgrade example.
|
||||||
|
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
char *name;
|
||||||
|
} topic_t;
|
||||||
|
|
||||||
|
/* ws->getUserData returns one of these */
|
||||||
|
struct PerSocketData
|
||||||
|
{
|
||||||
|
/* Fill with user data */
|
||||||
|
topic_t **topics;
|
||||||
|
int topics_quantity;
|
||||||
|
int nr;
|
||||||
|
};
|
||||||
|
|
||||||
|
uws_app_t *app;
|
||||||
|
|
||||||
|
int buffer_size(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int result = vsnprintf(NULL, 0, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return result + 1; // safe byte for \0
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket)
|
||||||
|
{
|
||||||
|
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You may read from req only here, and COPY whatever you need into your PerSocketData.
|
||||||
|
* PerSocketData is valid from .open to .close event, accessed with uws_ws_get_user_data(ws).
|
||||||
|
* HttpRequest (req) is ONLY valid in this very callback, so any data you will need later
|
||||||
|
* has to be COPIED into PerSocketData here. */
|
||||||
|
|
||||||
|
/* Immediately upgrading without doing anything "async" before, is simple */
|
||||||
|
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||||
|
data->topics = (topic_t **)calloc(32, sizeof(topic_t *));
|
||||||
|
data->topics_quantity = 32;
|
||||||
|
data->nr = 0;
|
||||||
|
|
||||||
|
const char *ws_key = NULL;
|
||||||
|
const char *ws_protocol = NULL;
|
||||||
|
const char *ws_extensions = NULL;
|
||||||
|
|
||||||
|
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||||
|
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||||
|
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||||
|
|
||||||
|
uws_res_upgrade(SSL,
|
||||||
|
response,
|
||||||
|
(void *)data,
|
||||||
|
ws_key,
|
||||||
|
ws_key_length,
|
||||||
|
ws_protocol,
|
||||||
|
ws_protocol_length,
|
||||||
|
ws_extensions,
|
||||||
|
ws_extensions_length,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct */
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
for (int i = 0; i < data->topics_quantity; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
char *topic = (char *)malloc((size_t)buffer_size("%ld-%d", (uintptr_t)ws, i));
|
||||||
|
size_t topic_length = sprintf(topic, "%ld-%d", (uintptr_t)ws, i);
|
||||||
|
|
||||||
|
topic_t *new_topic = (topic_t*) malloc(sizeof(topic_t));
|
||||||
|
new_topic->length = topic_length;
|
||||||
|
new_topic->name = topic;
|
||||||
|
data->topics[i] = new_topic;
|
||||||
|
uws_ws_subscribe(SSL, ws, topic, topic_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||||
|
{
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
topic_t *topic = data->topics[(size_t)(++data->nr % data->topics_quantity)];
|
||||||
|
uws_publish(SSL, app, topic->name, topic->length, message, length, opcode, false);
|
||||||
|
|
||||||
|
topic = data->topics[(size_t)(++data->nr % data->topics_quantity)];
|
||||||
|
uws_ws_publish(SSL, ws, topic->name, topic->length, message, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||||
|
* doing any kind of I/O with the socket is not valid. */
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < data->topics_quantity; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
topic_t* topic = data->topics[i];
|
||||||
|
free(topic->name);
|
||||||
|
free(topic);
|
||||||
|
}
|
||||||
|
free(data->topics);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drain_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You don't need to handle this one either */
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||||
|
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||||
|
.maxPayloadLength = 16 * 1024,
|
||||||
|
.idleTimeout = 12,
|
||||||
|
.maxBackpressure = 1 * 1024 * 1024,
|
||||||
|
.upgrade = upgrade_handler,
|
||||||
|
.open = open_handler,
|
||||||
|
.message = message_handler,
|
||||||
|
.drain = drain_handler,
|
||||||
|
.ping = ping_handler,
|
||||||
|
.pong = pong_handler,
|
||||||
|
.close = close_handler,
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
|
||||||
|
/* This is a simple WebSocket "sync" upgrade example.
|
||||||
|
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||||
|
|
||||||
|
/* ws->getUserData returns one of these */
|
||||||
|
struct PerSocketData {
|
||||||
|
/* Fill with user data */
|
||||||
|
};
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket){
|
||||||
|
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_handler(uws_websocket_t* ws){
|
||||||
|
|
||||||
|
/* Open event here, you may access uws_ws_get_user_data(WS) which points to a PerSocketData struct */
|
||||||
|
}
|
||||||
|
|
||||||
|
void message_handler(uws_websocket_t* ws, const char* message, size_t length, uws_opcode_t opcode){
|
||||||
|
uws_ws_send(SSL, ws, message, length, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handler(uws_websocket_t* ws, int code, const char* message, size_t length){
|
||||||
|
|
||||||
|
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||||
|
* doing any kind of I/O with the socket is not valid. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void drain_handler(uws_websocket_t* ws){
|
||||||
|
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ping_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||||
|
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pong_handler(uws_websocket_t* ws, const char* message, size_t length){
|
||||||
|
|
||||||
|
/* You don't need to handle this one either */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||||
|
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||||
|
.maxPayloadLength = 16 * 1024,
|
||||||
|
.idleTimeout = 12,
|
||||||
|
.maxBackpressure = 1 * 1024 * 1024,
|
||||||
|
.upgrade = NULL,
|
||||||
|
.open = open_handler,
|
||||||
|
.message = message_handler,
|
||||||
|
.drain = drain_handler,
|
||||||
|
.ping = ping_handler,
|
||||||
|
.pong = pong_handler,
|
||||||
|
.close = close_handler,
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_app_listen(SSL,app, 9001, listen_handler, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include "libusockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
void get_handler(uws_res_t *res, uws_req_t *req, void *user_data)
|
||||||
|
{
|
||||||
|
uws_res_end(SSL, res, "Hello CAPI!", 11, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket)
|
||||||
|
{
|
||||||
|
printf("Listening on port https://localhost:%d now\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* Overly simple hello world app */
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||||
|
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include "libusockets.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SSL 0
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uws_res_t* res;
|
||||||
|
bool aborted;
|
||||||
|
} async_request_t;
|
||||||
|
|
||||||
|
//Timer close helper
|
||||||
|
void uws_timer_close(struct us_timer_t *timer)
|
||||||
|
{
|
||||||
|
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
//Timer create helper
|
||||||
|
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||||
|
{
|
||||||
|
struct us_loop_t *loop = uws_get_loop();
|
||||||
|
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||||
|
|
||||||
|
struct timer_handler_data
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
void (*handler)(void *data);
|
||||||
|
bool repeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||||
|
timer_data->data = data;
|
||||||
|
timer_data->handler = handler;
|
||||||
|
timer_data->repeat = repeat_ms > 0;
|
||||||
|
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
us_timer_set(
|
||||||
|
delayTimer, [](struct us_timer_t *t)
|
||||||
|
{
|
||||||
|
/* We wrote the pointer to the timer's extension */
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
data->handler(data->data);
|
||||||
|
|
||||||
|
if (!data->repeat)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ms, repeat_ms);
|
||||||
|
|
||||||
|
return (struct us_timer_t *)delayTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_res_aborted(uws_res_t *response, void* data){
|
||||||
|
async_request_t* request_data = (async_request_t*)data;
|
||||||
|
/* We don't implement any kind of cancellation here,
|
||||||
|
* so simply flag us as aborted */
|
||||||
|
request_data->aborted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_res_corked(uws_res_t *response, void* data){
|
||||||
|
uws_res_end(SSL, response, "Hello CAPI!", 11, false);
|
||||||
|
}
|
||||||
|
void on_timer_done(void *data){
|
||||||
|
async_request_t* request_data = (async_request_t*)data;
|
||||||
|
/* Were'nt we aborted before our async task finished? Okay, send a message! */
|
||||||
|
if(!request_data->aborted){
|
||||||
|
|
||||||
|
uws_res_cork(SSL, request_data->res,on_res_corked, request_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* We have to attach an abort handler for us to be aware
|
||||||
|
* of disconnections while we perform async tasks */
|
||||||
|
async_request_t* request_data = (async_request_t*) malloc(sizeof(async_request_t));
|
||||||
|
request_data->res = res;
|
||||||
|
request_data->aborted = false;
|
||||||
|
|
||||||
|
uws_res_on_aborted(SSL, res, on_res_aborted, request_data);
|
||||||
|
|
||||||
|
/* Simulate checking auth for 5 seconds. This looks like crap, never write
|
||||||
|
* code that utilize us_timer_t like this; they are high-cost and should
|
||||||
|
* not be created and destroyed more than rarely!
|
||||||
|
* Either way, here we go!*/
|
||||||
|
uws_create_timer(1, 0, on_timer_done, request_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket)
|
||||||
|
{
|
||||||
|
printf("Listening on port https://localhost:%d now\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* Overly simple hello world app with async response */
|
||||||
|
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||||
|
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
/* automatically generated by rust-bindgen 0.59.2 */
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
pub type SizeT = ::std::os::raw::c_ulong;
|
||||||
|
pub type WcharT = ::std::os::raw::c_uint;
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(16))]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct max_align_t {
|
||||||
|
pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
|
||||||
|
pub __bindgen_padding_0: u64,
|
||||||
|
pub __clang_max_align_nonce2: u128,
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn bindgen_test_layout_max_align_t() {
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::size_of::<max_align_t>(),
|
||||||
|
32usize,
|
||||||
|
concat!("Size of: ", stringify!(max_align_t))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::align_of::<max_align_t>(),
|
||||||
|
16usize,
|
||||||
|
concat!("Alignment of ", stringify!(max_align_t))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe {
|
||||||
|
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce1 as *const _ as usize
|
||||||
|
},
|
||||||
|
0usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(max_align_t),
|
||||||
|
"::",
|
||||||
|
stringify!(__clang_max_align_nonce1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe {
|
||||||
|
&(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce2 as *const _ as usize
|
||||||
|
},
|
||||||
|
16usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(max_align_t),
|
||||||
|
"::",
|
||||||
|
stringify!(__clang_max_align_nonce2)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct uws_app_s {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct uws_req_s {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct uws_res_s {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct uws_app_listen_config_s {
|
||||||
|
port: ::std::os::raw::c_int,
|
||||||
|
host: *const ::std::os::raw::c_char,
|
||||||
|
options: ::std::os::raw::c_int,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct us_socket_context_options_s {
|
||||||
|
key_file_name: *const ::std::os::raw::c_char,
|
||||||
|
cert_file_name: *const ::std::os::raw::c_char,
|
||||||
|
passphrase: *const ::std::os::raw::c_char,
|
||||||
|
dh_params_file_name: *const ::std::os::raw::c_char,
|
||||||
|
ca_file_name: *const ::std::os::raw::c_char,
|
||||||
|
ssl_prefer_low_memory_usage: ::std::os::raw::c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type UwsAppListenConfigT = uws_app_listen_config_s;
|
||||||
|
pub type UsSocketContextOptionsT = us_socket_context_options_s;
|
||||||
|
pub struct UsSocketContextOptions<'a> {
|
||||||
|
key_file_name: &'a str,
|
||||||
|
cert_file_name: &'a str,
|
||||||
|
passphrase: &'a str,
|
||||||
|
dh_params_file_name: &'a str,
|
||||||
|
ca_file_name: &'a str,
|
||||||
|
ssl_prefer_low_memory_usage: i32,
|
||||||
|
}
|
||||||
|
pub type UwsAppT = uws_app_s;
|
||||||
|
pub type UwsReqT = uws_req_s;
|
||||||
|
pub type UwsResT = uws_res_s;
|
||||||
|
extern "C" {
|
||||||
|
pub fn uws_create_app(
|
||||||
|
ssl: ::std::os::raw::c_int,
|
||||||
|
options: UsSocketContextOptionsT,
|
||||||
|
) -> *mut UwsAppT;
|
||||||
|
pub fn uws_app_get(
|
||||||
|
ssl: ::std::os::raw::c_int,
|
||||||
|
app: *mut UwsAppT,
|
||||||
|
pattern: *const ::std::os::raw::c_char,
|
||||||
|
handler: ::std::option::Option<
|
||||||
|
unsafe extern "C" fn(
|
||||||
|
res: *mut UwsResT,
|
||||||
|
req: *mut UwsReqT,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
);
|
||||||
|
pub fn uws_app_run(ssl: ::std::os::raw::c_int, app: *mut UwsAppT);
|
||||||
|
|
||||||
|
pub fn uws_app_listen(
|
||||||
|
ssl: ::std::os::raw::c_int,
|
||||||
|
app: *mut UwsAppT,
|
||||||
|
port: ::std::os::raw::c_int,
|
||||||
|
handler: ::std::option::Option<
|
||||||
|
unsafe extern "C" fn(
|
||||||
|
listen_socket: *mut ::std::os::raw::c_void,
|
||||||
|
config: UwsAppListenConfigT,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
);
|
||||||
|
pub fn uws_res_end(
|
||||||
|
ssl: ::std::os::raw::c_int,
|
||||||
|
res: *mut UwsResT,
|
||||||
|
data: *const ::std::os::raw::c_char,
|
||||||
|
length: SizeT,
|
||||||
|
close_connection: bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AppResponse<const SSL: i32> {
|
||||||
|
native: *mut UwsResT,
|
||||||
|
}
|
||||||
|
pub struct AppRequest {
|
||||||
|
native: *mut UwsReqT,
|
||||||
|
}
|
||||||
|
impl AppRequest {
|
||||||
|
pub fn new(native: *mut UwsReqT) -> AppRequest {
|
||||||
|
AppRequest { native: native }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<const SSL: i32> AppResponse<SSL> {
|
||||||
|
pub fn new(native: *mut UwsResT) -> AppResponse<SSL> {
|
||||||
|
AppResponse::<SSL> { native: native }
|
||||||
|
}
|
||||||
|
fn end(self, message: &str) -> AppResponse<SSL> {
|
||||||
|
unsafe {
|
||||||
|
let c_message =
|
||||||
|
::std::ffi::CString::new(message).expect("Failed to create message CString");
|
||||||
|
//This will now const fold :/ performance impact needs refactor
|
||||||
|
uws_res_end(
|
||||||
|
SSL,
|
||||||
|
self.native,
|
||||||
|
c_message.as_ptr(),
|
||||||
|
message.len().try_into().unwrap(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type UwsMethodHandler<const SSL: i32> = fn(res: AppResponse<SSL>, req: AppRequest);
|
||||||
|
pub type UwsListenHandler =
|
||||||
|
fn(listen_socket: *mut ::std::os::raw::c_void, config: UwsAppListenConfigT);
|
||||||
|
|
||||||
|
pub struct TemplateApp<const SSL: i32> {
|
||||||
|
native: *mut UwsAppT,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn uws_generic_listen_handler(
|
||||||
|
listen_socket: *mut ::std::os::raw::c_void,
|
||||||
|
config: UwsAppListenConfigT,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let callback = &mut *(user_data as *mut UwsListenHandler);
|
||||||
|
callback(listen_socket, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn uws_generic_method_handler(
|
||||||
|
res: *mut UwsResT,
|
||||||
|
req: *mut UwsReqT,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let response = AppResponse::<0>::new(res);
|
||||||
|
let request = AppRequest::new(req);
|
||||||
|
let callback = &mut *(user_data as *mut UwsMethodHandler<0>);
|
||||||
|
callback(response, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extern "C" fn uws_ssl_generic_method_handler(
|
||||||
|
res: *mut UwsResT,
|
||||||
|
req: *mut UwsReqT,
|
||||||
|
user_data: *mut ::std::os::raw::c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let response = AppResponse::<1>::new(res);
|
||||||
|
let request = AppRequest::new(req);
|
||||||
|
let callback = &mut *(user_data as *mut UwsMethodHandler<1>);
|
||||||
|
callback(response, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const SSL: i32> TemplateApp<SSL> {
|
||||||
|
pub fn new(config: UsSocketContextOptions) -> TemplateApp<SSL> {
|
||||||
|
unsafe {
|
||||||
|
let key_file_name_s =
|
||||||
|
CString::new(config.key_file_name).expect("Failed to create key_file_name CString");
|
||||||
|
let cert_file_name_s = CString::new(config.cert_file_name)
|
||||||
|
.expect("Failed to create cert_file_name CString");
|
||||||
|
let passphrase_s =
|
||||||
|
CString::new(config.passphrase).expect("Failed to create passphrase CString");
|
||||||
|
let dh_params_file_name_s = CString::new(config.dh_params_file_name)
|
||||||
|
.expect("Failed to create dh_params_file_name CString");
|
||||||
|
let ca_file_name_s =
|
||||||
|
CString::new(config.ca_file_name).expect("Failed to create ca_file_name CString");
|
||||||
|
|
||||||
|
let native_options = UsSocketContextOptionsT {
|
||||||
|
key_file_name: key_file_name_s.as_ptr(),
|
||||||
|
cert_file_name: cert_file_name_s.as_ptr(),
|
||||||
|
passphrase: passphrase_s.as_ptr(),
|
||||||
|
dh_params_file_name: dh_params_file_name_s.as_ptr(),
|
||||||
|
ca_file_name: ca_file_name_s.as_ptr(),
|
||||||
|
ssl_prefer_low_memory_usage: config.ssl_prefer_low_memory_usage,
|
||||||
|
};
|
||||||
|
TemplateApp::<SSL> {
|
||||||
|
native: uws_create_app(SSL, native_options),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get(self, route: &str, mut handler: UwsMethodHandler<SSL>) -> TemplateApp<SSL> {
|
||||||
|
unsafe {
|
||||||
|
let c_route = ::std::ffi::CString::new(route).expect("Failed to create route CString");
|
||||||
|
if SSL == 1 {
|
||||||
|
uws_app_get(
|
||||||
|
SSL,
|
||||||
|
self.native,
|
||||||
|
c_route.as_ptr(),
|
||||||
|
std::option::Option::Some(uws_ssl_generic_method_handler),
|
||||||
|
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
uws_app_get(
|
||||||
|
SSL,
|
||||||
|
self.native,
|
||||||
|
c_route.as_ptr(),
|
||||||
|
std::option::Option::Some(uws_generic_method_handler),
|
||||||
|
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(self, port: i32, mut handler: UwsListenHandler) -> TemplateApp<SSL> {
|
||||||
|
unsafe {
|
||||||
|
uws_app_listen(
|
||||||
|
SSL,
|
||||||
|
self.native,
|
||||||
|
port,
|
||||||
|
::std::option::Option::Some(uws_generic_listen_handler),
|
||||||
|
&mut handler as *mut _ as *mut ::std::os::raw::c_void,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(self) -> TemplateApp<SSL> {
|
||||||
|
unsafe {
|
||||||
|
uws_app_run(SSL, self.native);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub type App = TemplateApp<0>;
|
||||||
|
pub type SSLApp = TemplateApp<1>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let config = UsSocketContextOptions {
|
||||||
|
key_file_name: "../misc/key.pem",
|
||||||
|
cert_file_name: "../misc/cert.pem",
|
||||||
|
passphrase: "1234",
|
||||||
|
ca_file_name: "",
|
||||||
|
dh_params_file_name: "",
|
||||||
|
ssl_prefer_low_memory_usage: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
SSLApp::new(config)
|
||||||
|
.get("/", |res, _req| {
|
||||||
|
res.end("Hello Rust!");
|
||||||
|
})
|
||||||
|
.listen(3000, |_listen_socket, config| {
|
||||||
|
println!("Listening on port https://127.0.0.1:{}", config.port);
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
|
||||||
|
struct us_listen_socket_t *globalListenSocket;
|
||||||
|
uws_app_t *app;
|
||||||
|
void get_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||||
|
{
|
||||||
|
|
||||||
|
uws_res_end(SSL, res, "Hello CAPI!", 11, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exit_handler(uws_res_t *res, uws_req_t *req, void* user_data)
|
||||||
|
{
|
||||||
|
uws_res_end(SSL, res, "Shutting down!",14, false);
|
||||||
|
/* We use this to check graceful closedown */
|
||||||
|
us_listen_socket_close(false, globalListenSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void missing_server_name_handler(const char *hostname, void* user_data){
|
||||||
|
printf("We are missing server name: <%s>\n", hostname);
|
||||||
|
|
||||||
|
/* Assume it is localhost, so add it */
|
||||||
|
uws_add_server_name(SSL, app, "localhost");
|
||||||
|
}
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void* user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket){
|
||||||
|
printf("Listening on port https://localhost:%d\n", config.port);
|
||||||
|
globalListenSocket = listen_socket;
|
||||||
|
}else{
|
||||||
|
printf("Failed to listen on port https://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
/* Overly simple hello world app (SNI)*/
|
||||||
|
|
||||||
|
app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
uws_missing_server_name(SSL, app, missing_server_name_handler, NULL);
|
||||||
|
uws_app_get(SSL, app, "/*", get_handler, NULL);
|
||||||
|
uws_app_get(SSL, app, "/exit", exit_handler, NULL);
|
||||||
|
uws_app_listen(SSL, app, 3000, listen_handler, NULL);
|
||||||
|
|
||||||
|
/* Let's add a wildcard SNI to begin with */
|
||||||
|
uws_add_server_name(SSL, app, "*.google.*");
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include "libusockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
/* This is a simple WebSocket "sync" upgrade example.
|
||||||
|
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||||
|
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *value;
|
||||||
|
size_t length;
|
||||||
|
} header_t;
|
||||||
|
struct PerSocketData
|
||||||
|
{
|
||||||
|
/* Define your user data */
|
||||||
|
int something;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpgradeData
|
||||||
|
{
|
||||||
|
header_t *secWebSocketKey;
|
||||||
|
header_t *secWebSocketProtocol;
|
||||||
|
header_t *secWebSocketExtensions;
|
||||||
|
uws_socket_context_t *context;
|
||||||
|
uws_res_t *response;
|
||||||
|
bool aborted;
|
||||||
|
};
|
||||||
|
|
||||||
|
header_t *create_header(size_t length, const char* value)
|
||||||
|
{
|
||||||
|
header_t *header = (header_t *)malloc(sizeof(header_t));
|
||||||
|
if(length > 0){
|
||||||
|
header->value = (char *)calloc(sizeof(char), length);
|
||||||
|
header->length = length;
|
||||||
|
memcpy(header->value, value, length);
|
||||||
|
}else{
|
||||||
|
header->value = NULL;
|
||||||
|
header->length = 0;
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
void free_header(header_t *header)
|
||||||
|
{
|
||||||
|
|
||||||
|
free(header->value);
|
||||||
|
free(header);
|
||||||
|
}
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket)
|
||||||
|
{
|
||||||
|
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Timer close helper
|
||||||
|
void uws_timer_close(struct us_timer_t *timer)
|
||||||
|
{
|
||||||
|
struct us_timer_t *t = (struct us_timer_t *)timer;
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
//Timer create helper
|
||||||
|
struct us_timer_t *uws_create_timer(int ms, int repeat_ms, void (*handler)(void *data), void *data)
|
||||||
|
{
|
||||||
|
struct us_loop_t *loop = uws_get_loop();
|
||||||
|
struct us_timer_t *delayTimer = us_create_timer(loop, 0, sizeof(void *));
|
||||||
|
|
||||||
|
struct timer_handler_data
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
void (*handler)(void *data);
|
||||||
|
bool repeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timer_handler_data *timer_data = (struct timer_handler_data *)malloc(sizeof(timer_handler_data));
|
||||||
|
timer_data->data = data;
|
||||||
|
timer_data->handler = handler;
|
||||||
|
timer_data->repeat = repeat_ms > 0;
|
||||||
|
memcpy(us_timer_ext(delayTimer), &timer_data, sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
us_timer_set(
|
||||||
|
delayTimer, [](struct us_timer_t *t)
|
||||||
|
{
|
||||||
|
/* We wrote the pointer to the timer's extension */
|
||||||
|
struct timer_handler_data *data;
|
||||||
|
memcpy(&data, us_timer_ext(t), sizeof(struct timer_handler_data *));
|
||||||
|
|
||||||
|
data->handler(data->data);
|
||||||
|
|
||||||
|
if (!data->repeat)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
us_timer_close(t);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ms, repeat_ms);
|
||||||
|
|
||||||
|
return (struct us_timer_t *)delayTimer;
|
||||||
|
}
|
||||||
|
void on_timer_done(void *data)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct UpgradeData *upgrade_data = (struct UpgradeData *)data;
|
||||||
|
|
||||||
|
/* Were'nt we aborted before our async task finished? Okay, upgrade then! */
|
||||||
|
if (!upgrade_data->aborted)
|
||||||
|
{
|
||||||
|
struct PerSocketData *socket_data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||||
|
socket_data->something = 15;
|
||||||
|
printf("Async task done, upgrading to WebSocket now!\n");
|
||||||
|
|
||||||
|
uws_res_upgrade(SSL,
|
||||||
|
upgrade_data->response,
|
||||||
|
(void *)socket_data,
|
||||||
|
upgrade_data->secWebSocketKey->value,
|
||||||
|
upgrade_data->secWebSocketKey->length,
|
||||||
|
upgrade_data->secWebSocketProtocol->value,
|
||||||
|
upgrade_data->secWebSocketProtocol->length,
|
||||||
|
upgrade_data->secWebSocketExtensions->value,
|
||||||
|
upgrade_data->secWebSocketExtensions->length,
|
||||||
|
upgrade_data->context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Async task done, but the HTTP socket was closed. Skipping upgrade to WebSocket!\n");
|
||||||
|
}
|
||||||
|
free_header(upgrade_data->secWebSocketKey);
|
||||||
|
free_header(upgrade_data->secWebSocketProtocol);
|
||||||
|
free_header(upgrade_data->secWebSocketExtensions);
|
||||||
|
free(upgrade_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_res_aborted(uws_res_t *response, void *data)
|
||||||
|
{
|
||||||
|
struct UpgradeData *upgrade_data = (struct UpgradeData *)data;
|
||||||
|
/* We don't implement any kind of cancellation here,
|
||||||
|
* so simply flag us as aborted */
|
||||||
|
upgrade_data->aborted = true;
|
||||||
|
}
|
||||||
|
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* HttpRequest (req) is only valid in this very callback, so we must COPY the headers
|
||||||
|
* we need later on while upgrading to WebSocket. You must not access req after first return.
|
||||||
|
* Here we create a heap allocated struct holding everything we will need later on. */
|
||||||
|
|
||||||
|
struct UpgradeData *data = (struct UpgradeData *)malloc(sizeof(struct UpgradeData));
|
||||||
|
data->aborted = false;
|
||||||
|
data->context = context;
|
||||||
|
data->response = response;
|
||||||
|
|
||||||
|
const char *ws_key = NULL;
|
||||||
|
const char *ws_protocol = NULL;
|
||||||
|
const char *ws_extensions = NULL;
|
||||||
|
|
||||||
|
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||||
|
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||||
|
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||||
|
|
||||||
|
|
||||||
|
data->secWebSocketKey = create_header(ws_key_length, ws_key);
|
||||||
|
data->secWebSocketProtocol = create_header(ws_protocol_length, ws_protocol);
|
||||||
|
data->secWebSocketExtensions = create_header(ws_extensions_length, ws_extensions);
|
||||||
|
|
||||||
|
/* We have to attach an abort handler for us to be aware
|
||||||
|
* of disconnections while we perform async tasks */
|
||||||
|
|
||||||
|
uws_res_on_aborted(SSL, response, on_res_aborted, data);
|
||||||
|
|
||||||
|
/* Simulate checking auth for 5 seconds. This looks like crap, never write
|
||||||
|
* code that utilize us_timer_t like this; they are high-cost and should
|
||||||
|
* not be created and destroyed more than rarely!
|
||||||
|
* Either way, here we go!*/
|
||||||
|
uws_create_timer(5000, 0, on_timer_done, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct.
|
||||||
|
* Here we simply validate that indeed, something == 15 as set in upgrade handler. */
|
||||||
|
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
data->something = 15;
|
||||||
|
printf("Something is: %d\n", data->something);
|
||||||
|
}
|
||||||
|
|
||||||
|
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* We simply echo whatever data we get */
|
||||||
|
uws_ws_send(SSL, ws, message, length, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||||
|
* doing any kind of I/O with the socket is not valid. */
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drain_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You don't need to handle this one either */
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){
|
||||||
|
.compression = uws_compress_options_t::SHARED_COMPRESSOR,
|
||||||
|
.maxPayloadLength = 16 * 1024,
|
||||||
|
.idleTimeout = 12,
|
||||||
|
.maxBackpressure = 1 * 1024 * 1024,
|
||||||
|
.upgrade = upgrade_handler,
|
||||||
|
.open = open_handler,
|
||||||
|
.message = message_handler,
|
||||||
|
.drain = drain_handler,
|
||||||
|
.ping = ping_handler,
|
||||||
|
.pong = pong_handler,
|
||||||
|
.close = close_handler,
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#include "../libuwebsockets.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#define SSL 1
|
||||||
|
|
||||||
|
/* This is a simple WebSocket "sync" upgrade example.
|
||||||
|
* You may compile it with "WITH_OPENSSL=1 make" or with "make" */
|
||||||
|
|
||||||
|
/* uws_ws_get_user_data(ws) returns one of these */
|
||||||
|
|
||||||
|
struct PerSocketData
|
||||||
|
{
|
||||||
|
/* Define your user data */
|
||||||
|
int something;
|
||||||
|
};
|
||||||
|
|
||||||
|
void listen_handler(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data)
|
||||||
|
{
|
||||||
|
if (listen_socket)
|
||||||
|
{
|
||||||
|
printf("Listening on port wss://localhost:%d\n", config.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upgrade_handler(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You may read from req only here, and COPY whatever you need into your PerSocketData.
|
||||||
|
* PerSocketData is valid from .open to .close event, accessed with uws_ws_get_user_data(ws).
|
||||||
|
* HttpRequest (req) is ONLY valid in this very callback, so any data you will need later
|
||||||
|
* has to be COPIED into PerSocketData here. */
|
||||||
|
|
||||||
|
/* Immediately upgrading without doing anything "async" before, is simple */
|
||||||
|
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)malloc(sizeof(struct PerSocketData));
|
||||||
|
data->something = 15;
|
||||||
|
|
||||||
|
const char *ws_key = NULL;
|
||||||
|
const char *ws_protocol = NULL;
|
||||||
|
const char *ws_extensions = NULL;
|
||||||
|
|
||||||
|
size_t ws_key_length = uws_req_get_header(request, "sec-websocket-key", 17, &ws_key);
|
||||||
|
size_t ws_protocol_length = uws_req_get_header(request, "sec-websocket-protocol", 22, &ws_protocol);
|
||||||
|
size_t ws_extensions_length = uws_req_get_header(request, "sec-websocket-extensions", 24, &ws_extensions);
|
||||||
|
|
||||||
|
uws_res_upgrade(SSL,
|
||||||
|
response,
|
||||||
|
(void *)data,
|
||||||
|
ws_key,
|
||||||
|
ws_key_length,
|
||||||
|
ws_protocol,
|
||||||
|
ws_protocol_length,
|
||||||
|
ws_extensions,
|
||||||
|
ws_extensions_length,
|
||||||
|
context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Open event here, you may access uws_ws_get_user_data(ws) which points to a PerSocketData struct.
|
||||||
|
* Here we simply validate that indeed, something == 15 as set in upgrade handler. */
|
||||||
|
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
data->something = 15;
|
||||||
|
printf("Something is: %d\n", data->something);
|
||||||
|
}
|
||||||
|
|
||||||
|
void message_handler(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode)
|
||||||
|
{
|
||||||
|
/* We simply echo whatever data we get */
|
||||||
|
uws_ws_send(SSL, ws, message, length, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_handler(uws_websocket_t *ws, int code, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You may access uws_ws_get_user_data(ws) here, but sending or
|
||||||
|
* doing any kind of I/O with the socket is not valid. */
|
||||||
|
struct PerSocketData *data = (struct PerSocketData *)uws_ws_get_user_data(SSL, ws);
|
||||||
|
if (data)
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drain_handler(uws_websocket_t *ws)
|
||||||
|
{
|
||||||
|
/* Check uws_ws_get_buffered_amount(ws) here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ping_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
/* You don't need to handle this one, we automatically respond to pings as per standard */
|
||||||
|
}
|
||||||
|
|
||||||
|
void pong_handler(uws_websocket_t *ws, const char *message, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* You don't need to handle this one either */
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
uws_app_t *app = uws_create_app(SSL, (struct us_socket_context_options_t){
|
||||||
|
/* There are example certificates in uWebSockets.js repo */
|
||||||
|
.key_file_name = "../misc/key.pem",
|
||||||
|
.cert_file_name = "../misc/cert.pem",
|
||||||
|
.passphrase = "1234"
|
||||||
|
});
|
||||||
|
|
||||||
|
uws_ws(SSL, app, "/*", (uws_socket_behavior_t){.compression = uws_compress_options_t::SHARED_COMPRESSOR, .maxPayloadLength = 16 * 1024, .idleTimeout = 12, .maxBackpressure = 1 * 1024 * 1024, .upgrade = upgrade_handler, .open = open_handler, .message = message_handler, .drain = drain_handler, .ping = ping_handler, .pong = pong_handler, .close = close_handler});
|
||||||
|
|
||||||
|
uws_app_listen(SSL, app, 9001, listen_handler, NULL);
|
||||||
|
|
||||||
|
uws_app_run(SSL, app);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+206
-12
@@ -1,26 +1,220 @@
|
|||||||
|
|
||||||
#ifndef LIBUWS_CAPI_HEADER
|
#ifndef LIBUWS_CAPI_HEADER
|
||||||
#define LIBUWS_CAPI_HEADER
|
#define LIBUWS_CAPI_HEADER
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "libusockets.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct uws_app_s;
|
typedef enum
|
||||||
struct uws_req_s;
|
{
|
||||||
struct uws_res_s;
|
/* These are not actual compression options */
|
||||||
typedef struct uws_app_s uws_app_t;
|
_COMPRESSOR_MASK = 0x00FF,
|
||||||
typedef struct uws_req_s uws_req_t;
|
_DECOMPRESSOR_MASK = 0x0F00,
|
||||||
typedef struct uws_res_s uws_res_t;
|
/* Disabled, shared, shared are "special" values */
|
||||||
|
DISABLED = 0,
|
||||||
|
SHARED_COMPRESSOR = 1,
|
||||||
|
SHARED_DECOMPRESSOR = 1 << 8,
|
||||||
|
/* Highest 4 bits describe decompressor */
|
||||||
|
DEDICATED_DECOMPRESSOR_32KB = 15 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_16KB = 14 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_8KB = 13 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_4KB = 12 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_2KB = 11 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_1KB = 10 << 8,
|
||||||
|
DEDICATED_DECOMPRESSOR_512B = 9 << 8,
|
||||||
|
/* Same as 32kb */
|
||||||
|
DEDICATED_DECOMPRESSOR = 15 << 8,
|
||||||
|
|
||||||
uws_app_t *uws_create_app();
|
/* Lowest 8 bit describe compressor */
|
||||||
void uws_app_get(uws_app_t *app, const char *pattern, void (*handler)(uws_res_t *, uws_req_t *));
|
DEDICATED_COMPRESSOR_3KB = 9 << 4 | 1,
|
||||||
void uws_app_run(uws_app_t *);
|
DEDICATED_COMPRESSOR_4KB = 9 << 4 | 2,
|
||||||
|
DEDICATED_COMPRESSOR_8KB = 10 << 4 | 3,
|
||||||
|
DEDICATED_COMPRESSOR_16KB = 11 << 4 | 4,
|
||||||
|
DEDICATED_COMPRESSOR_32KB = 12 << 4 | 5,
|
||||||
|
DEDICATED_COMPRESSOR_64KB = 13 << 4 | 6,
|
||||||
|
DEDICATED_COMPRESSOR_128KB = 14 << 4 | 7,
|
||||||
|
DEDICATED_COMPRESSOR_256KB = 15 << 4 | 8,
|
||||||
|
/* Same as 256kb */
|
||||||
|
DEDICATED_COMPRESSOR = 15 << 4 | 8
|
||||||
|
} uws_compress_options_t;
|
||||||
|
|
||||||
void uws_app_listen(uws_app_t *app, int port, void (*handler)(void *));
|
typedef enum
|
||||||
|
{
|
||||||
|
CONTINUATION = 0,
|
||||||
|
TEXT = 1,
|
||||||
|
BINARY = 2,
|
||||||
|
CLOSE = 8,
|
||||||
|
PING = 9,
|
||||||
|
PONG = 10
|
||||||
|
} uws_opcode_t;
|
||||||
|
|
||||||
void uws_res_end(uws_res_t *res, const char *data, size_t length);
|
typedef enum
|
||||||
|
{
|
||||||
|
BACKPRESSURE,
|
||||||
|
SUCCESS,
|
||||||
|
DROPPED
|
||||||
|
} uws_sendstatus_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
|
||||||
|
int port;
|
||||||
|
const char *host;
|
||||||
|
int options;
|
||||||
|
} uws_app_listen_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool ok;
|
||||||
|
bool has_responded;
|
||||||
|
} uws_try_end_result_t;
|
||||||
|
|
||||||
|
struct uws_app_s;
|
||||||
|
struct uws_req_s;
|
||||||
|
struct uws_res_s;
|
||||||
|
struct uws_websocket_s;
|
||||||
|
struct uws_header_iterator_s;
|
||||||
|
typedef struct uws_app_s uws_app_t;
|
||||||
|
typedef struct uws_req_s uws_req_t;
|
||||||
|
typedef struct uws_res_s uws_res_t;
|
||||||
|
typedef struct uws_socket_context_s uws_socket_context_t;
|
||||||
|
typedef struct uws_websocket_s uws_websocket_t;
|
||||||
|
|
||||||
|
typedef void (*uws_websocket_handler)(uws_websocket_t *ws);
|
||||||
|
typedef void (*uws_websocket_message_handler)(uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode);
|
||||||
|
typedef void (*uws_websocket_ping_pong_handler)(uws_websocket_t *ws, const char *message, size_t length);
|
||||||
|
typedef void (*uws_websocket_close_handler)(uws_websocket_t *ws, int code, const char *message, size_t length);
|
||||||
|
typedef void (*uws_websocket_upgrade_handler)(uws_res_t *response, uws_req_t *request, uws_socket_context_t *context);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uws_compress_options_t compression;
|
||||||
|
/* Maximum message size we can receive */
|
||||||
|
unsigned int maxPayloadLength;
|
||||||
|
/* 2 minutes timeout is good */
|
||||||
|
unsigned short idleTimeout;
|
||||||
|
/* 64kb backpressure is probably good */
|
||||||
|
unsigned int maxBackpressure;
|
||||||
|
bool closeOnBackpressureLimit;
|
||||||
|
/* This one depends on kernel timeouts and is a bad default */
|
||||||
|
bool resetIdleTimeoutOnSend;
|
||||||
|
/* A good default, esp. for newcomers */
|
||||||
|
bool sendPingsAutomatically;
|
||||||
|
/* Maximum socket lifetime in seconds before forced closure (defaults to disabled) */
|
||||||
|
unsigned short maxLifetime;
|
||||||
|
uws_websocket_upgrade_handler upgrade;
|
||||||
|
uws_websocket_handler open;
|
||||||
|
uws_websocket_message_handler message;
|
||||||
|
uws_websocket_handler drain;
|
||||||
|
uws_websocket_ping_pong_handler ping;
|
||||||
|
uws_websocket_ping_pong_handler pong;
|
||||||
|
uws_websocket_close_handler close;
|
||||||
|
} uws_socket_behavior_t;
|
||||||
|
|
||||||
|
typedef void (*uws_listen_handler)(struct us_listen_socket_t *listen_socket, uws_app_listen_config_t config, void *user_data);
|
||||||
|
typedef void (*uws_listen_domain_handler)(struct us_listen_socket_t *listen_socket, const char* domain, int options, void *user_data);
|
||||||
|
typedef void (*uws_method_handler)(uws_res_t *response, uws_req_t *request, void *user_data);
|
||||||
|
typedef void (*uws_filter_handler)(uws_res_t *response, int, void *user_data);
|
||||||
|
typedef void (*uws_missing_server_handler)(const char *hostname, void *user_data);
|
||||||
|
typedef void (*uws_get_headers_server_handler)(const char *header_name, size_t header_name_size, const char *header_value, size_t header_value_size, void *user_data);
|
||||||
|
//Basic HTTP
|
||||||
|
uws_app_t *uws_create_app(int ssl, struct us_socket_context_options_t options);
|
||||||
|
void uws_app_destroy(int ssl, uws_app_t *app);
|
||||||
|
void uws_app_get(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_post(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_options(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_delete(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_patch(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_put(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_head(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_connect(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_trace(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
void uws_app_any(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data);
|
||||||
|
|
||||||
|
void uws_app_run(int ssl, uws_app_t *);
|
||||||
|
|
||||||
|
void uws_app_domain(int ssl, uws_app_t *app, const char* server_name);
|
||||||
|
void uws_app_listen(int ssl, uws_app_t *app, int port, uws_listen_handler handler, void *user_data);
|
||||||
|
void uws_app_listen_with_config(int ssl, uws_app_t *app, uws_app_listen_config_t config, uws_listen_handler handler, void *user_data);
|
||||||
|
void uws_app_listen_domain(int ssl, uws_app_t *app, const char *domain, uws_listen_domain_handler handler, void *user_data);
|
||||||
|
void uws_app_listen_domain_with_options(int ssl, uws_app_t *app, const char *domain, int options, uws_listen_domain_handler handler, void *user_data);
|
||||||
|
|
||||||
|
bool uws_constructor_failed(int ssl, uws_app_t *app);
|
||||||
|
unsigned int uws_num_subscribers(int ssl, uws_app_t *app, const char *topic, size_t topic_length);
|
||||||
|
bool uws_publish(int ssl, uws_app_t *app, const char *topic, size_t topic_length, const char *message, size_t message_length, uws_opcode_t opcode, bool compress);
|
||||||
|
void *uws_get_native_handle(int ssl, uws_app_t *app);
|
||||||
|
void uws_remove_server_name(int ssl, uws_app_t *app, const char *hostname_pattern);
|
||||||
|
void uws_add_server_name(int ssl, uws_app_t *app, const char *hostname_pattern);
|
||||||
|
void uws_add_server_name_with_options(int ssl, uws_app_t *app, const char *hostname_pattern, struct us_socket_context_options_t options);
|
||||||
|
void uws_missing_server_name(int ssl, uws_app_t *app, uws_missing_server_handler handler, void *user_data);
|
||||||
|
void uws_filter(int ssl, uws_app_t *app, uws_filter_handler handler, void *user_data);
|
||||||
|
|
||||||
|
//WebSocket
|
||||||
|
void uws_ws(int ssl, uws_app_t *app, const char *pattern, uws_socket_behavior_t behavior);
|
||||||
|
void *uws_ws_get_user_data(int ssl, uws_websocket_t *ws);
|
||||||
|
void uws_ws_close(int ssl, uws_websocket_t *ws);
|
||||||
|
uws_sendstatus_t uws_ws_send(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode);
|
||||||
|
uws_sendstatus_t uws_ws_send_with_options(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, bool compress, bool fin);
|
||||||
|
uws_sendstatus_t uws_ws_send_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||||
|
uws_sendstatus_t uws_ws_send_first_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||||
|
uws_sendstatus_t uws_ws_send_first_fragment_with_opcode(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode, bool compress);
|
||||||
|
uws_sendstatus_t uws_ws_send_last_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress);
|
||||||
|
void uws_ws_end(int ssl, uws_websocket_t *ws, int code, const char *message, size_t length);
|
||||||
|
void uws_ws_cork(int ssl, uws_websocket_t *ws, void (*handler)(void *user_data), void *user_data);
|
||||||
|
|
||||||
|
bool uws_ws_subscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||||
|
bool uws_ws_unsubscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||||
|
bool uws_ws_is_subscribed(int ssl, uws_websocket_t *ws, const char *topic, size_t length);
|
||||||
|
void uws_ws_iterate_topics(int ssl, uws_websocket_t *ws, void (*callback)(const char *topic, size_t length, void *user_data), void *user_data);
|
||||||
|
bool uws_ws_publish(int ssl, uws_websocket_t *ws, const char *topic, size_t topic_length, const char *message, size_t message_length);
|
||||||
|
bool uws_ws_publish_with_options(int ssl, uws_websocket_t *ws, const char *topic, size_t topic_length, const char *message, size_t message_length, uws_opcode_t opcode, bool compress);
|
||||||
|
unsigned int uws_ws_get_buffered_amount(int ssl, uws_websocket_t *ws);
|
||||||
|
size_t uws_ws_get_remote_address(int ssl, uws_websocket_t *ws, const char **dest);
|
||||||
|
size_t uws_ws_get_remote_address_as_text(int ssl, uws_websocket_t *ws, const char **dest);
|
||||||
|
|
||||||
|
//Response
|
||||||
|
void uws_res_end(int ssl, uws_res_t *res, const char *data, size_t length, bool close_connection);
|
||||||
|
uws_try_end_result_t uws_res_try_end(int ssl, uws_res_t *res, const char *data, size_t length, uintmax_t total_size, bool close_connection);
|
||||||
|
void uws_res_cork(int ssl, uws_res_t *res, void(*callback)(uws_res_t *res, void* user_data) ,void* user_data);
|
||||||
|
void uws_res_pause(int ssl, uws_res_t *res);
|
||||||
|
void uws_res_resume(int ssl, uws_res_t *res);
|
||||||
|
void uws_res_write_continue(int ssl, uws_res_t *res);
|
||||||
|
void uws_res_write_status(int ssl, uws_res_t *res, const char *status, size_t length);
|
||||||
|
void uws_res_write_header(int ssl, uws_res_t *res, const char *key, size_t key_length, const char *value, size_t value_length);
|
||||||
|
|
||||||
|
void uws_res_write_header_int(int ssl, uws_res_t *res, const char *key, size_t key_length, uint64_t value);
|
||||||
|
void uws_res_end_without_body(int ssl, uws_res_t *res, bool close_connection);
|
||||||
|
bool uws_res_write(int ssl, uws_res_t *res, const char *data, size_t length);
|
||||||
|
uintmax_t uws_res_get_write_offset(int ssl, uws_res_t *res);
|
||||||
|
void uws_res_override_write_offset(int ssl, uws_res_t *res, uintmax_t offset);
|
||||||
|
bool uws_res_has_responded(int ssl, uws_res_t *res);
|
||||||
|
void uws_res_on_writable(int ssl, uws_res_t *res, bool (*handler)(uws_res_t *res, uintmax_t, void *opcional_data), void *user_data);
|
||||||
|
void uws_res_on_aborted(int ssl, uws_res_t *res, void (*handler)(uws_res_t *res, void *opcional_data), void *opcional_data);
|
||||||
|
void uws_res_on_data(int ssl, uws_res_t *res, void (*handler)(uws_res_t *res, const char *chunk, size_t chunk_length, bool is_end, void *opcional_data), void *opcional_data);
|
||||||
|
void uws_res_upgrade(int ssl, uws_res_t *res, void *data, const char *sec_web_socket_key, size_t sec_web_socket_key_length, const char *sec_web_socket_protocol, size_t sec_web_socket_protocol_length, const char *sec_web_socket_extensions, size_t sec_web_socket_extensions_length, uws_socket_context_t *ws);
|
||||||
|
|
||||||
|
void *uws_res_get_native_handle(int ssl, uws_res_t *res);
|
||||||
|
|
||||||
|
//Request
|
||||||
|
bool uws_req_is_ancient(uws_req_t *res);
|
||||||
|
bool uws_req_get_yield(uws_req_t *res);
|
||||||
|
void uws_req_set_field(uws_req_t *res, bool yield);
|
||||||
|
size_t uws_req_get_url(uws_req_t *res, const char **dest);
|
||||||
|
size_t uws_req_get_full_url(uws_req_t *res, const char **dest);
|
||||||
|
size_t uws_req_get_method(uws_req_t *res, const char **dest);
|
||||||
|
size_t uws_req_get_header(uws_req_t *res, const char *lower_case_header, size_t lower_case_header_length, const char **dest);
|
||||||
|
void uws_req_for_each_header(uws_req_t *res, uws_get_headers_server_handler handler, void *user_data);
|
||||||
|
size_t uws_req_get_query(uws_req_t *res, const char *key, size_t key_length, const char **dest);
|
||||||
|
size_t uws_req_get_parameter(uws_req_t *res, unsigned short index, const char **dest);
|
||||||
|
|
||||||
|
struct us_loop_t *uws_get_loop();
|
||||||
|
struct us_loop_t *uws_get_loop_with_native(void* existing_native_loop);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user