libs: Import code from upstream openldap 2.5.13.
[wine.git] / libs / ldap / libldap / abandon.c
blob35e81a7e3ed30cb1e1d9b70b0ca9de94eb5c1cc4
1 /* abandon.c */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
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.
20 #include "portable.h"
22 #include <stdio.h>
24 #include <ac/stdlib.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
28 #include <ac/time.h>
30 #include "ldap-int.h"
33 * An abandon request looks like this:
34 * AbandonRequest ::= [APPLICATION 16] MessageID
35 * and has no response. (Source: RFC 4511)
37 #include "lutil.h"
39 static int
40 do_abandon(
41 LDAP *ld,
42 ber_int_t origid,
43 LDAPRequest *lr,
44 LDAPControl **sctrls,
45 int sendabandon );
48 * ldap_abandon_ext - perform an ldap extended abandon operation.
50 * Parameters:
51 * ld LDAP descriptor
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)
59 * Example:
60 * ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
62 int
63 ldap_abandon_ext(
64 LDAP *ld,
65 int msgid,
66 LDAPControl **sctrls,
67 LDAPControl **cctrls )
69 int rc;
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 );
83 return rc;
88 * ldap_abandon - perform an ldap abandon operation. Parameters:
90 * ld LDAP descriptor
91 * msgid The message id of the operation to abandon
93 * ldap_abandon returns 0 if everything went ok, -1 otherwise.
95 * Example:
96 * ldap_abandon( ld, msgid );
98 int
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
103 ? 0 : -1;
108 ldap_pvt_discard(
109 LDAP *ld,
110 ber_int_t msgid )
112 int rc;
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 );
117 return rc;
120 static int
121 do_abandon(
122 LDAP *ld,
123 ber_int_t origid,
124 LDAPRequest *lr,
125 LDAPControl **sctrls,
126 int sendabandon )
128 BerElement *ber;
129 int i, err;
130 ber_int_t msgid = origid;
131 Sockbuf *sb;
132 LDAPRequest needle = {0};
134 needle.lr_msgid = origid;
136 if ( lr != NULL ) {
137 msgid = lr->lr_msgid;
138 Debug2( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
139 origid, msgid );
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",
142 origid, msgid );
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;
151 if ( lr != NULL ) {
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 */
158 sendabandon = 0;
161 while ( *childp ) {
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 );
178 if ( err == 0 ) {
179 ld->ld_errno = LDAP_SUCCESS;
180 return LDAP_SUCCESS;
183 /* fetch again the request that we are abandoning */
184 if ( lr != NULL ) {
185 lr = ldap_tavl_find( ld->ld_requests, &needle, ldap_req_cmp );
188 err = 0;
189 if ( sendabandon ) {
190 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
191 /* not connected */
192 err = -1;
193 ld->ld_errno = LDAP_SERVER_DOWN;
195 } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
196 /* BER element allocation failed */
197 err = -1;
198 ld->ld_errno = LDAP_NO_MEMORY;
200 } else {
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 ==
215 LDAP_VERSION2 )
217 char *dn;
218 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
219 dn = ld->ld_options.ldo_cldapdn;
220 if (!dn) dn = "";
221 err = ber_printf( ber, "{isti", /* '}' */
222 i, dn,
223 LDAP_REQ_ABANDON, msgid );
224 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
225 } else
226 #endif
228 /* create a message to send */
229 err = ber_printf( ber, "{iti", /* '}' */
231 LDAP_REQ_ABANDON, msgid );
234 if ( err == -1 ) {
235 /* encoding error */
236 ld->ld_errno = LDAP_ENCODING_ERROR;
238 } else {
239 /* Put Server Controls */
240 if ( ldap_int_put_controls( ld, sctrls, ber )
241 != LDAP_SUCCESS )
243 err = -1;
245 } else {
246 /* close '{' */
247 err = ber_printf( ber, /*{*/ "N}" );
249 if ( err == -1 ) {
250 /* encoding error */
251 ld->ld_errno = LDAP_ENCODING_ERROR;
256 if ( err == -1 ) {
257 ber_free( ber, 1 );
259 } else {
260 /* send the message */
261 if ( lr != NULL ) {
262 assert( lr->lr_conn != NULL );
263 sb = lr->lr_conn->lconn_sb;
264 } else {
265 sb = ld->ld_sb;
268 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
269 ld->ld_errno = LDAP_SERVER_DOWN;
270 err = -1;
271 } else {
272 err = 0;
278 if ( lr != NULL ) {
279 LDAPConn *lc;
280 int freeconn = 0;
281 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
282 freeconn = 1;
283 lc = lr->lr_conn;
285 if ( origid == msgid ) {
286 ldap_free_request( ld, lr );
288 } else {
289 lr->lr_abandoned = 1;
292 if ( freeconn ) {
293 /* release ld_req_mutex while grabbing ld_conn_mutex to
294 * prevent deadlock.
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 );
306 /* use bisection */
307 i = 0;
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 );
314 if ( err != -1 ) {
315 ld->ld_errno = LDAP_SUCCESS;
318 LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
319 return( ld->ld_errno );
323 * ldap_int_bisect_find
325 * args:
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
331 * return:
332 * 0: not found
333 * 1: found
334 * -1: error
337 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
339 int begin,
340 end,
341 rc = 0;
343 assert( id >= 0 );
345 begin = 0;
346 end = n - 1;
348 if ( n <= 0 || id < v[ begin ] ) {
349 *idxp = 0;
351 } else if ( id > v[ end ] ) {
352 *idxp = n;
354 } else {
355 int pos;
356 ber_int_t curid;
358 do {
359 pos = (begin + end)/2;
360 curid = v[ pos ];
362 if ( id < curid ) {
363 end = pos - 1;
365 } else if ( id > curid ) {
366 begin = ++pos;
368 } else {
369 /* already abandoned? */
370 rc = 1;
371 break;
373 } while ( end >= begin );
375 *idxp = pos;
378 return rc;
382 * ldap_int_bisect_insert
384 * args:
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())
390 * return:
391 * 0: inserted
392 * -1: error
395 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
397 ber_int_t *v;
398 ber_len_t n;
399 int i;
401 assert( vp != NULL );
402 assert( np != NULL );
403 assert( idx >= 0 );
404 assert( (unsigned) idx <= *np );
406 n = *np;
408 v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
409 if ( v == NULL ) {
410 return -1;
412 *vp = v;
414 for ( i = n; i > idx; i-- ) {
415 v[ i ] = v[ i - 1 ];
417 v[ idx ] = id;
418 ++(*np);
420 return 0;
424 * ldap_int_bisect_delete
426 * args:
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())
432 * return:
433 * 0: deleted
436 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
438 ber_int_t *v;
439 ber_len_t i, n;
441 assert( vp != NULL );
442 assert( np != NULL );
443 assert( idx >= 0 );
444 assert( (unsigned) idx < *np );
446 v = *vp;
448 assert( v[ idx ] == id );
450 --(*np);
451 n = *np;
453 for ( i = idx; i < n; i++ ) {
454 v[ i ] = v[ i + 1 ];
457 return 0;