From 1912124dbfc501c5109f6ac36e125406078d408c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 22 Apr 2007 23:00:22 +0000 Subject: r22470: merge handling of broken connections from wins replication client code 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 (This used to be commit 3403c0cb15e08ec838b0bc834f941051fb94d124) --- source4/librpc/rpc/dcerpc.c | 35 ++++++++++++++++++++--------------- source4/librpc/rpc/dcerpc.h | 5 ++++- source4/librpc/rpc/dcerpc_smb.c | 6 +++--- source4/librpc/rpc/dcerpc_smb2.c | 6 +++--- source4/librpc/rpc/dcerpc_sock.c | 33 +++++++++++++++++++++++++++------ 5 files changed, 57 insertions(+), 28 deletions(-) (limited to 'source4') diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 820516ba11..79e897313d 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -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); } /* diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h index 8fed56584d..c6dbc35477 100644 --- a/source4/librpc/rpc/dcerpc.h +++ b/source4/librpc/rpc/dcerpc.h @@ -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 *); diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c index d6d2cf0dfb..55fc37d84f 100644 --- a/source4/librpc/rpc/dcerpc_smb.c +++ b/source4/librpc/rpc/dcerpc_smb.c @@ -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; } /* diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c index 20d1c7c211..d2ab47898e 100644 --- a/source4/librpc/rpc/dcerpc_smb2.c +++ b/source4/librpc/rpc/dcerpc_smb2.c @@ -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; } /* diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c index ae7d00b669..fd54a20afc 100644 --- a/source4/librpc/rpc/dcerpc_sock.c +++ b/source4/librpc/rpc/dcerpc_sock.c @@ -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 */ -- cgit