r22470: merge handling of broken connections from wins replication client code
authorStefan Metzmacher <metze@samba.org>
Sun, 22 Apr 2007 23:00:22 +0000 (23:00 +0000)
committerStefan Metzmacher <metze@samba.org>
Sun, 22 Apr 2007 23:00:22 +0000 (23:00 +0000)
to the rpc client code

we need to always ask for read events on the socket otherwise we never
get the connection error reported.

shutdown the transport when a request timeout.

metze

source/librpc/rpc/dcerpc.c
source/librpc/rpc/dcerpc.h
source/librpc/rpc/dcerpc_smb.c
source/librpc/rpc/dcerpc_smb2.c
source/librpc/rpc/dcerpc_sock.c

index 820516ba11f3762cc6b8e3ca1a0e44951521481d..79e897313dd842a5a26078974c5cf3e4571d1d73 100644 (file)
@@ -37,14 +37,17 @@ NTSTATUS dcerpc_init(void)
        return NT_STATUS_OK;
 }
 
+static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
 
 /* destroy a dcerpc connection */
-static int dcerpc_connection_destructor(struct dcerpc_connection *c)
+static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
 {
-       if (c->transport.shutdown_pipe) {
-               c->transport.shutdown_pipe(c);
+       if (conn->dead) {
+               conn->free_skipped = True;
+               return -1;
        }
+       dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
        return 0;
 }
 
@@ -553,6 +556,14 @@ static int dcerpc_req_dequeue(struct rpc_request *req)
 */
 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
 {
+       if (conn->dead) return;
+
+       conn->dead = true;
+
+       if (conn->transport.shutdown_pipe) {
+               conn->transport.shutdown_pipe(conn, status);
+       }
+
        /* all pending requests get the error */
        while (conn->pending) {
                struct rpc_request *req = conn->pending;
@@ -563,6 +574,11 @@ static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS stat
                        req->async.callback(req);
                }
        }       
+
+       talloc_set_destructor(conn, NULL);
+       if (conn->free_skipped) {
+               talloc_free(conn);
+       }
 }
 
 /*
@@ -657,18 +673,7 @@ static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event
                                   struct timeval t, void *private)
 {
        struct rpc_request *req = talloc_get_type(private, struct rpc_request);
-
-       if (req->state == RPC_REQUEST_DONE) {
-               return;
-       }
-
-       dcerpc_req_dequeue(req);
-
-       req->status = NT_STATUS_IO_TIMEOUT;
-       req->state = RPC_REQUEST_DONE;
-       if (req->async.callback) {
-               req->async.callback(req);
-       }
+       dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
 }
 
 /*
index 8fed56584d190d7b7da68fbfde045ce6a1062900..c6dbc3547780decbc4ea691754eb38e9347542b1 100644 (file)
@@ -57,11 +57,14 @@ struct dcerpc_connection {
        const char *binding_string;
        struct event_context *event_ctx;
 
+       bool dead;
+       bool free_skipped;
+
        struct dcerpc_transport {
                enum dcerpc_transport_t transport;
                void *private;
 
-               NTSTATUS (*shutdown_pipe)(struct dcerpc_connection *);
+               NTSTATUS (*shutdown_pipe)(struct dcerpc_connection *, NTSTATUS status);
 
                const char *(*peer_name)(struct dcerpc_connection *);
 
index d6d2cf0dfbf8be72090567baaaa1e3e218a16cf7..55fc37d84f11d9c249889a1b1fdab0aaf611aa0d 100644 (file)
@@ -326,14 +326,14 @@ static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, B
 /* 
    shutdown SMB pipe connection
 */
-static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
+static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
 {
        struct smb_private *smb = c->transport.private;
        union smb_close io;
        struct smbcli_request *req;
 
        /* maybe we're still starting up */
-       if (!smb) return NT_STATUS_OK;
+       if (!smb) return status;
 
        io.close.level = RAW_CLOSE_CLOSE;
        io.close.in.file.fnum = smb->fnum;
@@ -346,7 +346,7 @@ static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
 
        talloc_free(smb);
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 /*
index 20d1c7c211c7be2137d7d0aa3018425badf8f200..d2ab47898eefc9f4a9de2d63c93f85877b9b70cf 100644 (file)
@@ -299,14 +299,14 @@ static NTSTATUS smb2_send_request(struct dcerpc_connection *c, DATA_BLOB *blob,
 /* 
    shutdown SMB pipe connection
 */
-static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c)
+static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
 {
        struct smb2_private *smb = c->transport.private;
        struct smb2_close io;
        struct smb2_request *req;
 
        /* maybe we're still starting up */
-       if (!smb) return NT_STATUS_OK;
+       if (!smb) return status;
 
        ZERO_STRUCT(io);
        io.in.file.handle = smb->handle;
@@ -318,7 +318,7 @@ static NTSTATUS smb2_shutdown_pipe(struct dcerpc_connection *c)
 
        talloc_free(smb);
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 /*
index ae7d00b6698bd25ff2b8324ef0ae10f7daba06e9..fd54a20afcfc39909e810810a836a39930bcc1f6 100644 (file)
@@ -48,12 +48,34 @@ static void sock_dead(struct dcerpc_connection *p, NTSTATUS status)
 {
        struct sock_private *sock = p->transport.private;
 
-       if (sock && sock->sock != NULL) {
+       if (!sock) return;
+
+       if (sock->fde) {
+               talloc_free(sock->fde);
+               sock->fde = NULL;
+       }
+
+       if (sock->sock) {
                talloc_free(sock->fde);
+               sock->fde = NULL;
                talloc_free(sock->sock);
                sock->sock = NULL;
        }
 
+       if (sock->packet) {
+               packet_recv_disable(sock->packet);
+               packet_set_fde(sock->packet, NULL);
+               packet_set_socket(sock->packet, NULL);
+       }
+
+       if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
+               status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
+               status = NT_STATUS_END_OF_FILE;
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                p->transport.recv_data(p, NULL, status);
        }
@@ -172,15 +194,15 @@ static NTSTATUS sock_send_request(struct dcerpc_connection *p, DATA_BLOB *data,
 /* 
    shutdown sock pipe connection
 */
-static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p)
+static NTSTATUS sock_shutdown_pipe(struct dcerpc_connection *p, NTSTATUS status)
 {
        struct sock_private *sock = p->transport.private;
 
        if (sock && sock->sock) {
-               sock_dead(p, NT_STATUS_OK);
+               sock_dead(p, status);
        }
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 /*
@@ -253,7 +275,7 @@ static void continue_socket_connect(struct composite_context *ctx)
        sock->server_name   = strupper_talloc(sock, s->target_hostname);
 
        sock->fde = event_add_fd(conn->event_ctx, sock->sock, socket_get_fd(sock->sock),
-                                0, sock_io_handler, conn);
+                                EVENT_FD_READ, sock_io_handler, conn);
        
        conn->transport.private = sock;
 
@@ -272,7 +294,6 @@ static void continue_socket_connect(struct composite_context *ctx)
        packet_set_event_context(sock->packet, conn->event_ctx);
        packet_set_fde(sock->packet, sock->fde);
        packet_set_serialise(sock->packet);
-       packet_recv_disable(sock->packet);
        packet_set_initial_read(sock->packet, 16);
 
        /* ensure we don't get SIGPIPE */