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