]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
123692dedaa8001675b1d90e0dd1f6395e71d92c
[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( 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<0) || (size>MAX_BUF_SIZE)) {
119       /* somebody is trying to mess me up. */
120       lber_log_printf( LDAP_DEBUG_SASL, sb->sb_debug,
121                       "SASL: received packet length of %d bytes\n",
122                       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( 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_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_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
535    assert( sb != NULL );
536         assert( SOCKBUF_VALID( sb ) );
537
538    to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr;
539    assert( to_go > 0 );
540    /* there is something left of the last time... */
541    for(;;) {
542       ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+
543                              sb->sb_sec_out.buf_ptr, to_go );
544 #ifdef EINTR
545       if ((ret<0) && (errno==EINTR))
546         continue;
547 #endif
548       break;
549    }
550    if (ret<=0) /* error */
551      return ret;
552    sb->sb_sec_out.buf_ptr += ret;
553    if (ret<to_go) /* not enough data, so pretend no data was sent. */
554      return -1;
555    return ret;
556 }
557 #endif
558
559 ber_slen_t ber_pvt_sb_write( Sockbuf *sb, void *buf, ber_len_t len_arg )
560 {
561    ber_slen_t ret;
562    ber_len_t len = len_arg;
563
564         assert( buf != NULL );
565         assert( sb != NULL );
566         assert( SOCKBUF_VALID( sb ) );
567    assert( status_is_ok(sb) );
568
569    /* slapd might have problems with this */
570    assert( ber_pvt_sb_in_use( sb ) );
571
572 #ifdef TEST_PARTIAL_WRITE
573    if ((rand() & 3)==1) { /* 1 out of 4 */
574       errno = EWOULDBLOCK;
575       return -1;
576    }
577
578    len_arg = (rand() % len_arg)+1;
579    len = len_arg;
580 #endif   
581    
582 #ifdef USE_SASL
583    if (sb->sb_sec) {
584       assert( sb->sb_sec_prev_len <= len );
585       if (sb->sb_sec_prev_len) {
586          ret = sockbuf_do_write( sb );
587          if (ret<=0)
588            return ret;
589          /* finished. */
590          len -= sb->sb_sec_prev_len;
591          sb->sb_sec_prev_len = 0;
592          sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0;
593       }
594       /* now protect the next packet. */
595       ret = sockbuf_sec_protect( sb, buf, len );
596       if (ret<=0)
597         return ret;
598       ret = sockbuf_do_write( sb );
599       if (ret<=0) {
600          sb->sb_sec_prev_len = len;
601          return ret;
602       }
603       return len_arg;
604    } else {
605 #endif
606       for(;;) {
607          ret = sockbuf_io_write( sb, buf, len );
608 #ifdef EINTR
609          if ((ret<0) && (errno==EINTR))
610            continue;
611 #endif
612          break;
613       }
614 #ifdef USE_SASL      
615    }
616 #endif
617
618    return ret;
619 }
620      
621 int ber_pvt_sb_close( Sockbuf *sb )
622 {
623    int ret;
624
625    assert( sb != NULL );
626    assert( SOCKBUF_VALID( sb ) );
627    assert( sb->sb_io );
628    assert( sb->sb_io->sbi_close );
629    assert( status_is_ok(sb) );
630    assert( ber_pvt_sb_in_use( sb ) );
631    
632    ret = sb->sb_io->sbi_close( sb );
633    ber_pvt_sb_set_desc( sb, -1 );
634
635    return ret;
636 }
637
638 int ber_pvt_sb_set_readahead( Sockbuf *sb, int rh )
639 {
640    assert( sb != NULL );
641    assert( SOCKBUF_VALID( sb ) );
642    assert( status_is_ok(sb) );
643    sb->sb_read_ahead = (rh!=0);
644    return 0;
645 }
646
647 #define USE_NONBLOCK
648 #ifdef USE_NONBLOCK
649 int ber_pvt_sb_set_nonblock( Sockbuf *sb, int nb )
650 {
651    assert( sb != NULL );
652    assert( SOCKBUF_VALID( sb ) );
653    assert( status_is_ok(sb) );
654    if (nb) {
655       sb->sb_non_block = 1;
656 #if 0      
657       sb->sb_read_ahead = 1;
658 #endif
659    } else {
660       sb->sb_non_block = 0;
661 #if 0
662       sb->sb_read_ahead = 0;
663 #endif
664    }
665    if (ber_pvt_sb_in_use(sb)) {
666 #if HAVE_FCNTL
667                 int flags = fcntl(ber_pvt_sb_get_desc(sb), F_GETFL);
668                 flags |= O_NONBLOCK;
669                 return fcntl(ber_pvt_sb_get_desc(sb), F_SETFL, flags);
670                 
671 #elif defined( FIONBIO )
672            /* WINSOCK requires the status to be a long */
673                 ioctl_t status = (nb!=0);
674                 return ioctl( ber_pvt_sb_get_desc(sb), FIONBIO, &status );
675 #endif /* FIONBIO */
676    }
677    return 0;
678 }
679 #endif
680          
681 #define sockbuf_buf_init( bb ) do { \
682                 Sockbuf_Buf *sbb = (bb); \
683                 sbb->buf_base = NULL; \
684                 sbb->buf_ptr = 0; \
685                 sbb->buf_end = 0; \
686                 sbb->buf_size = 0; \
687         } while(0)
688
689 static int 
690 sockbuf_buf_destroy( Sockbuf_Buf *buf )
691 {
692         assert( buf != NULL);
693
694    if (buf->buf_base)
695      LBER_FREE( buf->buf_base );
696    sockbuf_buf_init( buf );
697    return 0;
698 }
699
700 int ber_pvt_sb_init( Sockbuf *sb )
701 {
702         assert( sb != NULL);
703
704         ber_int_options.lbo_valid = LBER_INITIALIZED;
705
706    sb->sb_valid=LBER_VALID_SOCKBUF;
707    sb->sb_options = 0;
708    sb->sb_debug = 0;
709    sb->sb_trans_ready = 0;
710    sb->sb_buf_ready = 0;
711 #ifdef USE_SASL   
712    sb->sb_sec_ready = 0;
713 #endif   
714    sb->sb_read_ahead = 1; /* test */
715    sb->sb_non_block = 0;
716    sb->sb_trans_needs_read = 0;
717    sb->sb_trans_needs_write = 0;
718    sb->sb_fd = -1;
719    sb->sb_iodata = NULL;
720    sb->sb_io = &sb_IO_None;
721    sb->sb_sd = -1;
722 #ifdef DEADWOOD   
723    sb->sb_max_incoming = 0;
724 #endif   
725    sockbuf_buf_init( &(sb->sb_buf) );
726 #ifdef USE_SASL
727    sockbuf_buf_init( &(sb->sb_sec_buf_in) );
728    sockbuf_buf_init( &(sb->sb_sec_buf_out) );
729    sb->sb_sdata = NULL;
730    sb->sb_sec = NULL;
731    sb->sb_sec_prev_len = 0;
732 #endif 
733    
734    assert( SOCKBUF_VALID( sb ) );
735    return 0;
736 }
737    
738 int ber_pvt_sb_destroy( Sockbuf *sb )
739 {
740         assert( sb != NULL);
741         assert( SOCKBUF_VALID(sb) );
742 #ifdef USE_SASL
743    ber_pvt_sb_clear_sec(sb);
744    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
745    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
746 #endif
747    ber_pvt_sb_clear_io(sb);
748    sockbuf_buf_destroy( &(sb->sb_buf) );
749    return ber_pvt_sb_init( sb );
750 }
751
752 #ifdef USE_SASL
753 int ber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg )
754 {
755    int len;
756         assert( sb != NULL);
757         assert( SOCKBUF_VALID( *sb ) );
758    if ((sb->sb_sec) || (sec==NULL))
759      return -1;
760    
761    sb->sb_sec = sec;
762    
763    if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) {
764       return -1;
765    }
766    
767    len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr;
768    
769    if (len>0) {
770       /* move this to the security layer. */
771       if (grow_buffer( &(sb->sb_sec_buf_in), len )<0)
772         return -1;
773       memcpy( sb->sb_sec_buf_in.buf_base, 
774              sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len );
775       sb->sb_sec_buf_in.buf_ptr = len;
776       sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb->sb_sec_buf_in ) : 0;
777       sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
778    }
779    update_status();
780    return 0;
781 }
782
783 int ber_pvt_sb_clear_sec( Sockbuf *sb )
784 {
785         assert( sb != NULL);
786         assert( SOCKBUF_VALID( sb ) );
787
788    if (sb->sb_buf.buf_ptr!=0)
789      return -1;
790    if (sb->sb_sec==NULL)
791      return -1;
792    if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) 
793      return -1;
794    
795    sb->sb_sec = NULL;
796    if (sb->sb_sec_buf_in.buf_ptr!=0) {
797       if (grow_buffer( &(sb->sb_buf), 
798                       sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0)
799         return -1;
800       memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end,
801               sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr );
802       sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr;
803       sb->sb_buf_ready = 1;
804    }
805    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
806    assert( sb->sb_sec_buf.buf_end==0 );
807    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
808    
809    sb->sb_sec_ready = 0;
810    
811    return 0;
812 }
813 #endif
814
815 int ber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg )
816 {
817         assert( sb != NULL);
818         assert( SOCKBUF_VALID( sb ) );
819    assert( sb->sb_io == &sb_IO_None );
820
821    if (trans==NULL)
822      return -1;
823    
824    sb->sb_io = trans;
825    
826    if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0))
827      return -1;
828    
829    return 0;
830 }
831
832 int ber_pvt_sb_clear_io( Sockbuf *sb )
833 {
834         assert( sb != NULL);
835         assert( SOCKBUF_VALID( sb ) );
836
837    if (sb->sb_io==&sb_IO_None)
838      return -1;
839    
840    if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0))
841      return -1;
842
843    sb->sb_io = &sb_IO_None;
844    
845    sb->sb_trans_ready = 0;
846    sb->sb_trans_needs_read = 0;
847    sb->sb_trans_needs_write = 0;
848
849    return 0;
850 }
851
852 /*
853  * Support for TCP
854  */
855
856 static ber_slen_t
857 stream_read( Sockbuf *sb, void *buf, ber_len_t len )
858 {
859         assert( sb != NULL);
860         assert( SOCKBUF_VALID( sb ) );
861
862 #if defined(MACOS)
863 /*
864  * MacTCP/OpenTransport
865  */
866    return tcpread( ber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, 
867                    len, NULL );
868
869 #elif defined( HAVE_PCNFS ) || \
870    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
871 /*
872  * PCNFS (under DOS)
873  */
874 /*
875  * Windows Socket API (under DOS/Windows 3.x)
876  */
877 /*
878  * 32-bit Windows Socket API (under Windows NT or Windows 95)
879  */
880    {
881    int rc;
882    rc = recv( ber_pvt_sb_get_desc(sb), buf, len, 0 );
883 #ifdef HAVE_WINSOCK
884    if ( rc < 0 ) errno = WSAGetLastError();
885 #endif
886    return rc;
887    }
888 #elif defined( HAVE_NCSA )
889 /*
890  * NCSA Telnet TCP/IP stack (under DOS)
891  */
892    return nread( ber_pvt_sb_get_desc(sb), buf, len );
893
894 #else
895    return read( ber_pvt_sb_get_desc(sb), buf, len );
896 #endif
897 }
898
899 static ber_slen_t
900 stream_write( Sockbuf *sb, void *buf, ber_len_t len )
901 {
902         assert( sb != NULL);
903         assert( SOCKBUF_VALID( sb ) );
904
905 #if defined(MACOS) 
906 /*
907  * MacTCP/OpenTransport
908  */
909 #define MAX_WRITE       65535
910    return tcpwrite( ber_pvt_sb_get_desc(sb),
911                     (unsigned char *)(buf), 
912                     (len<MAX_WRITE)? len : MAX_WRITE );
913
914 #elif defined( HAVE_PCNFS) \
915    || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
916 /*
917  * PCNFS (under DOS)
918  */
919 /*
920  * Windows Socket API (under DOS/Windows 3.x)
921  */
922 /*
923  * 32-bit Windows Socket API (under Windows NT or Windows 95)
924  */
925
926    {
927    int rc;
928    rc = send( ber_pvt_sb_get_desc(sb), buf, len, 0 );
929 #ifdef HAVE_WINSOCK
930    if ( rc < 0 ) errno = WSAGetLastError();
931 #endif
932    return rc;
933    }
934
935 #elif defined(HAVE_NCSA)
936    return netwrite( ber_pvt_sb_get_desc(sb), buf, len );
937
938 #elif defined(VMS)
939 /*
940  * VMS -- each write must be 64K or smaller
941  */
942 #define MAX_WRITE 65535
943    return write( ber_pvt_sb_get_desc(sb), buf, 
944                  (len<MAX_WRITE)? len : MAX_WRITE);
945 #else
946    return write( ber_pvt_sb_get_desc(sb), buf, len );
947 #endif   
948 }   
949    
950 static int 
951 stream_close( Sockbuf *sb )
952 {
953         assert( sb != NULL);
954         assert( SOCKBUF_VALID( sb ) );
955    tcp_close( ber_pvt_sb_get_desc( sb ) );
956    return 0;
957 }
958
959 Sockbuf_IO ber_pvt_sb_io_tcp=
960 {
961         NULL,   /* sbi_setup */
962         NULL,   /* sbi_release */
963         stream_read,    /* sbi_read */
964         stream_write,   /* sbi_write */
965         stream_close,   /* sbi_close */
966 };
967
968 /*
969  * Support for UDP (CLDAP)
970  */
971
972 struct dgram_data
973 {
974         struct sockaddr dst;
975         struct sockaddr src;
976 };
977
978 static int 
979 dgram_setup( Sockbuf *sb, void *arg )
980 {
981         assert( sb != NULL);
982         assert( SOCKBUF_VALID( sb ) );
983
984    sb->sb_iodata = LBER_MALLOC( sizeof( struct dgram_data ) );
985    if (sb->sb_iodata==NULL)
986      return -1;
987    sb->sb_read_ahead = 1; /* important since udp is packet based. */
988    return 0;
989 }
990
991 static int 
992 dgram_release( Sockbuf *sb )
993 {
994         assert( sb != NULL);
995         assert( SOCKBUF_VALID( sb ) );
996
997    LBER_FREE( sb->sb_iodata );
998    return 0;
999 }
1000
1001 static ber_slen_t
1002 dgram_read( Sockbuf *sb, void *buf, ber_len_t len )
1003 {
1004 #ifdef LDAP_CONNECTIONLESS
1005    ber_slen_t rc;
1006    int addrlen;
1007    struct dgram_data *dd;
1008    
1009         assert( sb != NULL );
1010         assert( SOCKBUF_VALID( sb ) );
1011         assert( buf != NULL );
1012
1013    dd = (struct dgram_data *)(sb->sb_iodata);
1014    
1015    addrlen = sizeof( struct sockaddr );
1016    rc=recvfrom( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
1017    
1018    if ( sb->sb_debug ) {
1019       ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
1020                       "dgram_read udp_read %d bytes\n",
1021                       rc );
1022       if ( rc > 0 )
1023         ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
1024                         buf, rc );
1025    }
1026    return rc;
1027 # else /* LDAP_CONNECTIONLESS */
1028    return -1;
1029 # endif /* LDAP_CONNECTIONLESS */
1030 }
1031
1032 static ber_slen_t 
1033 dgram_write( Sockbuf *sb, void *buf, ber_len_t len )
1034 {
1035 #ifdef LDAP_CONNECTIONLESS
1036    ber_slen_t rc;
1037    struct dgram_data *dd;
1038    
1039         assert( sb != NULL );
1040         assert( SOCKBUF_VALID( sb ) );
1041         assert( buf != NULL );
1042
1043    dd = (struct dgram_data *)(sb->sb_iodata);
1044    
1045    rc=sendto( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
1046              sizeof( struct sockaddr ) );
1047
1048    if ( rc <= 0 )
1049        return( -1 );
1050    
1051    /* fake error if write was not atomic */
1052    if (rc < len) {
1053 # ifdef EMSGSIZE
1054       errno = EMSGSIZE;
1055 # endif
1056       return( -1 );
1057    }
1058    return rc;
1059 #else
1060    return -1;
1061 #endif  
1062 }
1063
1064 static int 
1065 dgram_close( Sockbuf *sb )
1066 {
1067         assert( sb != NULL );
1068         assert( SOCKBUF_VALID( sb ) );
1069
1070         tcp_close( ber_pvt_sb_get_desc(sb) );
1071         return 0;
1072 }
1073
1074 Sockbuf_IO ber_pvt_sb_io_udp=
1075 {
1076         dgram_setup,    /* sbi_setup */
1077         dgram_release,  /* sbi_release */
1078         dgram_read,     /* sbi_read */
1079         dgram_write,    /* sbi_write */
1080         dgram_close,    /* sbi_close */
1081 };
1082
1083 int ber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
1084 {
1085    struct dgram_data *dd;
1086         assert( sb != NULL );
1087         assert( SOCKBUF_VALID( sb ) );
1088    assert( sb->sb_io == &ber_pvt_sb_io_udp );
1089    dd = (struct dgram_data *) (sb->sb_iodata);
1090    memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) );
1091    return 0;
1092 }
1093
1094 void *ber_pvt_sb_udp_get_src( Sockbuf *sb )
1095 {
1096    struct dgram_data *dd;
1097
1098         assert( sb != NULL );
1099         assert( SOCKBUF_VALID( sb ) );
1100    assert( sb->sb_io == &ber_pvt_sb_io_udp );
1101    dd = (struct dgram_data *) (sb->sb_iodata);
1102    return &(dd->src);
1103 }
1104
1105 /*
1106  * debug routines.
1107  * 
1108  * BUGS:
1109  * These routines should really call abort, but at the moment that would
1110  * break the servers.
1111  */
1112
1113 static ber_slen_t
1114 have_no_read( Sockbuf *sb, void *buf, ber_len_t len )
1115 {
1116         assert( sb != NULL );
1117         assert( SOCKBUF_VALID( sb ) );
1118
1119    ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
1120                    "warning: reading from uninitialized sockbuf\n");
1121    errno =  EBADF;
1122    return -1;
1123 }
1124
1125 static ber_slen_t
1126 have_no_write( Sockbuf *sb, void *buf, ber_len_t len )
1127 {
1128         assert( sb != NULL );
1129         assert( SOCKBUF_VALID( sb ) );
1130
1131    ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
1132                    "warning: writing to uninitialized sockbuf\n");
1133    errno =  EBADF;
1134    return -1;
1135 }
1136
1137 static int 
1138 have_no_close( Sockbuf *sb )
1139 {   
1140         assert( sb != NULL );
1141         assert( SOCKBUF_VALID( sb ) );
1142
1143    assert( 0 );
1144    return -1;
1145 }