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