]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
574c3f2c7516b8e3fc825307e50ab0798e6c987d
[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 #ifdef USE_NONBLOCK
568 int lber_pvt_sb_set_nonblock( Sockbuf *sb, int nb )
569 {
570    assert( status_is_ok(sb) );
571    if (nb) {
572       sb->sb_non_block = 1;
573 #if 0      
574       sb->sb_read_ahead = 1;
575 #endif
576    } else {
577       sb->sb_non_block = 0;
578 #if 0
579       sb->sb_read_ahead = 0;
580 #endif
581    }
582    if (lber_pvt_sb_in_use(sb)) {
583       int status = (nb!=0);
584       if (ioctl( lber_pvt_sb_get_desc(sb), FIONBIO, (caddr_t)&status ) == -1 ) {
585          return -1;
586       }
587    }
588    return 0;
589 }
590 #endif
591          
592 #define sockbuf_buf_init( bb ) \
593 (bb)->buf_base=NULL;\
594 (bb)->buf_ptr = 0;\
595 (bb)->buf_end = 0;\
596 (bb)->buf_size = 0;
597
598 static int 
599 sockbuf_buf_destroy( Sockbuf_Buf *buf )
600 {
601    if (buf->buf_base)
602      free( buf->buf_base );
603    sockbuf_buf_init( buf );
604    return 0;
605 }
606
607 int lber_pvt_sb_init( Sockbuf *sb )
608 {
609    sb->sb_item_type=LBER_ITEM_SOCKBUF;
610    sb->sb_options = 0;
611    sb->sb_debug = 0;
612    sb->sb_trans_ready = 0;
613    sb->sb_buf_ready = 0;
614 #ifdef USE_SASL   
615    sb->sb_sec_ready = 0;
616 #endif   
617    sb->sb_read_ahead = 0;
618    sb->sb_non_block = 0;
619    sb->sb_fd = -1;
620    sb->sb_iodata = NULL;
621    sb->sb_io = &lber_pvt_sb_IO_None;
622    sb->sb_sd = -1;
623 #ifdef DEADWOOD   
624    sb->sb_max_incoming = 0;
625 #endif   
626    sockbuf_buf_init( &(sb->sb_buf) );
627 #ifdef USE_SASL
628    sockbuf_buf_init( &(sb->sb_sec_buf_in) );
629    sockbuf_buf_init( &(sb->sb_sec_buf_out) );
630    sb->sb_sdata = NULL;
631    sb->sb_sec = NULL;
632    sb->sb_sec_prev_len = 0;
633 #endif   
634    return 0;
635 }
636    
637 int lber_pvt_sb_destroy( Sockbuf *sb )
638 {
639 #ifdef USE_SASL
640    lber_pvt_sb_clear_sec(sb);
641    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
642    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
643 #endif
644    lber_pvt_sb_clear_io(sb);
645    sockbuf_buf_destroy( &(sb->sb_buf) );
646    return lber_pvt_sb_init( sb );
647 }
648
649 #ifdef USE_SASL
650 int lber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg )
651 {
652    int len;
653    if ((sb->sb_sec) || (sec==NULL))
654      return -1;
655    
656    sb->sb_sec = sec;
657    
658    if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) {
659       return -1;
660    }
661    
662    len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr;
663    
664    if (len>0) {
665       /* move this to the security layer. */
666       if (grow_buffer( &(sb->sb_sec_buf_in), len )<0)
667         return -1;
668       memcpy( sb->sb_sec_buf_in.buf_base, 
669              sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len );
670       sb->sb_sec_buf_in.buf_ptr = len;
671       sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb->sb_sec_buf_in ) : 0;
672       sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
673    }
674    update_status();
675    return 0;
676 }
677
678 int lber_pvt_sb_clear_sec( Sockbuf *sb )
679 {
680    if (sb->sb_buf.buf_ptr!=0)
681      return -1;
682    if (sb->sb_sec==NULL)
683      return -1;
684    if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) 
685      return -1;
686    
687    sb->sb_sec = NULL;
688    if (sb->sb_sec_buf_in.buf_ptr!=0) {
689       if (grow_buffer( &(sb->sb_buf), 
690                       sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0)
691         return -1;
692       memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end,
693               sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr );
694       sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr;
695       sb->sb_buf_ready = 1;
696    }
697    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
698    assert( sb->sb_sec_buf.buf_end==0 );
699    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
700    
701    sb->sb_sec_ready = 0;
702    
703    return 0;
704 }
705 #endif
706
707 int lber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg )
708 {
709    assert( sb->sb_io == &lber_pvt_sb_IO_None );
710
711    if (trans==NULL)
712      return -1;
713    
714    sb->sb_io = trans;
715    
716    if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0))
717      return -1;
718    
719    return 0;
720 }
721
722 int lber_pvt_sb_clear_io( Sockbuf *sb )
723 {
724    if (sb->sb_io==&lber_pvt_sb_IO_None)
725      return -1;
726    
727    if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0))
728      return -1;
729
730    sb->sb_io = &lber_pvt_sb_IO_None;
731    
732    sb->sb_trans_ready = 0;
733    
734    return 0;
735 }
736
737 /*
738  * Support for TCP
739  */
740
741 static long
742 stream_read( Sockbuf *sb, void *buf, long len )
743 {
744 #if defined(MACOS)
745 /*
746  * MacTCP/OpenTransport
747  */
748    return tcpread( lber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, 
749                    len, NULL );
750 #elif (defined(DOS) && (defined(PCNFS) || defined( WINSOCK))) \
751         || defined( _WIN32)
752 /*
753  * PCNFS (under DOS)
754  */
755 /*
756  * Windows Socket API (under DOS/Windows 3.x)
757  */
758 /*
759  * 32-bit Windows Socket API (under Windows NT or Windows 95)
760  */
761    return recv( lber_pvt_sb_get_desc(sb), buf, len, 0 );
762 #elif (defined(DOS) && defined( NCSA ))
763 /*
764  * NCSA Telnet TCP/IP stack (under DOS)
765  */
766    return nread( lber_pvt_sb_get_desc(sb), buf, len );
767 #else
768    return read( lber_pvt_sb_get_desc(sb), buf, len );
769 #endif
770 }
771
772 static long
773 stream_write( Sockbuf *sb, void *buf, long len )
774 {
775 #if defined(MACOS) 
776 /*
777  * MacTCP/OpenTransport
778  */
779 #define MAX_WRITE       65535
780    return tcpwrite( lber_pvt_sb_get_desc(sb),
781                     (unsigned char *)(buf), 
782                     (len<MAX_WRITE)? len : MAX_WRITE );
783 #elif (defined(DOS) && (defined(PCNFS) || defined( WINSOCK))) \
784         || defined( _WIN32)
785 /*
786  * PCNFS (under DOS)
787  */
788 /*
789  * Windows Socket API (under DOS/Windows 3.x)
790  */
791 /*
792  * 32-bit Windows Socket API (under Windows NT or Windows 95)
793  */
794    return send( lber_pvt_sb_get_desc(sb), buf, len, 0 );
795 #elif defined(NCSA)
796    return netwrite( lber_pvt_sb_get_desc(sb), buf, len );
797 #elif defined(VMS)
798 /*
799  * VMS -- each write must be 64K or smaller
800  */
801 #define MAX_WRITE 65535
802    return write( lber_pvt_sb_get_desc(sb), buf, 
803                  (len<MAX_WRITE)? len : MAX_WRITE);
804 #else
805    return write( lber_pvt_sb_get_desc(sb), buf, len );
806 #endif   
807 }   
808    
809 static int 
810 stream_close( Sockbuf *sb )
811 {
812    tcp_close( lber_pvt_sb_get_desc( sb ) );
813    return 0;
814 }
815
816 Sockbuf_IO lber_pvt_sb_io_tcp=
817 {
818         NULL,   /* sbi_setup */
819         NULL,   /* sbi_release */
820         stream_read,    /* sbi_read */
821         stream_write,   /* sbi_write */
822         stream_close,   /* sbi_close */
823 };
824
825 /*
826  * Support for UDP (CLDAP)
827  */
828
829 struct dgram_data
830 {
831         struct sockaddr dst;
832         struct sockaddr src;
833 };
834
835 static int 
836 dgram_setup( Sockbuf *sb, void *arg )
837 {
838    sb->sb_iodata = malloc( sizeof( struct dgram_data ) );
839    if (sb->sb_iodata==NULL)
840      return -1;
841    sb->sb_read_ahead = 1; /* important since udp is packet based. */
842    return 0;
843 }
844
845 static int 
846 dgram_release( Sockbuf *sb )
847 {
848    free( sb->sb_iodata );
849    return 0;
850 }
851
852 static long
853 dgram_read( Sockbuf *sb, void *buf, long len )
854 {
855 #ifdef LDAP_CONNECTIONLESS
856    long rc;
857    int addrlen;
858    struct dgram_data *dd;
859    
860    dd = (struct dgram_data *)(sb->sb_iodata);
861    
862 # if !defined( MACOS) && !defined(DOS) && !defined( _WIN32)
863    addrlen = sizeof( struct sockaddr );
864    rc=recvfrom( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
865 # else
866    UDP not supported
867 # endif
868    
869    if ( sb->sb_debug ) {
870       lber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
871                       "dgram_read udp_read %d bytes\n",
872                       rc );
873       if ( rc > 0 )
874         lber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
875                         buf, rc );
876    }
877    return rc;
878 # else /* LDAP_CONNECTIONLESS */
879    return -1;
880 # endif /* LDAP_CONNECTIONLESS */
881 }
882
883 static long 
884 dgram_write( Sockbuf *sb, void *buf, long len )
885 {
886 #ifdef LDAP_CONNECTIONLESS
887    int rc;
888    struct dgram_data *dd;
889    
890    dd = (struct dgram_data *)(sb->sb_iodata);
891    
892 # if !defined( MACOS) && !defined(DOS) && !defined( _WIN32)
893    rc=sendto( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
894              sizeof( struct sockaddr ) );
895 # else
896    UDP not supported
897 # endif
898      if ( rc <= 0 )
899        return( -1 );
900    
901    /* fake error if write was not atomic */
902    if (rc < len) {
903 # ifdef EMSGSIZE
904       errno = EMSGSIZE;
905 # endif
906       return( -1 );
907    }
908    return rc;
909 #else
910    return -1;
911 #endif  
912 }
913
914 static int 
915 dgram_close( Sockbuf *sb )
916 {
917         tcp_close( lber_pvt_sb_get_desc(sb) );
918         return 0;
919 }
920
921 Sockbuf_IO lber_pvt_sb_io_udp=
922 {
923         dgram_setup,    /* sbi_setup */
924         dgram_release,  /* sbi_release */
925         dgram_read,     /* sbi_read */
926         dgram_write,    /* sbi_write */
927         dgram_close,    /* sbi_close */
928 };
929
930 int lber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
931 {
932    struct dgram_data *dd;
933    assert( sb->sb_io == &lber_pvt_sb_io_udp );
934    dd = (struct dgram_data *) (sb->sb_iodata);
935    memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) );
936    return 0;
937 }
938
939 void *lber_pvt_sb_udp_get_src( Sockbuf *sb )
940 {
941    struct dgram_data *dd;
942    assert( sb->sb_io == &lber_pvt_sb_io_udp );
943    dd = (struct dgram_data *) (sb->sb_iodata);
944    return &(dd->src);
945 }
946
947 /*
948  * debug routines.
949  * 
950  * BUGS:
951  * These routines should really call abort, but at the moment that would
952  * break the servers.
953  */
954
955 static long
956 have_no_read( Sockbuf *sb, void *buf, long len )
957 {
958    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
959                    "warning: reading from uninitialized sockbuf\n");
960    errno =  EBADF;
961    return -1;
962 }
963
964 static long
965 have_no_write( Sockbuf *sb, void *buf, long len )
966 {
967    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
968                    "warning: writing to uninitialized sockbuf\n");
969    errno =  EBADF;
970    return -1;
971 }
972
973 static int 
974 have_no_close( Sockbuf *sb )
975 {   
976    assert( 0 );
977    return -1;
978 }