diff --git a/Makefile b/Makefile index fa6e2ff..7d33414 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# WITH_OPENSSL=1 enables OpenSSL 1.1+ support +# WITH_OPENSSL=1 enables OpenSSL 1.1+ support or BoringSSL ifeq ($(WITH_OPENSSL),1) override CFLAGS += -DLIBUS_USE_OPENSSL # With problems on macOS, make sure to pass needed LDFLAGS required to find these @@ -28,7 +28,7 @@ endif # WITH_ASAN builds with sanitizers ifeq ($(WITH_ASAN),1) - override CFLAGS += -fsanitize=address + override CFLAGS += -fsanitize=address -g override LDFLAGS += -lasan endif diff --git a/examples/echo_server.c b/examples/echo_server.c index 073abb2..8eb1737 100644 --- a/examples/echo_server.c +++ b/examples/echo_server.c @@ -57,7 +57,7 @@ struct us_socket_t *on_echo_socket_writable(struct us_socket_t *s) { } /* Socket closed handler */ -struct us_socket_t *on_echo_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_echo_socket_close(struct us_socket_t *s, int code, void *reason) { struct echo_socket *es = (struct echo_socket *) us_socket_ext(SSL, s); printf("Client disconnected\n"); @@ -70,7 +70,7 @@ struct us_socket_t *on_echo_socket_close(struct us_socket_t *s) { /* Socket half-closed handler */ struct us_socket_t *on_echo_socket_end(struct us_socket_t *s) { us_socket_shutdown(SSL, s); - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } /* Socket data handler */ @@ -116,7 +116,7 @@ struct us_socket_t *on_echo_socket_open(struct us_socket_t *s, int is_client, ch /* Socket timeout handler */ struct us_socket_t *on_echo_socket_timeout(struct us_socket_t *s) { printf("Client was idle for too long\n"); - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } int main() { diff --git a/examples/hammer_test.c b/examples/hammer_test.c index 91f5fc9..8d98cbe 100644 --- a/examples/hammer_test.c +++ b/examples/hammer_test.c @@ -70,7 +70,7 @@ struct us_socket_t *perform_random_operation(struct us_socket_t *s) { switch (rand() % 5) { case 0: { // close - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } case 1: { // adoption cannot happen if closed! @@ -141,7 +141,7 @@ struct us_socket_t *on_http_socket_writable(struct us_socket_t *s) { return perform_random_operation(s); } -struct us_socket_t *on_web_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_web_socket_close(struct us_socket_t *s, int code, void *reason) { assume_state(s, 0); closed_connections++; @@ -155,7 +155,7 @@ struct us_socket_t *on_web_socket_close(struct us_socket_t *s) { return s; } -struct us_socket_t *on_http_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) { assume_state(s, 1); closed_connections++; @@ -173,7 +173,7 @@ struct us_socket_t *on_web_socket_end(struct us_socket_t *s) { assume_state(s, 0); // we need to close on shutdown - s = us_socket_close(SSL, s); + s = us_socket_close(SSL, s, 0, NULL); return perform_random_operation(s); } @@ -181,7 +181,7 @@ struct us_socket_t *on_http_socket_end(struct us_socket_t *s) { assume_state(s, 1); // we need to close on shutdown - s = us_socket_close(SSL, s); + s = us_socket_close(SSL, s, 0, NULL); return perform_random_operation(s); } diff --git a/examples/http_load_test.c b/examples/http_load_test.c index 3c1e45c..e1af816 100644 --- a/examples/http_load_test.c +++ b/examples/http_load_test.c @@ -42,12 +42,12 @@ struct us_socket_t *on_http_socket_writable(struct us_socket_t *s) { return s; } -struct us_socket_t *on_http_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) { return s; } struct us_socket_t *on_http_socket_end(struct us_socket_t *s) { - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } struct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) { diff --git a/examples/http_server.c b/examples/http_server.c index 2b66e64..4c07401 100644 --- a/examples/http_server.c +++ b/examples/http_server.c @@ -42,7 +42,7 @@ struct us_socket_t *on_http_socket_writable(struct us_socket_t *s) { return s; } -struct us_socket_t *on_http_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) { printf("Client disconnected\n"); return s; @@ -51,7 +51,7 @@ struct us_socket_t *on_http_socket_close(struct us_socket_t *s) { struct us_socket_t *on_http_socket_end(struct us_socket_t *s) { /* HTTP does not support half-closed sockets */ us_socket_shutdown(SSL, s); - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } struct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int length) { @@ -84,7 +84,7 @@ struct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, ch struct us_socket_t *on_http_socket_timeout(struct us_socket_t *s) { /* Close idle HTTP sockets */ - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } int main() { diff --git a/examples/peer_verify_test.c b/examples/peer_verify_test.c index 534f6e9..20ce5e8 100644 --- a/examples/peer_verify_test.c +++ b/examples/peer_verify_test.c @@ -102,7 +102,7 @@ struct us_socket_t *on_client_socket_writable(struct us_socket_t *s) { return s; } -struct us_socket_t *on_server_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_server_socket_close(struct us_socket_t *s, int code, void *reason) { printf("on_server_socket_close\n"); us_listen_socket_close(SSL, listen_socket); @@ -110,7 +110,7 @@ struct us_socket_t *on_server_socket_close(struct us_socket_t *s) { return s; } -struct us_socket_t *on_client_socket_close(struct us_socket_t *s) { +struct us_socket_t *on_client_socket_close(struct us_socket_t *s, int code, void *reason) { printf("on_client_socket_close\n"); @@ -119,12 +119,12 @@ struct us_socket_t *on_client_socket_close(struct us_socket_t *s) { struct us_socket_t *on_server_socket_end(struct us_socket_t *s) { - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } struct us_socket_t *on_client_socket_end(struct us_socket_t *s) { - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } struct us_socket_t *on_server_socket_data(struct us_socket_t *s, char *data, int length) { @@ -154,7 +154,7 @@ struct us_socket_t *on_client_socket_data(struct us_socket_t *s, char *data, int client_received_data = true; - return us_socket_close(SSL, s); + return us_socket_close(SSL, s, 0, NULL); } struct us_socket_t *on_server_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) { @@ -267,8 +267,8 @@ int expect_peer_verify(const char *test_name, bool expect_data_exchanged, } int main() { - - expect_peer_verify("trusted client ca", true, + + expect_peer_verify("trusted client ca", true, (struct us_socket_context_options_t){ .key_file_name = ".certs/valid_server_key.pem", .cert_file_name = ".certs/valid_server_crt.pem", @@ -281,7 +281,7 @@ int main() { }); - expect_peer_verify("untrusted client ca", false, + expect_peer_verify("untrusted client ca", false, (struct us_socket_context_options_t){ .key_file_name = ".certs/valid_server_key.pem", .cert_file_name = ".certs/valid_server_crt.pem", @@ -293,7 +293,7 @@ int main() { .ca_file_name = ".certs/valid_ca_crt.pem" }); - expect_peer_verify("trusted selfsigned client", true, + expect_peer_verify("trusted selfsigned client", true, (struct us_socket_context_options_t){ .key_file_name = ".certs/valid_server_key.pem", .cert_file_name = ".certs/valid_server_crt.pem", @@ -305,7 +305,7 @@ int main() { .ca_file_name = ".certs/valid_ca_crt.pem" }); - expect_peer_verify("untrusted selfsigned client", false, + expect_peer_verify("untrusted selfsigned client", false, (struct us_socket_context_options_t){ .key_file_name = ".certs/valid_server_key.pem", .cert_file_name = ".certs/valid_server_crt.pem", @@ -317,7 +317,7 @@ int main() { .ca_file_name = ".certs/valid_ca_crt.pem" }); - expect_peer_verify("peer verify disabled", true, + expect_peer_verify("peer verify disabled", true, (struct us_socket_context_options_t){ .key_file_name = ".certs/valid_server_key.pem", .cert_file_name = ".certs/valid_server_crt.pem" diff --git a/src/context.c b/src/context.c index 4123877..467b6fa 100644 --- a/src/context.c +++ b/src/context.c @@ -105,6 +105,13 @@ void *us_socket_context_get_native_handle(int ssl, struct us_socket_context_t *c } 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 + /* For ease of use we copy all passed strings here */ options.ca_file_name = deep_str_copy(options.ca_file_name); options.cert_file_name = deep_str_copy(options.cert_file_name); @@ -112,12 +119,6 @@ struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t * options.key_file_name = deep_str_copy(options.key_file_name); options.passphrase = deep_str_copy(options.passphrase); -#ifndef LIBUS_NO_SSL - if (ssl) { - return (struct us_socket_context_t *) us_internal_create_ssl_socket_context(loop, context_ext_size, options); - } -#endif - struct us_socket_context_t *context = malloc(sizeof(struct us_socket_context_t) + context_ext_size); context->loop = loop; context->head = 0; @@ -131,20 +132,21 @@ struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t * } void us_socket_context_free(int ssl, struct us_socket_context_t *context) { - /* We also simply free every copied string here */ - free((void *) context->options.ca_file_name); - free((void *) context->options.cert_file_name); - free((void *) context->options.dh_params_file_name); - free((void *) context->options.key_file_name); - free((void *) context->options.passphrase); - #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 + /* We also simply free every copied string here */ + free((void *) context->options.ca_file_name); + free((void *) context->options.cert_file_name); + free((void *) context->options.dh_params_file_name); + free((void *) context->options.key_file_name); + free((void *) context->options.passphrase); + us_internal_loop_unlink(context->loop, context); free(context); } @@ -250,10 +252,10 @@ void us_socket_context_on_open(int ssl, struct us_socket_context_t *context, str 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)) { +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 *)) on_close); + 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 diff --git a/src/crypto/openssl.c b/src/crypto/openssl.c index a1a0064..68c1451 100644 --- a/src/crypto/openssl.c +++ b/src/crypto/openssl.c @@ -62,7 +62,7 @@ struct us_internal_ssl_socket_context_t { // här måste det vara! struct us_internal_ssl_socket_t *(*on_open)(struct us_internal_ssl_socket_t *, int is_client, char *ip, int ip_length); struct us_internal_ssl_socket_t *(*on_data)(struct us_internal_ssl_socket_t *, char *data, int length); - struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *); + struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *, int code, void *reason); }; // same here, should or shouldn't it contain s? @@ -155,19 +155,26 @@ struct us_internal_ssl_socket_t *ssl_on_open(struct us_internal_ssl_socket_t *s, return (struct us_internal_ssl_socket_t *) context->on_open(s, is_client, ip, ip_length); } -struct us_internal_ssl_socket_t *ssl_on_close(struct us_internal_ssl_socket_t *s) { +/* This one is a helper; it is entirely shared with non-SSL so can be removed */ +struct us_internal_ssl_socket_t *us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s, int code, void *reason) { + return (struct us_internal_ssl_socket_t *) us_socket_close(0, (struct us_socket_t *) s, code, reason); +} + +struct us_internal_ssl_socket_t *ssl_on_close(struct us_internal_ssl_socket_t *s, int code, void *reason) { struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s); SSL_free(s->ssl); - return context->on_close(s); + return context->on_close(s, code, reason); } struct us_internal_ssl_socket_t *ssl_on_end(struct us_internal_ssl_socket_t *s) { struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_socket_context(0, &s->s); // whatever state we are in, a TCP FIN is always an answered shutdown - return us_internal_ssl_socket_close(s); + + /* Todo: this should report CLEANLY SHUTDOWN as reason */ + return us_internal_ssl_socket_close(s, 0, NULL); } // this whole function needs a complete clean-up @@ -192,7 +199,8 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s, // two phase shutdown is complete here //printf("Two step SSL shutdown complete\n"); - return us_internal_ssl_socket_close(s); + /* Todo: this should also report some kind of clean shutdown */ + return us_internal_ssl_socket_close(s, 0, NULL); } else if (ret < 0) { int err = SSL_get_error(s->ssl, ret); @@ -226,13 +234,13 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s, } // terminate connection here - return us_internal_ssl_socket_close(s); + return us_internal_ssl_socket_close(s, 0, NULL); } else { // emit the data we have and exit // assume we emptied the input buffer fully or error here as well! if (loop_ssl_data->ssl_read_input_length) { - return us_internal_ssl_socket_close(s); + return us_internal_ssl_socket_close(s, 0, NULL); } // cannot emit zero length to app @@ -287,7 +295,7 @@ struct us_internal_ssl_socket_t *ssl_on_data(struct us_internal_ssl_socket_t *s, //exit(-2); // not correct anyways! - s = us_internal_ssl_socket_close(s); + s = us_internal_ssl_socket_close(s, 0, NULL); //us_ } @@ -376,11 +384,11 @@ void *us_internal_ssl_socket_context_get_native_handle(struct us_internal_ssl_so } struct us_internal_ssl_socket_context_t *us_internal_create_child_ssl_socket_context(struct us_internal_ssl_socket_context_t *context, int context_ext_size) { + /* Create a new non-SSL context */ struct us_socket_context_options_t options = {0}; - struct us_internal_ssl_socket_context_t *child_context = (struct us_internal_ssl_socket_context_t *) us_create_socket_context(0, context->sc.loop, sizeof(struct us_internal_ssl_socket_context_t) + context_ext_size, options); - // I think this is the only thing being shared + /* The only thing we share is SSL_CTX */ child_context->ssl_context = context->ssl_context; child_context->is_parent = 0; @@ -388,33 +396,38 @@ struct us_internal_ssl_socket_context_t *us_internal_create_child_ssl_socket_con } struct us_internal_ssl_socket_context_t *us_internal_create_ssl_socket_context(struct us_loop_t *loop, int context_ext_size, struct us_socket_context_options_t options) { - + /* If we haven't initialized the loop data yet, do so now */ us_internal_init_loop_ssl_data(loop); - struct us_socket_context_options_t no_options = {0}; + /* We begin by creating a non-SSL context, passing same options */ + struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_create_socket_context(0, loop, sizeof(struct us_internal_ssl_socket_context_t) + context_ext_size, options); - struct us_internal_ssl_socket_context_t *context = (struct us_internal_ssl_socket_context_t *) us_create_socket_context(0, loop, sizeof(struct us_internal_ssl_socket_context_t) + context_ext_size, no_options); + /* Now update our options parameter since above function made a deep copy, and we want to use that copy below */ + options = context->sc.options; + /* Then we extend its SSL parts */ context->ssl_context = SSL_CTX_new(TLS_method()); context->is_parent = 1; - // only parent ssl contexts may need to ignore data + + /* We, as parent context, may ignore data */ context->sc.ignore_data = (int (*)(struct us_socket_t *)) ssl_ignore_data; - // options + /* Default options we rely on */ SSL_CTX_set_read_ahead(context->ssl_context, 1); SSL_CTX_set_mode(context->ssl_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); //SSL_CTX_set_mode(context->ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE); - // this lowers performance a bit in benchmarks + /* Security options; we as application developers should not have to care about these! */ + SSL_CTX_set_options(context->ssl_context, SSL_OP_NO_SSLv3); + SSL_CTX_set_options(context->ssl_context, SSL_OP_NO_TLSv1); + + /* The following are helpers. You may easily implement whatever you want by using the native handle directly */ + + /* Important option for lowering memory usage, but lowers performance slightly */ if (options.ssl_prefer_low_memory_usage) { SSL_CTX_set_mode(context->ssl_context, SSL_MODE_RELEASE_BUFFERS); } - //SSL_CTX_set_mode(context->ssl_context, SSL_MODE_RELEASE_BUFFERS); - SSL_CTX_set_options(context->ssl_context, SSL_OP_NO_SSLv3); - SSL_CTX_set_options(context->ssl_context, SSL_OP_NO_TLSv1); - - // these are going to be extended if (options.passphrase) { SSL_CTX_set_default_passwd_cb_userdata(context->ssl_context, (void *) options.passphrase); SSL_CTX_set_default_passwd_cb(context->ssl_context, passphrase_cb); @@ -496,8 +509,8 @@ void us_internal_ssl_socket_context_on_open(struct us_internal_ssl_socket_contex context->on_open = on_open; } -void us_internal_ssl_socket_context_on_close(struct us_internal_ssl_socket_context_t *context, struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *s)) { - us_socket_context_on_close(0, (struct us_socket_context_t *) context, (struct us_socket_t *(*)(struct us_socket_t *)) ssl_on_close); +void us_internal_ssl_socket_context_on_close(struct us_internal_ssl_socket_context_t *context, struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *s, int code, void *reason)) { + us_socket_context_on_close(0, (struct us_socket_context_t *) context, (struct us_socket_t *(*)(struct us_socket_t *, int, void *)) ssl_on_close); context->on_close = on_close; } @@ -624,10 +637,6 @@ void us_internal_ssl_socket_shutdown(struct us_internal_ssl_socket_t *s) { } } -struct us_internal_ssl_socket_t *us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s) { - return (struct us_internal_ssl_socket_t *) us_socket_close(0, (struct us_socket_t *) s); -} - struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_adopt_socket(struct us_internal_ssl_socket_context_t *context, struct us_internal_ssl_socket_t *s, int ext_size) { // todo: this is completely untested return (struct us_internal_ssl_socket_t *) us_socket_context_adopt_socket(0, &context->sc, &s->s, sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) + ext_size); diff --git a/src/internal/internal.h b/src/internal/internal.h index 533fc8d..061aa89 100644 --- a/src/internal/internal.h +++ b/src/internal/internal.h @@ -108,7 +108,7 @@ struct 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 *); + 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_end)(struct us_socket_t *); @@ -135,7 +135,7 @@ void us_internal_ssl_socket_context_on_open(struct us_internal_ssl_socket_contex struct us_internal_ssl_socket_t *(*on_open)(struct us_internal_ssl_socket_t *s, int is_client, char *ip, int ip_length)); void us_internal_ssl_socket_context_on_close(struct us_internal_ssl_socket_context_t *context, - struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *s)); + struct us_internal_ssl_socket_t *(*on_close)(struct us_internal_ssl_socket_t *s, int code, void *reason)); void us_internal_ssl_socket_context_on_data(struct us_internal_ssl_socket_context_t *context, struct us_internal_ssl_socket_t *(*on_data)(struct us_internal_ssl_socket_t *s, char *data, int length)); @@ -162,7 +162,7 @@ struct us_internal_ssl_socket_context_t *us_internal_ssl_socket_get_context(stru void *us_internal_ssl_socket_ext(struct us_internal_ssl_socket_t *s); int us_internal_ssl_socket_is_shut_down(struct us_internal_ssl_socket_t *s); void us_internal_ssl_socket_shutdown(struct us_internal_ssl_socket_t *s); -struct us_internal_ssl_socket_t *us_internal_ssl_socket_close(struct us_internal_ssl_socket_t *s); + struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_adopt_socket(struct us_internal_ssl_socket_context_t *context, struct us_internal_ssl_socket_t *s, int ext_size); diff --git a/src/libusockets.h b/src/libusockets.h index 60e4dfa..94cbfa2 100644 --- a/src/libusockets.h +++ b/src/libusockets.h @@ -101,7 +101,7 @@ WIN32_EXPORT void us_socket_context_free(int ssl, struct us_socket_context_t *co WIN32_EXPORT 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)); WIN32_EXPORT 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)); + struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason)); WIN32_EXPORT 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)); WIN32_EXPORT void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context, @@ -224,7 +224,7 @@ WIN32_EXPORT int us_socket_is_shut_down(int ssl, struct us_socket_t *s); WIN32_EXPORT int us_socket_is_closed(int ssl, struct us_socket_t *s); /* Immediately closes the socket */ -WIN32_EXPORT struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s); +WIN32_EXPORT struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason); /* Copy remote (IP) address of socket, or fail with zero length. */ WIN32_EXPORT void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length); diff --git a/src/loop.c b/src/loop.c index 5fafc9b..e21047f 100644 --- a/src/loop.c +++ b/src/loop.c @@ -201,7 +201,8 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events) /* Such as epollerr epollhup */ if (error) { - s = us_socket_close(0, s); + /* Todo: decide what code we give here */ + s = us_socket_close(0, s, 0, NULL); return; } @@ -235,14 +236,16 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events) } else if (!length) { if (us_socket_is_shut_down(0, s)) { /* We got FIN back after sending it */ - s = us_socket_close(0, s); + /* Todo: We should give "CLEAN SHUTDOWN" as reason here */ + s = us_socket_close(0, s, 0, NULL); } else { /* We got FIN, so stop polling for readable */ us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE); s = s->context->on_end(s); } } else if (length == LIBUS_SOCKET_ERROR && !bsd_would_block()) { - s = us_socket_close(0, s); + /* Todo: decide also here what kind of reason we should give */ + s = us_socket_close(0, s, 0, NULL); } } } diff --git a/src/socket.c b/src/socket.c index c201b9c..1c80db9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -54,6 +54,24 @@ int us_socket_is_closed(int ssl, struct us_socket_t *s) { return s->prev == (struct us_socket_t *) s->context; } +struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { + if (!us_socket_is_closed(0, s)) { + us_internal_socket_context_unlink(s->context, s); + us_poll_stop((struct us_poll_t *) s, s->context->loop); + bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); + + /* Link this socket to the close-list and let it be deleted after this iteration */ + s->next = s->context->loop->data.closed_head; + s->context->loop->data.closed_head = s; + + /* Any socket with prev = context is marked as closed */ + s->prev = (struct us_socket_t *) s->context; + + return s->context->on_close(s, code, reason); + } + return s; +} + /* Not shared with SSL */ void *us_socket_get_native_handle(int ssl, struct us_socket_t *s) { @@ -96,30 +114,6 @@ void *us_socket_ext(int ssl, struct us_socket_t *s) { return s + 1; } -struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s) { -#ifndef LIBUS_NO_SSL - if (ssl) { - return (struct us_socket_t *) us_internal_ssl_socket_close((struct us_internal_ssl_socket_t *) s); - } -#endif - - if (!us_socket_is_closed(0, s)) { - us_internal_socket_context_unlink(s->context, s); - us_poll_stop((struct us_poll_t *) s, s->context->loop); - bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); - - /* Link this socket to the close-list and let it be deleted after this iteration */ - s->next = s->context->loop->data.closed_head; - s->context->loop->data.closed_head = s; - - /* Any socket with prev = context is marked as closed */ - s->prev = (struct us_socket_t *) s->context; - - return s->context->on_close(s); - } - return s; -} - int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { #ifndef LIBUS_NO_SSL if (ssl) {