1 /* abandon.c */ 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/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 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. 11 * 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>. 15 */ 16 /* Portions Copyright (c) 1990 Regents of the University of Michigan. 17 * All rights reserved. 18 */ 19 20 #include "portable.h" 21 22 #include <stdio.h> 23 24 #include <ac/stdlib.h> 25 26 #include <ac/socket.h> 27 #include <ac/string.h> 28 #include <ac/time.h> 29 30 #include "ldap-int.h" 31 32 /* 33 * An abandon request looks like this: 34 * AbandonRequest ::= [APPLICATION 16] MessageID 35 * and has no response. (Source: RFC 4511) 36 */ 37 #include "lutil.h" 38 39 static int 40 do_abandon( 41 LDAP *ld, 42 ber_int_t origid, 43 ber_int_t msgid, 44 LDAPControl **sctrls, 45 int sendabandon ); 46 47 /* 48 * ldap_abandon_ext - perform an ldap extended abandon operation. 49 * 50 * Parameters: 51 * ld LDAP descriptor 52 * msgid The message id of the operation to abandon 53 * scntrls Server Controls 54 * ccntrls Client Controls 55 * 56 * ldap_abandon_ext returns a LDAP error code. 57 * (LDAP_SUCCESS if everything went ok) 58 * 59 * Example: 60 * ldap_abandon_ext( ld, msgid, scntrls, ccntrls ); 61 */ 62 int 63 ldap_abandon_ext( 64 LDAP *ld, 65 int msgid, 66 LDAPControl **sctrls, 67 LDAPControl **cctrls ) 68 { 69 int rc; 70 71 Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); 72 73 /* check client controls */ 74 #ifdef LDAP_R_COMPILE 75 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); 76 #endif 77 78 rc = ldap_int_client_controls( ld, cctrls ); 79 if ( rc == LDAP_SUCCESS ) { 80 rc = do_abandon( ld, msgid, msgid, sctrls, 1 ); 81 } 82 83 #ifdef LDAP_R_COMPILE 84 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); 85 #endif 86 87 return rc; 88 } 89 90 91 /* 92 * ldap_abandon - perform an ldap abandon operation. Parameters: 93 * 94 * ld LDAP descriptor 95 * msgid The message id of the operation to abandon 96 * 97 * ldap_abandon returns 0 if everything went ok, -1 otherwise. 98 * 99 * Example: 100 * ldap_abandon( ld, msgid ); 101 */ 102 int 103 ldap_abandon( LDAP *ld, int msgid ) 104 { 105 Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); 106 return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS 107 ? 0 : -1; 108 } 109 110 111 int 112 ldap_pvt_discard( 113 LDAP *ld, 114 ber_int_t msgid ) 115 { 116 int rc; 117 118 #ifdef LDAP_R_COMPILE 119 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); 120 #endif 121 122 rc = do_abandon( ld, msgid, msgid, NULL, 0 ); 123 124 #ifdef LDAP_R_COMPILE 125 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); 126 #endif 127 128 return rc; 129 } 130 131 static int 132 do_abandon( 133 LDAP *ld, 134 ber_int_t origid, 135 ber_int_t msgid, 136 LDAPControl **sctrls, 137 int sendabandon ) 138 { 139 BerElement *ber; 140 int i, err; 141 Sockbuf *sb; 142 LDAPRequest *lr; 143 144 Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 145 origid, msgid, 0 ); 146 147 /* find the request that we are abandoning */ 148 start_again:; 149 lr = ld->ld_requests; 150 while ( lr != NULL ) { 151 /* this message */ 152 if ( lr->lr_msgid == msgid ) { 153 break; 154 } 155 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 ); 160 161 /* restart, as lr may now be dangling... */ 162 goto start_again; 163 } 164 165 lr = lr->lr_next; 166 } 167 168 if ( lr != NULL ) { 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 ); 173 } 174 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { 175 /* no need to send abandon message */ 176 sendabandon = 0; 177 } 178 } 179 180 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex 181 * while we're in there. 182 */ 183 #ifdef LDAP_R_COMPILE 184 ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); 185 #endif 186 err = ldap_msgdelete( ld, msgid ); 187 #ifdef LDAP_R_COMPILE 188 ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); 189 #endif 190 if ( err == 0 ) { 191 ld->ld_errno = LDAP_SUCCESS; 192 return LDAP_SUCCESS; 193 } 194 195 /* fetch again the request that we are abandoning */ 196 if ( lr != NULL ) { 197 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 198 /* this message */ 199 if ( lr->lr_msgid == msgid ) { 200 break; 201 } 202 } 203 } 204 205 err = 0; 206 if ( sendabandon ) { 207 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { 208 /* not connected */ 209 err = -1; 210 ld->ld_errno = LDAP_SERVER_DOWN; 211 212 } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { 213 /* BER element allocation failed */ 214 err = -1; 215 ld->ld_errno = LDAP_NO_MEMORY; 216 217 } else { 218 /* 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); 222 */ 223 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 ); 230 } 231 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == 232 LDAP_VERSION2 ) 233 { 234 char *dn = ld->ld_options.ldo_cldapdn; 235 if (!dn) dn = ""; 236 err = ber_printf( ber, "{isti", /* '}' */ 237 i, dn, 238 LDAP_REQ_ABANDON, msgid ); 239 } else 240 #endif 241 { 242 /* create a message to send */ 243 err = ber_printf( ber, "{iti", /* '}' */ 244 i, 245 LDAP_REQ_ABANDON, msgid ); 246 } 247 248 if ( err == -1 ) { 249 /* encoding error */ 250 ld->ld_errno = LDAP_ENCODING_ERROR; 251 252 } else { 253 /* Put Server Controls */ 254 if ( ldap_int_put_controls( ld, sctrls, ber ) 255 != LDAP_SUCCESS ) 256 { 257 err = -1; 258 259 } else { 260 /* close '{' */ 261 err = ber_printf( ber, /*{*/ "N}" ); 262 263 if ( err == -1 ) { 264 /* encoding error */ 265 ld->ld_errno = LDAP_ENCODING_ERROR; 266 } 267 } 268 } 269 270 if ( err == -1 ) { 271 ber_free( ber, 1 ); 272 273 } else { 274 /* send the message */ 275 if ( lr != NULL ) { 276 assert( lr->lr_conn != NULL ); 277 sb = lr->lr_conn->lconn_sb; 278 } else { 279 sb = ld->ld_sb; 280 } 281 282 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { 283 ld->ld_errno = LDAP_SERVER_DOWN; 284 err = -1; 285 } else { 286 err = 0; 287 } 288 } 289 } 290 } 291 292 if ( lr != NULL ) { 293 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { 294 ldap_free_connection( ld, lr->lr_conn, 0, 1 ); 295 } 296 297 if ( origid == msgid ) { 298 ldap_free_request( ld, lr ); 299 300 } else { 301 lr->lr_abandoned = 1; 302 } 303 } 304 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 ); 310 #endif 311 312 /* use bisection */ 313 i = 0; 314 if ( ld->ld_nabandoned == 0 || 315 ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) 316 { 317 ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); 318 } 319 320 if ( err != -1 ) { 321 ld->ld_errno = LDAP_SUCCESS; 322 } 323 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 ); 327 #endif 328 return( ld->ld_errno ); 329 } 330 331 /* 332 * ldap_int_bisect_find 333 * 334 * args: 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 339 * 340 * return: 341 * 0: not found 342 * 1: found 343 * -1: error 344 */ 345 int 346 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) 347 { 348 int begin, 349 end, 350 rc = 0; 351 352 assert( n >= 0 ); 353 assert( id >= 0 ); 354 355 begin = 0; 356 end = n - 1; 357 358 if ( n <= 0 || id < v[ begin ] ) { 359 *idxp = 0; 360 361 } else if ( id > v[ end ] ) { 362 *idxp = n; 363 364 } else { 365 int pos; 366 ber_int_t curid; 367 368 do { 369 pos = (begin + end)/2; 370 curid = v[ pos ]; 371 372 if ( id < curid ) { 373 end = pos - 1; 374 375 } else if ( id > curid ) { 376 begin = ++pos; 377 378 } else { 379 /* already abandoned? */ 380 rc = 1; 381 break; 382 } 383 } while ( end >= begin ); 384 385 *idxp = pos; 386 } 387 388 return rc; 389 } 390 391 /* 392 * ldap_int_bisect_insert 393 * 394 * args: 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()) 399 * 400 * return: 401 * 0: inserted 402 * -1: error 403 */ 404 int 405 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) 406 { 407 ber_int_t *v; 408 ber_len_t n; 409 int i; 410 411 assert( vp != NULL ); 412 assert( np != NULL ); 413 assert( *np >= 0 ); 414 assert( idx >= 0 ); 415 assert( 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 n; 451 int i; 452 453 assert( vp != NULL ); 454 assert( np != NULL ); 455 assert( *np >= 0 ); 456 assert( idx >= 0 ); 457 assert( idx < *np ); 458 459 v = *vp; 460 461 assert( v[ idx ] == id ); 462 463 --(*np); 464 n = *np; 465 466 for ( i = idx; i < n; i++ ) { 467 v[ i ] = v[ i + 1 ]; 468 } 469 470 return 0; 471 } 472 473