2 /* $OpenLDAP: pkg/ldap/libraries/libldap/abandon.c,v 1.41.2.7 2008/02/11 23:26:41 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 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 */
75 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
78 rc
= ldap_int_client_controls( ld
, cctrls
);
79 if ( rc
== LDAP_SUCCESS
) {
80 rc
= do_abandon( ld
, msgid
, msgid
, sctrls
, 1 );
84 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
92 * ldap_abandon - perform an ldap abandon operation. Parameters:
95 * msgid The message id of the operation to abandon
97 * ldap_abandon returns 0 if everything went ok, -1 otherwise.
100 * ldap_abandon( ld, msgid );
103 ldap_abandon( LDAP
*ld
, int msgid
)
105 Debug( LDAP_DEBUG_TRACE
, "ldap_abandon %d\n", msgid
, 0, 0 );
106 return ldap_abandon_ext( ld
, msgid
, NULL
, NULL
) == LDAP_SUCCESS
118 #ifdef LDAP_R_COMPILE
119 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
122 rc
= do_abandon( ld
, msgid
, msgid
, NULL
, 0 );
124 #ifdef LDAP_R_COMPILE
125 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
136 LDAPControl
**sctrls
,
144 Debug( LDAP_DEBUG_TRACE
, "do_abandon origid %d, msgid %d\n",
147 /* find the request that we are abandoning */
149 lr
= ld
->ld_requests
;
150 while ( lr
!= NULL
) {
152 if ( lr
->lr_msgid
== msgid
) {
156 /* child: abandon it */
157 if ( lr
->lr_origid
== msgid
&& !lr
->lr_abandoned
) {
158 (void)do_abandon( ld
, lr
->lr_origid
, lr
->lr_msgid
,
159 sctrls
, sendabandon
);
161 /* restart, as lr may now be dangling... */
169 if ( origid
== msgid
&& lr
->lr_parent
!= NULL
) {
170 /* don't let caller abandon child requests! */
171 ld
->ld_errno
= LDAP_PARAM_ERROR
;
172 return( LDAP_PARAM_ERROR
);
174 if ( lr
->lr_status
!= LDAP_REQST_INPROGRESS
) {
175 /* no need to send abandon message */
180 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
181 * while we're in there.
183 #ifdef LDAP_R_COMPILE
184 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
186 err
= ldap_msgdelete( ld
, msgid
);
187 #ifdef LDAP_R_COMPILE
188 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
191 ld
->ld_errno
= LDAP_SUCCESS
;
195 /* fetch again the request that we are abandoning */
197 for ( lr
= ld
->ld_requests
; lr
!= NULL
; lr
= lr
->lr_next
) {
199 if ( lr
->lr_msgid
== msgid
) {
207 if ( ber_sockbuf_ctrl( ld
->ld_sb
, LBER_SB_OPT_GET_FD
, NULL
) == -1 ) {
210 ld
->ld_errno
= LDAP_SERVER_DOWN
;
212 } else if ( ( ber
= ldap_alloc_ber_with_options( ld
) ) == NULL
) {
213 /* BER element allocation failed */
215 ld
->ld_errno
= LDAP_NO_MEMORY
;
219 * We already have the mutex in LDAP_R_COMPILE, so
220 * don't try to get it again.
221 * LDAP_NEXT_MSGID(ld, i);
224 i
= ++(ld
)->ld_msgid
;
225 #ifdef LDAP_CONNECTIONLESS
226 if ( LDAP_IS_UDP(ld
) ) {
227 struct sockaddr sa
= {0};
228 /* dummy, filled with ldo_peer in request.c */
229 err
= ber_write( ber
, &sa
, sizeof(sa
), 0 );
231 if ( LDAP_IS_UDP(ld
) && ld
->ld_options
.ldo_version
==
234 char *dn
= ld
->ld_options
.ldo_cldapdn
;
236 err
= ber_printf( ber
, "{isti", /* '}' */
238 LDAP_REQ_ABANDON
, msgid
);
242 /* create a message to send */
243 err
= ber_printf( ber
, "{iti", /* '}' */
245 LDAP_REQ_ABANDON
, msgid
);
250 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
253 /* Put Server Controls */
254 if ( ldap_int_put_controls( ld
, sctrls
, ber
)
261 err
= ber_printf( ber
, /*{*/ "N}" );
265 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
274 /* send the message */
276 assert( lr
->lr_conn
!= NULL
);
277 sb
= lr
->lr_conn
->lconn_sb
;
282 if ( ber_flush2( sb
, ber
, LBER_FLUSH_FREE_ALWAYS
) != 0 ) {
283 ld
->ld_errno
= LDAP_SERVER_DOWN
;
293 if ( sendabandon
|| lr
->lr_status
== LDAP_REQST_WRITING
) {
294 ldap_free_connection( ld
, lr
->lr_conn
, 0, 1 );
297 if ( origid
== msgid
) {
298 ldap_free_request( ld
, lr
);
301 lr
->lr_abandoned
= 1;
305 #ifdef LDAP_R_COMPILE
306 /* ld_abandoned is actually protected by the ld_res_mutex;
307 * give up the ld_req_mutex and get the other */
308 ldap_pvt_thread_mutex_unlock( &ld
->ld_req_mutex
);
309 ldap_pvt_thread_mutex_lock( &ld
->ld_res_mutex
);
314 if ( ld
->ld_nabandoned
== 0 ||
315 ldap_int_bisect_find( ld
->ld_abandoned
, ld
->ld_nabandoned
, msgid
, &i
) == 0 )
317 ldap_int_bisect_insert( &ld
->ld_abandoned
, &ld
->ld_nabandoned
, msgid
, i
);
321 ld
->ld_errno
= LDAP_SUCCESS
;
324 #ifdef LDAP_R_COMPILE
325 ldap_pvt_thread_mutex_unlock( &ld
->ld_res_mutex
);
326 ldap_pvt_thread_mutex_lock( &ld
->ld_req_mutex
);
328 return( ld
->ld_errno
);
332 * ldap_int_bisect_find
335 * v: array of length n (in)
336 * n: length of array v (in)
337 * id: value to look for (in)
338 * idxp: pointer to location of value/insert point
346 ldap_int_bisect_find( ber_int_t
*v
, ber_len_t n
, ber_int_t id
, int *idxp
)
358 if ( n
<= 0 || id
< v
[ begin
] ) {
361 } else if ( id
> v
[ end
] ) {
369 pos
= (begin
+ end
)/2;
375 } else if ( id
> curid
) {
379 /* already abandoned? */
383 } while ( end
>= begin
);
392 * ldap_int_bisect_insert
395 * vp: pointer to array of length *np (in/out)
396 * np: pointer to length of array *vp (in/out)
397 * id: value to insert (in)
398 * idx: location of insert point (as computed by ldap_int_bisect_find())
405 ldap_int_bisect_insert( ber_int_t
**vp
, ber_len_t
*np
, int id
, int idx
)
411 assert( vp
!= NULL
);
412 assert( np
!= NULL
);
415 assert( idx
<= *np
);
419 v
= ber_memrealloc( *vp
, sizeof( ber_int_t
) * ( n
+ 1 ) );
425 for ( i
= n
; i
> idx
; i
-- ) {
435 * ldap_int_bisect_delete
438 * vp: pointer to array of length *np (in/out)
439 * np: pointer to length of array *vp (in/out)
440 * id: value to delete (in)
441 * idx: location of value to delete (as computed by ldap_int_bisect_find())
447 ldap_int_bisect_delete( ber_int_t
**vp
, ber_len_t
*np
, int id
, int idx
)
453 assert( vp
!= NULL
);
454 assert( np
!= NULL
);
461 assert( v
[ idx
] == id
);
466 for ( i
= idx
; i
< n
; i
++ ) {