s4:libcli/ldap: send AbandonRequests for cancelled requests
authorStefan Metzmacher <metze@samba.org>
Mon, 1 Feb 2016 10:00:14 +0000 (11:00 +0100)
committerGarming Sam <garming@samba.org>
Wed, 17 Feb 2016 02:43:22 +0000 (03:43 +0100)
This happens on a local timeout of an talloc_free() of the request.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/libcli/ldap/ldap_client.c

index 4b8f9518cc9cd98f620910a17ac75fd9e5e1d77a..97a83cec4ab38988c98ec4d40c7d1cd607357b2b 100644 (file)
@@ -662,15 +662,50 @@ static void ldap_reconnect(struct ldap_connection *conn)
        }
 }
 
+static void ldap_request_destructor_abandon(struct ldap_request *abandon)
+{
+       TALLOC_FREE(abandon);
+}
+
 /* destroy an open ldap request */
 static int ldap_request_destructor(struct ldap_request *req)
 {
        if (req->state == LDAP_REQUEST_PENDING) {
+               struct ldap_message msg = {
+                       .type = LDAP_TAG_AbandonRequest,
+                       .r.AbandonRequest.messageid = req->messageid,
+               };
+               struct ldap_request *abandon = NULL;
+
                DLIST_REMOVE(req->conn->pending, req);
+
+               abandon = ldap_request_send(req->conn, &msg);
+               if (abandon == NULL) {
+                       ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+                       return 0;
+               }
+               abandon->async.fn = ldap_request_destructor_abandon;
+               abandon->async.private_data = NULL;
        }
+
        return 0;
 }
 
+static void ldap_request_timeout_abandon(struct ldap_request *abandon)
+{
+       struct ldap_request *req =
+               talloc_get_type_abort(abandon->async.private_data,
+               struct ldap_request);
+
+       if (req->state == LDAP_REQUEST_PENDING) {
+               DLIST_REMOVE(req->conn->pending, req);
+       }
+       req->state = LDAP_REQUEST_DONE;
+       if (req->async.fn) {
+               req->async.fn(req);
+       }
+}
+
 /*
   called on timeout of a ldap request
 */
@@ -683,7 +718,22 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer
 
        req->status = NT_STATUS_IO_TIMEOUT;
        if (req->state == LDAP_REQUEST_PENDING) {
+               struct ldap_message msg = {
+                       .type = LDAP_TAG_AbandonRequest,
+                       .r.AbandonRequest.messageid = req->messageid,
+               };
+               struct ldap_request *abandon = NULL;
+
+               abandon = ldap_request_send(req->conn, &msg);
+               if (abandon == NULL) {
+                       ldap_error_handler(req->conn, NT_STATUS_NO_MEMORY);
+                       return;
+               }
+               talloc_reparent(req->conn, req, abandon);
+               abandon->async.fn = ldap_request_timeout_abandon;
+               abandon->async.private_data = req;
                DLIST_REMOVE(req->conn->pending, req);
+               return;
        }
        req->state = LDAP_REQUEST_DONE;
        if (req->async.fn) {