diff --git a/src/network/socket.c b/src/network/socket.c index 4179b152..e0f6b402 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -69,6 +69,16 @@ struct connect_info { struct uri *uri; /* For updating the blacklist. */ }; +/** For detecting whether a struct socket has been deleted while a + * function was using it. */ +struct socket_weak_ref { + LIST_HEAD(struct socket_weak_ref); + + /** done_socket() resets this to NULL. */ + struct socket *socket; +}; + +static INIT_LIST_OF(struct socket_weak_ref, socket_weak_refs); /* To enable logging of tranfers, for debugging purposes. */ #if 0 @@ -143,6 +153,8 @@ init_socket(void *conn, struct socket_operations *ops) void done_socket(struct socket *socket) { + struct socket_weak_ref *ref; + close_socket(socket); if (socket->connect_info) @@ -150,6 +162,11 @@ done_socket(struct socket *socket) mem_free_set(&socket->read_buffer, NULL); mem_free_set(&socket->write_buffer, NULL); + + foreach(ref, socket_weak_refs) { + if (ref->socket == socket) + ref->socket = NULL; + } } void @@ -935,13 +952,26 @@ void read_from_socket(struct socket *socket, struct read_buffer *buffer, struct connection_state state, socket_read_T done) { + const int is_buffer_new = (buffer != socket->read_buffer); + struct socket_weak_ref ref; select_handler_T write_handler; + ref.socket = socket; + add_to_list(socket_weak_refs, &ref); + buffer->done = done; socket->ops->set_timeout(socket, connection_state(0)); socket->ops->set_state(socket, state); + del_from_list(&ref); + if (ref.socket == NULL) { + /* socket->ops->set_state deleted the socket. */ + if (is_buffer_new) + mem_free(buffer); + return; + } + if (socket->read_buffer && buffer != socket->read_buffer) mem_free(socket->read_buffer); socket->read_buffer = buffer;