From 0b2c6aec9217c40324dddcc2fef376f5a8c5c27d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 27 Sep 2005 16:53:08 +0000 Subject: r10547: - add wrepl_request timeout handling - when we got an unexpected READ event, we need to do a socket_recv() to find connection errors and we need to mark the socket as dead (and remove the fde_event) to prevent, endless loops on broken connections tridge: we should look carefull at other protocol, to handle broken connections without spinning metze (This used to be commit ff1272347739696dcdf2fd191b8f47ca82c205de) --- source4/libcli/wrepl/winsrepl.c | 75 ++++++++++++++++++++++++++++++++--------- source4/libcli/wrepl/winsrepl.h | 9 +++++ 2 files changed, 69 insertions(+), 15 deletions(-) (limited to 'source4/libcli/wrepl') diff --git a/source4/libcli/wrepl/winsrepl.c b/source4/libcli/wrepl/winsrepl.c index 853ee01d38..4284c5cdbb 100644 --- a/source4/libcli/wrepl/winsrepl.c +++ b/source4/libcli/wrepl/winsrepl.c @@ -29,17 +29,28 @@ /* mark all pending requests as dead - called when a socket error happens */ -static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket) +static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status) { wrepl_socket->dead = True; - event_set_fd_flags(wrepl_socket->fde, 0); + if (wrepl_socket->fde) { + talloc_free(wrepl_socket->fde); + wrepl_socket->fde = NULL; + } + + if (wrepl_socket->sock) { + talloc_free(wrepl_socket->sock); + wrepl_socket->sock = NULL; + } + if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { + status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + } while (wrepl_socket->send_queue) { struct wrepl_request *req = wrepl_socket->send_queue; DLIST_REMOVE(wrepl_socket->send_queue, req); req->state = WREPL_REQUEST_ERROR; - req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + req->status = status; if (req->async.fn) { req->async.fn(req); } @@ -48,13 +59,20 @@ static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket) struct wrepl_request *req = wrepl_socket->recv_queue; DLIST_REMOVE(wrepl_socket->recv_queue, req); req->state = WREPL_REQUEST_ERROR; - req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + req->status = status; if (req->async.fn) { req->async.fn(req); } } } +static void wrepl_request_timeout_handler(struct event_context *ev, struct timed_event *te, + struct timeval t, void *ptr) +{ + struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request); + wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT); +} + /* handle send events */ @@ -67,7 +85,7 @@ static void wrepl_handler_send(struct wrepl_socket *wrepl_socket) status = socket_send(wrepl_socket->sock, &req->buffer, &nsent, 0); if (NT_STATUS_IS_ERR(status)) { - wrepl_socket_dead(wrepl_socket); + wrepl_socket_dead(wrepl_socket, status); return; } if (!NT_STATUS_IS_OK(status) || nsent == 0) return; @@ -99,7 +117,16 @@ static void wrepl_handler_recv(struct wrepl_socket *wrepl_socket) DATA_BLOB blob; if (req == NULL) { + NTSTATUS status; + EVENT_FD_NOT_READABLE(wrepl_socket->fde); + + status = socket_recv(wrepl_socket->sock, NULL, 0, &nread, 0); + if (NT_STATUS_EQUAL(NT_STATUS_END_OF_FILE,status)) return; + if (NT_STATUS_IS_ERR(status)) { + wrepl_socket_dead(wrepl_socket, status); + return; + } return; } @@ -121,7 +148,7 @@ static void wrepl_handler_recv(struct wrepl_socket *wrepl_socket) 4 - req->num_read, &nread, 0); if (NT_STATUS_IS_ERR(req->status)) { - wrepl_socket_dead(wrepl_socket); + wrepl_socket_dead(wrepl_socket, req->status); return; } if (!NT_STATUS_IS_OK(req->status)) return; @@ -146,7 +173,7 @@ static void wrepl_handler_recv(struct wrepl_socket *wrepl_socket) req->buffer.length - req->num_read, &nread, 0); if (NT_STATUS_IS_ERR(req->status)) { - wrepl_socket_dead(wrepl_socket); + wrepl_socket_dead(wrepl_socket, req->status); return; } if (!NT_STATUS_IS_OK(req->status)) return; @@ -225,7 +252,8 @@ static void wrepl_connect_handler(struct event_context *ev, struct fd_event *fde struct wrepl_socket); struct wrepl_request *req = wrepl_socket->recv_queue; - talloc_free(fde); + talloc_free(wrepl_socket->fde); + wrepl_socket->fde = NULL; if (req == NULL) return; @@ -255,6 +283,15 @@ failed: } } +/* + destroy a wrepl_socket destructor +*/ +static int wrepl_socket_destructor(void *ptr) +{ + struct wrepl_socket *sock = talloc_get_type(ptr, struct wrepl_socket); + wrepl_socket_dead(sock, NT_STATUS_CONNECTION_DISCONNECTED); + return 0; +} /* initialise a wrepl_socket. The event_ctx is optional, if provided then @@ -281,9 +318,10 @@ struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, talloc_steal(wrepl_socket, wrepl_socket->sock); - wrepl_socket->send_queue = NULL; - wrepl_socket->recv_queue = NULL; - wrepl_socket->dead = False; + wrepl_socket->send_queue = NULL; + wrepl_socket->recv_queue = NULL; + wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT; + wrepl_socket->dead = False; wrepl_socket->fde = event_add_fd(wrepl_socket->event_ctx, wrepl_socket, socket_get_fd(wrepl_socket->sock), @@ -291,6 +329,8 @@ struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, wrepl_connect_handler, wrepl_socket); set_blocking(socket_get_fd(wrepl_socket->sock), False); + + talloc_set_destructor(wrepl_socket, wrepl_socket_destructor); return wrepl_socket; @@ -299,7 +339,6 @@ failed: return NULL; } - /* destroy a wrepl_request */ @@ -438,6 +477,12 @@ struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket, talloc_set_destructor(req, wrepl_request_destructor); + if (wrepl_socket->request_timeout > 0) { + req->te = event_add_timed(wrepl_socket->event_ctx, req, + timeval_current_ofs(wrepl_socket->request_timeout, 0), + wrepl_request_timeout_handler, req); + } + EVENT_FD_WRITEABLE(wrepl_socket->fde); return req; @@ -643,16 +688,16 @@ static NTSTATUS wrepl_extract_name(struct nbt_name *name, } if (len < 17) { - make_nbt_name_client(name, talloc_strndup(mem_ctx, namebuf, len)); + make_nbt_name_client(name, talloc_strndup(mem_ctx, (char *)namebuf, len)); return NT_STATUS_OK; } - s = talloc_strndup(mem_ctx, namebuf, 15); + s = talloc_strndup(mem_ctx, (char *)namebuf, 15); trim_string(s, NULL, " "); name->name = s; name->type = namebuf[15]; if (len > 18) { - name->scope = talloc_strndup(mem_ctx, namebuf+17, len-17); + name->scope = talloc_strndup(mem_ctx, (char *)(namebuf+17), len-17); } else { name->scope = NULL; } diff --git a/source4/libcli/wrepl/winsrepl.h b/source4/libcli/wrepl/winsrepl.h index a966cf5451..64e09d61c6 100644 --- a/source4/libcli/wrepl/winsrepl.h +++ b/source4/libcli/wrepl/winsrepl.h @@ -39,6 +39,13 @@ struct wrepl_socket { /* the fd event */ struct fd_event *fde; + /* the default timeout for requests, 0 means no timeout */ +#define WREPL_SOCKET_REQUEST_TIMEOUT (60) + uint32_t request_timeout; + + /* counter for request timeouts, after 2 timeouts the socket is marked as dead */ + uint32_t timeout_count; + /* remember is the socket is dead */ BOOL dead; }; @@ -64,6 +71,8 @@ struct wrepl_request { size_t num_read; + struct timed_event *te; + struct wrepl_packet *packet; struct { -- cgit