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