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