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