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