1/* abandon.c */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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 39static int 40do_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 */ 62int 63ldap_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 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 75 76 rc = ldap_int_client_controls( ld, cctrls ); 77 if ( rc == LDAP_SUCCESS ) { 78 rc = do_abandon( ld, msgid, msgid, sctrls, 1 ); 79 } 80 81 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 82 83 return rc; 84} 85 86 87/* 88 * ldap_abandon - perform an ldap abandon operation. Parameters: 89 * 90 * ld LDAP descriptor 91 * msgid The message id of the operation to abandon 92 * 93 * ldap_abandon returns 0 if everything went ok, -1 otherwise. 94 * 95 * Example: 96 * ldap_abandon( ld, msgid ); 97 */ 98int 99ldap_abandon( LDAP *ld, int msgid ) 100{ 101 Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); 102 return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS 103 ? 0 : -1; 104} 105 106 107int 108ldap_pvt_discard( 109 LDAP *ld, 110 ber_int_t msgid ) 111{ 112 int rc; 113 114 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 115 rc = do_abandon( ld, msgid, msgid, NULL, 0 ); 116 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 117 return rc; 118} 119 120static int 121do_abandon( 122 LDAP *ld, 123 ber_int_t origid, 124 ber_int_t msgid, 125 LDAPControl **sctrls, 126 int sendabandon ) 127{ 128 BerElement *ber; 129 int i, err; 130 Sockbuf *sb; 131 LDAPRequest *lr; 132 133 Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 134 origid, msgid, 0 ); 135 136 /* find the request that we are abandoning */ 137start_again:; 138 lr = ld->ld_requests; 139 while ( lr != NULL ) { 140 /* this message */ 141 if ( lr->lr_msgid == msgid ) { 142 break; 143 } 144 145 /* child: abandon it */ 146 if ( lr->lr_origid == msgid && !lr->lr_abandoned ) { 147 (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid, 148 sctrls, sendabandon ); 149 150 /* restart, as lr may now be dangling... */ 151 goto start_again; 152 } 153 154 lr = lr->lr_next; 155 } 156 157 if ( lr != NULL ) { 158 if ( origid == msgid && lr->lr_parent != NULL ) { 159 /* don't let caller abandon child requests! */ 160 ld->ld_errno = LDAP_PARAM_ERROR; 161 return( LDAP_PARAM_ERROR ); 162 } 163 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { 164 /* no need to send abandon message */ 165 sendabandon = 0; 166 } 167 } 168 169 /* ldap_msgdelete locks the res_mutex. Give up the req_mutex 170 * while we're in there. 171 */ 172 LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex ); 173 err = ldap_msgdelete( ld, msgid ); 174 LDAP_MUTEX_LOCK( &ld->ld_req_mutex ); 175 if ( err == 0 ) { 176 ld->ld_errno = LDAP_SUCCESS; 177 return LDAP_SUCCESS; 178 } 179 180 /* fetch again the request that we are abandoning */ 181 if ( lr != NULL ) { 182 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 183 /* this message */ 184 if ( lr->lr_msgid == msgid ) { 185 break; 186 } 187 } 188 } 189 190 err = 0; 191 if ( sendabandon ) { 192 if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { 193 /* not connected */ 194 err = -1; 195 ld->ld_errno = LDAP_SERVER_DOWN; 196 197 } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { 198 /* BER element allocation failed */ 199 err = -1; 200 ld->ld_errno = LDAP_NO_MEMORY; 201 202 } else { 203 /* 204 * We already have the mutex in LDAP_R_COMPILE, so 205 * don't try to get it again. 206 * LDAP_NEXT_MSGID(ld, i); 207 */ 208 209 LDAP_NEXT_MSGID(ld, i); 210#ifdef LDAP_CONNECTIONLESS 211 if ( LDAP_IS_UDP(ld) ) { 212 struct sockaddr sa = {0}; 213 /* dummy, filled with ldo_peer in request.c */ 214 err = ber_write( ber, (char *) &sa, sizeof(sa), 0 ); 215 } 216 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == 217 LDAP_VERSION2 ) 218 { 219 char *dn; 220 LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex ); 221 dn = ld->ld_options.ldo_cldapdn; 222 if (!dn) dn = ""; 223 err = ber_printf( ber, "{isti", /* '}' */ 224 i, dn, 225 LDAP_REQ_ABANDON, msgid ); 226 LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex ); 227 } else 228#endif 229 { 230 /* create a message to send */ 231 err = ber_printf( ber, "{iti", /* '}' */ 232 i, 233 LDAP_REQ_ABANDON, msgid ); 234 } 235 236 if ( err == -1 ) { 237 /* encoding error */ 238 ld->ld_errno = LDAP_ENCODING_ERROR; 239 240 } else { 241 /* Put Server Controls */ 242 if ( ldap_int_put_controls( ld, sctrls, ber ) 243 != LDAP_SUCCESS ) 244 { 245 err = -1; 246 247 } else { 248 /* close '{' */ 249 err = ber_printf( ber, /*{*/ "N}" ); 250 251 if ( err == -1 ) { 252 /* encoding error */ 253 ld->ld_errno = LDAP_ENCODING_ERROR; 254 } 255 } 256 } 257 258 if ( err == -1 ) { 259 ber_free( ber, 1 ); 260 261 } else { 262 /* send the message */ 263 if ( lr != NULL ) { 264 assert( lr->lr_conn != NULL ); 265 sb = lr->lr_conn->lconn_sb; 266 } else { 267 sb = ld->ld_sb; 268 } 269 270 if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { 271 ld->ld_errno = LDAP_SERVER_DOWN; 272 err = -1; 273 } else { 274 err = 0; 275 } 276 } 277 } 278 } 279 280 if ( lr != NULL ) { 281 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { 282 LDAP_MUTEX_LOCK( &ld->ld_conn_mutex ); 283 ldap_free_connection( ld, lr->lr_conn, 0, 1 ); 284 LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex ); 285 } 286 287 if ( origid == msgid ) { 288 ldap_free_request( ld, lr ); 289 290 } else { 291 lr->lr_abandoned = 1; 292 } 293 } 294 295 LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex ); 296 297 /* use bisection */ 298 i = 0; 299 if ( ld->ld_nabandoned == 0 || 300 ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) 301 { 302 ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); 303 } 304 305 if ( err != -1 ) { 306 ld->ld_errno = LDAP_SUCCESS; 307 } 308 309 LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex ); 310 return( ld->ld_errno ); 311} 312 313/* 314 * ldap_int_bisect_find 315 * 316 * args: 317 * v: array of length n (in) 318 * n: length of array v (in) 319 * id: value to look for (in) 320 * idxp: pointer to location of value/insert point 321 * 322 * return: 323 * 0: not found 324 * 1: found 325 * -1: error 326 */ 327int 328ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) 329{ 330 int begin, 331 end, 332 rc = 0; 333 334 assert( id >= 0 ); 335 336 begin = 0; 337 end = n - 1; 338 339 if ( n <= 0 || id < v[ begin ] ) { 340 *idxp = 0; 341 342 } else if ( id > v[ end ] ) { 343 *idxp = n; 344 345 } else { 346 int pos; 347 ber_int_t curid; 348 349 do { 350 pos = (begin + end)/2; 351 curid = v[ pos ]; 352 353 if ( id < curid ) { 354 end = pos - 1; 355 356 } else if ( id > curid ) { 357 begin = ++pos; 358 359 } else { 360 /* already abandoned? */ 361 rc = 1; 362 break; 363 } 364 } while ( end >= begin ); 365 366 *idxp = pos; 367 } 368 369 return rc; 370} 371 372/* 373 * ldap_int_bisect_insert 374 * 375 * args: 376 * vp: pointer to array of length *np (in/out) 377 * np: pointer to length of array *vp (in/out) 378 * id: value to insert (in) 379 * idx: location of insert point (as computed by ldap_int_bisect_find()) 380 * 381 * return: 382 * 0: inserted 383 * -1: error 384 */ 385int 386ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) 387{ 388 ber_int_t *v; 389 ber_len_t n; 390 int i; 391 392 assert( vp != NULL ); 393 assert( np != NULL ); 394 assert( idx >= 0 ); 395 assert( (unsigned) idx <= *np ); 396 397 n = *np; 398 399 v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) ); 400 if ( v == NULL ) { 401 return -1; 402 } 403 *vp = v; 404 405 for ( i = n; i > idx; i-- ) { 406 v[ i ] = v[ i - 1 ]; 407 } 408 v[ idx ] = id; 409 ++(*np); 410 411 return 0; 412} 413 414/* 415 * ldap_int_bisect_delete 416 * 417 * args: 418 * vp: pointer to array of length *np (in/out) 419 * np: pointer to length of array *vp (in/out) 420 * id: value to delete (in) 421 * idx: location of value to delete (as computed by ldap_int_bisect_find()) 422 * 423 * return: 424 * 0: deleted 425 */ 426int 427ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ) 428{ 429 ber_int_t *v; 430 ber_len_t i, n; 431 432 assert( vp != NULL ); 433 assert( np != NULL ); 434 assert( idx >= 0 ); 435 assert( (unsigned) idx < *np ); 436 437 v = *vp; 438 439 assert( v[ idx ] == id ); 440 441 --(*np); 442 n = *np; 443 444 for ( i = idx; i < n; i++ ) { 445 v[ i ] = v[ i + 1 ]; 446 } 447 448 return 0; 449} 450