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