]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
cda495202ac6f331d82a628bf9c988a4c51d5d11
[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            free( buf->buf_base );
146          assert( buf->buf_ptr==0 );
147          assert( buf->buf_end==0 );
148          buf->buf_base = malloc( minsize );
149          if (buf->buf_base==NULL)
150            return -1;
151       } else {
152          char *nb;
153          nb = 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 = calloc(1, sizeof(Sockbuf));
334
335         if( sb == NULL ) return NULL;
336
337         ber_pvt_sb_init( sb );
338         return sb;
339 }
340
341 Sockbuf *ber_sockbuf_alloc_fd( int fd )
342 {
343         Sockbuf *sb = ber_sockbuf_alloc();
344
345         if( sb == NULL ) return NULL;
346
347         ber_pvt_sb_set_desc( sb, fd );
348         ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL );
349         return sb;
350 }
351
352 void ber_sockbuf_free( Sockbuf *sb )
353 {
354         assert(sb != NULL);
355         assert( SOCKBUF_VALID( sb ) );
356         ber_pvt_sb_destroy( sb );
357         free(sb);
358 }
359
360 long 
361 ber_pvt_sb_read( Sockbuf *sb, void *buf_arg, long len )
362 {
363    char *buf;
364    long ret;
365    
366    assert( buf_arg != NULL );
367    assert( sb != NULL );
368         assert( SOCKBUF_VALID( sb ) );
369    assert( status_is_ok(sb) );
370 #if 0
371    /* breaks slapd :-< */
372    assert( ber_pvt_sb_in_use( sb ) );
373 #endif 
374
375 #ifdef TEST_PARTIAL_READ
376    if ((rand() & 3)==1) { /* 1 out of 4 */
377       errno = EWOULDBLOCK;
378       return -1;
379    }
380
381    if( len > 0 )
382            len = (rand() % len)+1;
383 #endif   
384    
385    buf = (char *) buf_arg;
386
387    if (sb->sb_buf.buf_ptr!=sb->sb_buf.buf_end) {
388       len = sockbuf_copy_out( sb, &buf, len );
389       if (len==0) {
390          return (buf - (char *) buf_arg);
391       }
392    }
393
394 #ifdef USE_SASL
395    if (sb->sb_sec) {
396       int max;
397       assert( sb->sb_sec->sbs_release );
398       assert( sb->sb_sec_buf_in.buf_base );
399       if (sb->sb_read_ahead) {
400          max = sb->sb_sec_buf_in.buf_size - sb->sb_sec_buf_in.buf_ptr;
401       } else {
402          max = sb->sb_sec_buf_in.buf_end - sb->sb_sec_buf_in.buf_ptr;
403          if (max<=0) {
404             /* special situation. This means that we need to read the first
405              * four bytes for the packet length.
406              */
407             max += 4;
408          }
409       }
410       for(;;) {
411          /* read from stream into sb_sec_buf_in */
412          for(;;) {
413             ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base +
414                                   sb->sb_sec_buf_in.buf_ptr, max );
415 #ifdef EINTR
416             if ((ret<0) && (errno==EINTR))
417               continue;
418 #endif
419             break;
420          }
421          if (ret<=0) {
422             /* read error. return */
423             goto do_return;
424          }
425          sb->sb_sec_buf_in.buf_ptr += ret;
426          
427          if (sb->sb_sec_buf_in.buf_ptr < sb->sb_sec_buf_in.buf_end) {
428             /* did not finish a packet. give up. */
429             goto do_return;
430          }
431             
432          if (sb->sb_sec_buf_in.buf_end == 0) {
433             /* Were trying to read the first four bytes... */
434             if (sb->sb_sec_buf_in.buf_ptr < 4) {
435                /* did not read enough for packet length. give up. */
436                goto do_return;
437             }
438             /* calculate the packet length. */
439             sb->sb_sec_buf_in.buf_end = 
440                packet_length(sb->sb_sec_buf_in.buf_base );
441             if ((sb->sb_sec_buf_in.buf_end > sb->sb_sec_buf_in.buf_size) &&
442                 (grow_buffer( &(sb->sb_sec_buf_in), sb->sb_sec_buf_in.buf_end)<0)) {
443                /* buffer has to be to big. exit with error. */
444                ret = -1;
445                goto do_return;
446             }
447             if (sb->sb_sec_buf_in.buf_ptr >= sb_sec_buf_in.buf_end) {
448                /* finished packet. decode it. */
449                goto decode_packet;
450             }
451             /* did not finish packet yet. try again ? */
452             if (sb->sb_read_ahead) {
453                /* we were trying to read the max anyway. forget it */
454                goto do_return;
455             }
456          }
457 decode_packet:
458          /* we read enough for at least 1 packet */
459          ret = sockbuf_sec_release( sb, buf, len );
460          if (ret<=0) {
461             /* something went wrong... */
462             goto do_return;
463          }
464          buf+=ret;
465          len-=ret;
466          /* we are finished !!! */
467          if ((len==0) || (ret!=max))
468            goto do_return;
469       }
470    } else {
471 #endif
472       if (sb->sb_read_ahead) {
473          long max;
474          max = sb->sb_buf.buf_size - sb->sb_buf.buf_end;
475          if (max>len) {
476             for(;;) {
477                ret = sockbuf_io_read( sb, 
478                                      sb->sb_buf.buf_base +
479                                      sb->sb_buf.buf_end,
480                                      max );
481 #ifdef EINTR           
482                if ((ret<0) && (errno==EINTR))
483                  continue;
484 #endif
485                break;
486             }
487             if (ret<=0) {
488                /* some error occured */
489                goto do_return;
490             }
491             sb->sb_buf.buf_end += ret;
492             /* move out the data... */
493             len = sockbuf_copy_out( sb, &buf, len );
494             goto do_return;
495          }
496       }
497       /* no read_ahead, just try to put the data in the buf. */
498       for(;;) {
499          ret = sockbuf_io_read( sb, buf, len );
500 #ifdef EINTR     
501          if ((ret<0) && (errno==EINTR))
502            continue;
503 #endif
504          break;
505       }
506       if (ret>0) {
507          buf+=ret;
508          len-=ret;
509       }
510       /* we might as well return, since there is nothing to do... */
511 #ifdef USE_SASL     
512    }
513 #endif
514 do_return:
515    assert( status_is_ok(sb) );
516    if ((ret<=0) && (buf==buf_arg)) {
517       /* there was an error. */
518       return ret;
519    }
520    return (buf - ((char *) buf_arg));
521 }
522
523 #ifdef USE_SASL
524 long sockbuf_do_write( Sockbuf *sb )
525 {
526    long to_go;
527
528    assert( sb != NULL );
529         assert( SOCKBUF_VALID( sb ) );
530
531    to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr;
532    assert( to_go > 0 );
533    /* there is something left of the last time... */
534    for(;;) {
535       ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+
536                              sb->sb_sec_out.buf_ptr, to_go );
537 #ifdef EINTR
538       if ((ret<0) && (errno==EINTR))
539         continue;
540 #endif
541       break;
542    }
543    if (ret<=0) /* error */
544      return ret;
545    sb->sb_sec_out.buf_ptr += ret;
546    if (ret<to_go) /* not enough data, so pretend no data was sent. */
547      return -1;
548    return ret;
549 }
550 #endif
551
552 long ber_pvt_sb_write( Sockbuf *sb, void *buf, long len_arg )
553 {
554    long ret;
555    long len = len_arg;
556
557         assert( buf != NULL );
558         assert( sb != NULL );
559         assert( SOCKBUF_VALID( sb ) );
560    assert( status_is_ok(sb) );
561 #if 0
562    /* unfortunately breaks slapd */
563    assert( ber_pvt_sb_in_use( sb ) );
564 #endif   
565 #ifdef TEST_PARTIAL_WRITE
566    if ((rand() & 3)==1) { /* 1 out of 4 */
567       errno = EWOULDBLOCK;
568       return -1;
569    }
570
571    len_arg = (rand() % len_arg)+1;
572    len = len_arg;
573 #endif   
574    
575 #ifdef USE_SASL
576    if (sb->sb_sec) {
577       assert( sb->sb_sec_prev_len <= len );
578       if (sb->sb_sec_prev_len) {
579          ret = sockbuf_do_write( sb );
580          if (ret<=0)
581            return ret;
582          /* finished. */
583          len -= sb->sb_sec_prev_len;
584          sb->sb_sec_prev_len = 0;
585          sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0;
586       }
587       /* now protect the next packet. */
588       ret = sockbuf_sec_protect( sb, buf, len );
589       if (ret<=0)
590         return ret;
591       ret = sockbuf_do_write( sb );
592       if (ret<=0) {
593          sb->sb_sec_prev_len = len;
594          return ret;
595       }
596       return len_arg;
597    } else {
598 #endif
599       for(;;) {
600          ret = sockbuf_io_write( sb, buf, len );
601 #ifdef EINTR
602          if ((ret<0) && (errno==EINTR))
603            continue;
604 #endif
605          break;
606       }
607 #ifdef USE_SASL      
608    }
609 #endif
610
611    return ret;
612 }
613      
614 int ber_pvt_sb_close( Sockbuf *sb )
615 {
616    int ret;
617
618    assert( sb != NULL );
619    assert( SOCKBUF_VALID( sb ) );
620    assert( sb->sb_io );
621    assert( sb->sb_io->sbi_close );
622    assert( status_is_ok(sb) );
623    assert( ber_pvt_sb_in_use( sb ) );
624    
625    ret = sb->sb_io->sbi_close( sb );
626    ber_pvt_sb_set_desc( sb, -1 );
627
628    return ret;
629 }
630
631 int ber_pvt_sb_set_readahead( Sockbuf *sb, int rh )
632 {
633    assert( sb != NULL );
634    assert( SOCKBUF_VALID( sb ) );
635    assert( status_is_ok(sb) );
636    sb->sb_read_ahead = (rh!=0);
637    return 0;
638 }
639
640 #define USE_NONBLOCK
641 #ifdef USE_NONBLOCK
642 int ber_pvt_sb_set_nonblock( Sockbuf *sb, int nb )
643 {
644    assert( sb != NULL );
645    assert( SOCKBUF_VALID( sb ) );
646    assert( status_is_ok(sb) );
647    if (nb) {
648       sb->sb_non_block = 1;
649 #if 0      
650       sb->sb_read_ahead = 1;
651 #endif
652    } else {
653       sb->sb_non_block = 0;
654 #if 0
655       sb->sb_read_ahead = 0;
656 #endif
657    }
658    if (ber_pvt_sb_in_use(sb)) {
659 #if HAVE_FCNTL
660                 int flags = fcntl(ber_pvt_sb_get_desc(sb), F_GETFL);
661                 flags |= O_NONBLOCK;
662                 return fcntl(ber_pvt_sb_get_desc(sb), F_SETFL, flags);
663                 
664 #elif defined( FIONBIO )
665            /* WINSOCK requires the status to be a long */
666                 ioctl_t status = (nb!=0);
667                 return ioctl( ber_pvt_sb_get_desc(sb), FIONBIO, &status );
668 #endif /* FIONBIO */
669    }
670    return 0;
671 }
672 #endif
673          
674 #define sockbuf_buf_init( bb ) do { \
675                 Sockbuf_Buf *sbb = (bb); \
676                 sbb->buf_base = NULL; \
677                 sbb->buf_ptr = 0; \
678                 sbb->buf_end = 0; \
679                 sbb->buf_size = 0; \
680         } while(0)
681
682 static int 
683 sockbuf_buf_destroy( Sockbuf_Buf *buf )
684 {
685         assert( buf != NULL);
686
687    if (buf->buf_base)
688      free( buf->buf_base );
689    sockbuf_buf_init( buf );
690    return 0;
691 }
692
693 int ber_pvt_sb_init( Sockbuf *sb )
694 {
695         assert( sb != NULL);
696
697    sb->sb_valid=LBER_VALID_SOCKBUF;
698    sb->sb_options = 0;
699    sb->sb_debug = 0;
700    sb->sb_trans_ready = 0;
701    sb->sb_buf_ready = 0;
702 #ifdef USE_SASL   
703    sb->sb_sec_ready = 0;
704 #endif   
705    sb->sb_read_ahead = 0;
706    sb->sb_non_block = 0;
707    sb->sb_fd = -1;
708    sb->sb_iodata = NULL;
709    sb->sb_io = &sb_IO_None;
710    sb->sb_sd = -1;
711 #ifdef DEADWOOD   
712    sb->sb_max_incoming = 0;
713 #endif   
714    sockbuf_buf_init( &(sb->sb_buf) );
715 #ifdef USE_SASL
716    sockbuf_buf_init( &(sb->sb_sec_buf_in) );
717    sockbuf_buf_init( &(sb->sb_sec_buf_out) );
718    sb->sb_sdata = NULL;
719    sb->sb_sec = NULL;
720    sb->sb_sec_prev_len = 0;
721 #endif 
722    
723    assert( SOCKBUF_VALID( sb ) );
724    return 0;
725 }
726    
727 int ber_pvt_sb_destroy( Sockbuf *sb )
728 {
729         assert( sb != NULL);
730         assert( SOCKBUF_VALID(sb) );
731 #ifdef USE_SASL
732    ber_pvt_sb_clear_sec(sb);
733    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
734    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
735 #endif
736    ber_pvt_sb_clear_io(sb);
737    sockbuf_buf_destroy( &(sb->sb_buf) );
738    return ber_pvt_sb_init( sb );
739 }
740
741 #ifdef USE_SASL
742 int ber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg )
743 {
744    int len;
745         assert( sb != NULL);
746         assert( SOCKBUF_VALID( *sb ) );
747    if ((sb->sb_sec) || (sec==NULL))
748      return -1;
749    
750    sb->sb_sec = sec;
751    
752    if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) {
753       return -1;
754    }
755    
756    len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr;
757    
758    if (len>0) {
759       /* move this to the security layer. */
760       if (grow_buffer( &(sb->sb_sec_buf_in), len )<0)
761         return -1;
762       memcpy( sb->sb_sec_buf_in.buf_base, 
763              sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len );
764       sb->sb_sec_buf_in.buf_ptr = len;
765       sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb->sb_sec_buf_in ) : 0;
766       sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
767    }
768    update_status();
769    return 0;
770 }
771
772 int ber_pvt_sb_clear_sec( Sockbuf *sb )
773 {
774         assert( sb != NULL);
775         assert( SOCKBUF_VALID( sb ) );
776
777    if (sb->sb_buf.buf_ptr!=0)
778      return -1;
779    if (sb->sb_sec==NULL)
780      return -1;
781    if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) 
782      return -1;
783    
784    sb->sb_sec = NULL;
785    if (sb->sb_sec_buf_in.buf_ptr!=0) {
786       if (grow_buffer( &(sb->sb_buf), 
787                       sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0)
788         return -1;
789       memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end,
790               sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr );
791       sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr;
792       sb->sb_buf_ready = 1;
793    }
794    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
795    assert( sb->sb_sec_buf.buf_end==0 );
796    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
797    
798    sb->sb_sec_ready = 0;
799    
800    return 0;
801 }
802 #endif
803
804 int ber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg )
805 {
806         assert( sb != NULL);
807         assert( SOCKBUF_VALID( sb ) );
808    assert( sb->sb_io == &sb_IO_None );
809
810    if (trans==NULL)
811      return -1;
812    
813    sb->sb_io = trans;
814    
815    if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0))
816      return -1;
817    
818    return 0;
819 }
820
821 int ber_pvt_sb_clear_io( Sockbuf *sb )
822 {
823         assert( sb != NULL);
824         assert( SOCKBUF_VALID( sb ) );
825
826    if (sb->sb_io==&sb_IO_None)
827      return -1;
828    
829    if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0))
830      return -1;
831
832    sb->sb_io = &sb_IO_None;
833    
834    sb->sb_trans_ready = 0;
835    
836    return 0;
837 }
838
839 /*
840  * Support for TCP
841  */
842
843 static long
844 stream_read( Sockbuf *sb, void *buf, long len )
845 {
846         assert( sb != NULL);
847         assert( SOCKBUF_VALID( sb ) );
848
849 #if defined(MACOS)
850 /*
851  * MacTCP/OpenTransport
852  */
853    return tcpread( ber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, 
854                    len, NULL );
855
856 #elif defined( HAVE_PCNFS ) || \
857    defined( HAVE_WINSOCK ) || defined ( __BEOS__ )
858 /*
859  * PCNFS (under DOS)
860  */
861 /*
862  * Windows Socket API (under DOS/Windows 3.x)
863  */
864 /*
865  * 32-bit Windows Socket API (under Windows NT or Windows 95)
866  */
867    {
868    int rc;
869    rc = recv( ber_pvt_sb_get_desc(sb), buf, len, 0 );
870 #ifdef HAVE_WINSOCK
871    if ( rc < 0 ) errno = WSAGetLastError();
872 #endif
873    return rc;
874    }
875 #elif defined( HAVE_NCSA )
876 /*
877  * NCSA Telnet TCP/IP stack (under DOS)
878  */
879    return nread( ber_pvt_sb_get_desc(sb), buf, len );
880
881 #else
882    return read( ber_pvt_sb_get_desc(sb), buf, len );
883 #endif
884 }
885
886 static long
887 stream_write( Sockbuf *sb, void *buf, long len )
888 {
889         assert( sb != NULL);
890         assert( SOCKBUF_VALID( sb ) );
891
892 #if defined(MACOS) 
893 /*
894  * MacTCP/OpenTransport
895  */
896 #define MAX_WRITE       65535
897    return tcpwrite( ber_pvt_sb_get_desc(sb),
898                     (unsigned char *)(buf), 
899                     (len<MAX_WRITE)? len : MAX_WRITE );
900
901 #elif defined( HAVE_PCNFS) \
902    || defined( HAVE_WINSOCK) || defined ( __BEOS__ )
903 /*
904  * PCNFS (under DOS)
905  */
906 /*
907  * Windows Socket API (under DOS/Windows 3.x)
908  */
909 /*
910  * 32-bit Windows Socket API (under Windows NT or Windows 95)
911  */
912
913    {
914    int rc;
915    rc = send( ber_pvt_sb_get_desc(sb), buf, len, 0 );
916 #ifdef HAVE_WINSOCK
917    if ( rc < 0 ) errno = WSAGetLastError();
918 #endif
919    return rc;
920    }
921
922 #elif defined(HAVE_NCSA)
923    return netwrite( ber_pvt_sb_get_desc(sb), buf, len );
924
925 #elif defined(VMS)
926 /*
927  * VMS -- each write must be 64K or smaller
928  */
929 #define MAX_WRITE 65535
930    return write( ber_pvt_sb_get_desc(sb), buf, 
931                  (len<MAX_WRITE)? len : MAX_WRITE);
932 #else
933    return write( ber_pvt_sb_get_desc(sb), buf, len );
934 #endif   
935 }   
936    
937 static int 
938 stream_close( Sockbuf *sb )
939 {
940         assert( sb != NULL);
941         assert( SOCKBUF_VALID( sb ) );
942    tcp_close( ber_pvt_sb_get_desc( sb ) );
943    return 0;
944 }
945
946 Sockbuf_IO ber_pvt_sb_io_tcp=
947 {
948         NULL,   /* sbi_setup */
949         NULL,   /* sbi_release */
950         stream_read,    /* sbi_read */
951         stream_write,   /* sbi_write */
952         stream_close,   /* sbi_close */
953 };
954
955 /*
956  * Support for UDP (CLDAP)
957  */
958
959 struct dgram_data
960 {
961         struct sockaddr dst;
962         struct sockaddr src;
963 };
964
965 static int 
966 dgram_setup( Sockbuf *sb, void *arg )
967 {
968         assert( sb != NULL);
969         assert( SOCKBUF_VALID( sb ) );
970
971    sb->sb_iodata = malloc( sizeof( struct dgram_data ) );
972    if (sb->sb_iodata==NULL)
973      return -1;
974    sb->sb_read_ahead = 1; /* important since udp is packet based. */
975    return 0;
976 }
977
978 static int 
979 dgram_release( Sockbuf *sb )
980 {
981         assert( sb != NULL);
982         assert( SOCKBUF_VALID( sb ) );
983
984    free( sb->sb_iodata );
985    return 0;
986 }
987
988 static long
989 dgram_read( Sockbuf *sb, void *buf, long len )
990 {
991 #ifdef LDAP_CONNECTIONLESS
992    long rc;
993    int addrlen;
994    struct dgram_data *dd;
995    
996         assert( sb != NULL );
997         assert( SOCKBUF_VALID( sb ) );
998         assert( buf != NULL );
999
1000    dd = (struct dgram_data *)(sb->sb_iodata);
1001    
1002    addrlen = sizeof( struct sockaddr );
1003    rc=recvfrom( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
1004    
1005    if ( sb->sb_debug ) {
1006       ber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
1007                       "dgram_read udp_read %d bytes\n",
1008                       rc );
1009       if ( rc > 0 )
1010         ber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
1011                         buf, rc );
1012    }
1013    return rc;
1014 # else /* LDAP_CONNECTIONLESS */
1015    return -1;
1016 # endif /* LDAP_CONNECTIONLESS */
1017 }
1018
1019 static long 
1020 dgram_write( Sockbuf *sb, void *buf, long len )
1021 {
1022 #ifdef LDAP_CONNECTIONLESS
1023    int rc;
1024    struct dgram_data *dd;
1025    
1026         assert( sb != NULL );
1027         assert( SOCKBUF_VALID( sb ) );
1028         assert( buf != NULL );
1029
1030    dd = (struct dgram_data *)(sb->sb_iodata);
1031    
1032    rc=sendto( ber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
1033              sizeof( struct sockaddr ) );
1034
1035    if ( rc <= 0 )
1036        return( -1 );
1037    
1038    /* fake error if write was not atomic */
1039    if (rc < len) {
1040 # ifdef EMSGSIZE
1041       errno = EMSGSIZE;
1042 # endif
1043       return( -1 );
1044    }
1045    return rc;
1046 #else
1047    return -1;
1048 #endif  
1049 }
1050
1051 static int 
1052 dgram_close( Sockbuf *sb )
1053 {
1054         assert( sb != NULL );
1055         assert( SOCKBUF_VALID( sb ) );
1056
1057         tcp_close( ber_pvt_sb_get_desc(sb) );
1058         return 0;
1059 }
1060
1061 Sockbuf_IO ber_pvt_sb_io_udp=
1062 {
1063         dgram_setup,    /* sbi_setup */
1064         dgram_release,  /* sbi_release */
1065         dgram_read,     /* sbi_read */
1066         dgram_write,    /* sbi_write */
1067         dgram_close,    /* sbi_close */
1068 };
1069
1070 int ber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
1071 {
1072    struct dgram_data *dd;
1073         assert( sb != NULL );
1074         assert( SOCKBUF_VALID( sb ) );
1075    assert( sb->sb_io == &ber_pvt_sb_io_udp );
1076    dd = (struct dgram_data *) (sb->sb_iodata);
1077    memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) );
1078    return 0;
1079 }
1080
1081 void *ber_pvt_sb_udp_get_src( Sockbuf *sb )
1082 {
1083    struct dgram_data *dd;
1084
1085         assert( sb != NULL );
1086         assert( SOCKBUF_VALID( sb ) );
1087    assert( sb->sb_io == &ber_pvt_sb_io_udp );
1088    dd = (struct dgram_data *) (sb->sb_iodata);
1089    return &(dd->src);
1090 }
1091
1092 /*
1093  * debug routines.
1094  * 
1095  * BUGS:
1096  * These routines should really call abort, but at the moment that would
1097  * break the servers.
1098  */
1099
1100 static long
1101 have_no_read( Sockbuf *sb, void *buf, long len )
1102 {
1103         assert( sb != NULL );
1104         assert( SOCKBUF_VALID( sb ) );
1105
1106    ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
1107                    "warning: reading from uninitialized sockbuf\n");
1108    errno =  EBADF;
1109    return -1;
1110 }
1111
1112 static long
1113 have_no_write( Sockbuf *sb, void *buf, long len )
1114 {
1115         assert( sb != NULL );
1116         assert( SOCKBUF_VALID( sb ) );
1117
1118    ber_log_printf( LDAP_DEBUG_ANY, ber_int_debug,
1119                    "warning: writing to uninitialized sockbuf\n");
1120    errno =  EBADF;
1121    return -1;
1122 }
1123
1124 static int 
1125 have_no_close( Sockbuf *sb )
1126 {   
1127         assert( sb != NULL );
1128         assert( SOCKBUF_VALID( sb ) );
1129
1130    assert( 0 );
1131    return -1;
1132 }