X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fabandon.c;h=8f2fb3419499583f22babc83938cba956afc923e;hb=a5d0e36798978f9fdc9a15ab908fe0666dd5350f;hp=39ecfe157efdca25ff9ced6a4862d3be2ea47c46;hpb=a53823a613a42bfa741385e862aca1bb3de0f628;p=openldap diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c index 39ecfe157e..8f2fb34194 100644 --- a/libraries/libldap/abandon.c +++ b/libraries/libldap/abandon.c @@ -1,17 +1,20 @@ -/* - * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file - */ -/* Portions - * Copyright (c) 1990 Regents of the University of Michigan. - * All rights reserved. +/* abandon.c */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2008 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * abandon.c + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ - -/* - * An abandon request looks like this: - * AbandonRequest ::= MessageID +/* Portions Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. */ #include "portable.h" @@ -26,12 +29,20 @@ #include "ldap-int.h" -static int do_abandon LDAP_P(( +/* + * An abandon request looks like this: + * AbandonRequest ::= [APPLICATION 16] MessageID + * and has no response. (Source: RFC 4511) + */ +#include "lutil.h" + +static int +do_abandon( LDAP *ld, - int origid, - int msgid, + ber_int_t origid, + ber_int_t msgid, LDAPControl **sctrls, - LDAPControl **cctrls)); + int sendabandon ); /* * ldap_abandon_ext - perform an ldap extended abandon operation. @@ -55,9 +66,25 @@ ldap_abandon_ext( LDAPControl **sctrls, LDAPControl **cctrls ) { + int rc; + Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); - return do_abandon( ld, msgid, msgid, sctrls, cctrls ); + /* check client controls */ +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); +#endif + + rc = ldap_int_client_controls( ld, cctrls ); + if ( rc == LDAP_SUCCESS ) { + rc = do_abandon( ld, msgid, msgid, sctrls, 1 ); + } + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); +#endif + + return rc; } @@ -76,39 +103,66 @@ int ldap_abandon( LDAP *ld, int msgid ) { Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); - return do_abandon( ld, msgid, msgid, NULL, NULL ) == LDAP_SUCCESS + return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ? 0 : -1; } +int +ldap_pvt_discard( + LDAP *ld, + ber_int_t msgid ) +{ + int rc; + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); +#endif + + rc = do_abandon( ld, msgid, msgid, NULL, 0 ); + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); +#endif + + return rc; +} + static int do_abandon( LDAP *ld, - int origid, - int msgid, + ber_int_t origid, + ber_int_t msgid, LDAPControl **sctrls, - LDAPControl **cctrls) + int sendabandon ) { BerElement *ber; - int i, err, sendabandon; - unsigned int *old_abandon; + int i, err; Sockbuf *sb; LDAPRequest *lr; Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", origid, msgid, 0 ); - sendabandon = 1; - /* find the request that we are abandoning */ - for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { - if ( lr->lr_msgid == msgid ) { /* this message */ +start_again:; + lr = ld->ld_requests; + while ( lr != NULL ) { + /* this message */ + if ( lr->lr_msgid == msgid ) { break; } - if ( lr->lr_origid == msgid ) {/* child: abandon it */ - (void) do_abandon( ld, - msgid, lr->lr_msgid, sctrls, cctrls ); + + /* child: abandon it */ + if ( lr->lr_origid == msgid && !lr->lr_abandoned ) { + (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid, + sctrls, sendabandon ); + + /* restart, as lr may now be dangling... */ + goto start_again; } + + lr = lr->lr_next; } if ( lr != NULL ) { @@ -123,33 +177,75 @@ do_abandon( } } - if ( ldap_msgdelete( ld, msgid ) == 0 ) { + /* ldap_msgdelete locks the res_mutex. Give up the req_mutex + * while we're in there. + */ +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); +#endif + err = ldap_msgdelete( ld, msgid ); +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); +#endif + if ( err == 0 ) { ld->ld_errno = LDAP_SUCCESS; return LDAP_SUCCESS; } + /* fetch again the request that we are abandoning */ + if ( lr != NULL ) { + for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { + /* this message */ + if ( lr->lr_msgid == msgid ) { + break; + } + } + } + err = 0; if ( sendabandon ) { - /* create a message to send */ - if ( (ber = ldap_alloc_ber_with_options( ld )) == NULLBER ) { + if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) { + /* not connected */ + err = -1; + ld->ld_errno = LDAP_SERVER_DOWN; + + } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) { + /* BER element allocation failed */ err = -1; ld->ld_errno = LDAP_NO_MEMORY; } else { + /* + * We already have the mutex in LDAP_R_COMPILE, so + * don't try to get it again. + * LDAP_NEXT_MSGID(ld, i); + */ + + i = ++(ld)->ld_msgid; #ifdef LDAP_CONNECTIONLESS - if ( ld->ld_cldapnaddr > 0 ) { - err = ber_printf( ber, "{isti", /* leave open '}' */ - ++ld->ld_msgid, ld->ld_cldapdn, - LDAP_REQ_ABANDON, msgid ); + if ( LDAP_IS_UDP(ld) ) { + struct sockaddr sa = {0}; + /* dummy, filled with ldo_peer in request.c */ + err = ber_write( ber, &sa, sizeof(sa), 0 ); + } + if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == + LDAP_VERSION2 ) + { + char *dn = ld->ld_options.ldo_cldapdn; + if (!dn) dn = ""; + err = ber_printf( ber, "{isti", /* '}' */ + i, dn, + LDAP_REQ_ABANDON, msgid ); } else -#endif /* LDAP_CONNECTIONLESS */ +#endif { - err = ber_printf( ber, "{iti", /* leave open '}' */ - ++ld->ld_msgid, - LDAP_REQ_ABANDON, msgid ); + /* create a message to send */ + err = ber_printf( ber, "{iti", /* '}' */ + i, + LDAP_REQ_ABANDON, msgid ); } - if( err == -1 ) { + if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; @@ -162,9 +258,9 @@ do_abandon( } else { /* close '{' */ - err = ber_printf( ber, "}" ); + err = ber_printf( ber, /*{*/ "N}" ); - if( err == -1 ) { + if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; } @@ -177,12 +273,13 @@ do_abandon( } else { /* send the message */ if ( lr != NULL ) { + assert( lr->lr_conn != NULL ); sb = lr->lr_conn->lconn_sb; } else { - sb = &ld->ld_sb; + sb = ld->ld_sb; } - if ( ber_flush( sb, ber, 1 ) != 0 ) { + if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) { ld->ld_errno = LDAP_SERVER_DOWN; err = -1; } else { @@ -193,37 +290,183 @@ do_abandon( } if ( lr != NULL ) { - if ( sendabandon ) { + if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) { ldap_free_connection( ld, lr->lr_conn, 0, 1 ); } + if ( origid == msgid ) { ldap_free_request( ld, lr ); + + } else { + lr->lr_abandoned = 1; } } +#ifdef LDAP_R_COMPILE + /* ld_abandoned is actually protected by the ld_res_mutex; + * give up the ld_req_mutex and get the other */ + ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex ); + ldap_pvt_thread_mutex_lock( &ld->ld_res_mutex ); +#endif + + /* use bisection */ i = 0; - if ( ld->ld_abandoned != NULL ) { - for ( ; ld->ld_abandoned[i] != -1; i++ ) - ; /* NULL */ + if ( ld->ld_nabandoned == 0 || + ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 ) + { + ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i ); } - old_abandon = ld->ld_abandoned; + if ( err != -1 ) { + ld->ld_errno = LDAP_SUCCESS; + } + +#ifdef LDAP_R_COMPILE + ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex ); + ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex ); +#endif + return( ld->ld_errno ); +} + +/* + * ldap_int_bisect_find + * + * args: + * v: array of length n (in) + * n: length of array v (in) + * id: value to look for (in) + * idxp: pointer to location of value/insert point + * + * return: + * 0: not found + * 1: found + * -1: error + */ +int +ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp ) +{ + int begin, + end, + rc = 0; + + assert( n >= 0 ); + assert( id >= 0 ); + + begin = 0; + end = n - 1; - ld->ld_abandoned = (int *) LDAP_REALLOC( (char *) - ld->ld_abandoned, (i + 2) * sizeof(int) ); - - if ( ld->ld_abandoned == NULL ) { - ld->ld_abandoned = old_abandon; - ld->ld_errno = LDAP_NO_MEMORY; - return( ld->ld_errno ); + if ( n <= 0 || id < v[ begin ] ) { + *idxp = 0; + + } else if ( id > v[ end ] ) { + *idxp = n; + + } else { + int pos; + ber_int_t curid; + + do { + pos = (begin + end)/2; + curid = v[ pos ]; + + if ( id < curid ) { + end = pos - 1; + + } else if ( id > curid ) { + begin = ++pos; + + } else { + /* already abandoned? */ + rc = 1; + break; + } + } while ( end >= begin ); + + *idxp = pos; + } + + return rc; +} + +/* + * ldap_int_bisect_insert + * + * args: + * vp: pointer to array of length *np (in/out) + * np: pointer to length of array *vp (in/out) + * id: value to insert (in) + * idx: location of insert point (as computed by ldap_int_bisect_find()) + * + * return: + * 0: inserted + * -1: error + */ +int +ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx ) +{ + ber_int_t *v; + ber_len_t n; + int i; + + assert( vp != NULL ); + assert( np != NULL ); + assert( *np >= 0 ); + assert( idx >= 0 ); + assert( idx <= *np ); + + n = *np; + + v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) ); + if ( v == NULL ) { + return -1; } + *vp = v; - ld->ld_abandoned[i] = msgid; - ld->ld_abandoned[i + 1] = -1; + for ( i = n; i > idx; i-- ) { + v[ i ] = v[ i - 1 ]; + } + v[ idx ] = id; + ++(*np); - if ( err != -1 ) { - ld->ld_errno = LDAP_SUCCESS; + return 0; +} + +/* + * ldap_int_bisect_delete + * + * args: + * vp: pointer to array of length *np (in/out) + * np: pointer to length of array *vp (in/out) + * id: value to delete (in) + * idx: location of value to delete (as computed by ldap_int_bisect_find()) + * + * return: + * 0: deleted + */ +int +ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx ) +{ + ber_int_t *v; + ber_len_t n; + int i; + + assert( vp != NULL ); + assert( np != NULL ); + assert( *np >= 0 ); + assert( idx >= 0 ); + assert( idx < *np ); + + v = *vp; + + assert( v[ idx ] == id ); + + --(*np); + n = *np; + + for ( i = idx; i < n; i++ ) { + v[ i ] = v[ i + 1 ]; } - return( ld->ld_errno ); + return 0; } +