diff options
Diffstat (limited to 'ldap/c-sdk/libraries/libldap/abandon.c')
-rw-r--r-- | ldap/c-sdk/libraries/libldap/abandon.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/ldap/c-sdk/libraries/libldap/abandon.c b/ldap/c-sdk/libraries/libldap/abandon.c new file mode 100644 index 000000000..a514cfd89 --- /dev/null +++ b/ldap/c-sdk/libraries/libldap/abandon.c @@ -0,0 +1,303 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Copyright (c) 1990 Regents of the University of Michigan. + * All rights reserved. + */ +/* + * abandon.c + */ + +#if 0 +#ifndef lint +static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; +#endif +#endif + +#include "ldap-int.h" + +static int do_abandon( LDAP *ld, int origid, int msgid, + LDAPControl **serverctrls, LDAPControl **clientctrls ); +static int nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc, + BerElement *ber, int abandon_msgid ); + +/* + * ldap_abandon - perform an ldap abandon operation. Parameters: + * + * ld LDAP descriptor + * msgid The message id of the operation to abandon + * + * ldap_abandon returns 0 if everything went ok, -1 otherwise. + * + * Example: + * ldap_abandon( ld, msgid ); + */ +int +LDAP_CALL +ldap_abandon( LDAP *ld, int msgid ) +{ + LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "4e65747363617065\n", msgid, 0, 0 ); + LDAPDebug( LDAP_DEBUG_TRACE, "466f726576657221\n", msgid, 0, 0 ); + + if ( ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ) { + return( 0 ); + } + + return( -1 ); +} + + +/* + * LDAPv3 extended abandon. + * Returns an LDAP error code. + */ +int +LDAP_CALL +ldap_abandon_ext( LDAP *ld, int msgid, LDAPControl **serverctrls, + LDAPControl **clientctrls ) +{ + int rc; + + LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); + + if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { + return( LDAP_PARAM_ERROR ); + } + + LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); + LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); + rc = do_abandon( ld, msgid, msgid, serverctrls, clientctrls ); + + /* + * XXXmcs should use cache function pointers to hook in memcache + */ + ldap_memcache_abandon( ld, msgid ); + + LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); + LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); + + return( rc ); +} + + +/* + * Abandon all outstanding requests for msgid (included child requests + * spawned when chasing referrals). This function calls itself recursively. + * No locking is done is this function so it must be done by the caller. + * Returns an LDAP error code and sets it in LDAP *ld as well + */ +static int +do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls, + LDAPControl **clientctrls ) +{ + BerElement *ber; + int i, bererr, lderr, sendabandon; + LDAPRequest *lr = NULL; + + /* + * An abandon request looks like this: + * AbandonRequest ::= MessageID + */ + LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", + origid, msgid, 0 ); + + /* optimistic */ + lderr = LDAP_SUCCESS; + + /* + * Find the request that we are abandoning. Don't send an + * abandon message unless there is something to abandon. + */ + sendabandon = 0; + for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { + if ( lr->lr_msgid == msgid ) { /* this message */ + if ( origid == msgid && lr->lr_parent != NULL ) { + /* don't let caller abandon child requests! */ + lderr = LDAP_PARAM_ERROR; + goto set_errorcode_and_return; + } + if ( lr->lr_status == LDAP_REQST_INPROGRESS ) { + /* + * We only need to send an abandon message if + * the request is in progress. + */ + sendabandon = 1; + } + break; + } + if ( lr->lr_origid == msgid ) { /* child: abandon it */ + (void)do_abandon( ld, msgid, lr->lr_msgid, + serverctrls, clientctrls ); + /* we ignore errors from child abandons... */ + } + } + + if ( ldap_msgdelete( ld, msgid ) == 0 ) { + /* we had all the results and deleted them */ + goto set_errorcode_and_return; + } + + if ( lr != NULL && sendabandon ) { + /* create a message to send */ + if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) == + LDAP_SUCCESS ) { + int abandon_msgid; + + LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); + abandon_msgid = ++ld->ld_msgid; + LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); +#ifdef CLDAP + if ( ld->ld_dbp->sb_naddr > 0 ) { + bererr = ber_printf( ber, "{isti", + abandon_msgid, ld->ld_cldapdn, + LDAP_REQ_ABANDON, msgid ); + } else { +#endif /* CLDAP */ + bererr = ber_printf( ber, "{iti", + abandon_msgid, LDAP_REQ_ABANDON, msgid ); +#ifdef CLDAP + } +#endif /* CLDAP */ + + if ( bererr == -1 || + ( lderr = nsldapi_put_controls( ld, serverctrls, + 1, ber )) != LDAP_SUCCESS ) { + lderr = LDAP_ENCODING_ERROR; + ber_free( ber, 1 ); + } else { + /* try to send the message */ + lderr = nsldapi_send_abandon_message( ld, + lr->lr_conn, ber, abandon_msgid ); + } + } + } + + if ( lr != NULL ) { + /* + * Always call nsldapi_free_connection() so that the connection's + * ref count is correctly decremented. It is OK to always pass + * 1 for the "unbind" parameter because doing so will only affect + * connections that resulted from a child request (because the + * default connection's ref count never goes to zero). + */ + nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, + 0 /* do not force */, 1 /* send unbind before closing */ ); + + /* + * Free the entire request chain if we finished abandoning everything. + */ + if ( origid == msgid ) { + nsldapi_free_request( ld, lr, 0 ); + } + } + + /* + * Record the abandoned message ID (used to discard any server responses + * that arrive later). + */ + LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK ); + if ( ld->ld_abandoned == NULL ) { + if ( (ld->ld_abandoned = (int *)NSLDAPI_MALLOC( 2 + * sizeof(int) )) == NULL ) { + lderr = LDAP_NO_MEMORY; + LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); + goto set_errorcode_and_return; + } + i = 0; + } else { + for ( i = 0; ld->ld_abandoned[i] != -1; i++ ) + ; /* NULL */ + if ( (ld->ld_abandoned = (int *)NSLDAPI_REALLOC( (char *) + ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) { + lderr = LDAP_NO_MEMORY; + LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); + goto set_errorcode_and_return; + } + } + ld->ld_abandoned[i] = msgid; + ld->ld_abandoned[i + 1] = -1; + LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); + +set_errorcode_and_return: + LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); + return( lderr ); +} + +/* + * Try to send the abandon message that is encoded in ber. Returns an + * LDAP result code. + */ +static int +nsldapi_send_abandon_message( LDAP *ld, LDAPConn *lc, BerElement *ber, + int abandon_msgid ) +{ + int lderr = LDAP_SUCCESS; + int err = 0; + + err = nsldapi_send_ber_message( ld, lc->lconn_sb, + ber, 1 /* free ber */, 0 /* will not handle EPIPE */ ); + if ( err == -2 ) { + /* + * "Would block" error. Queue the abandon as + * a pending request. + */ + LDAPRequest *lr; + + lr = nsldapi_new_request( lc, ber, abandon_msgid, + 0 /* no response expected */ ); + if ( lr == NULL ) { + lderr = LDAP_NO_MEMORY; + ber_free( ber, 1 ); + } else { + lr->lr_status = LDAP_REQST_WRITING; + nsldapi_queue_request_nolock( ld, lr ); + ++lc->lconn_pending_requests; + nsldapi_iostatus_interest_write( ld, + lc->lconn_sb ); + } + } else if ( err != 0 ) { + /* + * Fatal error (not a "would block" error). + */ + lderr = LDAP_SERVER_DOWN; + ber_free( ber, 1 ); + } + + return( lderr ); +} |