STEP01: librpc/rpc/dcerpc_connection.c dcerpc_connection_dead() dcerpc_connection_is_...
authorStefan Metzmacher <metze@samba.org>
Wed, 22 Jan 2014 10:15:05 +0000 (11:15 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 10:45:39 +0000 (12:45 +0200)
librpc/rpc/dcerpc_connection.c
librpc/rpc/dcerpc_connection.h

index 6e5440ad65d560336500d467cc8556b17622b0d9..a7707afc15362e166e4ca0e7a0657de5997f43fb 100644 (file)
@@ -166,6 +166,67 @@ void dcerpc_connection_set_use_trans_fn(struct dcerpc_connection *conn,
        conn->transport.use_trans_fn = fn;
 }
 
+bool dcerpc_connection_is_connected(const struct dcerpc_connection *conn)
+{
+       if (conn == NULL) {
+               return false;
+       }
+
+       if (conn->transport.stream == NULL) {
+               return false;
+       }
+
+       return true;
+}
+
+static void dcerpc_connection_dead(struct dcerpc_connection *conn,
+                                  NTSTATUS error)
+{
+       struct dcerpc_call *call = NULL;
+
+       if (conn == NULL) {
+               return;
+       }
+
+       if (conn->transport.stream == NULL) {
+               return;
+       }
+
+       tevent_queue_stop(conn->transport.write_queue);
+       tevent_queue_stop(conn->calls.out_queue);
+       TALLOC_FREE(conn->loop.subreq);
+       TALLOC_FREE(conn->transport.stream);
+
+       if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, error)) {
+               error = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       if (NT_STATUS_EQUAL(NT_STATUS_OK, error)) {
+               error = NT_STATUS_END_OF_FILE;
+       }
+
+       if (conn->calls.active != NULL) {
+               DLIST_PROMOTE(conn->calls.list, conn->calls.active);
+       }
+
+       if (conn->calls.new_call != NULL) {
+               DLIST_ADD_END(conn->calls.list, conn->calls.new_call, NULL);
+               conn->calls.new_call = NULL;
+       }
+
+       for (call = conn->calls.list; call; call = call->next) {
+               if (call->incoming.req == NULL) {
+                       continue;
+               }
+
+               /*
+                * the request was already prepared with
+                * tevent_req_defer_callback().
+                */
+               tevent_req_nterror(call->incoming.req, error);
+       }
+}
+
 struct dcerpc_security *dcerpc_security_allocate(
                                        TALLOC_CTX *mem_ctx,
                                        struct dcerpc_connection *conn,
@@ -789,7 +850,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
        error = dcerpc_read_ncacn_packet_recv(subreq, subreq, &pkt, &pdu);
        if (!NT_STATUS_IS_OK(error)) {
                TALLOC_FREE(subreq);
-               // disconnect and notify pending calls
+               dcerpc_connection_dead(conn, error);
                return;
        }
 
@@ -896,14 +957,14 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
 
        if (!valid_type) {
                TALLOC_FREE(subreq);
-               // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+               dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                return;
        }
 
        if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
                if (!allow_fragments) {
                        TALLOC_FREE(subreq);
-                       // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+                       dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                        return;
                }
        }
@@ -912,13 +973,13 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
 
                if (pkt->call_id != conn->calls.active->call_id) {
                        TALLOC_FREE(subreq);
-                       // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+                       dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                        return;
                }
 
                if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) {
                        TALLOC_FREE(subreq);
-                       // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+                       dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                        return;
                }
 
@@ -930,7 +991,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
        } else {
                if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
                        TALLOC_FREE(subreq);
-                       // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+                       dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                        return;
                }
 
@@ -949,13 +1010,13 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
 
        if (call == NULL) {
                TALLOC_FREE(subreq);
-               // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+               dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                return;
        }
 
        if (call->incoming.handler == NULL) {
                TALLOC_FREE(subreq);
-               // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
+               dcerpc_connection_dead(conn, NT_STATUS_RPC_PROTOCOL_ERROR);
                return;
        }
 
@@ -970,7 +1031,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
        error = call->incoming.handler(call->incoming.req, pkt, pdu);
        TALLOC_FREE(subreq);
        if (!NT_STATUS_IS_OK(error)) {
-               // disconnect and notify pending calls
+               dcerpc_connection_dead(conn, error);
                return;
        }
 
