1 #pragma ident "%Z%%M% %I% %E% SMI" 2 3 /* 4 * The contents of this file are subject to the Netscape Public 5 * License Version 1.1 (the "License"); you may not use this file 6 * except in compliance with the License. You may obtain a copy of 7 * the License at http://www.mozilla.org/NPL/ 8 * 9 * Software distributed under the License is distributed on an "AS 10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 11 * implied. See the License for the specific language governing 12 * rights and limitations under the License. 13 * 14 * The Original Code is Mozilla Communicator client code, released 15 * March 31, 1998. 16 * 17 * The Initial Developer of the Original Code is Netscape 18 * Communications Corporation. Portions created by Netscape are 19 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 20 * Rights Reserved. 21 * 22 * Contributor(s): 23 */ 24 25 /* 26 * Copyright (c) 1990 Regents of the University of Michigan. 27 * All rights reserved. 28 */ 29 /* 30 * abandon.c 31 */ 32 33 #if 0 34 #ifndef lint 35 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n"; 36 #endif 37 #endif 38 39 #include "ldap-int.h" 40 41 static int do_abandon( LDAP *ld, int origid, int msgid, 42 LDAPControl **serverctrls, LDAPControl **clientctrls ); 43 44 /* 45 * ldap_abandon - perform an ldap abandon operation. Parameters: 46 * 47 * ld LDAP descriptor 48 * msgid The message id of the operation to abandon 49 * 50 * ldap_abandon returns 0 if everything went ok, -1 otherwise. 51 * 52 * Example: 53 * ldap_abandon( ld, msgid ); 54 */ 55 int 56 LDAP_CALL 57 ldap_abandon( LDAP *ld, int msgid ) 58 { 59 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 ); 60 61 if ( ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS ) { 62 return( 0 ); 63 } 64 65 return( -1 ); 66 } 67 68 69 /* 70 * LDAPv3 extended abandon. 71 * Returns an LDAP error code. 72 */ 73 int 74 LDAP_CALL 75 ldap_abandon_ext( LDAP *ld, int msgid, LDAPControl **serverctrls, 76 LDAPControl **clientctrls ) 77 { 78 int rc; 79 80 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 ); 81 82 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) { 83 return( LDAP_PARAM_ERROR ); 84 } 85 86 LDAP_MUTEX_LOCK( ld, LDAP_CONN_LOCK ); 87 LDAP_MUTEX_LOCK( ld, LDAP_REQ_LOCK ); 88 rc = do_abandon( ld, msgid, msgid, serverctrls, clientctrls ); 89 90 /* 91 * XXXmcs should use cache function pointers to hook in memcache 92 */ 93 ldap_memcache_abandon( ld, msgid ); 94 95 LDAP_MUTEX_UNLOCK( ld, LDAP_REQ_LOCK ); 96 LDAP_MUTEX_UNLOCK( ld, LDAP_CONN_LOCK ); 97 98 return( rc ); 99 } 100 101 102 /* 103 * Abandon all outstanding requests for msgid (included child requests 104 * spawned when chasing referrals). This function calls itself recursively. 105 * No locking is done is this function so it must be done by the caller. 106 * Returns an LDAP error code and sets it in LDAP *ld as well 107 */ 108 static int 109 do_abandon( LDAP *ld, int origid, int msgid, LDAPControl **serverctrls, 110 LDAPControl **clientctrls ) 111 { 112 BerElement *ber; 113 int i, bererr, lderr, sendabandon; 114 Sockbuf *sb; 115 LDAPRequest *lr = NULL; 116 117 /* 118 * An abandon request looks like this: 119 * AbandonRequest ::= MessageID 120 */ 121 LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n", 122 origid, msgid, 0 ); 123 124 /* optimistic */ 125 lderr = LDAP_SUCCESS; 126 127 /* 128 * this is not the best implementation... 129 * the code special cases the when async io is enabled. 130 * The logic is clear this way, at the cost of code bloat. 131 * This logic should be cleaned up post nova 4.5 rtm 132 */ 133 if (ld->ld_options & LDAP_BITOPT_ASYNC) 134 { 135 /* Don't send an abandon message unless there is something to abandon. */ 136 sendabandon = 0; 137 138 /* Find the request that we are abandoning. */ 139 if (ld->ld_requests != NULL) { 140 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 141 if ( lr->lr_msgid == msgid ) { /* this message */ 142 if ( origid == msgid && lr->lr_parent != NULL ) { 143 /* don't let caller abandon child requests! */ 144 lderr = LDAP_PARAM_ERROR; 145 goto set_errorcode_and_return; 146 } 147 if ( lr->lr_status == LDAP_REQST_INPROGRESS ) { 148 /* We only need to send an abandon message if the request 149 * is in progress. 150 */ 151 sendabandon = 1; 152 } 153 break; 154 } 155 if ( lr->lr_origid == msgid ) { /* child: abandon it */ 156 (void)do_abandon( ld, msgid, lr->lr_msgid, 157 serverctrls, clientctrls ); 158 /* we ignore errors from child abandons... */ 159 } 160 } 161 } 162 } 163 else 164 { 165 sendabandon = 1; 166 /* find the request that we are abandoning */ 167 for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) { 168 if ( lr->lr_msgid == msgid ) { /* this message */ 169 break; 170 } 171 if ( lr->lr_origid == msgid ) { /* child: abandon it */ 172 (void)do_abandon( ld, msgid, lr->lr_msgid, 173 serverctrls, clientctrls ); 174 /* we ignore errors from child abandons... */ 175 } 176 } 177 178 if ( lr != NULL ) { 179 if ( origid == msgid && lr->lr_parent != NULL ) { 180 /* don't let caller abandon child requests! */ 181 lderr = LDAP_PARAM_ERROR; 182 goto set_errorcode_and_return; 183 } 184 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) { 185 /* no need to send abandon message */ 186 sendabandon = 0; 187 } 188 } 189 } 190 if ( ldap_msgdelete( ld, msgid ) == 0 ) { 191 /* we had all the results and deleted them */ 192 goto set_errorcode_and_return; 193 } 194 195 if ( sendabandon ) { 196 /* create a message to send */ 197 if (( lderr = nsldapi_alloc_ber_with_options( ld, &ber )) == 198 LDAP_SUCCESS ) { 199 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK ); 200 #ifdef CLDAP 201 if ( ld->ld_dbp->sb_naddr > 0 ) { 202 bererr = ber_printf( ber, "{isti", 203 ++ld->ld_msgid, ld->ld_cldapdn, 204 LDAP_REQ_ABANDON, msgid ); 205 } else { 206 #endif /* CLDAP */ 207 bererr = ber_printf( ber, "{iti", 208 ++ld->ld_msgid, LDAP_REQ_ABANDON, msgid ); 209 #ifdef CLDAP 210 } 211 #endif /* CLDAP */ 212 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK ); 213 214 if ( bererr == -1 || 215 ( lderr = nsldapi_put_controls( ld, serverctrls, 216 1, ber )) != LDAP_SUCCESS ) { 217 lderr = LDAP_ENCODING_ERROR; 218 ber_free( ber, 1 ); 219 } else { 220 /* send the message */ 221 if ( lr != NULL ) { 222 sb = lr->lr_conn->lconn_sb; 223 } else { 224 sb = ld->ld_sbp; 225 } 226 if ( nsldapi_ber_flush( ld, sb, ber, 1, 0 ) 227 != 0 ) { 228 lderr = LDAP_SERVER_DOWN; 229 } 230 } 231 } 232 } 233 234 if ( lr != NULL ) { 235 if ( sendabandon ) { 236 nsldapi_free_connection( ld, lr->lr_conn, NULL, NULL, 237 0, 1 ); 238 } 239 if ( origid == msgid ) { 240 nsldapi_free_request( ld, lr, 0 ); 241 } 242 } 243 244 245 LDAP_MUTEX_LOCK( ld, LDAP_ABANDON_LOCK ); 246 if ( ld->ld_abandoned == NULL ) { 247 if ( (ld->ld_abandoned = (int *)NSLDAPI_MALLOC( 2 248 * sizeof(int) )) == NULL ) { 249 lderr = LDAP_NO_MEMORY; 250 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); 251 goto set_errorcode_and_return; 252 } 253 i = 0; 254 } else { 255 for ( i = 0; ld->ld_abandoned[i] != -1; i++ ) 256 ; /* NULL */ 257 if ( (ld->ld_abandoned = (int *)NSLDAPI_REALLOC( (char *) 258 ld->ld_abandoned, (i + 2) * sizeof(int) )) == NULL ) { 259 lderr = LDAP_NO_MEMORY; 260 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); 261 goto set_errorcode_and_return; 262 } 263 } 264 ld->ld_abandoned[i] = msgid; 265 ld->ld_abandoned[i + 1] = -1; 266 LDAP_MUTEX_UNLOCK( ld, LDAP_ABANDON_LOCK ); 267 268 set_errorcode_and_return: 269 LDAP_SET_LDERRNO( ld, lderr, NULL, NULL ); 270 return( lderr ); 271 } 272