]> git.sur5r.net Git - openldap/blob - libraries/libldap/result.c
39f26522c2197d967c1337d4e4a80d2407f134f4
[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                         ldap_dump_connection( ld, ld->ld_conns, 1 );
235                         ldap_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                                             ldap_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         ldap_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 = ldap_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 = ldap_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                                 ldap_free_request( ld, lr );
459                         }
460
461                         if ( lc != NULL ) {
462                                 ldap_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                         ldap_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 #ifdef LDAP_WORLD_P16
546                 /* inclusion of this patch causes searchs to hang on
547                         multiple platforms */
548                 return( l->lm_msgtype );
549 #else
550                 return( tag );
551 #endif
552         }
553
554         return( -2 );   /* continue looking */
555 }
556
557
558 #ifdef LDAP_REFERRALS
559 static int
560 build_result_ber( LDAP *ld, BerElement *ber, LDAPRequest *lr )
561 {
562         unsigned long   len;
563         long            along;
564
565         ber_init( ber, 0 );
566         ldap_set_ber_options( ld, ber );
567         if ( ber_printf( ber, "{it{ess}}", lr->lr_msgid,
568             (long)lr->lr_res_msgtype, lr->lr_res_errno,
569             lr->lr_res_matched ? lr->lr_res_matched : "",
570             lr->lr_res_error ? lr->lr_res_error : "" ) == LBER_ERROR ) {
571                 return( LBER_ERROR );
572         }
573
574         ber_reset( ber, 1 );
575         if ( ber_skip_tag( ber, &len ) == LBER_ERROR ) {
576                 return( LBER_ERROR );
577         }
578
579         if ( ber_get_int( ber, &along ) == LBER_ERROR ) {
580                 return( LBER_ERROR );
581         }
582
583         return( ber_peek_tag( ber, &len ));
584 }
585
586
587 static void
588 merge_error_info( LDAP *ld, LDAPRequest *parentr, LDAPRequest *lr )
589 {
590 /*
591  * Merge error information in "lr" with "parentr" error code and string.
592  */
593         if ( lr->lr_res_errno == LDAP_PARTIAL_RESULTS ) {
594                 parentr->lr_res_errno = lr->lr_res_errno;
595                 if ( lr->lr_res_error != NULL ) {
596                         (void)ldap_append_referral( ld, &parentr->lr_res_error,
597                             lr->lr_res_error );
598                 }
599         } else if ( lr->lr_res_errno != LDAP_SUCCESS &&
600             parentr->lr_res_errno == LDAP_SUCCESS ) {
601                 parentr->lr_res_errno = lr->lr_res_errno;
602                 if ( parentr->lr_res_error != NULL ) {
603                         free( parentr->lr_res_error );
604                 }
605                 parentr->lr_res_error = lr->lr_res_error;
606                 lr->lr_res_error = NULL;
607                 if ( NAME_ERROR( lr->lr_res_errno )) {
608                         if ( parentr->lr_res_matched != NULL ) {
609                                 free( parentr->lr_res_matched );
610                         }
611                         parentr->lr_res_matched = lr->lr_res_matched;
612                         lr->lr_res_matched = NULL;
613                 }
614         }
615
616         Debug( LDAP_DEBUG_TRACE, "merged parent (id %d) error info:  ",
617             parentr->lr_msgid, 0, 0 );
618         Debug( LDAP_DEBUG_TRACE, "result errno %d, error <%s>, matched <%s>\n",
619             parentr->lr_res_errno, parentr->lr_res_error ?
620             parentr->lr_res_error : "", parentr->lr_res_matched ?
621             parentr->lr_res_matched : "" );
622 }
623 #endif /* LDAP_REFERRALS */
624
625
626
627 #if defined( CLDAP ) || !defined( LDAP_REFERRALS )
628 #if !defined( MACOS ) && !defined( DOS ) && !defined( _WIN32 )
629 static int
630 ldap_select1( LDAP *ld, struct timeval *timeout )
631 {
632         fd_set          readfds;
633         static int      tblsize;
634
635         if ( tblsize == 0 ) {
636 #ifdef USE_SYSCONF
637                 tblsize = sysconf( _SC_OPEN_MAX );
638 #else /* USE_SYSCONF */
639                 tblsize = getdtablesize();
640 #endif /* USE_SYSCONF */
641         }
642
643         FD_ZERO( &readfds );
644         FD_SET( ld->ld_sb.sb_sd, &readfds );
645
646         return( select( tblsize, &readfds, 0, 0, timeout ) );
647 }
648 #endif /* !MACOS */
649
650
651 #ifdef MACOS
652 static int
653 ldap_select1( LDAP *ld, struct timeval *timeout )
654 {
655         return( tcpselect( ld->ld_sb.sb_sd, timeout ));
656 }
657 #endif /* MACOS */
658
659
660 #if ( defined( DOS ) && defined( WINSOCK )) || defined( _WIN32 )
661 static int
662 ldap_select1( LDAP *ld, struct timeval *timeout )
663 {
664     fd_set          readfds;
665     int             rc;
666
667     FD_ZERO( &readfds );
668     FD_SET( ld->ld_sb.sb_sd, &readfds );
669
670     rc = select( 1, &readfds, 0, 0, timeout );
671     return( rc == SOCKET_ERROR ? -1 : rc );
672 }
673 #endif /* WINSOCK || _WIN32 */
674
675
676 #ifdef DOS
677 #ifdef PCNFS
678 static int
679 ldap_select1( LDAP *ld, struct timeval *timeout )
680 {
681         fd_set  readfds;
682         int     res;
683
684         FD_ZERO( &readfds );
685         FD_SET( ld->ld_sb.sb_sd, &readfds );
686
687         res = select( FD_SETSIZE, &readfds, NULL, NULL, timeout );
688         if ( res == -1 && errno == EINTR) {
689                 /* We've been CTRL-C'ed at this point.  It'd be nice to
690                    carry on but PC-NFS currently won't let us! */
691                 printf("\n*** CTRL-C ***\n");
692                 exit(-1);
693         }
694         return( res );
695 }
696 #endif /* PCNFS */
697
698 #ifdef NCSA
699 static int
700 ldap_select1( LDAP *ld, struct timeval *timeout )
701 {
702         int rc;
703         clock_t endtime;
704
705         if ( timeout != NULL ) {
706                 endtime = timeout->tv_sec * CLK_TCK +
707                         timeout->tv_usec * CLK_TCK / 1000000 + clock();
708         }
709
710         do {
711                 Stask();
712                 rc = netqlen( ld->ld_sb.sb_sd );
713         } while ( rc <= 0 && ( timeout == NULL || clock() < endtime ));
714
715         return( rc > 0 ? 1 : 0 );
716 }
717 #endif /* NCSA */
718 #endif /* DOS */
719 #endif /* !LDAP_REFERRALS */
720
721
722 int
723 ldap_msgfree( LDAPMessage *lm )
724 {
725         LDAPMessage     *next;
726         int             type = 0;
727
728         Debug( LDAP_DEBUG_TRACE, "ldap_msgfree\n", 0, 0, 0 );
729
730         for ( ; lm != NULLMSG; lm = next ) {
731                 next = lm->lm_chain;
732                 type = lm->lm_msgtype;
733                 ber_free( lm->lm_ber, 1 );
734                 free( (char *) lm );
735         }
736
737         return( type );
738 }
739
740 /*
741  * ldap_msgdelete - delete a message.  It returns:
742  *      0       if the entire message was deleted
743  *      -1      if the message was not found, or only part of it was found
744  */
745 int
746 ldap_msgdelete( LDAP *ld, int msgid )
747 {
748         LDAPMessage     *lm, *prev;
749
750         Debug( LDAP_DEBUG_TRACE, "ldap_msgdelete\n", 0, 0, 0 );
751
752         prev = NULLMSG;
753         for ( lm = ld->ld_responses; lm != NULLMSG; lm = lm->lm_next ) {
754                 if ( lm->lm_msgid == msgid )
755                         break;
756                 prev = lm;
757         }
758
759         if ( lm == NULLMSG )
760                 return( -1 );
761
762         if ( prev == NULLMSG )
763                 ld->ld_responses = lm->lm_next;
764         else
765                 prev->lm_next = lm->lm_next;
766
767         if ( ldap_msgfree( lm ) == LDAP_RES_SEARCH_ENTRY )
768                 return( -1 );
769
770         return( 0 );
771 }
772
773
774 /*
775  * return 1 if message msgid is waiting to be abandoned, 0 otherwise
776  */
777 static int
778 ldap_abandoned( LDAP *ld, int msgid )
779 {
780         int     i;
781
782         if ( ld->ld_abandoned == NULL )
783                 return( 0 );
784
785         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
786                 if ( ld->ld_abandoned[i] == msgid )
787                         return( 1 );
788
789         return( 0 );
790 }
791
792
793 static int
794 ldap_mark_abandoned( LDAP *ld, int msgid )
795 {
796         int     i;
797
798         if ( ld->ld_abandoned == NULL )
799                 return( -1 );
800
801         for ( i = 0; ld->ld_abandoned[i] != -1; i++ )
802                 if ( ld->ld_abandoned[i] == msgid )
803                         break;
804
805         if ( ld->ld_abandoned[i] == -1 )
806                 return( -1 );
807
808         for ( ; ld->ld_abandoned[i] != -1; i++ ) {
809                 ld->ld_abandoned[i] = ld->ld_abandoned[i + 1];
810         }
811
812         return( 0 );
813 }
814
815
816 #ifdef CLDAP
817 int
818 cldap_getmsg( LDAP *ld, struct timeval *timeout, BerElement *ber )
819 {
820         int             rc;
821         unsigned long   tag, len;
822
823         if ( ld->ld_sb.sb_ber.ber_ptr >= ld->ld_sb.sb_ber.ber_end ) {
824                 rc = ldap_select1( ld, timeout );
825                 if ( rc == -1 || rc == 0 ) {
826                         ld->ld_errno = (rc == -1 ? LDAP_SERVER_DOWN :
827                             LDAP_TIMEOUT);
828                         return( rc );
829                 }
830         }
831
832         /* get the next message */
833         if ( (tag = ber_get_next( &ld->ld_sb, &len, ber ))
834             != LDAP_TAG_MESSAGE ) {
835                 ld->ld_errno = (tag == LBER_DEFAULT ? LDAP_SERVER_DOWN :
836                     LDAP_LOCAL_ERROR);
837                 return( -1 );
838         }
839
840         return( tag );
841 }
842 #endif /* CLDAP */