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