]> git.sur5r.net Git - openldap/blob - libraries/libldap/abandon.c
Added ld_req_mutex and ld_res_mutex to protect ld_requests and ld_responses
[openldap] / libraries / libldap / abandon.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1990 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  abandon.c
11  */
12
13 /*
14  * An abandon request looks like this:
15  *      AbandonRequest ::= MessageID
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/stdlib.h>
23
24 #include <ac/socket.h>
25 #include <ac/string.h>
26 #include <ac/time.h>
27
28 #include "ldap-int.h"
29
30 static int do_abandon LDAP_P((
31         LDAP *ld,
32         ber_int_t origid,
33         ber_int_t msgid,
34         LDAPControl **sctrls,
35         LDAPControl **cctrls,
36         int lock));
37
38 /*
39  * ldap_abandon_ext - perform an ldap extended abandon operation.
40  *
41  * Parameters:
42  *      ld                      LDAP descriptor
43  *      msgid           The message id of the operation to abandon
44  *      scntrls         Server Controls
45  *      ccntrls         Client Controls
46  *
47  * ldap_abandon_ext returns a LDAP error code.
48  *              (LDAP_SUCCESS if everything went ok)
49  *
50  * Example:
51  *      ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
52  */
53 int
54 ldap_abandon_ext(
55         LDAP *ld,
56         int msgid,
57         LDAPControl **sctrls,
58         LDAPControl **cctrls )
59 {
60         int rc;
61 #ifdef NEW_LOGGING
62         LDAP_LOG ( OPERATION, ARGS, "ldap_abandon_ext %d\n", msgid, 0, 0 );
63 #else
64         Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
65 #endif
66
67         /* check client controls */
68         rc = ldap_int_client_controls( ld, cctrls );
69         if( rc != LDAP_SUCCESS ) return rc;
70
71         return do_abandon( ld, msgid, msgid, sctrls, cctrls, 1 );
72 }
73
74
75 /*
76  * ldap_abandon - perform an ldap abandon operation. Parameters:
77  *
78  *      ld              LDAP descriptor
79  *      msgid           The message id of the operation to abandon
80  *
81  * ldap_abandon returns 0 if everything went ok, -1 otherwise.
82  *
83  * Example:
84  *      ldap_abandon( ld, msgid );
85  */
86 int
87 ldap_abandon( LDAP *ld, int msgid )
88 {
89 #ifdef NEW_LOGGING
90         LDAP_LOG ( OPERATION, ARGS, "ldap_abandon %d\n", msgid, 0, 0 );
91 #else
92         Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
93 #endif
94         return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
95                 ? 0 : -1;
96 }
97
98
99 static int
100 do_abandon(
101         LDAP *ld,
102         ber_int_t origid,
103         ber_int_t msgid,
104         LDAPControl **sctrls,
105         LDAPControl **cctrls,
106         int lock)
107 {
108         BerElement      *ber;
109         int             i, err, sendabandon;
110         ber_int_t *old_abandon;
111         Sockbuf         *sb;
112         LDAPRequest     *lr;
113
114 #ifdef NEW_LOGGING
115         LDAP_LOG ( OPERATION, ARGS, "do_abandon %d, msgid %d\n", origid, msgid, 0 );
116 #else
117         Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
118                 origid, msgid, 0 );
119 #endif
120
121         sendabandon = 1;
122
123 #ifdef LDAP_R_COMPILE
124         if ( lock ) ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
125 #endif
126         /* find the request that we are abandoning */
127         for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
128                 if ( lr->lr_msgid == msgid ) {  /* this message */
129                         break;
130                 }
131                 if ( lr->lr_origid == msgid ) {/* child:  abandon it */
132                         (void) do_abandon( ld,
133                                 msgid, lr->lr_msgid, sctrls, cctrls, 0 );
134                 }
135         }
136 #ifdef LDAP_R_COMPILE
137         if ( lock ) ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
138 #endif
139
140         if ( lr != NULL ) {
141                 if ( origid == msgid && lr->lr_parent != NULL ) {
142                         /* don't let caller abandon child requests! */
143                         ld->ld_errno = LDAP_PARAM_ERROR;
144                         return( LDAP_PARAM_ERROR );
145                 }
146                 if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
147                         /* no need to send abandon message */
148                         sendabandon = 0;
149                 }
150         }
151
152         if ( ldap_msgdelete( ld, msgid ) == 0 ) {
153                 ld->ld_errno = LDAP_SUCCESS;
154                 return LDAP_SUCCESS;
155         }
156
157         err = 0;
158         if ( sendabandon ) {
159                 if( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
160                         /* not connected */
161                         err = -1;
162                         ld->ld_errno = LDAP_SERVER_DOWN;
163
164                 } else if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
165                         /* BER element alocation failed */
166                         err = -1;
167                         ld->ld_errno = LDAP_NO_MEMORY;
168
169                 } else {
170 #ifdef LDAP_CONNECTIONLESS
171                         if ( LDAP_IS_UDP(ld) ) {
172                             err = ber_write( ber, ld->ld_options.ldo_peer,
173                                 sizeof(struct sockaddr), 0);
174                         }
175                         if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
176                                 LDAP_VERSION2) {
177                             char *dn = ld->ld_options.ldo_cldapdn;
178                             if (!dn) dn = "";
179                             err = ber_printf( ber, "{isti",  /* '}' */
180                                 ++ld->ld_msgid, dn,
181                                 LDAP_REQ_ABANDON, msgid );
182                         } else
183 #endif
184                         {
185                             /* create a message to send */
186                             err = ber_printf( ber, "{iti",  /* '}' */
187                                 ++ld->ld_msgid,
188                                 LDAP_REQ_ABANDON, msgid );
189                         }
190
191                         if( err == -1 ) {
192                                 /* encoding error */
193                                 ld->ld_errno = LDAP_ENCODING_ERROR;
194
195                         } else {
196                                 /* Put Server Controls */
197                                 if ( ldap_int_put_controls( ld, sctrls, ber )
198                                         != LDAP_SUCCESS )
199                                 {
200                                         err = -1;
201
202                                 } else {
203                                         /* close '{' */
204                                         err = ber_printf( ber, /*{*/ "N}" );
205
206                                         if( err == -1 ) {
207                                                 /* encoding error */
208                                                 ld->ld_errno = LDAP_ENCODING_ERROR;
209                                         }
210                                 }
211                         }
212
213                         if ( err == -1 ) {
214                                 ber_free( ber, 1 );
215
216                         } else {
217                                 /* send the message */
218                                 if ( lr != NULL ) {
219                                         sb = lr->lr_conn->lconn_sb;
220                                 } else {
221                                         sb = ld->ld_sb;
222                                 }
223
224 #ifdef LDAP_R_COMPILE
225         if ( lock ) ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
226 #endif
227                                 if ( ber_flush( sb, ber, 1 ) != 0 ) {
228                                         ld->ld_errno = LDAP_SERVER_DOWN;
229                                         err = -1;
230                                 } else {
231                                         err = 0;
232                                 }
233 #ifdef LDAP_R_COMPILE
234         if ( lock ) ldap_pvt_thread_mutex_unlock( &ld->ld_req_mutex );
235 #endif
236                         }
237                 }
238         }
239
240         if ( lr != NULL ) {
241                 if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
242                         ldap_free_connection( ld, lr->lr_conn, 0, 1 );
243                 }
244                 if ( origid == msgid ) {
245                         ldap_free_request( ld, lr );
246                 }
247         }
248
249         i = 0;
250         if ( ld->ld_abandoned != NULL ) {
251                 for ( ; ld->ld_abandoned[i] != -1; i++ )
252                         ;       /* NULL */
253         }
254
255         old_abandon = ld->ld_abandoned;
256
257         ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *)
258                 ld->ld_abandoned, (i + 2) * sizeof(ber_int_t) );
259                 
260         if ( ld->ld_abandoned == NULL ) {
261                 ld->ld_abandoned = old_abandon;
262                 ld->ld_errno = LDAP_NO_MEMORY;
263                 return( ld->ld_errno );
264         }
265
266         ld->ld_abandoned[i] = msgid;
267         ld->ld_abandoned[i + 1] = -1;
268
269         if ( err != -1 ) {
270                 ld->ld_errno = LDAP_SUCCESS;
271         }
272
273         return( ld->ld_errno );
274 }