@@ -981,7 +1042,7 @@ static void dcerpc_connection_loop(struct tevent_req *subreq)
 
        error = dcerpc_connection_loop_restart(conn, conn->loop.ev);
        if (!NT_STATUS_IS_OK(error)) {
-               // disconnect and notify pending calls
+               dcerpc_connection_dead(conn, error);
                return;
        }
 }
@@ -1096,6 +1157,9 @@ static void dcerpc_do_bind_cleanup(struct tevent_req *req,
        }
 
        if (state->call != NULL) {
+               if (state->call == state->conn->calls.active) {
+                       state->conn->calls.active = NULL;
+               }
                ZERO_STRUCT(state->call->incoming);
                DLIST_REMOVE(state->conn->calls.list, state->call);
                state->call = NULL;
@@ -1380,25 +1444,23 @@ static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
        struct dcerpc_do_bind_out_frag *frag =
                tevent_req_callback_data(subreq,
                struct dcerpc_do_bind_out_frag);
-       struct tevent_req *req = frag->req;
+       struct dcerpc_connection *conn = frag->conn;
        NTSTATUS status;
        bool ok;
 
        /*
+        * always wait1???
         * TODO; what if the caller has been free'ed?
+        * TALLOC_FREE(frag->subreq_write)
         */
 
        frag->subreq_wait1 = NULL;
-       frag->conn->loop.subreq = NULL;
+       conn->loop.subreq = NULL;
 
        ok = tevent_queue_wait_recv(subreq);
        if (!ok) {
-               status = NT_STATUS_INTERNAL_ERROR;
                TALLOC_FREE(frag);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
-               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               dcerpc_connection_dead(conn, NT_STATUS_INTERNAL_ERROR);
                return;
        }
 
@@ -1425,10 +1487,7 @@ static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
        status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frag);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
-               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               dcerpc_connection_dead(conn, status);
                return;
        }
 
@@ -1438,10 +1497,7 @@ static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
        status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frag);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
-               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               dcerpc_connection_dead(conn, status);
                return;
        }
 }
@@ -1451,6 +1507,7 @@ static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq)
        struct dcerpc_do_bind_out_frag *frag =
                tevent_req_callback_data(subreq,
                struct dcerpc_do_bind_out_frag);
+       struct dcerpc_connection *conn = frag->conn;
        struct tevent_req *req = frag->req;
        NTSTATUS status;
        int ret;
@@ -1473,9 +1530,7 @@ static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq)
        if (ret == -1) {
                TALLOC_FREE(frag);
                status = map_nt_error_from_unix_common(sys_errno);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
+               dcerpc_connection_dead(conn, status);
                return;
        }
 
@@ -1502,7 +1557,7 @@ static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
        struct dcerpc_do_bind_out_frag *frag =
                tevent_req_callback_data(subreq,
                struct dcerpc_do_bind_out_frag);
-       struct tevent_req *req = frag->req;
+       struct dcerpc_connection *conn = frag->conn;
        NTSTATUS status;
        bool ok;
 
@@ -1510,12 +1565,8 @@ static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
 
        ok = tevent_queue_wait_recv(subreq);
        if (!ok) {
-               status = NT_STATUS_INTERNAL_ERROR;
                TALLOC_FREE(frag);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
-               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               dcerpc_connection_dead(conn, NT_STATUS_INTERNAL_ERROR);
                return;
        }
 
@@ -1524,10 +1575,7 @@ static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
        status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frag);
-               if (req) {
-                       tevent_req_nterror(req, status);
-               }
-               //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
+               dcerpc_connection_dead(conn, status);
                return;
        }
 
index d1acf64606c034b1681334285803ce30d28820c1..c0a286c3eff59c8a80a29f2b573ee933792f91c7 100644 (file)
@@ -40,6 +40,7 @@ struct dcerpc_connection *dcerpc_connection_create(TALLOC_CTX *mem_ctx,
 typedef NTSTATUS (*dcerpc_connection_use_trans_fn)(struct tstream_context *stream);
 void dcerpc_connection_set_use_trans_fn(struct dcerpc_connection *conn,
                                        dcerpc_connection_use_trans_fn fn);
+bool dcerpc_connection_is_connected(const struct dcerpc_connection *conn);
 struct dcerpc_security *dcerpc_security_allocate(
                                        TALLOC_CTX *mem_ctx,
                                        struct dcerpc_connection *conn,