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