]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
Define env.variable SLAPD_DEBUG to override the default debug level
[openldap] / libraries / liblber / sockbuf.c
1 /* sockbuf.c - i/o routines with support for adding i/o layers. */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 #include <ac/ctype.h>
13 #include <ac/errno.h>
14 #include <ac/socket.h>
15 #include <ac/string.h>
16 #include <ac/unistd.h>
17
18 #ifdef HAVE_IO_H
19 #include <io.h>
20 #endif /* HAVE_IO_H */
21
22 #if defined( HAVE_SYS_FILIO_H )
23 #include <sys/filio.h>
24 #elif defined( HAVE_SYS_IOCTL_H )
25 #include <sys/ioctl.h>
26 #endif
27
28 #include "lber-int.h"
29
30 #ifdef LDAP_TEST
31 #undef TEST_PARTIAL_READ
32 #undef TEST_PARTIAL_WRITE
33 #endif
34
35 #define MAX_BUF_SIZE    65535
36 #define MIN_BUF_SIZE    4096
37
38 #define sockbuf_io_write( sb, buf, len ) \
39 ((sb)->sb_io->sbi_write( (sb), (buf), (len) ))
40
41 #define sockbuf_io_read( sb, buf, len ) \
42 ((sb)->sb_io->sbi_read( (sb), (buf), (len) ))
43
44 static long have_no_read( Sockbuf *sb, void *buf, long len );
45 static long have_no_write( Sockbuf *sb, void *buf, long len );
46 static int have_no_close( Sockbuf *sb );
47
48 static Sockbuf_IO lber_pvt_sb_IO_None=
49 {
50         NULL,   /* sbi_setup */
51         NULL,   /* sbi_release */
52         have_no_read,   /* sbi_read */
53         have_no_write,  /* sbi_write */
54         have_no_close   /* sbi_close */
55 };
56
57 static void
58 update_status( Sockbuf *sb )
59 {
60    sb->sb_buf_ready = (sb->sb_buf.buf_ptr < sb->sb_buf.buf_end);
61 #ifdef USE_SASL   
62    sb->sb_sec_ready = ((sb->sb_sec_buf_in.buf_end!=0) &&
63                        (sb->sb_sec_buf_in.buf_ptr >= 
64                         sb->sb_sec_buf_in.buf_end));
65 #endif   
66 }
67
68 #ifdef LDAP_DEBUG
69 static int 
70 status_is_ok( Sockbuf *sb )
71 {
72    int obr = sb->sb_buf_ready;
73 #ifdef USE_SASL
74    int osr = sb->sb_sec_ready;
75 #endif
76
77    update_status(sb);
78    if (obr!=sb->sb_buf_ready)
79      return 0;
80
81 #ifdef USE_SASL
82    if (osr!=sb->sb_sec_ready)
83      return 0;
84 #endif
85
86    return 1;
87 }
88 #endif
89
90 #ifdef USE_SASL
91 static long
92 packet_length( char *buf )
93 {
94    long size;
95    size = (((unsigned long)buf[0])<<24)|
96      (((unsigned long)buf[1])<<16)|
97      (((unsigned long)buf[2])<<8)|
98      (((unsigned long)buf[3]));
99    
100    if ((size<0) || (size>MAX_BUF_SIZE)) {
101       /* somebody is trying to mess me up. */
102       lber_log_printf( LDAP_DEBUG_SASL, sb->sb_debug,
103                       "SASL: received packet length of %d bytes\n",
104                       size );      
105       size = 16; /* this should lead to an error. */
106    }
107    
108    return size + 4; /* include the size !!! */
109 }
110 #endif
111
112 static int
113 grow_buffer( Sockbuf_Buf * buf, long minsize )
114 {
115    long pw=MIN_BUF_SIZE;
116    
117    for(;(pw<minsize);pw<<=1) {
118       if (pw > MAX_BUF_SIZE) {
119          /* this could mean that somebody is trying to crash us. */
120          return -1;
121       }
122    }
123    minsize = pw;
124
125    if (buf->buf_size<minsize) {
126       if ((buf->buf_base==NULL) || ((buf->buf_end==0) && (buf->buf_ptr==0))) {
127          /* empty buffer */
128          if (buf->buf_base!=NULL)
129            free( buf->buf_base );
130          assert( buf->buf_ptr==0 );
131          assert( buf->buf_end==0 );
132          buf->buf_base = malloc( minsize );
133          if (buf->buf_base==NULL)
134            return -1;
135       } else {
136          char *nb;
137          nb = realloc( buf->buf_base, minsize );
138          if (nb==NULL)
139            return -1;
140          buf->buf_base = nb;
141       }
142       buf->buf_size = minsize;
143    }
144    return 0;
145 }
146
147 #ifdef USE_SASL
148 static long
149 sockbuf_sec_release( Sockbuf *sb, char *buf, long len )
150 {
151    /* when this is called:
152     *  sb->sb_sec_buf_in.buf_base  points to a packet.
153     *  sb->sb_sec_buf_in.buf_ptr   contains the total bytes read.
154     *  sb->sb_sec_end.buf_end   contains the packet length.
155     * 
156     *  sb->sb_buf.buf_ptr == sb->sb_buf.buf_end == 0;
157     */
158    long rlen;
159    long total;
160    char *ptr;
161    char *end;
162    long size;
163    
164    assert( sb->sb_sec );
165    assert( sb->sb_sec->sbs_release );
166    assert( sb->sb_sec_buf_in.sb_ptr >= sb->sb_sec_buf_in.sb_end );
167    
168    assert( sb->sb_buf.sb_ptr == 0 );
169    assert( sb->sb_buf.sb_end == 0 );
170
171    assert( status_is_ok(sb) );
172    
173    total = 0;
174    
175    ptr = sb->sb_sec_buf_in.buf_base;
176    end = ptr+ sb->sb_sec_buf_in.buf_ptr;
177    size = sb->sb_sec_buf_in.buf_end;
178    
179    sb->sb_sec_ready = 1;
180    
181    for(;(ptr+size<=end);) {
182       for(;;) {
183          rlen = sb->sb_sec->sbs_release( sb, ptr, size,
184                                         buf, len, 
185                                         sb->sb_buf.buf_base,
186                                         sb->sb_buf.buf_size );
187          if (rlen==0) {
188             /* this means a security violation. */
189             return total; /* total ? total : 0 */
190          }
191          if (rlen<0) {
192             /* this means that the buffer isn't big enough. */
193             if (grow_buffer( &(sb->sb_buf), -rlen )<0)
194               /* memory violation. */
195               return total; /* total ? total : 0 */
196             continue;
197          }
198          /* if (rlen>0) */
199          break;
200       }
201       total+=rlen;
202       
203       /* move to the next packet... */
204       ptr+=size;
205       
206       if (ptr+4<=end)
207         size = packet_length( ptr ); 
208       /* size is always at least 4, so the loop condition is always OK !!*/
209       assert( size>=4 );
210       
211       if (rlen<len) {
212          len-=rlen;
213          buf+=rlen;
214       } else {
215          sb->sb_buf_ready = (sb->sb_buf.buf_end = rlen - len) ? 1 : 0;
216          break;
217       }
218    }
219    
220    if (ptr+size>end)
221      sb->sb_sec_ready = 0;
222    /* clean up the mess. */
223    if (ptr<end) {
224       /* copy back to beginning of buffer. */
225       SAFEMEMCPY( sb->sb_sec_buf_in.buf_base, ptr, end-ptr );
226       sb->sb_sec_buf_in.buf_ptr = 0;
227       sb->sb_sec_buf_in.buf_end -= (ptr - sb->sb_sec_buf_in.buf_base);
228    }
229    assert( status_is_ok(sb) );
230    return total;
231 }
232
233 static long
234 sockbuf_sec_protect( Sockbuf *sb, char *buf, long len )
235 {
236    long ret;
237    long blen;
238    long total;
239    
240    assert( sb->sb_sec_out.buf_end == 0 );
241    assert( sb->sb_sec_out.buf_ptr == 0 );
242    
243    assert( sb->sb_sec );
244    assert( sb->sb_sec->sbs_protect );
245    
246    assert( status_is_ok(sb) );
247    
248    total = 0;
249    for(;(len);) {
250       for(;;) {
251          blen = len;
252          ret = sb->sb_sec->sbs_protect( sb, buf, &blen, 
253                                        sb->sb_sec_out.buf_base+
254                                        sb->sb_sec_out.buf_end, 
255                                        sb->sb_sec_out.buf_size -
256                                        sb->sb_sec_out.buf_end );
257          if (ret==0)
258            /* protection error ? */
259            return total;
260          if (ret<0) {
261             if (grow_buffer( &(sb->sb_sec_out),-ret-sb->sb_sec_out.buf_end )<0)
262               /* memory error */
263               return total;
264             continue;
265          }
266          /* else if (ret>0) */
267          break;
268       }
269       sb->sb_sec_out.buf_end += ret;
270       len -= blen;
271       total += blen;
272    }
273    assert( status_is_ok(sb) );
274    return total;
275 }
276 #endif
277
278 static long 
279 sockbuf_copy_out( Sockbuf *sb, char **buf, long len )
280 {
281    long blen = (sb->sb_buf.buf_end - sb->sb_buf.buf_ptr );
282    assert( status_is_ok(sb) );
283    if (blen) {
284       long rlen = (blen<len) ? blen : len;
285       memcpy( *buf, sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, rlen );
286       sb->sb_buf.buf_ptr+=rlen;
287       *buf+=rlen;
288       len -= rlen;
289       if (sb->sb_buf.buf_ptr >= sb->sb_buf.buf_end) {
290          sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
291          sb->sb_buf_ready = 0;
292       } else {
293          sb->sb_buf_ready = 1;
294       }
295    }
296    assert( status_is_ok(sb) );
297    return len;
298 }
299
300
301 long 
302 lber_pvt_sb_read( Sockbuf *sb, void *buf_arg, long len )
303 {
304    char *buf;
305    long ret;
306    
307    assert( status_is_ok(sb) );
308 #if 0
309    /* breaks slapd :-) */
310    assert( lber_pvt_sb_in_use( sb ) );
311 #endif 
312
313 #ifdef TEST_PARTIAL_READ
314    if ((rand() & 3)==1) { /* 1 out of 4 */
315       errno = EWOULDBLOCK;
316       return -1;
317    }
318
319    len = (rand() % len)+1;
320 #endif   
321    
322    buf = (char *) buf_arg;
323
324    if (sb->sb_buf.buf_ptr!=sb->sb_buf.buf_end) {
325       len = sockbuf_copy_out( sb, &buf, len );
326       if (len==0) {
327          return (buf - (char *) buf_arg);
328       }
329    }
330
331 #ifdef USE_SASL
332    if (sb->sb_sec) {
333       int max;
334       assert( sb->sb_sec->sbs_release );
335       assert( sb->sb_sec_buf_in.buf_base );
336       if (sb->sb_read_ahead) {
337          max = sb->sb_sec_buf_in.buf_size - sb->sb_sec_buf_in.buf_ptr;
338       } else {
339          max = sb->sb_sec_buf_in.buf_end - sb->sb_sec_buf_in.buf_ptr;
340          if (max<=0) {
341             /* special situation. This means that we need to read the first
342              * four bytes for the packet length.
343              */
344             max += 4;
345          }
346       }
347       for(;;) {
348          /* read from stream into sb_sec_buf_in */
349          for(;;) {
350             ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base +
351                                   sb->sb_sec_buf_in.buf_ptr, max );
352 #ifdef EINTR
353             if ((ret<0) && (errno==EINTR))
354               continue;
355 #endif
356             break;
357          }
358          if (ret<=0) {
359             /* read error. return */
360             goto do_return;
361          }
362          sb->sb_sec_buf_in.buf_ptr += ret;
363          
364          if (sb->sb_sec_buf_in.buf_ptr < sb->sb_sec_buf_in.buf_end) {
365             /* did not finish a packet. give up. */
366             goto do_return;
367          }
368             
369          if (sb->sb_sec_buf_in.buf_end == 0) {
370             /* Were trying to read the first four bytes... */
371             if (sb->sb_sec_buf_in.buf_ptr < 4) {
372                /* did not read enough for packet length. give up. */
373                goto do_return;
374             }
375             /* calculate the packet length. */
376             sb->sb_sec_buf_in.buf_end = 
377                packet_length(sb->sb_sec_buf_in.buf_base );
378             if ((sb->sb_sec_buf_in.buf_end > sb->sb_sec_buf_in.buf_size) &&
379                 (grow_buffer( &(sb->sb_sec_buf_in), sb->sb_sec_buf_in.buf_end)<0)) {
380                /* buffer has to be to big. exit with error. */
381                ret = -1;
382                goto do_return;
383             }
384             if (sb->sb_sec_buf_in.buf_ptr >= sb_sec_buf_in.buf_end) {
385                /* finished packet. decode it. */
386                goto decode_packet;
387             }
388             /* did not finish packet yet. try again ? */
389             if (sb->sb_read_ahead) {
390                /* we were trying to read the max anyway. forget it */
391                goto do_return;
392             }
393          }
394 decode_packet:
395          /* we read enough for at least 1 packet */
396          ret = sockbuf_sec_release( sb, buf, len );
397          if (ret<=0) {
398             /* something went wrong... */
399             goto do_return;
400          }
401          buf+=ret;
402          len-=ret;
403          /* we are finished !!! */
404          if ((len==0) || (ret!=max))
405            goto do_return;
406       }
407    } else {
408 #endif
409       if (sb->sb_read_ahead) {
410          long max;
411          max = sb->sb_buf.buf_size - sb->sb_buf.buf_end;
412          if (max>len) {
413             for(;;) {
414                ret = sockbuf_io_read( sb, 
415                                      sb->sb_buf.buf_base +
416                                      sb->sb_buf.buf_end,
417                                      max );
418 #ifdef EINTR           
419                if ((ret<0) && (errno==EINTR))
420                  continue;
421 #endif
422                break;
423             }
424             if (ret<=0) {
425                /* some error occured */
426                goto do_return;
427             }
428             sb->sb_buf.buf_end += ret;
429             /* move out the data... */
430             len = sockbuf_copy_out( sb, &buf, len );
431             goto do_return;
432          }
433       }
434       /* no read_ahead, just try to put the data in the buf. */
435       for(;;) {
436          ret = sockbuf_io_read( sb, buf, len );
437 #ifdef EINTR     
438          if ((ret<0) && (errno==EINTR))
439            continue;
440 #endif
441          break;
442       }
443       if (ret>0) {
444          buf+=ret;
445          len-=ret;
446       }
447       /* we might as well return, since there is nothing to do... */
448 #ifdef USE_SASL     
449    }
450 #endif
451 do_return:
452    assert( status_is_ok(sb) );
453    if ((ret<=0) && (buf==buf_arg)) {
454       /* there was an error. */
455       return ret;
456    }
457    return (buf - ((char *) buf_arg));
458 }
459
460 #ifdef USE_SASL
461 long sockbuf_do_write( Sockbuf *sb )
462 {
463    long to_go;
464    to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr;
465    assert( to_go > 0 );
466    /* there is something left of the last time... */
467    for(;;) {
468       ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+
469                              sb->sb_sec_out.buf_ptr, to_go );
470 #ifdef EINTR
471       if ((ret<0) && (errno==EINTR))
472         continue;
473 #endif
474       break;
475    }
476    if (ret<=0) /* error */
477      return ret;
478    sb->sb_sec_out.buf_ptr += ret;
479    if (ret<to_go) /* not enough data, so pretend no data was sent. */
480      return -1;
481    return ret;
482 }
483 #endif
484
485 long lber_pvt_sb_write( Sockbuf *sb, void *buf, long len_arg )
486 {
487    long ret;
488    long len = len_arg;
489    assert( status_is_ok(sb) );
490 #if 0
491    /* unfortunately breaks slapd */
492    assert( lber_pvt_sb_in_use( sb ) );
493 #endif   
494 #ifdef TEST_PARTIAL_WRITE
495    if ((rand() & 3)==1) { /* 1 out of 4 */
496       errno = EWOULDBLOCK;
497       return -1;
498    }
499
500    len_arg = (rand() % len_arg)+1;
501    len = len_arg;
502 #endif   
503    
504 #ifdef USE_SASL
505    if (sb->sb_sec) {
506       assert( sb->sb_sec_prev_len <= len );
507       if (sb->sb_sec_prev_len) {
508          ret = sockbuf_do_write( sb );
509          if (ret<=0)
510            return ret;
511          /* finished. */
512          len -= sb->sb_sec_prev_len;
513          sb->sb_sec_prev_len = 0;
514          sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0;
515       }
516       /* now protect the next packet. */
517       ret = sockbuf_sec_protect( sb, buf, len );
518       if (ret<=0)
519         return ret;
520       ret = sockbuf_do_write( sb );
521       if (ret<=0) {
522          sb->sb_sec_prev_len = len;
523          return ret;
524       }
525       return len_arg;
526    } else {
527 #endif
528       for(;;) {
529          ret = sockbuf_io_write( sb, buf, len );
530 #ifdef EINTR
531          if ((ret<0) && (errno==EINTR))
532            continue;
533 #endif
534          break;
535       }
536 #ifdef USE_SASL      
537    }
538 #endif
539
540    return ret;
541 }
542      
543 int lber_pvt_sb_close( Sockbuf *sb )
544 {
545    int ret;
546    assert( sb->sb_io );
547    assert( sb->sb_io->sbi_close );
548    assert( status_is_ok(sb) );
549    assert( lber_pvt_sb_in_use( sb ) );
550    
551    ret = sb->sb_io->sbi_close( sb );
552    lber_pvt_sb_set_desc( sb, -1 );
553
554    return ret;
555 }
556
557 int lber_pvt_sb_set_readahead( Sockbuf *sb, int rh )
558 {
559    assert( status_is_ok(sb) );
560    sb->sb_read_ahead = (rh!=0);
561    return 0;
562 }
563
564 #define USE_NONBLOCK
565 #ifdef USE_NONBLOCK
566 int lber_pvt_sb_set_nonblock( Sockbuf *sb, int nb )
567 {
568    assert( status_is_ok(sb) );
569    if (nb) {
570       sb->sb_non_block = 1;
571 #if 0      
572       sb->sb_read_ahead = 1;
573 #endif
574    } else {
575       sb->sb_non_block = 0;
576 #if 0
577       sb->sb_read_ahead = 0;
578 #endif
579    }
580    if (lber_pvt_sb_in_use(sb)) {
581 #if HAVE_FCNTL
582                 int flags = fcntl(lber_pvt_sb_get_desc(sb), F_GETFL);
583                 flags |= O_NONBLOCK;
584                 return fcntl(lber_pvt_sb_get_desc(sb), F_SETFL, flags);
585                 
586 #elif defined( FIONBIO )
587            /* WINSOCK requires the status to be a long */
588                 ioctl_t status = (nb!=0);
589                 return ioctl( lber_pvt_sb_get_desc(sb), FIONBIO, &status );
590 #endif /* FIONBIO */
591    }
592    return 0;
593 }
594 #endif
595          
596 #define sockbuf_buf_init( bb ) do { \
597                 Sockbuf_Buf *sbb = (bb); \
598                 sbb->buf_base = NULL; \
599                 sbb->buf_ptr = 0; \
600                 sbb->buf_end = 0; \
601                 sbb->buf_size = 0; \
602         } while(0)
603
604 static int 
605 sockbuf_buf_destroy( Sockbuf_Buf *buf )
606 {
607    if (buf->buf_base)
608      free( buf->buf_base );
609    sockbuf_buf_init( buf );
610    return 0;
611 }
612
613 int lber_pvt_sb_init( Sockbuf *sb )
614 {
615    sb->sb_item_type=LBER_ITEM_SOCKBUF;
616    sb->sb_options = 0;
617    sb->sb_debug = 0;
618    sb->sb_trans_ready = 0;
619    sb->sb_buf_ready = 0;
620 #ifdef USE_SASL   
621    sb->sb_sec_ready = 0;
622 #endif   
623    sb->sb_read_ahead = 0;
624    sb->sb_non_block = 0;
625    sb->sb_fd = -1;
626    sb->sb_iodata = NULL;
627    sb->sb_io = &lber_pvt_sb_IO_None;
628    sb->sb_sd = -1;
629 #ifdef DEADWOOD   
630    sb->sb_max_incoming = 0;
631 #endif   
632    sockbuf_buf_init( &(sb->sb_buf) );
633 #ifdef USE_SASL
634    sockbuf_buf_init( &(sb->sb_sec_buf_in) );
635    sockbuf_buf_init( &(sb->sb_sec_buf_out) );
636    sb->sb_sdata = NULL;
637    sb->sb_sec = NULL;
638    sb->sb_sec_prev_len = 0;
639 #endif   
640    return 0;
641 }
642    
643 int lber_pvt_sb_destroy( Sockbuf *sb )
644 {
645 #ifdef USE_SASL
646    lber_pvt_sb_clear_sec(sb);
647    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
648    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
649 #endif
650    lber_pvt_sb_clear_io(sb);
651    sockbuf_buf_destroy( &(sb->sb_buf) );
652    return lber_pvt_sb_init( sb );
653 }
654
655 #ifdef USE_SASL
656 int lber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg )
657 {
658    int len;
659    if ((sb->sb_sec) || (sec==NULL))
660      return -1;
661    
662    sb->sb_sec = sec;
663    
664    if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) {
665       return -1;
666    }
667    
668    len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr;
669    
670    if (len>0) {
671       /* move this to the security layer. */
672       if (grow_buffer( &(sb->sb_sec_buf_in), len )<0)
673         return -1;
674       memcpy( sb->sb_sec_buf_in.buf_base, 
675              sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len );
676       sb->sb_sec_buf_in.buf_ptr = len;
677       sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb->sb_sec_buf_in ) : 0;
678       sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
679    }
680    update_status();
681    return 0;
682 }
683
684 int lber_pvt_sb_clear_sec( Sockbuf *sb )
685 {
686    if (sb->sb_buf.buf_ptr!=0)
687      return -1;
688    if (sb->sb_sec==NULL)
689      return -1;
690    if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) 
691      return -1;
692    
693    sb->sb_sec = NULL;
694    if (sb->sb_sec_buf_in.buf_ptr!=0) {
695       if (grow_buffer( &(sb->sb_buf), 
696                       sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0)
697         return -1;
698       memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end,
699               sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr );
700       sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr;
701       sb->sb_buf_ready = 1;
702    }
703    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
704    assert( sb->sb_sec_buf.buf_end==0 );
705    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
706    
707    sb->sb_sec_ready = 0;
708    
709    return 0;
710 }
711 #endif
712
713 int lber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg )
714 {
715    assert( sb->sb_io == &lber_pvt_sb_IO_None );
716
717    if (trans==NULL)
718      return -1;
719    
720    sb->sb_io = trans;
721    
722    if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0))
723      return -1;
724    
725    return 0;
726 }
727
728 int lber_pvt_sb_clear_io( Sockbuf *sb )
729 {
730    if (sb->sb_io==&lber_pvt_sb_IO_None)
731      return -1;
732    
733    if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0))
734      return -1;
735
736    sb->sb_io = &lber_pvt_sb_IO_None;
737    
738    sb->sb_trans_ready = 0;
739    
740    return 0;
741 }
742
743 /*
744  * Support for TCP
745  */
746
747 static long
748 stream_read( Sockbuf *sb, void *buf, long len )
749 {
750 #if defined(MACOS)
751 /*
752  * MacTCP/OpenTransport
753  */
754    return tcpread( lber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, 
755                    len, NULL );
756
757 #elif defined( HAVE_PCNFS ) || \
758    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
759 /*
760  * PCNFS (under DOS)
761  */
762 /*
763  * Windows Socket API (under DOS/Windows 3.x)
764  */
765 /*
766  * 32-bit Windows Socket API (under Windows NT or Windows 95)
767  */
768    int rc;
769    rc = recv( lber_pvt_sb_get_desc(sb), buf, len, 0 );
770 #ifdef HAVE_WINSOCK
771    if ( rc < 0 ) errno = WSAGetLastError();
772 #endif
773    return rc;
774
775 #elif defined( HAVE_NCSA )
776 /*
777  * NCSA Telnet TCP/IP stack (under DOS)
778  */
779    return nread( lber_pvt_sb_get_desc(sb), buf, len );
780
781 #else
782    return read( lber_pvt_sb_get_desc(sb), buf, len );
783 #endif
784 }
785
786 static long
787 stream_write( Sockbuf *sb, void *buf, long len )
788 {
789 #if defined(MACOS) 
790 /*
791  * MacTCP/OpenTransport
792  */
793 #define MAX_WRITE       65535
794    return tcpwrite( lber_pvt_sb_get_desc(sb),
795                     (unsigned char *)(buf), 
796                     (len<MAX_WRITE)? len : MAX_WRITE );
797
798 #elif defined( HAVE_PCNFS) \
799    || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
800 /*
801  * PCNFS (under DOS)
802  */
803 /*
804  * Windows Socket API (under DOS/Windows 3.x)
805  */
806 /*
807  * 32-bit Windows Socket API (under Windows NT or Windows 95)
808  */
809    int rc;
810    rc = send( lber_pvt_sb_get_desc(sb), buf, len, 0 );
811 #ifdef HAVE_WINSOCK
812    if ( rc < 0 ) errno = WSAGetLastError();
813 #endif
814    return rc;
815
816 #elif defined(HAVE_NCSA)
817    return netwrite( lber_pvt_sb_get_desc(sb), buf, len );
818
819 #elif defined(VMS)
820 /*
821  * VMS -- each write must be 64K or smaller
822  */
823 #define MAX_WRITE 65535
824    return write( lber_pvt_sb_get_desc(sb), buf, 
825                  (len<MAX_WRITE)? len : MAX_WRITE);
826 #else
827    return write( lber_pvt_sb_get_desc(sb), buf, len );
828 #endif   
829 }   
830    
831 static int 
832 stream_close( Sockbuf *sb )
833 {
834    tcp_close( lber_pvt_sb_get_desc( sb ) );
835    return 0;
836 }
837
838 Sockbuf_IO lber_pvt_sb_io_tcp=
839 {
840         NULL,   /* sbi_setup */
841         NULL,   /* sbi_release */
842         stream_read,    /* sbi_read */
843         stream_write,   /* sbi_write */
844         stream_close,   /* sbi_close */
845 };
846
847 /*
848  * Support for UDP (CLDAP)
849  */
850
851 struct dgram_data
852 {
853         struct sockaddr dst;
854         struct sockaddr src;
855 };
856
857 static int 
858 dgram_setup( Sockbuf *sb, void *arg )
859 {
860    sb->sb_iodata = malloc( sizeof( struct dgram_data ) );
861    if (sb->sb_iodata==NULL)
862      return -1;
863    sb->sb_read_ahead = 1; /* important since udp is packet based. */
864    return 0;
865 }
866
867 static int 
868 dgram_release( Sockbuf *sb )
869 {
870    free( sb->sb_iodata );
871    return 0;
872 }
873
874 static long
875 dgram_read( Sockbuf *sb, void *buf, long len )
876 {
877 #ifdef LDAP_CONNECTIONLESS
878    long rc;
879    int addrlen;
880    struct dgram_data *dd;
881    
882    dd = (struct dgram_data *)(sb->sb_iodata);
883    
884    addrlen = sizeof( struct sockaddr );
885    rc=recvfrom( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
886    
887    if ( sb->sb_debug ) {
888       lber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
889                       "dgram_read udp_read %d bytes\n",
890                       rc );
891       if ( rc > 0 )
892         lber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
893                         buf, rc );
894    }
895    return rc;
896 # else /* LDAP_CONNECTIONLESS */
897    return -1;
898 # endif /* LDAP_CONNECTIONLESS */
899 }
900
901 static long 
902 dgram_write( Sockbuf *sb, void *buf, long len )
903 {
904 #ifdef LDAP_CONNECTIONLESS
905    int rc;
906    struct dgram_data *dd;
907    
908    dd = (struct dgram_data *)(sb->sb_iodata);
909    
910    rc=sendto( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
911              sizeof( struct sockaddr ) );
912
913    if ( rc <= 0 )
914        return( -1 );
915    
916    /* fake error if write was not atomic */
917    if (rc < len) {
918 # ifdef EMSGSIZE
919       errno = EMSGSIZE;
920 # endif
921       return( -1 );
922    }
923    return rc;
924 #else
925    return -1;
926 #endif  
927 }
928
929 static int 
930 dgram_close( Sockbuf *sb )
931 {
932         tcp_close( lber_pvt_sb_get_desc(sb) );
933         return 0;
934 }
935
936 Sockbuf_IO lber_pvt_sb_io_udp=
937 {
938         dgram_setup,    /* sbi_setup */
939         dgram_release,  /* sbi_release */
940         dgram_read,     /* sbi_read */
941         dgram_write,    /* sbi_write */
942         dgram_close,    /* sbi_close */
943 };
944
945 int lber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
946 {
947    struct dgram_data *dd;
948    assert( sb->sb_io == &lber_pvt_sb_io_udp );
949    dd = (struct dgram_data *) (sb->sb_iodata);
950    memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) );
951    return 0;
952 }
953
954 void *lber_pvt_sb_udp_get_src( Sockbuf *sb )
955 {
956    struct dgram_data *dd;
957    assert( sb->sb_io == &lber_pvt_sb_io_udp );
958    dd = (struct dgram_data *) (sb->sb_iodata);
959    return &(dd->src);
960 }
961
962 /*
963  * debug routines.
964  * 
965  * BUGS:
966  * These routines should really call abort, but at the moment that would
967  * break the servers.
968  */
969
970 static long
971 have_no_read( Sockbuf *sb, void *buf, long len )
972 {
973    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
974                    "warning: reading from uninitialized sockbuf\n");
975    errno =  EBADF;
976    return -1;
977 }
978
979 static long
980 have_no_write( Sockbuf *sb, void *buf, long len )
981 {
982    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
983                    "warning: writing to uninitialized sockbuf\n");
984    errno =  EBADF;
985    return -1;
986 }
987
988 static int 
989 have_no_close( Sockbuf *sb )
990 {   
991    assert( 0 );
992    return -1;
993 }