diff --git a/include/zephyr/net/websocket.h b/include/zephyr/net/websocket.h index dc0eaf36d18..606957e9fd5 100644 --- a/include/zephyr/net/websocket.h +++ b/include/zephyr/net/websocket.h @@ -201,6 +201,17 @@ int websocket_disconnect(int ws_sock); */ int websocket_register(int http_sock, uint8_t *recv_buf, size_t recv_buf_len); +/** + * @brief Unregister a websocket. This is called when we no longer need + * the underlaying "real" socket. This will close first the websocket + * and then the original socket. + * + * @param ws_sock Websocket connection socket. + * + * @return <0 if error, 0 the websocket connection is now fully closed + */ +int websocket_unregister(int ws_sock); + #if defined(CONFIG_WEBSOCKET_CLIENT) void websocket_init(void); #else diff --git a/subsys/net/lib/websocket/websocket.c b/subsys/net/lib/websocket/websocket.c index d8c719483ac..c7b896ecb8a 100644 --- a/subsys/net/lib/websocket/websocket.c +++ b/subsys/net/lib/websocket/websocket.c @@ -1193,6 +1193,58 @@ out: return ret; } +static struct websocket_context *websocket_search(int sock) +{ + struct websocket_context *ctx = NULL; + int i; + + k_sem_take(&contexts_lock, K_FOREVER); + + for (i = 0; i < ARRAY_SIZE(contexts); i++) { + if (!websocket_context_is_used(&contexts[i])) { + continue; + } + + if (contexts[i].sock != sock) { + continue; + } + + ctx = &contexts[i]; + break; + } + + k_sem_give(&contexts_lock); + + return ctx; +} + +int websocket_unregister(int sock) +{ + struct websocket_context *ctx; + + if (sock < 0) { + return -EINVAL; + } + + ctx = websocket_search(sock); + if (ctx == NULL) { + NET_DBG("[%p] Real socket for websocket sock %d not found!", ctx, sock); + return -ENOENT; + } + + if (ctx->real_sock < 0) { + return -EALREADY; + } + + (void)zsock_close(sock); + (void)zsock_close(ctx->real_sock); + + ctx->real_sock = -1; + ctx->sock = -1; + + return 0; +} + static const struct socket_op_vtable websocket_fd_op_vtable = { .fd_vtable = { .read = websocket_read_vmeth,