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