First part of fix for bug #7159 - client rpc_transport doesn't cope with bad server...
[samba.git] / source3 / rpc_client / rpc_transport_sock.c
index 4ab6500900349544b367177791468e084919f6d7..4ab17dbd8daf0f86e206f6203fef7a67592f6394 100644 (file)
@@ -24,6 +24,7 @@
 
 struct rpc_transport_sock_state {
        int fd;
+       int timeout;
 };
 
 static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
@@ -51,6 +52,7 @@ static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
                priv, struct rpc_transport_sock_state);
        struct tevent_req *req, *subreq;
        struct rpc_sock_read_state *state;
+       struct timeval endtime;
 
        req = tevent_req_create(mem_ctx, &state, struct rpc_sock_read_state);
        if (req == NULL) {
@@ -61,10 +63,16 @@ static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->transp = sock_transp;
+       endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
        subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
        if (subreq == NULL) {
                goto fail;
        }
+
+       if (!tevent_req_set_endtime(subreq, ev, endtime)) {
+               goto fail;
+       }
+
        tevent_req_set_callback(subreq, rpc_sock_read_done, req);
        return req;
  fail:
@@ -80,15 +88,21 @@ static void rpc_sock_read_done(struct tevent_req *subreq)
                req, struct rpc_sock_read_state);
        int err;
 
+       /* We must free subreq in this function as there is
+         a timer event attached to it. */
+
        state->received = async_recv_recv(subreq, &err);
+
        if (state->received == -1) {
                if (state->transp->fd != -1) {
                        close(state->transp->fd);
                        state->transp->fd = -1;
                }
+               TALLOC_FREE(subreq);
                tevent_req_nterror(req, map_nt_error_from_unix(err));
                return;
        }
+       TALLOC_FREE(subreq);
        tevent_req_done(req);
 }
 
@@ -121,6 +135,7 @@ static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
                priv, struct rpc_transport_sock_state);
        struct tevent_req *req, *subreq;
        struct rpc_sock_write_state *state;
+       struct timeval endtime;
 
        req = tevent_req_create(mem_ctx, &state, struct rpc_sock_write_state);
        if (req == NULL) {
@@ -131,10 +146,16 @@ static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
        state->transp = sock_transp;
+       endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
        subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
        if (subreq == NULL) {
                goto fail;
        }
+
+       if (!tevent_req_set_endtime(subreq, ev, endtime)) {
+               goto fail;
+       }
+
        tevent_req_set_callback(subreq, rpc_sock_write_done, req);
        return req;
  fail:
@@ -150,15 +171,21 @@ static void rpc_sock_write_done(struct tevent_req *subreq)
                req, struct rpc_sock_write_state);
        int err;
 
+       /* We must free subreq in this function as there is
+         a timer event attached to it. */
+
        state->sent = async_send_recv(subreq, &err);
+
        if (state->sent == -1) {
                if (state->transp->fd != -1) {
                        close(state->transp->fd);
                        state->transp->fd = -1;
                }
+               TALLOC_FREE(subreq);
                tevent_req_nterror(req, map_nt_error_from_unix(err));
                return;
        }
+       TALLOC_FREE(subreq);
        tevent_req_done(req);
 }
 
@@ -193,6 +220,7 @@ NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
        result->priv = state;
 
        state->fd = fd;
+       state->timeout = 10000; /* 10 seconds. */
        talloc_set_destructor(state, rpc_transport_sock_state_destructor);
 
        result->trans_send = NULL;
@@ -205,3 +233,40 @@ NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
        *presult = result;
        return NT_STATUS_OK;
 }
+
+int rpccli_set_sock_timeout(struct rpc_pipe_client *cli, int timeout)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       int orig_timeout;
+       if (!state) {
+               return 0;
+       }
+       orig_timeout = state->timeout;
+       state->timeout = timeout;
+       return orig_timeout;
+}
+
+void rpccli_close_sock_fd(struct rpc_pipe_client *cli)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       if (state) {
+               if (state->fd != -1) {
+                       close(state->fd);
+                       state->fd = -1;
+               }
+       }
+       return;
+}
+
+bool rpc_pipe_tcp_connection_ok(struct rpc_pipe_client *cli)
+{
+       struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
+                                                       struct rpc_transport_sock_state);
+       if (state && state->fd != -1) {
+               return true;
+       }
+
+       return false;
+}