summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Disseldorp <ddiss@samba.org>2014-03-03 19:49:35 +0100
committerJeremy Allison <jra@samba.org>2014-03-04 03:03:24 +0100
commitebe6627c1f0e6b488a0c456860a055fd5701e84d (patch)
tree0999bfe4923e92593aaf573964bdae8bb390d9f9
parentfb2631f5dfd3ec58fd277dbe155afab58f882202 (diff)
downloadsamba-ebe6627c1f0e6b488a0c456860a055fd5701e84d.tar.gz
samba-ebe6627c1f0e6b488a0c456860a055fd5701e84d.tar.xz
samba-ebe6627c1f0e6b488a0c456860a055fd5701e84d.zip
rpc_client: retry open on STATUS_PIPE_NOT_AVAILABLE
Windows Server starts some named pipe services on demand, and responds to initial open requests with STATUS_PIPE_NOT_AVAILABLE. The FssagentRpc named pipe on Windows Server 2012 exhibits this behaviour. This change sees rpcclient retry named pipe open requests when the server responds with STATUS_PIPE_NOT_AVAILABLE. The retry logic is contained in an asynchronous tevent_timer callback, to allow for non-blocking callers. Signed-off-by: David Disseldorp <ddiss@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r--source3/rpc_client/rpc_transport_np.c85
1 files changed, 68 insertions, 17 deletions
diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c
index 86190c67338..7f2f1bf5162 100644
--- a/source3/rpc_client/rpc_transport_np.c
+++ b/source3/rpc_client/rpc_transport_np.c
@@ -30,6 +30,15 @@
struct rpc_transport_np_init_state {
struct rpc_cli_transport *transport;
+ int retries;
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ int timeout;
+ struct timeval abs_timeout;
+ const char *pipe_name;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint16_t pid;
};
static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq);
@@ -41,11 +50,7 @@ struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req;
struct rpc_transport_np_init_state *state;
- const char *pipe_name;
struct tevent_req *subreq;
- struct smbXcli_session *session;
- struct smbXcli_tcon *tcon;
- uint16_t pid = 0;
req = tevent_req_create(mem_ctx, &state,
struct rpc_transport_np_init_state);
@@ -54,26 +59,32 @@ struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
}
if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
- tcon = cli->smb2.tcon;
- session = cli->smb2.session;
+ state->tcon = cli->smb2.tcon;
+ state->session = cli->smb2.session;
} else {
- tcon = cli->smb1.tcon;
- session = cli->smb1.session;
- pid = cli->smb1.pid;
+ state->tcon = cli->smb1.tcon;
+ state->session = cli->smb1.session;
+ state->pid = cli->smb1.pid;
}
- pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
- if (tevent_req_nomem(pipe_name, req)) {
+ state->ev = ev;
+ state->conn = cli->conn;
+ state->timeout = cli->timeout;
+ state->abs_timeout = timeval_current_ofs_msec(cli->timeout);
+ state->pipe_name = dcerpc_default_transport_endpoint(state, NCACN_NP,
+ table);
+ if (tevent_req_nomem(state->pipe_name, req)) {
return tevent_req_post(req, ev);
}
- while (pipe_name[0] == '\\') {
- pipe_name++;
+ while (state->pipe_name[0] == '\\') {
+ state->pipe_name++;
}
- subreq = tstream_smbXcli_np_open_send(state, ev, cli->conn,
- session, tcon, pid,
- cli->timeout, pipe_name);
+ subreq = tstream_smbXcli_np_open_send(state, ev, state->conn,
+ state->session, state->tcon,
+ state->pid, state->timeout,
+ state->pipe_name);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
@@ -82,6 +93,30 @@ struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
return req;
}
+static void rpc_transport_np_init_pipe_open_retry(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t,
+ void *priv_data)
+{
+ struct tevent_req *subreq;
+ struct tevent_req *req = talloc_get_type(priv_data, struct tevent_req);
+ struct rpc_transport_np_init_state *state = tevent_req_data(
+ req, struct rpc_transport_np_init_state);
+
+ subreq = tstream_smbXcli_np_open_send(state, ev,
+ state->conn,
+ state->session,
+ state->tcon,
+ state->pid,
+ state->timeout,
+ state->pipe_name);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open, req);
+ state->retries++;
+}
+
static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
@@ -93,7 +128,23 @@ static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
status = tstream_smbXcli_np_open_recv(subreq, state, &stream);
TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_NOT_AVAILABLE)
+ && (!timeval_expired(&state->abs_timeout))) {
+ struct tevent_timer *te;
+ /*
+ * Retry on STATUS_PIPE_NOT_AVAILABLE, Windows starts some
+ * servers (FssagentRpc) on demand.
+ */
+ DEBUG(2, ("RPC pipe %s not available, retry %d\n",
+ state->pipe_name, state->retries));
+ te = tevent_add_timer(state->ev, state,
+ timeval_current_ofs_msec(100 * state->retries),
+ rpc_transport_np_init_pipe_open_retry, req);
+ if (tevent_req_nomem(te, req)) {
+ return;
+ }
+ return;
+ } else if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
return;
}