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