diff --git a/capi/App.cpp b/capi/App.cpp deleted file mode 100644 index 2b18ad9..0000000 --- a/capi/App.cpp +++ /dev/null @@ -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 *uwsRes = (uWS::HttpResponse *) 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); - }); - } - -} \ No newline at end of file diff --git a/capi/Makefile b/capi/Makefile index 7e99e8e..fc935ad 100644 --- a/capi/Makefile +++ b/capi/Makefile @@ -1,7 +1,38 @@ +CAPI_EXAMPLE_FILES := HelloWorld HelloWorldAsync ServerName UpgradeSync UpgradeAsync EchoServer Broadcast BroadcastEchoServer +RUST_EXAMPLE_FILES := RustHelloWorld +LIBRARY_NAME := libuwebsockets + default: - rm -f *.o - make -C ../uSockets - 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 - gcc -O3 -flto example.c *.o -lstdc++ ../uSockets/uSockets.a -o c_example - rustc -C link-arg=uWebSockets.a -C link-arg=-lstdc++ -C opt-level=3 -C lto -L all=. example.rs -o rust_example \ No newline at end of file + $(MAKE) capi + $(CXX) -O3 -flto -I ../src -I ../uSockets/src examples/HelloWorld.c *.o -lz -luv -lssl -lcrypto -lstdc++ ../uSockets/uSockets.a -o HelloWorld + +capi: + $(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 + $(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 + diff --git a/capi/example.c b/capi/example.c deleted file mode 100644 index 111ee4a..0000000 --- a/capi/example.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "libuwebsockets.h" -#include - -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); -} \ No newline at end of file diff --git a/capi/example.rs b/capi/example.rs deleted file mode 100644 index b3d9787..0000000 --- a/capi/example.rs +++ /dev/null @@ -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::(), - 32usize, - concat!("Size of: ", stringify!(max_align_t)) - ); - assert_eq!( - ::std::mem::align_of::(), - 16usize, - concat!("Alignment of ", stringify!(max_align_t)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).__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::())).__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, - ); -} -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); - } -} \ No newline at end of file diff --git a/capi/examples/Broadcast.c b/capi/examples/Broadcast.c new file mode 100644 index 0000000..dc67873 --- /dev/null +++ b/capi/examples/Broadcast.c @@ -0,0 +1,157 @@ +#include "../libuwebsockets.h" +#include +#include +#include +#include +#include +#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); +} \ No newline at end of file diff --git a/capi/examples/BroadcastEchoServer.c b/capi/examples/BroadcastEchoServer.c new file mode 100644 index 0000000..65e0444 --- /dev/null +++ b/capi/examples/BroadcastEchoServer.c @@ -0,0 +1,175 @@ +#include "../libuwebsockets.h" +#include +#include +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/capi/examples/EchoServer.c b/capi/examples/EchoServer.c new file mode 100644 index 0000000..adcf1ed --- /dev/null +++ b/capi/examples/EchoServer.c @@ -0,0 +1,81 @@ +#include "../libuwebsockets.h" +#include +#include + +#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); +} \ No newline at end of file diff --git a/capi/examples/HelloWorld.c b/capi/examples/HelloWorld.c new file mode 100644 index 0000000..613ba59 --- /dev/null +++ b/capi/examples/HelloWorld.c @@ -0,0 +1,33 @@ +#include "../libuwebsockets.h" +#include "libusockets.h" +#include + +#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); +} diff --git a/capi/examples/HelloWorldAsync.c b/capi/examples/HelloWorldAsync.c new file mode 100644 index 0000000..b8549b0 --- /dev/null +++ b/capi/examples/HelloWorldAsync.c @@ -0,0 +1,123 @@ +#include "../libuwebsockets.h" +#include "libusockets.h" + +#include +#include +#include + +#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); +} diff --git a/capi/examples/RustHelloWorld.rs b/capi/examples/RustHelloWorld.rs new file mode 100644 index 0000000..b122d81 --- /dev/null +++ b/capi/examples/RustHelloWorld.rs @@ -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::(), + 32usize, + concat!("Size of: ", stringify!(max_align_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(max_align_t)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).__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::())).__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 { + native: *mut UwsResT, +} +pub struct AppRequest { + native: *mut UwsReqT, +} +impl AppRequest { + pub fn new(native: *mut UwsReqT) -> AppRequest { + AppRequest { native: native } + } +} +impl AppResponse { + pub fn new(native: *mut UwsResT) -> AppResponse { + AppResponse:: { native: native } + } + fn end(self, message: &str) -> AppResponse { + 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 = fn(res: AppResponse, req: AppRequest); +pub type UwsListenHandler = + fn(listen_socket: *mut ::std::os::raw::c_void, config: UwsAppListenConfigT); + +pub struct TemplateApp { + 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 TemplateApp { + pub fn new(config: UsSocketContextOptions) -> TemplateApp { + 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:: { + native: uws_create_app(SSL, native_options), + } + } + } + pub fn get(self, route: &str, mut handler: UwsMethodHandler) -> TemplateApp { + 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 { + 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 { + 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(); +} diff --git a/capi/examples/ServerName.c b/capi/examples/ServerName.c new file mode 100644 index 0000000..1415823 --- /dev/null +++ b/capi/examples/ServerName.c @@ -0,0 +1,59 @@ +#include "../libuwebsockets.h" +#include +#include +#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); +} \ No newline at end of file diff --git a/capi/examples/UpgradeAsync.c b/capi/examples/UpgradeAsync.c new file mode 100644 index 0000000..3dacd8c --- /dev/null +++ b/capi/examples/UpgradeAsync.c @@ -0,0 +1,255 @@ +#include "../libuwebsockets.h" +#include "libusockets.h" +#include +#include +#include +/* 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); +} \ No newline at end of file diff --git a/capi/examples/UpgradeSync.c b/capi/examples/UpgradeSync.c new file mode 100644 index 0000000..83252b5 --- /dev/null +++ b/capi/examples/UpgradeSync.c @@ -0,0 +1,117 @@ +#include "../libuwebsockets.h" +#include +#include + +#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); +} \ No newline at end of file diff --git a/capi/libuwebsockets.cpp b/capi/libuwebsockets.cpp new file mode 100644 index 0000000..1999562 --- /dev/null +++ b/capi/libuwebsockets.cpp @@ -0,0 +1,1218 @@ +#include "libuwebsockets.h" +#include +#include "App.h" +#include +extern "C" +{ + + uws_app_t *uws_create_app(int ssl, struct us_socket_context_options_t options) + { + if (ssl) + { + uWS::SocketContextOptions sco; + sco.ca_file_name = options.ca_file_name; + sco.cert_file_name = options.cert_file_name; + sco.dh_params_file_name = options.dh_params_file_name; + sco.key_file_name = options.key_file_name; + sco.passphrase = options.passphrase; + sco.ssl_prefer_low_memory_usage = options.ssl_prefer_low_memory_usage; + return (uws_app_t *)new uWS::SSLApp(sco); + } + + return (uws_app_t *)new uWS::App(); + } + + void uws_app_get(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->get(pattern, nullptr); + return; + } + uwsApp->get(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->get(pattern, nullptr); + return; + } + uwsApp->get(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_post(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->post(pattern, nullptr); + return; + } + uwsApp->post(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->post(pattern, nullptr); + return; + } + uwsApp->post(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_options(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->options(pattern, nullptr); + return; + } + uwsApp->options(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->options(pattern, nullptr); + return; + } + uwsApp->options(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_delete(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->del(pattern, nullptr); + return; + } + uwsApp->del(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->del(pattern, nullptr); + return; + } + uwsApp->del(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_patch(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->patch(pattern, nullptr); + return; + } + uwsApp->patch(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->patch(pattern, nullptr); + return; + } + uwsApp->patch(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_put(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->put(pattern, nullptr); + return; + } + uwsApp->put(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->put(pattern, nullptr); + return; + } + uwsApp->put(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_head(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->head(pattern, nullptr); + return; + } + uwsApp->head(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->head(pattern, nullptr); + return; + } + uwsApp->head(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_connect(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->connect(pattern, nullptr); + return; + } + uwsApp->connect(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->connect(pattern, nullptr); + return; + } + uwsApp->connect(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + + void uws_app_trace(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->trace(pattern, nullptr); + return; + } + uwsApp->trace(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->trace(pattern, nullptr); + return; + } + uwsApp->trace(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + void uws_app_any(int ssl, uws_app_t *app, const char *pattern, uws_method_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (handler == nullptr) + { + uwsApp->any(pattern, nullptr); + return; + } + uwsApp->any(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + if (handler == nullptr) + { + uwsApp->any(pattern, nullptr); + return; + } + uwsApp->any(pattern, [handler, user_data](auto *res, auto *req) + { handler((uws_res_t *)res, (uws_req_t *)req, user_data); }); + } + } + + void uws_app_run(int ssl, uws_app_t *app) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->run(); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->run(); + } + } + + void uws_app_listen(int ssl, uws_app_t *app, int port, uws_listen_handler handler, void *user_data) + { + uws_app_listen_config_t config; + config.port = port; + config.host = nullptr; + config.options = 0; + + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->listen(port, [handler, config, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, config, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + + uwsApp->listen(port, [handler, config, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, config, 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) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->listen(config.host, config.port, config.options, [handler, config, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, config, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->listen(config.host, config.port, config.options, [handler, config, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, config, user_data); }); + } + } + + /* callback, path to unix domain socket */ + void uws_app_listen_domain(int ssl, uws_app_t *app, const char *domain, uws_listen_domain_handler handler, void *user_data) + { + + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->listen([handler, domain, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, domain, 0, user_data); }, + domain); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + + uwsApp->listen([handler, domain, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, domain, 0, user_data); }, + domain); + } + } + + /* callback, path to unix domain socket */ + 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) + { + + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->listen( + options, [handler, domain, options, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, domain, options, user_data); }, + domain); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + + uwsApp->listen( + options, [handler, domain, options, user_data](struct us_listen_socket_t *listen_socket) + { handler((struct us_listen_socket_t *)listen_socket, domain, options, user_data); }, + domain); + } + } + void uws_app_domain(int ssl, uws_app_t *app, const char *server_name) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->domain(server_name); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->domain(server_name); + } + } + void uws_app_destroy(int ssl, uws_app_t *app) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + delete uwsApp; + } + else + { + + uWS::App *uwsApp = (uWS::App *)app; + delete uwsApp; + } + } + + bool uws_constructor_failed(int ssl, uws_app_t *app) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + if (!uwsApp) + return true; + return uwsApp->constructorFailed(); + } + uWS::App *uwsApp = (uWS::App *)app; + if (!uwsApp) + return true; + return uwsApp->constructorFailed(); + } + + unsigned int uws_num_subscribers(int ssl, uws_app_t *app, const char *topic, size_t topic_length) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + return uwsApp->numSubscribers(std::string_view(topic, topic_length)); + } + uWS::App *uwsApp = (uWS::App *)app; + return uwsApp->numSubscribers(std::string_view(topic, 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) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + return uwsApp->publish(std::string_view(topic, topic_length), std::string_view(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); + } + uWS::App *uwsApp = (uWS::App *)app; + return uwsApp->publish(std::string_view(topic, topic_length), std::string_view(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); + } + void *uws_get_native_handle(int ssl, uws_app_t *app) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + return uwsApp->getNativeHandle(); + } + uWS::App *uwsApp = (uWS::App *)app; + return uwsApp->getNativeHandle(); + } + void uws_remove_server_name(int ssl, uws_app_t *app, const char *hostname_pattern) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->removeServerName(hostname_pattern); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->removeServerName(hostname_pattern); + } + } + void uws_add_server_name(int ssl, uws_app_t *app, const char *hostname_pattern) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->addServerName(hostname_pattern); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->addServerName(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) + { + uWS::SocketContextOptions sco; + sco.ca_file_name = options.ca_file_name; + sco.cert_file_name = options.cert_file_name; + sco.dh_params_file_name = options.dh_params_file_name; + sco.key_file_name = options.key_file_name; + sco.passphrase = options.passphrase; + sco.ssl_prefer_low_memory_usage = options.ssl_prefer_low_memory_usage; + + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->addServerName(hostname_pattern, sco); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->addServerName(hostname_pattern, sco); + } + } + + void uws_missing_server_name(int ssl, uws_app_t *app, uws_missing_server_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->missingServerName([handler, user_data](auto hostname) + { handler(hostname, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->missingServerName([handler, user_data](auto hostname) + { handler(hostname, user_data); }); + } + } + void uws_filter(int ssl, uws_app_t *app, uws_filter_handler handler, void *user_data) + { + if (ssl) + { + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + uwsApp->filter([handler, user_data](auto res, auto i) + { handler((uws_res_t *)res, i, user_data); }); + } + else + { + uWS::App *uwsApp = (uWS::App *)app; + + uwsApp->filter([handler, user_data](auto res, auto i) + { handler((uws_res_t *)res, i, user_data); }); + } + } + + void uws_ws(int ssl, uws_app_t *app, const char *pattern, uws_socket_behavior_t behavior) + { + if (ssl) + { + auto generic_handler = uWS::SSLApp::WebSocketBehavior{ + .compression = (uWS::CompressOptions)(uint64_t)behavior.compression, + .maxPayloadLength = behavior.maxPayloadLength, + .idleTimeout = behavior.idleTimeout, + .maxBackpressure = behavior.maxBackpressure, + .closeOnBackpressureLimit = behavior.closeOnBackpressureLimit, + .resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend, + .sendPingsAutomatically = behavior.sendPingsAutomatically, + .maxLifetime = behavior.maxLifetime, + }; + + if (behavior.upgrade) + generic_handler.upgrade = [behavior](auto *res, auto *req, auto *context) + { + behavior.upgrade((uws_res_t *)res, (uws_req_t *)req, (uws_socket_context_t *)context); + }; + if (behavior.open) + generic_handler.open = [behavior](auto *ws) + { + behavior.open((uws_websocket_t *)ws); + }; + if (behavior.message) + generic_handler.message = [behavior](auto *ws, auto message, auto opcode) + { + behavior.message((uws_websocket_t *)ws, message.data(), message.length(), (uws_opcode_t)opcode); + }; + if (behavior.drain) + generic_handler.drain = [behavior](auto *ws) + { + behavior.drain((uws_websocket_t *)ws); + }; + if (behavior.ping) + generic_handler.ping = [behavior](auto *ws, auto message) + { + behavior.ping((uws_websocket_t *)ws, message.data(), message.length()); + }; + if (behavior.pong) + generic_handler.pong = [behavior](auto *ws, auto message) + { + behavior.pong((uws_websocket_t *)ws, message.data(), message.length()); + }; + if (behavior.close) + generic_handler.close = [behavior](auto *ws, int code, auto message) + { + behavior.close((uws_websocket_t *)ws, code, message.data(), message.length()); + }; + uWS::SSLApp *uwsApp = (uWS::SSLApp *)app; + + uwsApp->ws(pattern, std::move(generic_handler)); + } + else + { + auto generic_handler = uWS::App::WebSocketBehavior{ + .compression = (uWS::CompressOptions)(uint64_t)behavior.compression, + .maxPayloadLength = behavior.maxPayloadLength, + .idleTimeout = behavior.idleTimeout, + .maxBackpressure = behavior.maxBackpressure, + .closeOnBackpressureLimit = behavior.closeOnBackpressureLimit, + .resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend, + .sendPingsAutomatically = behavior.sendPingsAutomatically, + .maxLifetime = behavior.maxLifetime, + }; + + if (behavior.upgrade) + generic_handler.upgrade = [behavior](auto *res, auto *req, auto *context) + { + behavior.upgrade((uws_res_t *)res, (uws_req_t *)req, (uws_socket_context_t *)context); + }; + if (behavior.open) + generic_handler.open = [behavior](auto *ws) + { + behavior.open((uws_websocket_t *)ws); + }; + if (behavior.message) + generic_handler.message = [behavior](auto *ws, auto message, auto opcode) + { + behavior.message((uws_websocket_t *)ws, message.data(), message.length(), (uws_opcode_t)opcode); + }; + if (behavior.drain) + generic_handler.drain = [behavior](auto *ws) + { + behavior.drain((uws_websocket_t *)ws); + }; + if (behavior.ping) + generic_handler.ping = [behavior](auto *ws, auto message) + { + behavior.ping((uws_websocket_t *)ws, message.data(), message.length()); + }; + if (behavior.pong) + generic_handler.pong = [behavior](auto *ws, auto message) + { + behavior.pong((uws_websocket_t *)ws, message.data(), message.length()); + }; + if (behavior.close) + generic_handler.close = [behavior](auto *ws, int code, auto message) + { + behavior.close((uws_websocket_t *)ws, code, message.data(), message.length()); + }; + uWS::App *uwsApp = (uWS::App *)app; + uwsApp->ws(pattern, std::move(generic_handler)); + } + } + + void *uws_ws_get_user_data(int ssl, uws_websocket_t *ws) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return *uws->getUserData(); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return *uws->getUserData(); + } + + void uws_ws_close(int ssl, uws_websocket_t *ws) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->close(); + } + else + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->close(); + } + } + + uws_sendstatus_t uws_ws_send(int ssl, uws_websocket_t *ws, const char *message, size_t length, uws_opcode_t opcode) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->send(std::string_view(message, length), (uWS::OpCode)(unsigned char)opcode); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->send(std::string_view(message, length), (uWS::OpCode)(unsigned char)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) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->send(std::string_view(message), (uWS::OpCode)(unsigned char)opcode, compress, fin); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->send(std::string_view(message), (uWS::OpCode)(unsigned char)opcode, compress, fin); + } + + uws_sendstatus_t uws_ws_send_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFragment(std::string_view(message, length), compress); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFragment(std::string_view(message, length), compress); + } + uws_sendstatus_t uws_ws_send_first_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFirstFragment(std::string_view(message), uWS::OpCode::BINARY, compress); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFirstFragment(std::string_view(message), uWS::OpCode::BINARY, 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) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFirstFragment(std::string_view(message, length), (uWS::OpCode)(unsigned char)opcode, compress); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendFirstFragment(std::string_view(message, length), (uWS::OpCode)(unsigned char)opcode, compress); + } + uws_sendstatus_t uws_ws_send_last_fragment(int ssl, uws_websocket_t *ws, const char *message, size_t length, bool compress) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendLastFragment(std::string_view(message, length), compress); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return (uws_sendstatus_t)uws->sendLastFragment(std::string_view(message, length), compress); + } + + void uws_ws_end(int ssl, uws_websocket_t *ws, int code, const char *message, size_t length) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->end(code, std::string_view(message, length)); + } + else + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->end(code, std::string_view(message, length)); + } + } + + void uws_ws_cork(int ssl, uws_websocket_t *ws, void (*handler)(void *user_data), void *user_data) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->cork([handler, user_data]() + { handler(user_data); }); + } + else + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + + uws->cork([handler, user_data]() + { handler(user_data); }); + } + } + bool uws_ws_subscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->subscribe(std::string_view(topic, length)); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->subscribe(std::string_view(topic, length)); + } + bool uws_ws_unsubscribe(int ssl, uws_websocket_t *ws, const char *topic, size_t length) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->unsubscribe(std::string_view(topic, length)); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->unsubscribe(std::string_view(topic, length)); + } + + bool uws_ws_is_subscribed(int ssl, uws_websocket_t *ws, const char *topic, size_t length) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->isSubscribed(std::string_view(topic, length)); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->isSubscribed(std::string_view(topic, 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) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + uws->iterateTopics([callback, user_data](auto topic) + { callback(topic.data(), topic.length(), user_data); }); + } + else + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + + uws->iterateTopics([callback, user_data](auto topic) + { callback(topic.data(), topic.length(), 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) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->publish(std::string_view(topic, topic_length), std::string_view(message, message_length)); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->publish(std::string_view(topic, topic_length), std::string_view(message, 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) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->publish(std::string_view(topic, topic_length), std::string_view(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->publish(std::string_view(topic, topic_length), std::string_view(message, message_length), (uWS::OpCode)(unsigned char)opcode, compress); + } + + unsigned int uws_ws_get_buffered_amount(int ssl, uws_websocket_t *ws) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->getBufferedAmount(); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + return uws->getBufferedAmount(); + } + + size_t uws_ws_get_remote_address(int ssl, uws_websocket_t *ws, const char **dest) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + std::string_view value = uws->getRemoteAddress(); + *dest = value.data(); + return value.length(); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + + std::string_view value = uws->getRemoteAddress(); + *dest = value.data(); + return value.length(); + } + + size_t uws_ws_get_remote_address_as_text(int ssl, uws_websocket_t *ws, const char **dest) + { + if (ssl) + { + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + + std::string_view value = uws->getRemoteAddressAsText(); + *dest = value.data(); + return value.length(); + } + uWS::WebSocket *uws = (uWS::WebSocket *)ws; + + std::string_view value = uws->getRemoteAddressAsText(); + *dest = value.data(); + return value.length(); + } + + void uws_res_end(int ssl, uws_res_t *res, const char *data, size_t length, bool close_connection) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->end(std::string_view(data, length), close_connection); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->end(std::string_view(data, length), 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) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + // uwsRes->end(std::string_view(data, length), close_connection); + std::pair result = uwsRes->tryEnd(std::string_view(data, length), total_size, close_connection); + return uws_try_end_result_t{ + .ok = result.first, + .has_responded = result.second, + }; + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + std::pair result = uwsRes->tryEnd(std::string_view(data, length), total_size); + return uws_try_end_result_t{ + .ok = result.first, + .has_responded = result.second, + }; + } + } + + + void uws_res_cork(int ssl, uws_res_t *res, void (*callback)(uws_res_t *res, void *user_data), void *user_data) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->cork([=]() + { callback(res, user_data); }); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->cork([=]() + { callback(res, user_data); }); + } + } + + void uws_res_pause(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->pause(); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->pause(); + } + } + + void uws_res_resume(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->pause(); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->pause(); + } + } + + void uws_res_write_continue(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeContinue(); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeContinue(); + } + } + + void uws_res_write_status(int ssl, uws_res_t *res, const char *status, size_t length) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeStatus(std::string_view(status, length)); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeStatus(std::string_view(status, 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) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeHeader(std::string_view(key, key_length), std::string_view(value, value_length)); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeHeader(std::string_view(key, key_length), std::string_view(value, value_length)); + } + } + void uws_res_write_header_int(int ssl, uws_res_t *res, const char *key, size_t key_length, uint64_t value) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeHeader(std::string_view(key, key_length), value); + } + else + { + + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->writeHeader(std::string_view(key, key_length), value); + } + } + + void uws_res_end_without_body(int ssl, uws_res_t *res, bool close_connection) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->endWithoutBody(std::nullopt, close_connection); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->endWithoutBody(std::nullopt, close_connection); + } + } + + bool uws_res_write(int ssl, uws_res_t *res, const char *data, size_t length) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->write(std::string_view(data)); + } + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->write(std::string_view(data)); + } + uintmax_t uws_res_get_write_offset(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->getWriteOffset(); + } + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->getWriteOffset(); + } + void uws_res_override_write_offset(int ssl, uws_res_t *res, uintmax_t offset) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->overrideWriteOffset(offset); + } + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->overrideWriteOffset(offset); + } + bool uws_res_has_responded(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->hasResponded(); + } + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->hasResponded(); + } + + void uws_res_on_writable(int ssl, uws_res_t *res, bool (*handler)(uws_res_t *res, uintmax_t, void *opcional_data), void *opcional_data) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onWritable([handler, res, opcional_data](uintmax_t a) + { return handler(res, a, opcional_data); }); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onWritable([handler, res, opcional_data](uintmax_t a) + { return handler(res, a, opcional_data); }); + } + } + + void uws_res_on_aborted(int ssl, uws_res_t *res, void (*handler)(uws_res_t *res, void *opcional_data), void *opcional_data) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onAborted([handler, res, opcional_data] + { handler(res, opcional_data); }); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onAborted([handler, res, opcional_data] + { handler(res, 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) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onData([handler, res, opcional_data](auto chunk, bool is_end) + { handler(res, chunk.data(), chunk.length(), is_end, opcional_data); }); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + uwsRes->onData([handler, res, opcional_data](auto chunk, bool is_end) + { handler(res, chunk.data(), chunk.length(), is_end, opcional_data); }); + } + } + + bool uws_req_is_ancient(uws_req_t *res) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + return uwsReq->isAncient(); + } + + bool uws_req_get_yield(uws_req_t *res) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + return uwsReq->getYield(); + } + + void uws_req_set_field(uws_req_t *res, bool yield) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + return uwsReq->setYield(yield); + } + + size_t uws_req_get_url(uws_req_t *res, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + std::string_view value = uwsReq->getUrl(); + *dest = value.data(); + return value.length(); + } + + size_t uws_req_get_full_url(uws_req_t *res, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + std::string_view value = uwsReq->getFullUrl(); + *dest = value.data(); + return value.length(); + } + + size_t uws_req_get_method(uws_req_t *res, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + std::string_view value = uwsReq->getMethod(); + *dest = value.data(); + return value.length(); + } + + void uws_req_for_each_header(uws_req_t *res, uws_get_headers_server_handler handler, void *user_data) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + for (auto header : *uwsReq) + { + handler(header.first.data(), header.first.length(), header.second.data(), header.second.length(), user_data); + } + } + + size_t uws_req_get_header(uws_req_t *res, const char *lower_case_header, size_t lower_case_header_length, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + + std::string_view value = uwsReq->getHeader(std::string_view(lower_case_header, lower_case_header_length)); + *dest = value.data(); + return value.length(); + } + + size_t uws_req_get_query(uws_req_t *res, const char *key, size_t key_length, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + + std::string_view value = uwsReq->getQuery(std::string_view(key, key_length)); + *dest = value.data(); + return value.length(); + } + + size_t uws_req_get_parameter(uws_req_t *res, unsigned short index, const char **dest) + { + uWS::HttpRequest *uwsReq = (uWS::HttpRequest *)res; + std::string_view value = uwsReq->getParameter(index); + *dest = value.data(); + return value.length(); + } + + 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) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + + uwsRes->template upgrade(data ? std::move(data) : NULL, + std::string_view(sec_web_socket_key, sec_web_socket_key_length), + std::string_view(sec_web_socket_protocol, sec_web_socket_protocol_length), + std::string_view(sec_web_socket_extensions, sec_web_socket_extensions_length), + (struct us_socket_context_t *)ws); + } + + + void *uws_res_get_native_handle(int ssl, uws_res_t *res) + { + if (ssl) + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->getNativeHandle(); + } + else + { + uWS::HttpResponse *uwsRes = (uWS::HttpResponse *)res; + return uwsRes->getNativeHandle(); + } + } + + struct us_loop_t *uws_get_loop() + { + return (struct us_loop_t *)uWS::Loop::get(); + } + + struct us_loop_t *uws_get_loop_with_native(void *existing_native_loop) + { + return (struct us_loop_t *)uWS::Loop::get(existing_native_loop); + } +} \ No newline at end of file diff --git a/capi/libuwebsockets.h b/capi/libuwebsockets.h index a30a8b9..4135146 100644 --- a/capi/libuwebsockets.h +++ b/capi/libuwebsockets.h @@ -1,26 +1,220 @@ + #ifndef LIBUWS_CAPI_HEADER #define LIBUWS_CAPI_HEADER #include +#include +#include +#include "libusockets.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -struct uws_app_s; -struct uws_req_s; -struct uws_res_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 enum + { + /* These are not actual compression options */ + _COMPRESSOR_MASK = 0x00FF, + _DECOMPRESSOR_MASK = 0x0F00, + /* 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(); -void uws_app_get(uws_app_t *app, const char *pattern, void (*handler)(uws_res_t *, uws_req_t *)); -void uws_app_run(uws_app_t *); + /* Lowest 8 bit describe compressor */ + DEDICATED_COMPRESSOR_3KB = 9 << 4 | 1, + 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 }