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