xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/abandon.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: abandon.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* abandon.c */
4 /* OpenLDAP: pkg/ldap/libraries/libldap/abandon.c,v 1.41.2.11 2009/02/17 21:02:51 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2009 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* Portions  Copyright (c) 1990 Regents of the University of Michigan.
19  * All rights reserved.
20  */
21 
22 #include "portable.h"
23 
24 #include <stdio.h>
25 
26 #include <ac/stdlib.h>
27 
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31 
32 #include "ldap-int.h"
33 
34 /*
35  * An abandon request looks like this:
36  *		AbandonRequest ::= [APPLICATION 16] MessageID
37  * and has no response.  (Source: RFC 4511)
38  */
39 #include "lutil.h"
40 
41 static int
42 do_abandon(
43 	LDAP *ld,
44 	ber_int_t origid,
45 	ber_int_t msgid,
46 	LDAPControl **sctrls,
47 	int sendabandon );
48 
49 /*
50  * ldap_abandon_ext - perform an ldap extended abandon operation.
51  *
52  * Parameters:
53  *	ld			LDAP descriptor
54  *	msgid		The message id of the operation to abandon
55  *	scntrls		Server Controls
56  *	ccntrls		Client Controls
57  *
58  * ldap_abandon_ext returns a LDAP error code.
59  *		(LDAP_SUCCESS if everything went ok)
60  *
61  * Example:
62  *	ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
63  */
64 int
65 ldap_abandon_ext(
66 	LDAP *ld,
67 	int msgid,
68 	LDAPControl **sctrls,
69 	LDAPControl **cctrls )
70 {
71 	int	rc;
72 
73 	Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
74 
75 	/* check client controls */
76 #ifdef LDAP_R_COMPILE
77 	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
78 #endif
79 
80 	rc = ldap_int_client_controls( ld, cctrls );
81 	if ( rc == LDAP_SUCCESS ) {
82 		rc = do_abandon( ld, msgid, msgid, sctrls, 1 );
83 	}
84 
85 #ifdef LDAP_R_COMPILE
86 	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
87 #endif
88 
89 	return rc;
90 }
91 
92 
93 /*
94  * ldap_abandon - perform an ldap abandon operation. Parameters:
95  *
96  *	ld		LDAP descriptor
97  *	msgid		The message id of the operation to abandon
98  *
99  * ldap_abandon returns 0 if everything went ok, -1 otherwise.
100  *
101  * Example:
102  *	ldap_abandon( ld, msgid );
103  */
104 int
105 ldap_abandon( LDAP *ld, int msgid )
106 {
107 	Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
108 	return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
109 		? 0 : -1;
110 }
111 
112 
113 int
114 ldap_pvt_discard(
115 	LDAP *ld,
116 	ber_int_t msgid )
117 {
118 	int	rc;
119 
120 #ifdef LDAP_R_COMPILE
121 	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
122 #endif
123 
124 	rc = do_abandon( ld, msgid, msgid, NULL, 0 );
125 
126 #ifdef LDAP_R_COMPILE
127 	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
128 #endif
129 
130 	return rc;
131 }
132 
133 static int
134 do_abandon(
135 	LDAP *ld,
136 	ber_int_t origid,
137 	ber_int_t msgid,
138 	LDAPControl **sctrls,
139 	int sendabandon )
140 {
141 	BerElement	*ber;
142 	int		i, err;
143 	Sockbuf		*sb;
144 	LDAPRequest	*lr;
145 
146 	Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
147 		origid, msgid, 0 );
148 
149 	/* find the request that we are abandoning */
150 start_again:;
151 	lr = ld->ld_requests;
152 	while ( lr != NULL ) {
153 		/* this message */
154 		if ( lr->lr_msgid == msgid ) {
155 			break;
156 		}
157 
158 		/* child: abandon it */
159 		if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
160 			(void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
161 				sctrls, sendabandon );
162 
163 			/* restart, as lr may now be dangling... */
164 			goto start_again;
165 		}
166 
167 		lr = lr->lr_next;
168 	}
169 
170 	if ( lr != NULL ) {
171 		if ( origid == msgid && lr->lr_parent != NULL ) {
172 			/* don't let caller abandon child requests! */
173 			ld->ld_errno = LDAP_PARAM_ERROR;
174 			return( LDAP_PARAM_ERROR );
175 		}
176 		if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
177 			/* no need to send abandon message */
178 			sendabandon = 0;
179 		}
180 	}
181 
182 	/* ldap_msgdelete locks the res_mutex. Give up the req_mutex
183 	 * while we're in there.
184 	 */
185 #ifdef LDAP_R_COMPILE
186 	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
187 #endif
188 	err = ldap_msgdelete( ld, msgid );
189 #ifdef LDAP_R_COMPILE
190 	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
191 #endif
192 	if ( err == 0 ) {
193 		ld->ld_errno = LDAP_SUCCESS;
194 		return LDAP_SUCCESS;
195 	}
196 
197 	/* fetch again the request that we are abandoning */
198 	if ( lr != NULL ) {
199 		for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
200 			/* this message */
201 			if ( lr->lr_msgid == msgid ) {
202 				break;
203 			}
204 		}
205 	}
206 
207 	err = 0;
208 	if ( sendabandon ) {
209 		if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
210 			/* not connected */
211 			err = -1;
212 			ld->ld_errno = LDAP_SERVER_DOWN;
213 
214 		} else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
215 			/* BER element allocation failed */
216 			err = -1;
217 			ld->ld_errno = LDAP_NO_MEMORY;
218 
219 		} else {
220 			/*
221 			 * We already have the mutex in LDAP_R_COMPILE, so
222 			 * don't try to get it again.
223 			 *		LDAP_NEXT_MSGID(ld, i);
224 			 */
225 
226 			i = ++(ld)->ld_msgid;
227 #ifdef LDAP_CONNECTIONLESS
228 			if ( LDAP_IS_UDP(ld) ) {
229 				struct sockaddr sa = {0};
230 				/* dummy, filled with ldo_peer in request.c */
231 				err = ber_write( ber, &sa, sizeof(sa), 0 );
232 			}
233 			if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
234 				LDAP_VERSION2 )
235 			{
236 				char *dn = ld->ld_options.ldo_cldapdn;
237 				if (!dn) dn = "";
238 				err = ber_printf( ber, "{isti",  /* '}' */
239 					i, dn,
240 					LDAP_REQ_ABANDON, msgid );
241 			} else
242 #endif
243 			{
244 				/* create a message to send */
245 				err = ber_printf( ber, "{iti",  /* '}' */
246 					i,
247 					LDAP_REQ_ABANDON, msgid );
248 			}
249 
250 			if ( err == -1 ) {
251 				/* encoding error */
252 				ld->ld_errno = LDAP_ENCODING_ERROR;
253 
254 			} else {
255 				/* Put Server Controls */
256 				if ( ldap_int_put_controls( ld, sctrls, ber )
257 					!= LDAP_SUCCESS )
258 				{
259 					err = -1;
260 
261 				} else {
262 					/* close '{' */
263 					err = ber_printf( ber, /*{*/ "N}" );
264 
265 					if ( err == -1 ) {
266 						/* encoding error */
267 						ld->ld_errno = LDAP_ENCODING_ERROR;
268 					}
269 				}
270 			}
271 
272 			if ( err == -1 ) {
273 				ber_free( ber, 1 );
274 
275 			} else {
276 				/* send the message */
277 				if ( lr != NULL ) {
278 					assert( lr->lr_conn != NULL );
279 					sb = lr->lr_conn->lconn_sb;
280 				} else {
281 					sb = ld->ld_sb;
282 				}
283 
284 				if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
285 					ld->ld_errno = LDAP_SERVER_DOWN;
286 					err = -1;
287 				} else {
288 					err = 0;
289 				}
290 			}
291 		}
292 	}
293 
294 	if ( lr != NULL ) {
295 		if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
296 			ldap_free_connection( ld, lr->lr_conn, 0, 1 );
297 		}
298 
299 		if ( origid == msgid ) {
300 			ldap_free_request( ld, lr );
301 
302 		} else {
303 			lr->lr_abandoned = 1;
304 		}
305 	}
306 
307 #ifdef LDAP_R_COMPILE
308 	/* ld_abandoned is actually protected by the ld_res_mutex;
309 	 * give up the ld_req_mutex and get the other */
310 	ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
311 	ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex );
312 #endif
313 
314 	/* use bisection */
315 	i = 0;
316 	if ( ld->ld_nabandoned == 0 ||
317 		ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
318 	{
319 		ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
320 	}
321 
322 	if ( err != -1 ) {
323 		ld->ld_errno = LDAP_SUCCESS;
324 	}
325 
326 #ifdef LDAP_R_COMPILE
327 	ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
328 	ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
329 #endif
330 	return( ld->ld_errno );
331 }
332 
333 /*
334  * ldap_int_bisect_find
335  *
336  * args:
337  *	v:	array of length n (in)
338  *	n:	length of array v (in)
339  *	id:	value to look for (in)
340  *	idxp:	pointer to location of value/insert point
341  *
342  * return:
343  *	0:	not found
344  *	1:	found
345  *	-1:	error
346  */
347 int
348 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
349 {
350 	int		begin,
351 			end,
352 			rc = 0;
353 
354 	assert( id >= 0 );
355 
356 	begin = 0;
357 	end = n - 1;
358 
359 		if ( n <= 0 || id < v[ begin ] ) {
360 			*idxp = 0;
361 
362 		} else if ( id > v[ end ] ) {
363 			*idxp = n;
364 
365 		} else {
366 			int		pos;
367 			ber_int_t	curid;
368 
369 			do {
370 				pos = (begin + end)/2;
371 				curid = v[ pos ];
372 
373 				if ( id < curid ) {
374 					end = pos - 1;
375 
376 				} else if ( id > curid ) {
377 					begin = ++pos;
378 
379 				} else {
380 					/* already abandoned? */
381 					rc = 1;
382 					break;
383 				}
384 			} while ( end >= begin );
385 
386 			*idxp = pos;
387 		}
388 
389 	return rc;
390 }
391 
392 /*
393  * ldap_int_bisect_insert
394  *
395  * args:
396  *	vp:	pointer to array of length *np (in/out)
397  *	np:	pointer to length of array *vp (in/out)
398  *	id:	value to insert (in)
399  *	idx:	location of insert point (as computed by ldap_int_bisect_find())
400  *
401  * return:
402  *	0:	inserted
403  *	-1:	error
404  */
405 int
406 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
407 {
408 	ber_int_t	*v;
409 	ber_len_t	n;
410 	int		i;
411 
412 	assert( vp != NULL );
413 	assert( np != NULL );
414 	assert( idx >= 0 );
415 	assert( (unsigned) idx <= *np );
416 
417 	n = *np;
418 
419 	v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
420 	if ( v == NULL ) {
421 		return -1;
422 	}
423 	*vp = v;
424 
425 	for ( i = n; i > idx; i-- ) {
426 		v[ i ] = v[ i - 1 ];
427 	}
428 	v[ idx ] = id;
429 	++(*np);
430 
431 	return 0;
432 }
433 
434 /*
435  * ldap_int_bisect_delete
436  *
437  * args:
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())
442  *
443  * return:
444  *	0:	deleted
445  */
446 int
447 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
448 {
449 	ber_int_t	*v;
450 	ber_len_t	i, n;
451 
452 	assert( vp != NULL );
453 	assert( np != NULL );
454 	assert( idx >= 0 );
455 	assert( (unsigned) idx < *np );
456 
457 	v = *vp;
458 
459 	assert( v[ idx ] == id );
460 
461 	--(*np);
462 	n = *np;
463 
464 	for ( i = idx; i < n; i++ ) {
465 		v[ i ] = v[ i + 1 ];
466 	}
467 
468 	return 0;
469 }
470 
471