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