3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2012 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 Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
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, msgid, 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 Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
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, msgid, NULL, 0 );
116 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
125 LDAPControl **sctrls,
133 Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
136 /* find the request that we are abandoning */
138 lr = ld->ld_requests;
139 while ( lr != NULL ) {
141 if ( lr->lr_msgid == msgid ) {
145 /* child: abandon it */
146 if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
147 (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
148 sctrls, sendabandon );
150 /* restart, as lr may now be dangling... */
158 if ( origid == msgid && lr->lr_parent != NULL ) {
159 /* don't let caller abandon child requests! */
160 ld->ld_errno = LDAP_PARAM_ERROR;
161 return( LDAP_PARAM_ERROR );
163 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
164 /* no need to send abandon message */
169 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
170 * while we're in there.
172 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
173 err = ldap_msgdelete( ld, msgid );
174 LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
176 ld->ld_errno = LDAP_SUCCESS;
180 /* fetch again the request that we are abandoning */
182 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
184 if ( lr->lr_msgid == msgid ) {
192 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
195 ld->ld_errno = LDAP_SERVER_DOWN;
197 } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
198 /* BER element allocation failed */
200 ld->ld_errno = LDAP_NO_MEMORY;
204 * We already have the mutex in LDAP_R_COMPILE, so
205 * don't try to get it again.
206 * LDAP_NEXT_MSGID(ld, i);
209 LDAP_NEXT_MSGID(ld, i);
210 #ifdef LDAP_CONNECTIONLESS
211 if ( LDAP_IS_UDP(ld) ) {
212 struct sockaddr sa = {0};
213 /* dummy, filled with ldo_peer in request.c */
214 err = ber_write( ber, (char *) &sa, sizeof(sa), 0 );
216 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
220 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
221 dn = ld->ld_options.ldo_cldapdn;
223 err = ber_printf( ber, "{isti", /* '}' */
225 LDAP_REQ_ABANDON, msgid );
226 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
230 /* create a message to send */
231 err = ber_printf( ber, "{iti", /* '}' */
233 LDAP_REQ_ABANDON, msgid );
238 ld->ld_errno = LDAP_ENCODING_ERROR;
241 /* Put Server Controls */
242 if ( ldap_int_put_controls( ld, sctrls, ber )
249 err = ber_printf( ber, /*{*/ "N}" );
253 ld->ld_errno = LDAP_ENCODING_ERROR;
262 /* send the message */
264 assert( lr->lr_conn != NULL );
265 sb = lr->lr_conn->lconn_sb;
270 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
271 ld->ld_errno = LDAP_SERVER_DOWN;
281 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
282 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
283 ldap_free_connection( ld, lr->lr_conn, 0, 1 );
284 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
287 if ( origid == msgid ) {
288 ldap_free_request( ld, lr );
291 lr->lr_abandoned = 1;
295 LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
299 if ( ld->ld_nabandoned == 0 ||
300 ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
302 ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
306 ld->ld_errno = LDAP_SUCCESS;
309 LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
310 return( ld->ld_errno );
314 * ldap_int_bisect_find
317 * v: array of length n (in)
318 * n: length of array v (in)
319 * id: value to look for (in)
320 * idxp: pointer to location of value/insert point
328 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
339 if ( n <= 0 || id < v[ begin ] ) {
342 } else if ( id > v[ end ] ) {
350 pos = (begin + end)/2;
356 } else if ( id > curid ) {
360 /* already abandoned? */
364 } while ( end >= begin );
373 * ldap_int_bisect_insert
376 * vp: pointer to array of length *np (in/out)
377 * np: pointer to length of array *vp (in/out)
378 * id: value to insert (in)
379 * idx: location of insert point (as computed by ldap_int_bisect_find())
386 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
392 assert( vp != NULL );
393 assert( np != NULL );
395 assert( (unsigned) idx <= *np );
399 v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
405 for ( i = n; i > idx; i-- ) {
415 * ldap_int_bisect_delete
418 * vp: pointer to array of length *np (in/out)
419 * np: pointer to length of array *vp (in/out)
420 * id: value to delete (in)
421 * idx: location of value to delete (as computed by ldap_int_bisect_find())
427 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
432 assert( vp != NULL );
433 assert( np != NULL );
435 assert( (unsigned) idx < *np );
439 assert( v[ idx ] == id );
444 for ( i = idx; i < n; i++ ) {