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
ldap_abandon(LDAP * ld,int msgid)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
ldap_abandon_ext(LDAP * ld,int msgid,LDAPControl ** serverctrls,LDAPControl ** clientctrls)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
do_abandon(LDAP * ld,int origid,int msgid,LDAPControl ** serverctrls,LDAPControl ** clientctrls)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