X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Flibldap%2Fabandon.c;h=2f83ae6766e7aa70f0061a6bd8afd1e37030608d;hb=dc871de33d529622f90c75f3d2be570e1e315821;hp=b2b24b2f58bbad038b03e4afc6d7ccd2aa124c08;hpb=29d9fa20a2823c827f098d78f1ea8539d86bf4cf;p=openldap diff --git a/libraries/libldap/abandon.c b/libraries/libldap/abandon.c index b2b24b2f58..2f83ae6766 100644 --- a/libraries/libldap/abandon.c +++ b/libraries/libldap/abandon.c @@ -1,18 +1,20 @@ +/* abandon.c */ /* $OpenLDAP$ */ -/* - * Copyright 1998-2000 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. +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2006 The OpenLDAP Foundation. + * All rights reserved. * - * abandon.c + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * 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" @@ -27,12 +29,19 @@ #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) + */ + +static int +do_abandon( LDAP *ld, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, - LDAPControl **cctrls)); + int sendabandon ); /* * ldap_abandon_ext - perform an ldap extended abandon operation. @@ -56,9 +65,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; } @@ -77,39 +102,65 @@ 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, ber_int_t origid, ber_int_t msgid, LDAPControl **sctrls, - LDAPControl **cctrls) + int sendabandon ) { BerElement *ber; - int i, err, sendabandon; - ber_int_t *old_abandon; + int i, err; + ber_int_t *old_abandon; 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 ) { +start_again:; + lr = ld->ld_requests; + while ( lr != NULL ) { if ( lr->lr_msgid == msgid ) { /* this message */ break; } + if ( lr->lr_origid == msgid ) {/* child: abandon it */ - (void) do_abandon( ld, - msgid, lr->lr_msgid, sctrls, cctrls ); + (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 ) { @@ -124,33 +175,74 @@ 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 )) == NULL ) { + 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", /* '}' */ - ++ld->ld_msgid, ld->ld_cldapdn, - LDAP_REQ_ABANDON, msgid ); + if ( LDAP_IS_UDP(ld) ) { + err = ber_write( ber, ld->ld_options.ldo_peer, + sizeof(struct sockaddr), 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 { + /* create a message to send */ err = ber_printf( ber, "{iti", /* '}' */ - ++ld->ld_msgid, - LDAP_REQ_ABANDON, msgid ); + i, + LDAP_REQ_ABANDON, msgid ); } - if( err == -1 ) { + if ( err == -1 ) { /* encoding error */ ld->ld_errno = LDAP_ENCODING_ERROR; @@ -163,9 +255,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; } @@ -178,12 +270,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 { @@ -194,37 +287,94 @@ 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 ); } } +#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 */ - } + int begin, + end; + + assert( ld->ld_nabandoned >= 0 ); + + begin = 0; + end = ld->ld_nabandoned - 1; + + if ( ld->ld_nabandoned == 0 || ld->ld_abandoned[ begin ] > msgid ) { + i = 0; + + } else if ( ld->ld_abandoned[ end ] < msgid ) { + i = ld->ld_nabandoned; + + } else { + int pos, curid; - old_abandon = ld->ld_abandoned; + while ( end >= begin ) { + pos = (begin + end)/2; + curid = ld->ld_abandoned[ pos ]; - ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *) - ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) ); - - if ( ld->ld_abandoned == NULL ) { - ld->ld_abandoned = old_abandon; - ld->ld_errno = LDAP_NO_MEMORY; - return( ld->ld_errno ); + if ( msgid < curid ) { + end = pos - 1; + + } else if ( msgid > curid ) { + begin = pos + 1; + + } else { + /* already abandoned? */ + i = -1; + break; + } + } + + if ( i == 0 ) { + i = pos; + } + } } - ld->ld_abandoned[i] = msgid; - ld->ld_abandoned[i + 1] = -1; + if ( i != -1 ) { + int pos = i; + + old_abandon = ld->ld_abandoned; + + ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *)ld->ld_abandoned, + ( ld->ld_nabandoned + 1 ) * sizeof( ber_int_t ) ); + + if ( ld->ld_abandoned == NULL ) { + ld->ld_abandoned = old_abandon; + ld->ld_errno = LDAP_NO_MEMORY; + goto done; + } + + for ( i = ld->ld_nabandoned; i > pos; i-- ) { + ld->ld_abandoned[ i ] = ld->ld_abandoned[ i - 1 ]; + } + ld->ld_abandoned[ pos ] = msgid; + ++ld->ld_nabandoned; + } if ( err != -1 ) { ld->ld_errno = LDAP_SUCCESS; } +done:; +#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 ); }