]> git.sur5r.net Git - openldap/blob - libraries/libldap/result.c
34966dc17ab4b15926825ca324b5547386027920
[openldap] / libraries / libldap / result.c
1 /*
2  *  Copyright (c) 1990 Regents of the University of Michigan.
3  *  All rights reserved.
4  *
5  *  result.c - wait for an ldap result
6  */
7
8 #ifndef lint 
9 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
10 #endif
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15
16 #ifdef MACOS
17 #include <time.h>
18 #include "macos.h"
19 #else /* MACOS */
20 #if defined( DOS ) || defined( _WIN32 )
21 #include <time.h>
22 #include "msdos.h"
23 #ifdef PCNFS
24 #include <tklib.h>
25 #include <tk_errno.h>
26 #include <bios.h>
27 #endif /* PCNFS */
28 #ifdef NCSA
29 #include "externs.h"
30 #endif /* NCSA */
31 #else /* DOS */
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/errno.h>
36 #ifdef _AIX
37 #include <sys/select.h>
38 #endif /* _AIX */
39 #endif /* DOS */
40 #endif /* MACOS */
41 #ifdef VMS
42 #include "ucx_select.h"
43 #endif
44
45 #include "portable.h"
46
47 #include "lber.h"
48 #include "ldap.h"
49 #include "ldap-int.h"
50
51 #ifdef USE_SYSCONF
52 #include <unistd.h>
53 #endif /* USE_SYSCONF */
54
55 #ifdef NEEDPROTOS
56 static int ldap_abandoned( LDAP *ld, int msgid );
57 static int ldap_mark_abandoned( LDAP *ld, int msgid );
58 static int wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
59         LDAPMessage **result );
60 #ifdef LDAP_REFERRALS
61 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb, LDAPConn *lc,
62         LDAPMessage **result );
63 static int build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr );
64 static void merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr );
65 #else /* LDAP_REFERRALS */
66 static int read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
67         LDAPMessage **result );
68 #endif /* LDAP_REFERRALS */
69 #if defined( CLDAP ) || !defined( LDAP_REFERRALS )
70 static int ldap_select1( LDAP *ld, struct timeval *timeout );
71 #endif
72 #else /* NEEDPROTOS */
73 static int ldap_abandoned();
74 static int ldap_mark_abandoned();
75 static int wait4msg();
76 static int read1msg();
77 #ifdef LDAP_REFERRALS
78 static int build_result_ber();
79 static void merge_error_info();
80 #endif /* LDAP_REFERRALS */
81 #if defined( CLDAP ) || !defined( LDAP_REFERRALS )
82 static int ldap_select1();
83 #endif
84 #endif /* NEEDPROTOS */
85
86 #if !defined( MACOS ) && !defined( DOS )
87 extern int      errno;
88 #endif
89
90
91 /*
92  * ldap_result - wait for an ldap result response to a message from the
93  * ldap server.  If msgid is -1, any message will be accepted, otherwise
94  * ldap_result will wait for a response with msgid.  If all is 0 the
95  * first message with id msgid will be accepted, otherwise, ldap_result
96  * will wait for all responses with id msgid and then return a pointer to
97  * the entire list of messages.  This is only useful for search responses,
98  * which can be of two message types (zero or more entries, followed by an
99  * ldap result).  The type of the first message received is returned.
100  * When waiting, any messages that have been abandoned are discarded.
101  *
102  * Example:
103  *      ldap_result( s, msgid, all, timeout, result )
104  */
105 int
106 ldap_result( LDAP *ld, int msgid, int all, struct timeval *timeout,
107         LDAPMessage **result )
108 {
109         LDAPMessage     *lm, *lastlm, *nextlm;
110
111         /*
112          * First, look through the list of responses we have received on
113          * this association and see if the response we're interested in
114          * is there.  If it is, return it.  If not, call wait4msg() to
115          * wait until it arrives or timeout occurs.
116          */
117
118         Debug( LDAP_DEBUG_TRACE, "ldap_result\n", 0, 0, 0 );
119
120         *result = NULLMSG;
121         lastlm = NULLMSG;
122         for ( lm = ld->ld_responses; lm != NULLMSG; lm = nextlm ) {
123                 nextlm = lm->lm_next;
124
125                 if ( ldap_abandoned( ld, lm->lm_msgid ) ) {
126                         ldap_mark_abandoned( ld, lm->lm_msgid );
127
128                         if ( lastlm == NULLMSG ) {
129                                 ld->ld_responses = lm->lm_next;
130                         } else {
131                                 lastlm->lm_next = nextlm;
132                         }
133
134                         ldap_msgfree( lm );
135
136                         continue;
137                 }
138
139                 if ( msgid == LDAP_RES_ANY || lm->lm_msgid == msgid ) {
140                         LDAPMessage     *tmp;
141
142                         if ( all == 0
143                             || (lm->lm_msgtype != LDAP_RES_SEARCH_RESULT
144                             && lm->lm_msgtype != LDAP_RES_SEARCH_ENTRY) )
145                                 break;
146
147                         for ( tmp = lm; tmp != NULLMSG; tmp = tmp->lm_chain ) {
148                                 if ( tmp->lm_msgtype == LDAP_RES_SEARCH_RESULT )
149                                         break;
150                         }
151
152                         if ( tmp == NULLMSG ) {
153                                 return( wait4msg( ld, msgid, all, timeout,
154                                     result ) );
155                         }
156
157                         break;
158                 }
159                 lastlm = lm;
160         }
161         if ( lm == NULLMSG ) {
162                 return( wait4msg( ld, msgid, all, timeout, result ) );
163         }
164
165         if ( lastlm == NULLMSG ) {
166                 ld->ld_responses = (all == 0 && lm->lm_chain != NULLMSG
167                     ? lm->lm_chain : lm->lm_next);
168         } else {
169                 lastlm->lm_next = (all == 0 && lm->lm_chain != NULLMSG
170                     ? lm->lm_chain : lm->lm_next);
171         }
172         if ( all == 0 )
173                 lm->lm_chain = NULLMSG;
174         lm->lm_next = NULLMSG;
175
176         *result = lm;
177         ld->ld_errno = LDAP_SUCCESS;
178         return( lm->lm_msgtype );
179 }
180
181 static int
182 wait4msg( LDAP *ld, int msgid, int all, struct timeval *timeout,
183         LDAPMessage **result )
184 {
185         int             rc;
186         struct timeval  tv, *tvp;
187         time_t          start_time = 0;
188         time_t          tmp_time;
189 #ifdef LDAP_REFERRALS
190         LDAPConn        *lc, *nextlc;
191 #endif /* LDAP_REFERRALS */
192
193 #ifdef LDAP_DEBUG
194         if ( timeout == NULL ) {
195                 Debug( LDAP_DEBUG_TRACE, "wait4msg (infinite timeout)\n",
196                     0, 0, 0 );
197         } else {
198                 Debug( LDAP_DEBUG_TRACE, "wait4msg (timeout %ld sec, %ld usec)\n",
199                     timeout->tv_sec, timeout->tv_usec, 0 );
200         }
201 #endif /* LDAP_DEBUG */
202
203         if ( timeout == NULL ) {
204                 tvp = NULL;
205         } else {
206                 tv = *timeout;
207                 tvp = &tv;
208                 start_time = time( NULL );
209         }
210                     
211         rc = -2;
212         while ( rc == -2 ) {
213 #ifndef LDAP_REFERRALS
214                 /* hack attack */
215                 if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
216                         rc = ldap_select1( ld, tvp );
217
218 #if !defined( MACOS ) && !defined( DOS )
219                         if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
220                             LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) {
221 #else
222                         if ( rc == -1 || rc == 0 ) {
223 #endif
224                                 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
225                                     LDAP_TIMEOUT);
226                                 return( rc );
227                         }
228
229                 }
230                 if ( rc == -1 ) {
231                         rc = -2;        /* select interrupted: loop */
232                 } else {
233                         rc = read1msg( ld, msgid, all, &ld->ld_sb, result );
234                 }
235 #else /* !LDAP_REFERRALS */
236 #ifdef LDAP_DEBUG
237                 if ( ldap_debug & LDAP_DEBUG_TRACE ) {
238                         ldap_dump_connection( ld, ld->ld_conns, 1 );
239                         ldap_dump_requests_and_responses( ld );
240                 }
241 #endif /* LDAP_DEBUG */
242                 for ( lc = ld->ld_conns; lc != NULL; lc = lc->lconn_next ) {
243                         if ( lc->lconn_sb->sb_ber.ber_ptr <
244                             lc->lconn_sb->sb_ber.ber_end ) {
245                                 rc = read1msg( ld, msgid, all, lc->lconn_sb,
246                                     lc, result );
247                                 break;
248                         }
249                 }
250
251                 if ( lc == NULL ) {
252                         rc = do_ldap_select( ld, tvp );
253
254
255 #if defined( LDAP_DEBUG ) && !defined( MACOS ) && !defined( DOS )
256                         if ( rc == -1 ) {
257                             Debug( LDAP_DEBUG_TRACE,
258                                     "do_ldap_select returned -1: errno %d\n",
259                                     errno, 0, 0 );
260                         }
261 #endif
262
263 #if !defined( MACOS ) && !defined( DOS )
264                         if ( rc == 0 || ( rc == -1 && (( ld->ld_options &
265                             LDAP_OPT_RESTART ) == 0 || errno != EINTR ))) {
266 #else
267                         if ( rc == -1 || rc == 0 ) {
268 #endif
269                                 ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
270                                     LDAP_TIMEOUT);
271                                 return( rc );
272                         }
273
274                         if ( rc == -1 ) {
275                                 rc = -2;        /* select interrupted: loop */
276                         } else {
277                                 rc = -2;
278                                 for ( lc = ld->ld_conns; rc == -2 && lc != NULL;
279                                     lc = nextlc ) {
280                                         nextlc = lc->lconn_next;
281                                         if ( lc->lconn_status ==
282                                             LDAP_CONNST_CONNECTED &&
283                                             ldap_is_read_ready( ld,
284                                             lc->lconn_sb )) {
285                                                 rc = read1msg( ld, msgid, all,
286                                                     lc->lconn_sb, lc, result );
287                                         }
288                                 }
289                         }
290                 }
291 #endif /* !LDAP_REFERRALS */
292
293                 if ( rc == -2 && tvp != NULL ) {
294                         tmp_time = time( NULL );
295                         if (( tv.tv_sec -=  ( tmp_time - start_time )) <= 0 ) {
296                                 rc = 0; /* timed out */
297                                 ld->ld_errno = LDAP_TIMEOUT;
298                                 break;
299                         }
300
301                         Debug( LDAP_DEBUG_TRACE, "wait4msg:  %ld secs to go\n",
302                                 tv.tv_sec, 0, 0 );
303                         start_time = tmp_time;
304                 }
305         }
306
307         return( rc );
308 }
309
310
311 static int
312 read1msg( LDAP *ld, int msgid, int all, Sockbuf *sb,
313 #ifdef LDAP_REFERRALS
314     LDAPConn *lc,
315 #endif /* LDAP_REFERRALS */
316     LDAPMessage **result )
317 {
318         BerElement      ber;
319         LDAPMessage     *new, *l, *prev, *tmp;
320         long            id;
321         unsigned long   tag, len;
322         int             foundit = 0;
323 #ifdef LDAP_REFERRALS
324         LDAPRequest     *lr;
325         BerElement      tmpber;
326         int             rc, refer_cnt, hadref, simple_request;
327         unsigned long   lderr;
328 #endif /* LDAP_REFERRALS */
329
330         Debug( LDAP_DEBUG_TRACE, "read1msg\n", 0, 0, 0 );
331
332         ber_init( &ber, 0 );
333         ldap_set_ber_options( ld, &ber );
334
335         /* get the next message */
336         if ( (tag = ber_get_next( sb, &len, &ber ))
337             != LDAP_TAG_MESSAGE ) {
338                 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
339                     LDAP_LOCAL_ERROR);
340                 return( -1 );
341         }
342
343         /* message id */
344         if ( ber_get_int( &ber, &id ) == LBER_ERROR ) {
345                 ld->ld_errno = LDAP_DECODING_ERROR;
346                 return( -1 );
347         }
348
349         /* if it's been abandoned, toss it */
350         if ( ldap_abandoned( ld, (int)id ) ) {
351                 free( ber.ber_buf );    /* gack! */
352                 return( -2 );   /* continue looking */
353         }
354
355 #ifdef LDAP_REFERRALS
356         if (( lr = ldap_find_request_by_msgid( ld, id )) == NULL ) {
357                 Debug( LDAP_DEBUG_ANY,
358                     "no request for response with msgid %ld (tossing)\n",
359                     id, 0, 0 );
360                 free( ber.ber_buf );    /* gack! */
361                 return( -2 );   /* continue looking */
362         }
363         Debug( LDAP_DEBUG_TRACE, "got %s msgid %ld, original id %d\n",
364             ( tag == LDAP_RES_SEARCH_ENTRY ) ? "entry" : "result", id,
365             lr->lr_origid );
366         id = lr->lr_origid;
367 #endif /* LDAP_REFERRALS */
368
369         /* the message type */
370         if ( (tag = ber_peek_tag( &ber, &len )) == LBER_ERROR ) {
371                 ld->ld_errno = LDAP_DECODING_ERROR;
372                 return( -1 );
373         }
374
375 #ifdef LDAP_REFERRALS
376         refer_cnt = 0;
377         hadref = simple_request = 0;
378         rc = -2;        /* default is to keep looking (no response found) */
379         lr->lr_res_msgtype = tag;
380
381         if ( tag != LDAP_RES_SEARCH_ENTRY ) {
382                 if ( ld->ld_version >= LDAP_VERSION2 &&
383                             ( lr->lr_parent != NULL ||
384                             ( ld->ld_options & LDAP_OPT_REFERRALS ) != 0 )) {
385                         tmpber = ber;   /* struct copy */
386                         if ( ber_scanf( &tmpber, "{iaa}", &lderr,
387                             &lr->lr_res_matched, &lr->lr_res_error )
388                             != LBER_ERROR ) {
389                                 if ( lderr != LDAP_SUCCESS ) {
390                                         /* referrals are in error string */
391                                         refer_cnt = ldap_chase_referrals( ld, lr,
392                                             &lr->lr_res_error, &hadref );
393                                 }
394
395                                 /* save errno, message, and matched string */
396                                 if ( !hadref || lr->lr_res_error == NULL ) {
397                                         lr->lr_res_errno = ( lderr ==
398                                         LDAP_PARTIAL_RESULTS ) ? LDAP_SUCCESS
399                                         : lderr;
400                                 } else if ( ld->ld_errno != LDAP_SUCCESS ) {
401                                         lr->lr_res_errno = ld->ld_errno;
402                                 } else {
403                                         lr->lr_res_errno = LDAP_PARTIAL_RESULTS;
404                                 }
405 Debug( LDAP_DEBUG_TRACE,
406     "new result:  res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
407     lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
408     lr->lr_res_matched ? lr->lr_res_matched : "" );
409                         }
410                 }
411
412                 Debug( LDAP_DEBUG_TRACE,
413                     "read1msg:  %d new referrals\n", refer_cnt, 0, 0 );
414
415                 if ( refer_cnt != 0 ) { /* chasing referrals */
416                         free( ber.ber_buf );    /* gack! */
417                         ber.ber_buf = NULL;
418                         if ( refer_cnt < 0 ) {
419                                 return( -1 );   /* fatal error */
420                         }
421                         lr->lr_status = LDAP_REQST_CHASINGREFS;
422                 } else {
423                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
424                                 /* request without any referrals */
425                                 simple_request = ( hadref ? 0 : 1 );
426                         } else {
427                                 /* request with referrals or child request */
428                                 free( ber.ber_buf );    /* gack! */
429                                 ber.ber_buf = NULL;
430                         }
431
432                         while ( lr->lr_parent != NULL ) {
433                                 merge_error_info( ld, lr->lr_parent, lr );
434
435                                 lr = lr->lr_parent;
436                                 if ( --lr->lr_outrefcnt > 0 ) {
437                                         break;  /* not completely done yet */
438                                 }
439                         }
440
441                         if ( lr->lr_outrefcnt <= 0 && lr->lr_parent == NULL ) {
442                                 id = lr->lr_msgid;
443                                 tag = lr->lr_res_msgtype;
444                                 Debug( LDAP_DEBUG_ANY, "request %ld done\n",
445                                     id, 0, 0 );
446 Debug( LDAP_DEBUG_TRACE,
447 "res_errno: %d, res_error: <%s>, res_matched: <%s>\n",
448 lr->lr_res_errno, lr->lr_res_error ? lr->lr_res_error : "",
449 lr->lr_res_matched ? lr->lr_res_matched : "" );
450                                 if ( !simple_request ) {
451                                         if ( ber.ber_buf != NULL ) {
452                                                 free( ber.ber_buf ); /* gack! */
453                                                 ber.ber_buf = NULL;
454                                         }
455                                         if ( build_result_ber( ld, &ber, lr )
456                                             == LBER_ERROR ) {
457                                                 ld->ld_errno = LDAP_NO_MEMORY;
458                                                 rc = -1; /* fatal error */
459                                         }
460                                 }
461
462                                 ldap_free_request( ld, lr );
463                         }
464
465                         if ( lc != NULL ) {
466                                 ldap_free_connection( ld, lc, 0, 1 );
467                         }
468                 }
469         }
470
471         if ( ber.ber_buf == NULL ) {
472                 return( rc );
473         }
474
475 #endif /* LDAP_REFERRALS */
476         /* make a new ldap message */
477         if ( (new = (LDAPMessage *) calloc( 1, sizeof(LDAPMessage) ))
478             == NULL ) {
479                 ld->ld_errno = LDAP_NO_MEMORY;
480                 return( -1 );
481         }
482         new->lm_msgid = (int)id;
483         new->lm_msgtype = tag;
484         new->lm_ber = ber_dup( &ber );
485
486 #ifndef NO_CACHE
487                 if ( ld->ld_cache != NULL ) {
488                         ldap_add_result_to_cache( ld, new );
489                 }
490 #endif /* NO_CACHE */
491
492         /* is this the one we're looking for? */
493         if ( msgid == LDAP_RES_ANY || id == msgid ) {
494                 if ( all == 0
495                     || (new->lm_msgtype != LDAP_RES_SEARCH_RESULT
496                     && new->lm_msgtype != LDAP_RES_SEARCH_ENTRY) ) {
497                         *result = new;
498                         ld->ld_errno = LDAP_SUCCESS;
499                         return( tag );
500                 } else if ( new->lm_msgtype == LDAP_RES_SEARCH_RESULT) {
501                         foundit = 1;    /* return the chain later */
502                 }
503         }
504
505         /* 
506          * if not, we must add it to the list of responses.  if
507          * the msgid is already there, it must be part of an existing
508          * search response.
509          */
510
511         prev = NULLMSG;
512         for ( l = ld->ld_responses; l != NULLMSG; l = l->lm_next ) {
513                 if ( l->lm_msgid == new->lm_msgid )
514                         break;
515                 prev = l;
516         }
517
518         /* not part of an existing search response */
519         if ( l == NULLMSG ) {
520                 if ( foundit ) {
521                         *result = new;
522                         ld->ld_errno = LDAP_SUCCESS;
523                         return( tag );
524                 }
525
526                 new->lm_next = ld->ld_responses;
527                 ld->ld_responses = new;
528                 return( -2 );   /* continue looking */
529         }
530
531         Debug( LDAP_DEBUG_TRACE, "adding response id %d type %d:\n",
532             new->lm_msgid, new->lm_msgtype, 0 );
533
534         /* part of a search response - add to end of list of entries */
535         for ( tmp = l; tmp->lm_chain != NULLMSG &&
536             tmp->lm_chain->lm_msgtype == LDAP_RES_SEARCH_ENTRY;
537             tmp = tmp->lm_chain )
538                 ;       /* NULL */
539         tmp->lm_chain = new;
540
541         /* return the whole chain if that's what we were looking for */
542         if ( foundit ) {
543                 if ( prev == NULLMSG )
544                         ld->ld_responses = l->lm_next;
545                 else
546                         prev->lm_next = l->lm_next;
547                 *result = l;
548                 ld->ld_errno = LDAP_SUCCESS;
549 #ifdef LDAP_WORLD_P16
550                 /*
551                  * XXX questionable fix; see text for [P16] on
552                  * http://www.critical-angle.com/ldapworld/patch/
553                  *
554                  * inclusion of this patch causes searchs to hang on
555                  * multiple platforms
556                  */
557                 return( l->lm_msgtype );
558 #else   /* LDAP_WORLD_P16 */
559                 return( tag );
560 #endif  /* !LDAP_WORLD_P16 */
561         }
562
563         return( -2 );   /* continue looking */
564 }
565
566
567 #ifdef LDAP_REFERRALS
568 static int
569 build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )
570 {
571         unsigned long   len;
572         long            along;
573
574         ber_init( ber, 0 );
575         ldap_set_ber_options( ld, ber );
576         if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
577             (long)lr->lr_res_msgtype, lr->lr_res_errno,
578             lr->lr_res_matched ? lr->lr_res_matched : "",
579             lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) {
580                 return( LBER_ERROR );
581         }
582
583         ber_reset( ber, 1 );
584         if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
585                 return( LBER_ERROR );
586         }
587
588         if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
589                 return( LBER_ERROR );
590         }
591
592         return( ber_peek_tag( ber, &len ));
593 }
594
595
596 static void
597 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
598 {
599 /*
600  * Merge error information in "lr" with "parentr" error code and string.
601  */
602         if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
603                 parentr->lr_res_errno = lr->lr_res_errno;
604                 if ( lr->lr_res_error != NULL ) {
605                         (void)ldap_append_referral( ld, &parentr->lr_res_error,
606                             lr->lr_res_error );
607                 }
608         } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
609             parentr->lr_res_errno == LDAP_SUCCESS ) {
610                 parentr->lr_res_errno = lr->lr_res_errno;
611                 if ( parentr->lr_res_error != NULL ) {
612                         free( parentr->lr_res_error );
613                 }
614                 parentr->lr_res_error = lr->lr_res_error;
615                 lr->lr_res_error = NULL;
616                 if ( NAME_ERROR( lr->lr_res_errno )) {
617                         if ( parentr->lr_res_matched != NULL ) {
618                                 free( parentr->lr_res_matched );
619                         }
620                         parentr->lr_res_matched = lr->lr_res_matched;
621                         lr->lr_res_matched = NULL;
622                 }
623         }
624
625         Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
626             parentr->lr_msgid, 0, 0 );
627         Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
628             parentr->lr_res_errno, parentr->lr_res_error ?
629             parentr->lr_res_error : "", parentr->lr_res_matched ?
630             parentr->lr_res_matched : "" );
631 }
632 #endif /* LDAP_REFERRALS */
633
634
635
636 #if defined( CLDAP ) || !defined( LDAP_REFERRALS )
637 #if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 )
638 static int
639 ldap_select1( LDAP *ld, struct timeval *timeout )
640 {
641         fd_set          readfds;
642         static int      tblsize;
643
644         if ( tblsize == 0 ) {
645 #ifdef USE_SYSCONF
646                 tblsize = sysconf( _SC_OPEN_MAX );
647 #else /* !USE_SYSCONF */
648                 tblsize = getdtablesize();
649 #endif /* !USE_SYSCONF */
650 #ifdef FD_SETSIZE
651                 if ( tblsize > FD_SETSIZE ) {
652                         tblsize = FD_SETSIZE;
653                 }
654 #endif  /* FD_SETSIZE */
655         }
656
657         FD_ZERO( &readfds );
658         FD_SET( ld->ld_sb.sb_sd, &readfds );
659
660         return( select( tblsize, &readfds, 0, 0, timeout ) );
661 }
662 #endif /* !MACOS */
663
664
665 #ifdef MACOS
666 static int
667 ldap_select1( LDAP *ld, struct timeval *timeout )
668 {
669         return( tcpselect( ld->ld_sb.sb_sd, timeout ));
670 }
671 #endif /* MACOS */
672
673
674 #if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 )
675 static int
676 ldap_select1( LDAP *ld, struct timeval *timeout )
677 {
678     fd_set          readfds;
679     int             rc;
680
681     FD_ZERO( &readfds );
682     FD_SET( ld->ld_sb.sb_sd, &readfds );
683
684     rc = select( 1, &readfds, 0, 0, timeout );
685     return( rc == SOCKET_ERROR ? -1 : rc );
686 }
687 #endif /* WINSOCK || _WIN32 */
688
689
690 #ifdef DOS
691 #ifdef PCNFS
692 static int
693 ldap_select1( LDAP *ld, struct timeval *timeout )
694 {
695         fd_set  readfds;
696         int     res;
697
698         FD_ZERO( &readfds );
699         FD_SET( ld->ld_sb.sb_sd, &readfds );
700
701         res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout );
702         if ( res == -1 && errno == EINTR) {
703                 /* We've been CTRL-C'ed at this point.  It'd be nice to
704                    carry on but PC-NFS currently won't let us! */
705                 printf("\n*** CTRL-C ***\n");
706                 exit(-1);
707         }
708         return( res );
709 }
710 #endif /* PCNFS */
711
712 #ifdef NCSA
713 static int
714 ldap_select1( LDAP *ld, struct timeval *timeout )
715 {
716         int rc;
717         clock_t endtime;
718
719         if ( timeout != NULL ) {
720                 endtime = timeout->tv_sec * CLK_TCK +
721                         timeout->tv_usec * CLK_TCK / 1000000 + clock();
722         }
723
724         do {
725                 Stask();
726                 rc = netqlen( ld->ld_sb.sb_sd );
727         } while ( rc <= 0 && ( timeout == NULL || clock() < endtime ));
728
729         return( rc > 0 ? 1 : 0 );
730 }
731 #endif /* NCSA */
732 #endif /* DOS */
733 #endif /* !LDAP_REFERRALS */
734
735
736 int
737 ldap_msgfree( LDAPMessage *lm )
738 {
739         LDAPMessage     *next;
740         int             type = 0;
741
742         Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
743
744         for ( ; lm != NULLMSG; lm = next ) {
745                 next = lm->lm_chain;
746                 type = lm->lm_msgtype;
747                 ber_free( lm->lm_ber, 1 );
748                 free( (char *) lm );
749         }
750
751         return( type );
752 }
753
754 /*
755  * ldap_msgdelete - delete a message.  It returns:
756  *      0       if the entire message was deleted
757  *      -1      if the message was not found, or only part of it was found
758  */
759 int
760 ldap_msgdelete( LDAP *ld, int msgid )
761 {
762         LDAPMessage     *lm, *prev;
763
764         Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
765
766         prev = NULLMSG;
767         for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {
768                 if ( lm->lm_msgid == msgid )
769                         break;
770                 prev = lm;
771         }
772
773         if ( lm == NULLMSG )
774                 return( -1 );
775
776         if ( prev == NULLMSG )
777                 ld->ld_responses = lm->lm_next;
778         else
779                 prev->lm_next = lm->lm_next;
780
781         if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
782                 return( -1 );
783
784         return( 0 );
785 }
786
787
788 /*
789  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
790  */
791 static int
792 ldap_abandoned( LDAP *ld, int msgid )
793 {
794         int     i;
795
796         if ( ld->ld_abandoned == NULL )
797                 return( 0 );
798
799         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
800                 if ( ld->ld_abandoned[i] == msgid )
801                         return( 1 );
802
803         return( 0 );
804 }
805
806
807 static int
808 ldap_mark_abandoned( LDAP *ld, int msgid )
809 {
810         int     i;
811
812         if ( ld->ld_abandoned == NULL )
813                 return( -1 );
814
815         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
816                 if ( ld->ld_abandoned[i] == msgid )
817                         break;
818
819         if ( ld->ld_abandoned[i] == -1 )
820                 return( -1 );
821
822         for ( ; ld->ld_abandoned[i] != -1; i++ ) {
823                 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
824         }
825
826         return( 0 );
827 }
828
829
830 #ifdef CLDAP
831 int
832 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
833 {
834         int             rc;
835         unsigned long   tag, len;
836
837         if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
838                 rc = ldap_select1( ld, timeout );
839                 if ( rc == -1 || rc == 0 ) {
840                         ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
841                             LDAP_TIMEOUT);
842                         return( rc );
843                 }
844         }
845
846         /* get the next message */
847         if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
848             != LDAP_TAG_MESSAGE ) {
849                 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
850                     LDAP_LOCAL_ERROR);
851                 return( -1 );
852         }
853
854         return( tag );
855 }
856 #endif /* CLDAP */