3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
17 * All rights reserved.
24 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
33 * An abandon request looks like this:
34 * AbandonRequest ::= [APPLICATION 16] MessageID
35 * and has no response. (Source: RFC 4511)
48 * ldap_abandon_ext - perform an ldap extended abandon operation.
52 * msgid The message id of the operation to abandon
53 * scntrls Server Controls
54 * ccntrls Client Controls
56 * ldap_abandon_ext returns a LDAP error code.
57 * (LDAP_SUCCESS if everything went ok)
60 * ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
67 LDAPControl
**cctrls
)
71 Debug1( LDAP_DEBUG_TRACE
, "ldap_abandon_ext %d\n", msgid
);
73 /* check client controls */
74 LDAP_MUTEX_LOCK( &ld
->ld_req_mutex
);
76 rc
= ldap_int_client_controls( ld
, cctrls
);
77 if ( rc
== LDAP_SUCCESS
) {
78 rc
= do_abandon( ld
, msgid
, NULL
, sctrls
, 1 );
81 LDAP_MUTEX_UNLOCK( &ld
->ld_req_mutex
);
88 * ldap_abandon - perform an ldap abandon operation. Parameters:
91 * msgid The message id of the operation to abandon
93 * ldap_abandon returns 0 if everything went ok, -1 otherwise.
96 * ldap_abandon( ld, msgid );
99 ldap_abandon( LDAP
*ld
, int msgid
)
101 Debug1( LDAP_DEBUG_TRACE
, "ldap_abandon %d\n", msgid
);
102 return ldap_abandon_ext( ld
, msgid
, NULL
, NULL
) == LDAP_SUCCESS
114 LDAP_MUTEX_LOCK( &ld
->ld_req_mutex
);
115 rc
= do_abandon( ld
, msgid
, NULL
, NULL
, 0 );
116 LDAP_MUTEX_UNLOCK( &ld
->ld_req_mutex
);
125 LDAPControl
**sctrls
,
130 ber_int_t msgid
= origid
;
132 LDAPRequest needle
= {0};
134 needle
.lr_msgid
= origid
;
137 msgid
= lr
->lr_msgid
;
138 Debug2( LDAP_DEBUG_TRACE
, "do_abandon origid %d, msgid %d\n",
140 } else if ( (lr
= ldap_tavl_find( ld
->ld_requests
, &needle
, ldap_req_cmp
)) != NULL
) {
141 Debug2( LDAP_DEBUG_TRACE
, "do_abandon origid %d, msgid %d\n",
143 if ( lr
->lr_parent
!= NULL
) {
144 /* don't let caller abandon child requests! */
145 ld
->ld_errno
= LDAP_PARAM_ERROR
;
146 return( LDAP_PARAM_ERROR
);
148 msgid
= lr
->lr_msgid
;
152 LDAPRequest
**childp
= &lr
->lr_child
;
154 needle
.lr_msgid
= lr
->lr_msgid
;
156 if ( lr
->lr_status
!= LDAP_REQST_INPROGRESS
) {
157 /* no need to send abandon message */
162 /* Abandon children */
163 LDAPRequest
*child
= *childp
;
165 (void)do_abandon( ld
, lr
->lr_origid
, child
, sctrls
, sendabandon
);
166 if ( *childp
== child
) {
167 childp
= &child
->lr_refnext
;
172 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
173 * while we're in there.
175 LDAP_MUTEX_UNLOCK( &ld
->ld_req_mutex
);
176 err
= ldap_msgdelete( ld
, msgid
);
177 LDAP_MUTEX_LOCK( &ld
->ld_req_mutex
);
179 ld
->ld_errno
= LDAP_SUCCESS
;
183 /* fetch again the request that we are abandoning */
185 lr
= ldap_tavl_find( ld
->ld_requests
, &needle
, ldap_req_cmp
);
190 if ( ber_sockbuf_ctrl( ld
->ld_sb
, LBER_SB_OPT_GET_FD
, NULL
) == -1 ) {
193 ld
->ld_errno
= LDAP_SERVER_DOWN
;
195 } else if ( ( ber
= ldap_alloc_ber_with_options( ld
) ) == NULL
) {
196 /* BER element allocation failed */
198 ld
->ld_errno
= LDAP_NO_MEMORY
;
202 * We already have the mutex in LDAP_R_COMPILE, so
203 * don't try to get it again.
204 * LDAP_NEXT_MSGID(ld, i);
207 LDAP_NEXT_MSGID(ld
, i
);
208 #ifdef LDAP_CONNECTIONLESS
209 if ( LDAP_IS_UDP(ld
) ) {
210 struct sockaddr_storage sa
= {0};
211 /* dummy, filled with ldo_peer in request.c */
212 err
= ber_write( ber
, (char *) &sa
, sizeof(sa
), 0 );
214 if ( LDAP_IS_UDP(ld
) && ld
->ld_options
.ldo_version
==
218 LDAP_MUTEX_LOCK( &ld
->ld_options
.ldo_mutex
);
219 dn
= ld
->ld_options
.ldo_cldapdn
;
221 err
= ber_printf( ber
, "{isti", /* '}' */
223 LDAP_REQ_ABANDON
, msgid
);
224 LDAP_MUTEX_UNLOCK( &ld
->ld_options
.ldo_mutex
);
228 /* create a message to send */
229 err
= ber_printf( ber
, "{iti", /* '}' */
231 LDAP_REQ_ABANDON
, msgid
);
236 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
239 /* Put Server Controls */
240 if ( ldap_int_put_controls( ld
, sctrls
, ber
)
247 err
= ber_printf( ber
, /*{*/ "N}" );
251 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
260 /* send the message */
262 assert( lr
->lr_conn
!= NULL
);
263 sb
= lr
->lr_conn
->lconn_sb
;
268 if ( ber_flush2( sb
, ber
, LBER_FLUSH_FREE_ALWAYS
) != 0 ) {
269 ld
->ld_errno
= LDAP_SERVER_DOWN
;
281 if ( sendabandon
|| lr
->lr_status
== LDAP_REQST_WRITING
) {
285 if ( origid
== msgid
) {
286 ldap_free_request( ld
, lr
);
289 lr
->lr_abandoned
= 1;
293 /* release ld_req_mutex while grabbing ld_conn_mutex to
296 LDAP_MUTEX_UNLOCK( &ld
->ld_req_mutex
);
297 LDAP_MUTEX_LOCK( &ld
->ld_conn_mutex
);
298 ldap_free_connection( ld
, lc
, 0, 1 );
299 LDAP_MUTEX_UNLOCK( &ld
->ld_conn_mutex
);
300 LDAP_MUTEX_LOCK( &ld
->ld_req_mutex
);
304 LDAP_MUTEX_LOCK( &ld
->ld_abandon_mutex
);
308 if ( ld
->ld_nabandoned
== 0 ||
309 ldap_int_bisect_find( ld
->ld_abandoned
, ld
->ld_nabandoned
, msgid
, &i
) == 0 )
311 ldap_int_bisect_insert( &ld
->ld_abandoned
, &ld
->ld_nabandoned
, msgid
, i
);
315 ld
->ld_errno
= LDAP_SUCCESS
;
318 LDAP_MUTEX_UNLOCK( &ld
->ld_abandon_mutex
);
319 return( ld
->ld_errno
);
323 * ldap_int_bisect_find
326 * v: array of length n (in)
327 * n: length of array v (in)
328 * id: value to look for (in)
329 * idxp: pointer to location of value/insert point
337 ldap_int_bisect_find( ber_int_t
*v
, ber_len_t n
, ber_int_t id
, int *idxp
)
348 if ( n
<= 0 || id
< v
[ begin
] ) {
351 } else if ( id
> v
[ end
] ) {
359 pos
= (begin
+ end
)/2;
365 } else if ( id
> curid
) {
369 /* already abandoned? */
373 } while ( end
>= begin
);
382 * ldap_int_bisect_insert
385 * vp: pointer to array of length *np (in/out)
386 * np: pointer to length of array *vp (in/out)
387 * id: value to insert (in)
388 * idx: location of insert point (as computed by ldap_int_bisect_find())
395 ldap_int_bisect_insert( ber_int_t
**vp
, ber_len_t
*np
, int id
, int idx
)
401 assert( vp
!= NULL
);
402 assert( np
!= NULL
);
404 assert( (unsigned) idx
<= *np
);
408 v
= ber_memrealloc( *vp
, sizeof( ber_int_t
) * ( n
+ 1 ) );
414 for ( i
= n
; i
> idx
; i
-- ) {
424 * ldap_int_bisect_delete
427 * vp: pointer to array of length *np (in/out)
428 * np: pointer to length of array *vp (in/out)
429 * id: value to delete (in)
430 * idx: location of value to delete (as computed by ldap_int_bisect_find())
436 ldap_int_bisect_delete( ber_int_t
**vp
, ber_len_t
*np
, int id
, int idx
)
441 assert( vp
!= NULL
);
442 assert( np
!= NULL
);
444 assert( (unsigned) idx
< *np
);
448 assert( v
[ idx
] == id
);
453 for ( i
= idx
; i
< n
; i
++ ) {