r10547: - add wrepl_request timeout handling
authorStefan Metzmacher <metze@samba.org>
Tue, 27 Sep 2005 16:53:08 +0000 (16:53 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:39:04 +0000 (13:39 -0500)
- 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

source/libcli/wrepl/winsrepl.c
source/libcli/wrepl/winsrepl.h

index 853ee01d388a14bd4c4200a7ab0b4a6151680fb1..4284c5cdbbd85353f8a92b353b75f7f7f524389a 100644 (file)
 /*
   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;
        }
index a966cf5451a13f84c56e421b554b409649c2ea76..64e09d61c62d3c4f3265671c84c4477287c679a1 100644 (file)
@@ -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 {