diff --git a/.gitattributes b/.gitattributes index 15a5c580..fb0a8332 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,4 @@ *.h linguist-language=C +examples/* linguist-vendored +misc/* linguist-vendored +tests/* linguist-vendored diff --git a/Makefile b/Makefile index f6e2c6ba..72557597 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ else override LDFLAGS += -L/usr/local/lib -lwolfssl else override CFLAGS += -DLIBUS_NO_SSL + override RUSTFLAGS += --cfg LIBUS_NO_SSL endif endif endif @@ -30,6 +31,7 @@ endif # WITH_LIBUV=1 builds with libuv as event-loop ifeq ($(WITH_LIBUV),1) override CFLAGS += -DLIBUS_USE_LIBUV + override RUSTFLAGS += --cfg LIBUS_USE_LIBUV override LDFLAGS += -luv endif @@ -57,12 +59,14 @@ ifeq ($(WITH_QUIC),1) override LDFLAGS += -pthread -lz -lm uSockets.a lsquic/src/liblsquic/liblsquic.a else override CFLAGS += -std=c11 -Isrc - override LDFLAGS += uSockets.a + override LDFLAGS += uSockets.a libflush.a endif # By default we build the uSockets.a static library default: rm -f *.o + # Do require Rust as experiment + rustc $(RUSTFLAGS) src/flush.rs -Clto --crate-type=staticlib -O $(CC) $(CFLAGS) -O3 -c src/*.c src/eventing/*.c src/crypto/*.c # Also link in Boost Asio support ifeq ($(WITH_ASIO),1) @@ -78,6 +82,7 @@ ifeq ($(WITH_BORINGSSL),1) endif # Create a static library (try windows, then unix) lib.exe /out:uSockets.a *.o || $(AR) rvs uSockets.a *.o + cp flush.lib libflush.a || echo ok # BoringSSL needs cmake and golang .PHONY: boringssl diff --git a/src/bsd.c b/src/bsd.c index 33ecb443..7993431d 100644 --- a/src/bsd.c +++ b/src/bsd.c @@ -299,14 +299,6 @@ LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) { return bsd_set_nonblocking(apple_no_sigpipe(created_fd)); } -void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) { -#ifdef _WIN32 - closesocket(fd); -#else - close(fd); -#endif -} - void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) { #ifdef _WIN32 shutdown(fd, SD_SEND); @@ -393,10 +385,6 @@ LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd)); } -int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { - return recv(fd, buf, length, flags); -} - int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) { // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD) diff --git a/src/context.c b/src/context.c index 514d2e69..ef2d7b29 100644 --- a/src/context.c +++ b/src/context.c @@ -20,16 +20,10 @@ #include #include -int default_is_low_prio_handler(struct us_socket_t *s) { - return 0; -} +int default_is_low_prio_handler(struct us_socket_t *s); /* Shared with SSL */ -unsigned short us_socket_context_timestamp(int ssl, struct us_socket_context_t *context) { - return context->timestamp; -} - void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) { /* us_listen_socket_t extends us_socket_t so we close in similar ways */ if (!us_socket_is_closed(0, &ls->s)) { @@ -128,10 +122,6 @@ void us_internal_socket_context_link_socket(struct us_socket_context_t *context, context->head_sockets = s; } -struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) { - return context->loop; -} - /* Not shared with SSL */ /* Lookup userdata by server name pattern */ @@ -198,53 +188,6 @@ void *us_socket_context_get_native_handle(int ssl, struct us_socket_context_t *c return 0; } -/* Options is currently only applicable for SSL - this will change with time (prefer_low_memory is one example) */ -struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *loop, int context_ext_size, struct us_socket_context_options_t options) { -#ifndef LIBUS_NO_SSL - if (ssl) { - /* This function will call us, again, with SSL = false and a bigger ext_size */ - return (struct us_socket_context_t *) us_internal_create_ssl_socket_context(loop, context_ext_size, options); - } -#endif - - /* This path is taken once either way - always BEFORE whatever SSL may do LATER. - * context_ext_size will however be modified larger in case of SSL, to hold SSL extensions */ - - struct us_socket_context_t *context = malloc(sizeof(struct us_socket_context_t) + context_ext_size); - context->loop = loop; - context->head_sockets = 0; - context->head_listen_sockets = 0; - context->iterator = 0; - context->next = 0; - context->is_low_prio = default_is_low_prio_handler; - - /* Begin at 0 */ - context->timestamp = 0; - context->long_timestamp = 0; - context->global_tick = 0; - - us_internal_loop_link(loop, context); - - /* If we are called from within SSL code, SSL code will make further changes to us */ - return context; -} - -void us_socket_context_free(int ssl, struct us_socket_context_t *context) { -#ifndef LIBUS_NO_SSL - if (ssl) { - /* This function will call us again with SSL=false */ - us_internal_ssl_socket_context_free((struct us_internal_ssl_socket_context_t *) context); - return; - } -#endif - - /* This path is taken once either way - always AFTER whatever SSL may do BEFORE. - * This is the opposite order compared to when creating the context - SSL code is cleaning up before non-SSL */ - - us_internal_loop_unlink(context->loop, context); - free(context); -} - struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) { #ifndef LIBUS_NO_SSL if (ssl) { @@ -412,94 +355,6 @@ struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_con return new_s; } -void us_socket_context_on_open(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_open((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int, char *, int)) on_open); - return; - } -#endif - - context->on_open = on_open; -} - -void us_socket_context_on_close(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_close((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int code, void *reason)) on_close); - return; - } -#endif - - context->on_close = on_close; -} - -void us_socket_context_on_data(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_data((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int)) on_data); - return; - } -#endif - - context->on_data = on_data; -} - -void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_writable)(struct us_socket_t *s)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_writable((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_writable); - return; - } -#endif - - context->on_writable = on_writable; -} - -void us_socket_context_on_long_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_long_timeout)(struct us_socket_t *)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_long_timeout((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_long_timeout); - return; - } -#endif - - context->on_socket_long_timeout = on_long_timeout; -} - -void us_socket_context_on_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_timeout)(struct us_socket_t *)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_timeout((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_timeout); - return; - } -#endif - - context->on_socket_timeout = on_timeout; -} - -void us_socket_context_on_end(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_end)(struct us_socket_t *)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_end((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_end); - return; - } -#endif - - context->on_end = on_end; -} - -void us_socket_context_on_connect_error(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_connect_error)(struct us_socket_t *s, int code)) { -#ifndef LIBUS_NO_SSL - if (ssl) { - us_internal_ssl_socket_context_on_connect_error((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int)) on_connect_error); - return; - } -#endif - - context->on_connect_error = on_connect_error; -} - void *us_socket_context_ext(int ssl, struct us_socket_context_t *context) { #ifndef LIBUS_NO_SSL if (ssl) { diff --git a/src/epoll_kqueue.rs b/src/epoll_kqueue.rs new file mode 100644 index 00000000..212d2651 --- /dev/null +++ b/src/epoll_kqueue.rs @@ -0,0 +1,63 @@ +use super::*; + +struct epoll_event { + events: u32, /* Epoll events */ + data: u64 /* User data variable */ +} + +struct kevent { + ident: usize, /* identifier for this event */ + filter: i16, /* filter for event */ + flags: u16, /* action flags for kqueue */ + fflags: u32, /* filter flag value */ + data: i64, /* filter data value */ + udata: usize /* opaque user data identifier */ +} + + +const LIBUS_SOCKET_READABLE: i32 = 1; +const LIBUS_SOCKET_WRITABLE: i32 = 2; + +#[repr(C)] +pub struct us_loop_t { + /* us_loop_t is always convertible to us_internal_loop_data_t */ + pub data: us_internal_loop_data_t, + + /* Number of non-fallthrough polls in the loop */ + num_polls: i32, + + /* Number of ready polls this iteration */ + num_ready_polls: i32, + + /* Current index in list of ready polls */ + current_ready_poll: i32, + + /* Loop's own file descriptor */ + fd: i32, + + /* The list of ready polls */ + #[cfg(LIBUS_USE_EPOLL)] + ready_polls: [epoll_event; 1024], + #[cfg(not(LIBUS_USE_EPOLL))] + ready_polls: [kevent; 1024] +} + +pub struct us_poll_t { + data: u32 + // alignas(LIBUS_EXT_ALIGNMENT) struct { + // signed int fd : 28; // we could have this unsigned if we wanted to, -1 should never be used + // unsigned int poll_type : 4; + // } state; +} + +/* Loop */ +#[no_mangle] +pub unsafe extern "C" fn us_loop_free(_loop: *mut us_loop_t) { + us_internal_loop_data_free(_loop/*(*_loop)*//*.data*/); + close((*_loop).fd); + free(_loop as *mut us_socket_context_t); +} + +unsafe fn k() { + bsd_socket_flush(0); +} \ No newline at end of file diff --git a/src/eventing/epoll_kqueue.c b/src/eventing/epoll_kqueue.c index c4444b7f..7f586200 100644 --- a/src/eventing/epoll_kqueue.c +++ b/src/eventing/epoll_kqueue.c @@ -32,13 +32,6 @@ #define SET_READY_POLL(loop, index, poll) loop->ready_polls[index].udata = poll #endif -/* Loop */ -void us_loop_free(struct us_loop_t *loop) { - us_internal_loop_data_free(loop); - close(loop->fd); - free(loop); -} - /* Poll */ struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { if (!fallthrough) { diff --git a/src/flush.rs b/src/flush.rs new file mode 100644 index 00000000..9dfec460 --- /dev/null +++ b/src/flush.rs @@ -0,0 +1,418 @@ +//#[cfg(any(LIBUS_USE_LIBUV, LIBUS_USE_ASIO)))] +//pub mod epoll_kqueue; +//#[cfg(not(any(LIBUS_USE_LIBUV, LIBUS_USE_ASIO)))] + +#[cfg(not(any(LIBUS_USE_LIBUV, LIBUS_USE_ASIO, LIBUS_USE_GCD)))] +pub mod epoll_kqueue; +#[cfg(not(any(LIBUS_USE_LIBUV, LIBUS_USE_ASIO, LIBUS_USE_GCD)))] +use epoll_kqueue::*; + +#[cfg(LIBUS_USE_LIBUV)] +pub struct us_loop_t { + +} + +extern "C" { + fn us_socket_is_shut_down(ssl: i32, s: u64) -> i32; + fn bsd_socket_flush(fd: i32); + fn bsd_shutdown_socket_read(fd: i32); + fn us_poll_fd(p: u64) -> i32; + fn us_internal_create_async(loop_data: *mut us_internal_loop_data_t, fallthrough: i32, ext_size: i32) -> *mut us_socket_context_t; + fn us_internal_async_set(_async: *mut us_socket_context_t, cb: *mut us_socket_context_t); + fn us_create_timer(loop_data: *mut us_internal_loop_data_t, fallthrough: i32, ext_size: i32) -> *mut us_socket_context_t; + + fn us_internal_ssl_socket_context_on_data(context: *mut us_socket_context_t, on_data: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_open(context: *mut us_socket_context_t, on_open: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_close(context: *mut us_socket_context_t, on_close: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_connect_error(context: *mut us_socket_context_t, on_connect_error: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_end(context: *mut us_socket_context_t, on_end: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_writable(context: *mut us_socket_context_t, on_writable: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_socket_timeout(context: *mut us_socket_context_t, on_socket_timeout: *mut us_socket_context_t); + fn us_internal_ssl_socket_context_on_socket_long_timeout(context: *mut us_socket_context_t, on_socket_long_timeout: *mut us_socket_context_t); + + fn recv(fd: i32, buf: u64, length: i32, flags: i32) -> i32; + fn closesocket(fd: i32); // only on windows + fn close(fd: i32); // not on windows? + fn malloc(size: usize) -> *mut us_socket_context_t; + fn free(m: *mut us_socket_context_t); + + + // for kqueue temporary + fn us_timer_close(timer: *mut us_socket_context_t); + fn us_internal_async_close(timer: *mut us_socket_context_t); +} + +#[repr(C)] +pub struct us_socket_context_options_t { + key_file_name: *const char, + cert_file_name: *const char, + passphrase: *const char, + dh_params_file_name: *const char, + ca_file_name: *const char, + ssl_ciphers: *const char, + ssl_prefer_low_memory_usage: i32 /* Todo: rename to prefer_low_memory_usage and apply for TCP as well */ +} + +#[repr(C)] +pub struct us_socket_context_t { + _loop: *mut us_internal_loop_data_t, + global_tick: u32, + timestamp: u8, + long_timestamp: u8, + + head_sockets: u64, + head_listen_sockets: u64, + iterator: u64, + prev: *mut us_socket_context_t, + next: *mut us_socket_context_t, + + /*struct us_socket_t *(*on_open)(struct us_socket_t *, int is_client, char *ip, int ip_length); + struct us_socket_t *(*on_data)(struct us_socket_t *, char *data, int length); + struct us_socket_t *(*on_writable)(struct us_socket_t *); + struct us_socket_t *(*on_close)(struct us_socket_t *, int code, void *reason); + //void (*on_timeout)(struct us_socket_context *); + struct us_socket_t *(*on_socket_timeout)(struct us_socket_t *); + struct us_socket_t *(*on_socket_long_timeout)(struct us_socket_t *); + struct us_socket_t *(*on_end)(struct us_socket_t *); + struct us_socket_t *(*on_connect_error)(struct us_socket_t *, int code); + int (*is_low_prio)(struct us_socket_t *);*/ + + on_open: *mut us_socket_context_t, + on_data: *mut us_socket_context_t, + on_writable: *mut us_socket_context_t, + on_close: *mut us_socket_context_t, + on_socket_timeout: *mut us_socket_context_t, + on_socket_long_timeout: *mut us_socket_context_t, + on_end: *mut us_socket_context_t, + on_connect_error: *mut us_socket_context_t, + is_low_prio: unsafe extern "C" fn (_s: u64) -> i32 +} + +#[no_mangle] +pub unsafe extern "C" fn us_internal_loop_data_free(_loop: *mut us_loop_t) { + #[cfg(not(LIBUS_NO_SSL))] + us_internal_free_loop_ssl_data(_loop); + + let loop_data = _loop as *mut us_internal_loop_data_t; + + free((*loop_data).recv_buf); + + us_timer_close((*loop_data).sweep_timer); + us_internal_async_close((*loop_data).wakeup_async); +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_data(ssl: i32, context: *mut us_socket_context_t, on_data: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_data(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_data); + return; + } + + (*context).on_data = on_data; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_open(ssl: i32, context: *mut us_socket_context_t, on_open: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_open(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_open); + return; + } + + (*context).on_open = on_open; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_close(ssl: i32, context: *mut us_socket_context_t, on_close: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_close(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_close); + return; + } + + (*context).on_close = on_close; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_end(ssl: i32, context: *mut us_socket_context_t, on_end: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_end(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_end); + return; + } + + (*context).on_end = on_end; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_connect_error(ssl: i32, context: *mut us_socket_context_t, on_connect_error: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_connect_error(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_connect_error); + return; + } + + (*context).on_connect_error = on_connect_error; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_timeout(ssl: i32, context: *mut us_socket_context_t, on_timeout: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_timeout(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_timeout); + return; + } + + (*context).on_socket_timeout = on_timeout; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_long_timeout(ssl: i32, context: *mut us_socket_context_t, on_long_timeout: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_long_timeout(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_long_timeout); + return; + } + + (*context).on_socket_long_timeout = on_long_timeout; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_on_writable(ssl: i32, context: *mut us_socket_context_t, on_writable: *mut us_socket_context_t) { + + #[cfg(not(LIBUS_NO_SSL))] + if ssl != 0 { + us_internal_ssl_socket_context_on_writable(/*(struct us_internal_ssl_socket_context_t *)*/ context, /*(struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int))*/ on_writable); + return; + } + + (*context).on_writable = on_writable; +} + +#[repr(C)] +pub struct us_internal_loop_data_t { + sweep_timer: *mut us_socket_context_t, + wakeup_async: *mut us_socket_context_t, + last_write_failed: i32, + head: *mut us_socket_context_t, + iterator: *mut us_socket_context_t, + + + recv_buf: *mut us_socket_context_t, // wrong + ssl_data: *mut us_socket_context_t, // wrong + pre_cb: *mut us_socket_context_t, // wrong + post_cb: *mut us_socket_context_t, // wrong + closed_head: *mut us_socket_context_t, // wrong + low_prio_head: *mut us_socket_context_t, // wrong + low_prio_budget: i32, + /* We do not care if this flips or not, it doesn't matter */ + iteration_nr: u64 // long long? +} + +const LIBUS_RECV_BUFFER_LENGTH: usize = 524288; +const LIBUS_RECV_BUFFER_PADDING: usize = 32; + +/* The loop has 2 fallthrough polls */ +#[no_mangle] +pub unsafe extern "C" fn us_internal_loop_data_init(loop_data: *mut us_internal_loop_data_t, wakeup_cb: *mut us_socket_context_t, pre_cb: *mut us_socket_context_t, post_cb: *mut us_socket_context_t) { + + (*loop_data).sweep_timer = us_create_timer(loop_data, 1, 0); + (*loop_data).recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2) as *mut us_socket_context_t; + (*loop_data).ssl_data = std::ptr::null_mut(); + (*loop_data).head = std::ptr::null_mut(); + (*loop_data).iterator = std::ptr::null_mut(); + (*loop_data).closed_head = std::ptr::null_mut(); + (*loop_data).low_prio_head = std::ptr::null_mut(); + (*loop_data).low_prio_budget = 0; + + (*loop_data).pre_cb = pre_cb; + (*loop_data).post_cb = post_cb; + (*loop_data).iteration_nr = 0; + + (*loop_data).wakeup_async = us_internal_create_async(loop_data, 1, 0); + us_internal_async_set((*loop_data).wakeup_async, /*(void (*)(struct us_internal_async *))*/ wakeup_cb); +} + +#[no_mangle] +pub unsafe extern "C" fn us_loop_iteration_number(loop_data: *mut us_internal_loop_data_t) -> u64 { + (*loop_data).iteration_nr +} + +// us_loop_t is castable to us_internal_loop_data +#[no_mangle] +pub unsafe extern "C" fn us_internal_loop_link(loop_data: *mut us_internal_loop_data_t, context: *mut us_socket_context_t) { + /* Insert this context as the head of loop */ + (*context).next = (*loop_data).head; + (*context).prev = std::ptr::null_mut(); + if !(*loop_data).head.is_null() { + (*(*loop_data).head).prev = context; + } + (*loop_data).head = context; +} + +/* Unlink is called before free */ +#[no_mangle] +pub unsafe extern "C" fn us_internal_loop_unlink(loop_data: *mut us_internal_loop_data_t, context: *mut us_socket_context_t) { + if (*loop_data).head == context { + (*loop_data).head = (*context).next; + if !(*loop_data).head.is_null() { + (*(*loop_data).head).prev = std::ptr::null_mut(); + } + } else { + (*(*context).prev).next = (*context).next; + if !(*context).next.is_null() { + (*(*context).next).prev = (*context).prev; + } + } +} + +/* +struct us_internal_loop_data_t { + sweep_timer: const *us_timer_t, + wakeup_async: const *us_internal_async, + last_write_failed: i32,*/ + + /*struct us_socket_context_t *head; + struct us_socket_context_t *iterator; + char *recv_buf; + void *ssl_data; + void (*pre_cb)(struct us_loop_t *); + void (*post_cb)(struct us_loop_t *); + struct us_socket_t *closed_head; + struct us_socket_t *low_prio_head; + int low_prio_budget; + /* We do not care if this flips or not, it doesn't matter */ + long long iteration_nr;*/ +//} + +/* +struct us_socket_context_t { + alignas(LIBUS_EXT_ALIGNMENT) struct us_loop_t *loop; + uint32_t global_tick; + unsigned char timestamp; + unsigned char long_timestamp; + struct us_socket_t *head_sockets; + struct us_listen_socket_t *head_listen_sockets; + struct us_socket_t *iterator; + struct us_socket_context_t *prev, *next; + + struct us_socket_t *(*on_open)(struct us_socket_t *, int is_client, char *ip, int ip_length); + struct us_socket_t *(*on_data)(struct us_socket_t *, char *data, int length); + struct us_socket_t *(*on_writable)(struct us_socket_t *); + struct us_socket_t *(*on_close)(struct us_socket_t *, int code, void *reason); + //void (*on_timeout)(struct us_socket_context *); + struct us_socket_t *(*on_socket_timeout)(struct us_socket_t *); + struct us_socket_t *(*on_socket_long_timeout)(struct us_socket_t *); + struct us_socket_t *(*on_end)(struct us_socket_t *); + struct us_socket_t *(*on_connect_error)(struct us_socket_t *, int code); + int (*is_low_prio)(struct us_socket_t *); +}; +*/ + +#[no_mangle] +pub extern "C" fn us_socket_flush(_ssl: i32, s: u64) { + unsafe { + if us_socket_is_shut_down(0, s) == 0 { + bsd_socket_flush(us_poll_fd(s)); + } + } +} + +#[no_mangle] +pub extern "C" fn us_socket_shutdown_read(_ssl: i32, s: u64) { + unsafe { + // This syscall is idempotent so no extra check is needed + bsd_shutdown_socket_read(us_poll_fd(s)); + } +} + + +#[no_mangle] +pub extern "C" fn default_is_low_prio_handler(_s: u64) -> i32 { + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_timestamp(_ssl: i32, context: *const us_socket_context_t) -> u16 { + (*context).timestamp.into() +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_loop(_ssl: i32, context: *const us_socket_context_t) -> *mut us_internal_loop_data_t { + (*context)._loop +} + +#[no_mangle] +pub extern "C" fn bsd_recv(fd: i32, buf: u64, length: i32, flags: i32) -> i32 { + unsafe { + recv(fd, buf, length, flags) + } +} + +#[no_mangle] +pub extern "C" fn bsd_close_socket(fd: i32) { + if cfg!(windows) { + unsafe { + closesocket(fd); + } + } else { + unsafe { + close(fd); + } + } +} + +/* Options is currently only applicable for SSL - this will change with time (prefer_low_memory is one example) */ +#[no_mangle] +pub unsafe extern "C" fn us_create_socket_context(ssl: i32, _loop: *mut us_internal_loop_data_t, context_ext_size: i32, options: us_socket_context_options_t) -> *mut us_socket_context_t { + #[cfg(not(LIBUS_NO_SSL))] + if ssl { + /* This function will call us, again, with SSL = false and a bigger ext_size */ + return /*(struct us_socket_context_t *)*/ us_internal_create_ssl_socket_context(_loop, context_ext_size, options); + } + + /* This path is taken once either way - always BEFORE whatever SSL may do LATER. + * context_ext_size will however be modified larger in case of SSL, to hold SSL extensions */ + + let context: *mut us_socket_context_t = malloc(std::mem::size_of::() + context_ext_size as usize); + (*context)._loop = _loop; + (*context).head_sockets = 0; + (*context).head_listen_sockets = 0; + (*context).iterator = 0; + (*context).next = std::ptr::null_mut(); + (*context).is_low_prio = default_is_low_prio_handler; + + /* Begin at 0 */ + (*context).timestamp = 0; + (*context).long_timestamp = 0; + (*context).global_tick = 0; + + us_internal_loop_link(_loop, context); + + /* If we are called from within SSL code, SSL code will make further changes to us */ + return context; +} + +#[no_mangle] +pub unsafe extern "C" fn us_socket_context_free(ssl: i32, context: *mut us_socket_context_t) { + #[cfg(not(LIBUS_NO_SSL))] + if (ssl) { + /* This function will call us again with SSL=false */ + us_internal_ssl_socket_context_free(/*(struct us_internal_ssl_socket_context_t *)*/ context); + return; + } + + /* This path is taken once either way - always AFTER whatever SSL may do BEFORE. + * This is the opposite order compared to when creating the context - SSL code is cleaning up before non-SSL */ + + us_internal_loop_unlink((*context)._loop, context); + free(context); +} \ No newline at end of file diff --git a/src/loop.c b/src/loop.c index b0b20106..c4b5faef 100644 --- a/src/loop.c +++ b/src/loop.c @@ -19,66 +19,10 @@ #include "internal/internal.h" #include -/* The loop has 2 fallthrough polls */ -void us_internal_loop_data_init(struct us_loop_t *loop, void (*wakeup_cb)(struct us_loop_t *loop), - void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop)) { - loop->data.sweep_timer = us_create_timer(loop, 1, 0); - loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); - loop->data.ssl_data = 0; - loop->data.head = 0; - loop->data.iterator = 0; - loop->data.closed_head = 0; - loop->data.low_prio_head = 0; - loop->data.low_prio_budget = 0; - - loop->data.pre_cb = pre_cb; - loop->data.post_cb = post_cb; - loop->data.iteration_nr = 0; - - loop->data.wakeup_async = us_internal_create_async(loop, 1, 0); - us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb); -} - -void us_internal_loop_data_free(struct us_loop_t *loop) { -#ifndef LIBUS_NO_SSL - us_internal_free_loop_ssl_data(loop); -#endif - - free(loop->data.recv_buf); - - us_timer_close(loop->data.sweep_timer); - us_internal_async_close(loop->data.wakeup_async); -} - void us_wakeup_loop(struct us_loop_t *loop) { us_internal_async_wakeup(loop->data.wakeup_async); } -void us_internal_loop_link(struct us_loop_t *loop, struct us_socket_context_t *context) { - /* Insert this context as the head of loop */ - context->next = loop->data.head; - context->prev = 0; - if (loop->data.head) { - loop->data.head->prev = context; - } - loop->data.head = context; -} - -/* Unlink is called before free */ -void us_internal_loop_unlink(struct us_loop_t *loop, struct us_socket_context_t *context) { - if (loop->data.head == context) { - loop->data.head = context->next; - if (loop->data.head) { - loop->data.head->prev = 0; - } - } else { - context->prev->next = context->next; - if (context->next) { - context->next->prev = context->prev; - } - } -} - /* This functions should never run recursively */ void us_internal_timer_sweep(struct us_loop_t *loop) { struct us_internal_loop_data_t *loop_data = &loop->data; @@ -176,10 +120,6 @@ void sweep_timer_cb(struct us_internal_callback_t *cb) { us_internal_timer_sweep(cb->loop); } -long long us_loop_iteration_number(struct us_loop_t *loop) { - return loop->data.iteration_nr; -} - /* These may have somewhat different meaning depending on the underlying event library */ void us_internal_loop_pre(struct us_loop_t *loop) { loop->data.iteration_nr++; diff --git a/src/socket.c b/src/socket.c index d6f133ac..e10c2abc 100644 --- a/src/socket.c +++ b/src/socket.c @@ -32,11 +32,6 @@ int us_socket_local_port(int ssl, struct us_socket_t *s) { } } -void us_socket_shutdown_read(int ssl, struct us_socket_t *s) { - /* This syscall is idempotent so no extra check is needed */ - bsd_shutdown_socket_read(us_poll_fd((struct us_poll_t *) s)); -} - void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length) { struct bsd_addr_t addr; if (bsd_remote_addr(us_poll_fd(&s->p), &addr) || *length < bsd_addr_get_ip_length(&addr)) { @@ -67,12 +62,6 @@ void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes } } -void us_socket_flush(int ssl, struct us_socket_t *s) { - if (!us_socket_is_shut_down(0, s)) { - bsd_socket_flush(us_poll_fd((struct us_poll_t *) s)); - } -} - int us_socket_is_closed(int ssl, struct us_socket_t *s) { return s->prev == (struct us_socket_t *) s->context; }