diff options
author | 2023-08-28 08:38:30 -0700 | |
---|---|---|
committer | 2023-08-28 08:38:30 -0700 | |
commit | a2ddfe6913c1884bfef6314d00cf2b708281ff79 (patch) | |
tree | 88e436313a73d2ab1426ac94be122d62fecb72bc /packages/bun-usockets/src/socket.c | |
parent | 6e4a1f2918cb4dbcc035d350d6cd9f018ea8df59 (diff) | |
download | bun-a2ddfe6913c1884bfef6314d00cf2b708281ff79.tar.gz bun-a2ddfe6913c1884bfef6314d00cf2b708281ff79.tar.zst bun-a2ddfe6913c1884bfef6314d00cf2b708281ff79.zip |
Bring uSockets & uWebSockets forks into Bun's repository (#4372)
* Move uWebSockets and uSockets forks into Bun's repository
* Update Makefile
* Update settings.json
* Update libuwsockets.cpp
* Remove backends we won't be using
* Update bindings.cpp
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'packages/bun-usockets/src/socket.c')
-rw-r--r-- | packages/bun-usockets/src/socket.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/packages/bun-usockets/src/socket.c b/packages/bun-usockets/src/socket.c new file mode 100644 index 000000000..61cbb2c0f --- /dev/null +++ b/packages/bun-usockets/src/socket.c @@ -0,0 +1,295 @@ +/* + * Authored by Alex Hultman, 2018-2021. + * Intellectual property of third-party. + + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "libusockets.h" +#include "internal/internal.h" +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +/* Shared with SSL */ + +int us_socket_local_port(int ssl, struct us_socket_t *s) { + struct bsd_addr_t addr; + if (bsd_local_addr(us_poll_fd(&s->p), &addr)) { + return -1; + } else { + return bsd_addr_get_port(&addr); + } +} + +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)) { + *length = 0; + } else { + *length = bsd_addr_get_ip_length(&addr); + memcpy(buf, bsd_addr_get_ip(&addr), *length); + } +} + +struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { + return s->context; +} + +void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { + if (seconds) { + s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240; + } else { + s->timeout = 255; + } +} + +void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes) { + if (minutes) { + s->long_timeout = ((unsigned int)s->context->long_timestamp + minutes) % 240; + } else { + s->long_timeout = 255; + } +} + +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; +} + +int us_socket_is_established(int ssl, struct us_socket_t *s) { + /* Everything that is not POLL_TYPE_SEMI_SOCKET is established */ + return us_internal_poll_type((struct us_poll_t *) s) != POLL_TYPE_SEMI_SOCKET; +} + +/* Exactly the same as us_socket_close but does not emit on_close event */ +struct us_socket_t *us_socket_close_connecting(int ssl, struct us_socket_t *s) { + if (!us_socket_is_closed(0, s)) { + us_internal_socket_context_unlink_socket(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; +} + +/* Same as above but emits on_close */ +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)) { + if (s->low_prio_state == 1) { + /* Unlink this socket from the low-priority queue */ + if (!s->prev) s->context->loop->data.low_prio_head = s->next; + else s->prev->next = s->next; + + if (s->next) s->next->prev = s->prev; + + s->prev = 0; + s->next = 0; + s->low_prio_state = 0; + } else { + us_internal_socket_context_unlink_socket(s->context, s); + } + #ifdef LIBUS_USE_KQUEUE + // kqueue automatically removes the fd from the set on close + // we can skip the system call for that case + us_internal_loop_update_pending_ready_polls(s->context->loop, (struct us_poll_t *)s, 0, us_poll_events((struct us_poll_t*)s), 0); + #else + /* Disable any instance of us in the pending ready poll list */ + us_poll_stop((struct us_poll_t *) s, s->context->loop); + #endif + 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; +} + +// This function is the same as us_socket_close but: +// - does not emit on_close event +// - does not close +struct us_socket_t *us_socket_detach(int ssl, struct us_socket_t *s) { + if (!us_socket_is_closed(0, s)) { + if (s->low_prio_state == 1) { + /* Unlink this socket from the low-priority queue */ + if (!s->prev) s->context->loop->data.low_prio_head = s->next; + else s->prev->next = s->next; + + if (s->next) s->next->prev = s->prev; + + s->prev = 0; + s->next = 0; + s->low_prio_state = 0; + } else { + us_internal_socket_context_unlink(s->context, s); + } + us_poll_stop((struct us_poll_t *) s, s->context->loop); + + /* 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; + } + return s; +} + +// This function is used for moving a socket between two different event loops +struct us_socket_t *us_socket_attach(int ssl, LIBUS_SOCKET_DESCRIPTOR client_fd, struct us_socket_context_t *ctx, int flags, int socket_ext_size) { + struct us_poll_t *accepted_p = us_create_poll(ctx->loop, 0, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + socket_ext_size); + us_poll_init(accepted_p, client_fd, POLL_TYPE_SOCKET); + us_poll_start(accepted_p, ctx->loop, flags); + + struct us_socket_t *s = (struct us_socket_t *) accepted_p; + + s->context = ctx; + s->timeout = 0; + s->low_prio_state = 0; + + /* We always use nodelay */ + bsd_socket_nodelay(client_fd, 1); + us_internal_socket_context_link(ctx, s); + + if (ctx->on_open) ctx->on_open(s, 0, 0, 0); + + return s; +} + +/* Not shared with SSL */ + +void *us_socket_get_native_handle(int ssl, struct us_socket_t *s) { +#ifndef LIBUS_NO_SSL + if (ssl) { + return us_internal_ssl_socket_get_native_handle((struct us_internal_ssl_socket_t *) s); + } +#endif + + return (void *) (uintptr_t) us_poll_fd((struct us_poll_t *) s); +} + +int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { +#ifndef LIBUS_NO_SSL + if (ssl) { + return us_internal_ssl_socket_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more); + } +#endif + + if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { + return 0; + } + + int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more); + if (written != length) { + s->context->loop->data.last_write_failed = 1; + us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); + } + + return written < 0 ? 0 : written; +} + +void *us_socket_ext(int ssl, struct us_socket_t *s) { +#ifndef LIBUS_NO_SSL + if (ssl) { + return us_internal_ssl_socket_ext((struct us_internal_ssl_socket_t *) s); + } +#endif + + return s + 1; +} + +int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { +#ifndef LIBUS_NO_SSL + if (ssl) { + return us_internal_ssl_socket_is_shut_down((struct us_internal_ssl_socket_t *) s); + } +#endif + + return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN; +} + +void us_socket_shutdown(int ssl, struct us_socket_t *s) { +#ifndef LIBUS_NO_SSL + if (ssl) { + us_internal_ssl_socket_shutdown((struct us_internal_ssl_socket_t *) s); + return; + } +#endif + + /* Todo: should we emit on_close if calling shutdown on an already half-closed socket? + * We need more states in that case, we need to track RECEIVED_FIN + * so far, the app has to track this and call close as needed */ + if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) { + us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN); + us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); + bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s)); + } +} + +/* + Note: this assumes that the socket is non-TLS and will be adopted and wrapped with a new TLS context + context ext will not be copied to the new context, new context will contain us_wrapped_socket_context_t on ext +*/ +struct us_socket_t *us_socket_wrap_with_tls(int ssl, struct us_socket_t *s, struct us_bun_socket_context_options_t options, struct us_socket_events_t events, int socket_ext_size) { + // only accepts non-TLS sockets + if (ssl) { + return NULL; + } + + return(struct us_socket_t *) us_internal_ssl_socket_wrap_with_tls(s, options, events, socket_ext_size); +} + +// if a TLS socket calls this, it will start SSL call open event and TLS handshake if required +// will have no effect if the socket is closed or is not TLS +struct us_socket_t* us_socket_open(int ssl, struct us_socket_t * s, int is_client, char* ip, int ip_length) { + if (ssl) { + return(struct us_socket_t *) us_internal_ssl_socket_open((struct us_internal_ssl_socket_t *)s, is_client, ip, ip_length); + } + return s; +} + +int us_socket_raw_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { +#ifndef LIBUS_NO_SSL + if (ssl) { + return us_internal_ssl_socket_raw_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more); + } +#endif + // non-TLS is always raw + return us_socket_write(ssl, s, data, length, msg_more); +} |