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