]> git.sur5r.net Git - openldap/blob - libraries/liblber/sockbuf.c
8902af162dfc8a3a3cb4ac253766f433d622310d
[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_DEBUG
31 #include <assert.h>
32 #else
33 #define assert( cond )
34 #endif
35
36 #define MAX_BUF_SIZE    65535
37 #define MIN_BUF_SIZE    4096
38
39 #define sockbuf_io_write( sb, buf, len ) \
40 ((sb)->sb_io->sbi_write( (sb), (buf), (len) ))
41
42 #define sockbuf_io_read( sb, buf, len ) \
43 ((sb)->sb_io->sbi_read( (sb), (buf), (len) ))
44
45 static long have_no_read( Sockbuf *sb, void *buf, long len );
46 static long have_no_write( Sockbuf *sb, void *buf, long len );
47 static int have_no_close( Sockbuf *sb );
48
49 static Sockbuf_IO lber_pvt_sb_IO_None=
50 {
51         NULL,   /* sbi_setup */
52         NULL,   /* sbi_release */
53         have_no_read,   /* sbi_read */
54         have_no_write,  /* sbi_write */
55         have_no_close   /* sbi_close */
56 };
57
58 static void
59 update_status( Sockbuf *sb )
60 {
61    sb->sb_buf_ready = (sb->sb_buf.buf_ptr < sb->sb_buf.buf_end);
62 #ifdef USE_SASL   
63    sb->sb_sec_ready = ((sb->sb_sec_buf_in.buf_end!=0) &&
64                        (sb->sb_sec_buf_in.buf_ptr >= 
65                         sb->sb_sec_buf_in.buf_end));
66 #endif   
67 }
68
69 #ifdef LDAP_DEBUG
70 static int 
71 status_is_ok( Sockbuf *sb )
72 {
73    int obr;
74    int osr;
75    obr = sb->sb_buf_ready;
76 #ifdef USE_SASL
77    osr = sb->sb_sec_ready;
78 #endif
79    update_status(sb);
80    if (obr!=sb->sb_buf_ready)
81      return 0;
82 #ifdef USE_SASL
83    if (osr!=sb->sb_sec_ready)
84      return 0;
85 #endif
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    /* round to nearest 2k */
116    if (minsize < MIN_BUF_SIZE) {
117       minsize = MIN_BUF_SIZE;
118    }  else {
119       minsize=((minsize-1)|2047)+1;
120       if (minsize > MAX_BUF_SIZE) {
121          /* this could mean that somebody is trying to crash us. */
122          return -1;
123       }
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    buf = (char *) buf_arg;
314
315    len = sockbuf_copy_out( sb, &buf, len );
316    
317    if (len==0) {
318       return (buf - (char *) buf_arg);
319    }
320
321 #ifdef USE_SASL
322    if (sb->sb_sec) {
323       int max;
324       assert( sb->sb_sec->sbs_release );
325       assert( sb->sb_sec_buf_in.buf_base );
326       if (sb->sb_read_ahead) {
327          max = sb->sb_sec_buf_in.buf_size - sb->sb_sec_buf_in.buf_ptr;
328       } else {
329          max = sb->sb_sec_buf_in.buf_end - sb->sb_sec_buf_in.buf_ptr;
330          if (max<=0) {
331             /* special situation. This means that we need to read the first
332              * four bytes for the packet length.
333              */
334             max += 4;
335          }
336       }
337       for(;;) {
338          /* read from stream into sb_sec_buf_in */
339          ret = sockbuf_io_read( sb, sb->sb_sec_buf_in.buf_base +
340                                   sb->sb_sec_buf_in.buf_ptr, max );
341          if (ret<=0) {
342             /* read error. return */
343             goto do_return;
344          }
345          sb->sb_sec_buf_in.buf_ptr += ret;
346          
347          if (sb->sb_sec_buf_in.buf_ptr < sb->sb_sec_buf_in.buf_end) {
348             /* did not finish a packet. give up. */
349             goto do_return;
350          }
351             
352          if (sb->sb_sec_buf_in.buf_end == 0) {
353             /* Were trying to read the first four bytes... */
354             if (sb->sb_sec_buf_in.buf_ptr < 4) {
355                /* did not read enough for packet length. give up. */
356                goto do_return;
357             }
358             /* calculate the packet length. */
359             sb->sb_sec_buf_in.buf_end = 
360                packet_length(sb->sb_sec_buf_in.buf_base );
361             if ((sb->sb_sec_buf_in.buf_end > sb->sb_sec_buf_in.buf_size) &&
362                 (grow_buffer( &(sb->sb_sec_buf_in), sb->sb_sec_buf_in.buf_end)<0)) {
363                /* buffer has to be to big. exit with error. */
364                ret = -1;
365                goto do_return;
366             }
367             if (sb->sb_sec_buf_in.buf_ptr >= sb_sec_buf_in.buf_end) {
368                /* finished packet. decode it. */
369                goto decode_packet;
370             }
371             /* did not finish packet yet. try again ? */
372             if (sb->sb_read_ahead) {
373                /* we were trying to read the max anyway. forget it */
374                goto do_return;
375             }
376          }
377 decode_packet:
378          /* we read enough for at least 1 packet */
379          ret = sockbuf_sec_release( sb, buf, len );
380          if (ret<=0) {
381             /* something went wrong... */
382             goto do_return;
383          }
384          buf+=ret;
385          len-=ret;
386          /* we are finished !!! */
387          if ((len==0) || (ret!=max))
388            goto do_return;
389       }
390    } else {
391 #endif
392       if (sb->sb_read_ahead) {
393          long max;
394          max = sb->sb_buf.buf_size - sb->sb_buf.buf_end;
395          if (max>len) {
396             ret = sockbuf_io_read( sb, 
397                                      sb->sb_buf.buf_base +
398                                      sb->sb_buf.buf_end,
399                                         max );
400             if (ret<=0) {
401                /* some error occured */
402                goto do_return;
403             }
404             sb->sb_buf.buf_end += ret;
405             /* move out the data... */
406             len = sockbuf_copy_out( sb, &buf, len );
407             goto do_return;
408          }
409       }
410       /* no read_ahead, just try to put the data in the buf. */
411       ret = sockbuf_io_read( sb, buf, len );
412       if (ret>0) {
413          buf+=ret;
414          len-=ret;
415       }
416       /* we might as well return, since there is nothing to do... */
417 #ifdef USE_SASL     
418    }
419 #endif
420 do_return:
421    assert( status_is_ok(sb) );
422    if ((ret<=0) && (buf==buf_arg)) {
423       /* there was an error. */
424       return ret;
425    }
426    return (buf - ((char *) buf_arg));
427 }
428
429 #ifdef USE_SASL
430 long sockbuf_do_write( Sockbuf *sb )
431 {
432    long to_go;
433    to_go = sb->sb_sec_out.buf_end - sb->sb_sec_out.buf_ptr;
434    assert( to_go > 0 );
435    /* there is something left of the last time... */
436    ret = sockbuf_io_write( sb, sb->sb_sec_out.buf_base+
437                               sb->sb_sec_out.buf_ptr, to_go );
438    if (ret<=0) /* error */
439      return ret;
440    sb->sb_sec_out.buf_ptr += ret;
441    if (ret<to_go) /* not enough data, so pretend no data was sent. */
442      return -1;
443    return ret;
444 }
445 #endif
446
447 long lber_pvt_sb_write( Sockbuf *sb, void *buf, long len_arg )
448 {
449    long ret;
450    long len = len_arg;
451    assert( status_is_ok(sb) );
452 #if 0
453    /* unfortunately breaks slapd */
454    assert( lber_pvt_sb_in_use( sb ) );
455 #endif   
456 #ifdef USE_SASL
457    if (sb->sb_sec) {
458       assert( sb->sb_sec_prev_len <= len );
459       if (sb->sb_sec_prev_len) {
460          ret = sockbuf_do_write( sb );
461          if (ret<=0)
462            return ret;
463          /* finished. */
464          len -= sb->sb_sec_prev_len;
465          sb->sb_sec_prev_len = 0;
466          sb->sb_sec_out.buf_end = sb->sb_sec_out.buf_ptr = 0;
467       }
468       /* now protect the next packet. */
469       ret = sockbuf_sec_protect( sb, buf, len );
470       if (ret<=0)
471         return ret;
472       ret = sockbuf_do_write( sb );
473       if (ret<=0) {
474          sb->sb_sec_prev_len = len;
475          return ret;
476       }
477       return len_arg;
478    } else {
479 #endif
480       return sockbuf_io_write( sb, buf, len );
481 #ifdef USE_SASL      
482    }
483 #endif
484 }
485      
486 int lber_pvt_sb_close( Sockbuf *sb )
487 {
488    int ret;
489    assert( sb->sb_io );
490    assert( sb->sb_io->sbi_close );
491    assert( status_is_ok(sb) );
492    assert( lber_pvt_sb_in_use( sb ) );
493    
494    ret = sb->sb_io->sbi_close( sb );
495    lber_pvt_sb_set_desc( sb, -1 );
496
497    return ret;
498 }
499
500 int lber_pvt_sb_set_readahead( Sockbuf *sb, int rh )
501 {
502    assert( status_is_ok(sb) );
503    sb->sb_read_ahead = (rh!=0);
504    return 0;
505 }
506
507 int lber_pvt_sb_set_nonblock( Sockbuf *sb, int nb )
508 {
509    assert( status_is_ok(sb) );
510    if (nb) {
511       sb->sb_non_block = 1;
512 #if 0      
513       sb->sb_read_ahead = 1;
514 #endif
515    } else {
516       sb->sb_non_block = 0;
517 #if 0
518       sb->sb_read_ahead = 0;
519 #endif
520    }
521    if (lber_pvt_sb_in_use(sb)) {
522       int status = (nb!=0);
523       if (ioctl( lber_pvt_sb_get_desc(sb), FIONBIO, (caddr_t)&status ) == -1 ) {
524          return -1;
525       }
526    }
527    return 0;
528 }
529          
530 #define sockbuf_buf_init( bb ) \
531 (bb)->buf_base=NULL;\
532 (bb)->buf_ptr = 0;\
533 (bb)->buf_end = 0;\
534 (bb)->buf_size = 0;
535
536 static int 
537 sockbuf_buf_destroy( Sockbuf_Buf *buf )
538 {
539    if (buf->buf_base)
540      free( buf->buf_base );
541    sockbuf_buf_init( buf );
542    return 0;
543 }
544
545 int lber_pvt_sb_init( Sockbuf *sb )
546 {
547    sb->sb_item_type=LBER_ITEM_SOCKBUF;
548    sb->sb_options = 0;
549    sb->sb_debug = 0;
550    sb->sb_trans_ready = 0;
551    sb->sb_buf_ready = 0;
552 #ifdef USE_SASL   
553    sb->sb_sec_ready = 0;
554 #endif   
555    sb->sb_read_ahead = 0;
556    sb->sb_non_block = 0;
557    sb->sb_fd = -1;
558    sb->sb_iodata = NULL;
559    sb->sb_io = &lber_pvt_sb_IO_None;
560    sb->sb_sd = -1;
561 #ifdef DEADWOOD   
562    sb->sb_max_incoming = 0;
563 #endif   
564    sockbuf_buf_init( &(sb->sb_buf) );
565 #ifdef USE_SASL
566    sockbuf_buf_init( &(sb->sb_sec_buf_in) );
567    sockbuf_buf_init( &(sb->sb_sec_buf_out) );
568    sb->sb_sdata = NULL;
569    sb->sb_sec = NULL;
570    sb->sb_sec_prev_len = 0;
571 #endif   
572    return 0;
573 }
574    
575 int lber_pvt_sb_destroy( Sockbuf *sb )
576 {
577 #ifdef USE_SASL
578    lber_pvt_sb_clear_sec(sb);
579    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
580    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
581 #endif
582    lber_pvt_sb_clear_io(sb);
583    sockbuf_buf_destroy( &(sb->sb_buf) );
584    return lber_pvt_sb_init( sb );
585 }
586
587 #ifdef USE_SASL
588 int lber_pvt_sb_set_sec( Sockbuf *sb, Sockbuf_Sec * sec, void *arg )
589 {
590    int len;
591    if ((sb->sb_sec) || (sec==NULL))
592      return -1;
593    
594    sb->sb_sec = sec;
595    
596    if ((sec->sbs_setup) && (sec->sbs_setup( sb, arg)<0)) {
597       return -1;
598    }
599    
600    len = sb->sb_buf.buf_end - sb->sb_buf.buf_ptr;
601    
602    if (len>0) {
603       /* move this to the security layer. */
604       if (grow_buffer( &(sb->sb_sec_buf_in), len )<0)
605         return -1;
606       memcpy( sb->sb_sec_buf_in.buf_base, 
607              sb->sb_buf.buf_base + sb->sb_buf.buf_ptr, len );
608       sb->sb_sec_buf_in.buf_ptr = len;
609       sb->sb_sec_buf_in.buf_end = (len>4) ? packet_length( sb->sb_sec_buf_in ) : 0;
610       sb->sb_buf.buf_ptr = sb->sb_buf.buf_end = 0;
611    }
612    update_status();
613    return 0;
614 }
615
616 int lber_pvt_sb_clear_sec( Sockbuf *sb )
617 {
618    if (sb->sb_buf.buf_ptr!=0)
619      return -1;
620    if (sb->sb_sec==NULL)
621      return -1;
622    if ((sb->sb_sec->sbs_remove) && (sb->sb_sec->sbs_remove(sb)<0)) 
623      return -1;
624    
625    sb->sb_sec = NULL;
626    if (sb->sb_sec_buf_in.buf_ptr!=0) {
627       if (grow_buffer( &(sb->sb_buf), 
628                       sb->sb_buf.buf_end + sb->sb_sec_buf_in.buf_ptr)<0)
629         return -1;
630       memcpy( sb->sb_buf.buf_base + sb->sb_buf.buf_end,
631               sb->sb_sec_buf_in.buf_base, sb->sb_sec_buf_in.buf_ptr );
632       sb->sb_buf.buf_end += sb->sb_sec_buf_in.buf_ptr;
633       sb->sb_buf_ready = 1;
634    }
635    sockbuf_buf_destroy( &(sb->sb_sec_buf_in) );
636    assert( sb->sb_sec_buf.buf_end==0 );
637    sockbuf_buf_destroy( &(sb->sb_sec_buf_out) );
638    
639    sb->sb_sec_ready = 0;
640    
641    return 0;
642 }
643 #endif
644
645 int lber_pvt_sb_set_io( Sockbuf *sb, Sockbuf_IO *trans, void *arg )
646 {
647    assert( sb->sb_io == &lber_pvt_sb_IO_None );
648
649    if (trans==NULL)
650      return -1;
651    
652    sb->sb_io = trans;
653    
654    if ((trans->sbi_setup) && (trans->sbi_setup( sb, arg)<0))
655      return -1;
656    
657    return 0;
658 }
659
660 int lber_pvt_sb_clear_io( Sockbuf *sb )
661 {
662    if (sb->sb_io==&lber_pvt_sb_IO_None)
663      return -1;
664    
665    if ((sb->sb_io->sbi_remove) && (sb->sb_io->sbi_remove( sb )<0))
666      return -1;
667
668    sb->sb_io = &lber_pvt_sb_IO_None;
669    
670    sb->sb_trans_ready = 0;
671    
672    return 0;
673 }
674
675 /*
676  * Support for TCP
677  */
678
679 static long
680 stream_read( Sockbuf *sb, void *buf, long len )
681 {
682 #if defined(MACOS)
683 /*
684  * MacTCP/OpenTransport
685  */
686    return tcpread( lber_pvt_sb_get_desc(sb), 0, (unsigned char *)buf, 
687                    len, NULL );
688 #elif (defined(DOS) && (defined(PCNFS) || defined( WINSOCK))) \
689         || defined( _WIN32)
690 /*
691  * PCNFS (under DOS)
692  */
693 /*
694  * Windows Socket API (under DOS/Windows 3.x)
695  */
696 /*
697  * 32-bit Windows Socket API (under Windows NT or Windows 95)
698  */
699    return recv( lber_pvt_sb_get_desc(sb), buf, len, 0 );
700 #elif (defined(DOS) && defined( NCSA ))
701 /*
702  * NCSA Telnet TCP/IP stack (under DOS)
703  */
704    return nread( lber_pvt_sb_get_desc(sb), buf, len );
705 #else
706    return read( lber_pvt_sb_get_desc(sb), buf, len );
707 #endif
708 }
709
710 static long
711 stream_write( Sockbuf *sb, void *buf, long len )
712 {
713 #if defined(MACOS) 
714 /*
715  * MacTCP/OpenTransport
716  */
717 #define MAX_WRITE       65535
718    return tcpwrite( lber_pvt_sb_get_desc(sb),
719                     (unsigned char *)(buf), 
720                     (len<MAX_WRITE)? len : MAX_WRITE );
721 #elif (defined(DOS) && (defined(PCNFS) || defined( WINSOCK))) \
722         || defined( _WIN32)
723 /*
724  * PCNFS (under DOS)
725  */
726 /*
727  * Windows Socket API (under DOS/Windows 3.x)
728  */
729 /*
730  * 32-bit Windows Socket API (under Windows NT or Windows 95)
731  */
732    return send( lber_pvt_sb_get_desc(sb), buf, len, 0 );
733 #elif defined(NCSA)
734    return netwrite( lber_pvt_sb_get_desc(sb), buf, len );
735 #elif defined(VMS)
736 /*
737  * VMS -- each write must be 64K or smaller
738  */
739 #define MAX_WRITE 65535
740    return write( lber_pvt_sb_get_desc(sb), buf, 
741                  (len<MAX_WRITE)? len : MAX_WRITE);
742 #else
743    return write( lber_pvt_sb_get_desc(sb), buf, len );
744 #endif   
745 }   
746    
747 static int 
748 stream_close( Sockbuf *sb )
749 {
750    tcp_close( lber_pvt_sb_get_desc( sb ) );
751    return 0;
752 }
753
754 Sockbuf_IO lber_pvt_sb_io_tcp=
755 {
756         NULL,   /* sbi_setup */
757         NULL,   /* sbi_release */
758         stream_read,    /* sbi_read */
759         stream_write,   /* sbi_write */
760         stream_close,   /* sbi_close */
761 };
762
763 /*
764  * Support for UDP (CLDAP)
765  */
766
767 struct dgram_data
768 {
769         struct sockaddr dst;
770         struct sockaddr src;
771 };
772
773 static int 
774 dgram_setup( Sockbuf *sb, void *arg )
775 {
776    sb->sb_iodata = malloc( sizeof( struct dgram_data ) );
777    if (sb->sb_iodata==NULL)
778      return -1;
779    sb->sb_read_ahead = 1; /* important since udp is packet based. */
780    return 0;
781 }
782
783 static int 
784 dgram_release( Sockbuf *sb )
785 {
786    free( sb->sb_iodata );
787    return 0;
788 }
789
790 static long
791 dgram_read( Sockbuf *sb, void *buf, long len )
792 {
793 #ifdef LDAP_CONNECTIONLESS
794    long rc;
795    int addrlen;
796    struct dgram_data *dd;
797    
798    dd = (struct dgram_data *)(sb->sb_iodata);
799    
800 # if !defined( MACOS) && !defined(DOS) && !defined( _WIN32)
801    addrlen = sizeof( struct sockaddr );
802    rc=recvfrom( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->src), &addrlen );
803 # else
804    UDP not supported
805 # endif
806    
807    if ( sb->sb_debug ) {
808       lber_log_printf( LDAP_DEBUG_ANY, sb->sb_debug,
809                       "dgram_read udp_read %d bytes\n",
810                       rc );
811       if ( rc > 0 )
812         lber_log_bprint( LDAP_DEBUG_PACKETS, sb->sb_debug,
813                         buf, rc );
814    }
815    return rc;
816 # else /* LDAP_CONNECTIONLESS */
817    return -1;
818 # endif /* LDAP_CONNECTIONLESS */
819 }
820
821 static long 
822 dgram_write( Sockbuf *sb, void *buf, long len )
823 {
824 #ifdef LDAP_CONNECTIONLESS
825    int rc;
826    struct dgram_data *dd;
827    
828    dd = (struct dgram_data *)(sb->sb_iodata);
829    
830 # if !defined( MACOS) && !defined(DOS) && !defined( _WIN32)
831    rc=sendto( lber_pvt_sb_get_desc(sb), buf, len, 0, &(dd->dst),
832              sizeof( struct sockaddr ) );
833 # else
834    UDP not supported
835 # endif
836      if ( rc <= 0 )
837        return( -1 );
838    
839    /* fake error if write was not atomic */
840    if (rc < len) {
841 # ifdef EMSGSIZE
842       errno = EMSGSIZE;
843 # endif
844       return( -1 );
845    }
846    return rc;
847 #else
848    return -1;
849 #endif  
850 }
851
852 static int 
853 dgram_close( Sockbuf *sb )
854 {
855         tcp_close( lber_pvt_sb_get_desc(sb) );
856         return 0;
857 }
858
859 Sockbuf_IO lber_pvt_sb_io_udp=
860 {
861         dgram_setup,    /* sbi_setup */
862         dgram_release,  /* sbi_release */
863         dgram_read,     /* sbi_read */
864         dgram_write,    /* sbi_write */
865         dgram_close,    /* sbi_close */
866 };
867
868 int lber_pvt_sb_udp_set_dst(Sockbuf *sb, void *addr )
869 {
870    struct dgram_data *dd;
871    assert( sb->sb_io == &lber_pvt_sb_io_udp );
872    dd = (struct dgram_data *) (sb->sb_iodata);
873    memcpy( &(dd->dst), addr, sizeof( struct sockaddr ) );
874    return 0;
875 }
876
877 void *lber_pvt_sb_udp_get_src( Sockbuf *sb )
878 {
879    struct dgram_data *dd;
880    assert( sb->sb_io == &lber_pvt_sb_io_udp );
881    dd = (struct dgram_data *) (sb->sb_iodata);
882    return &(dd->src);
883 }
884
885 /*
886  * debug routines.
887  * 
888  * BUGS:
889  * These routines should really call abort, but at the moment that would
890  * break the servers.
891  */
892
893 static long
894 have_no_read( Sockbuf *sb, void *buf, long len )
895 {
896    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
897                    "warning: reading from uninitialized sockbuf\n");
898    errno =  EBADF;
899    return -1;
900 }
901
902 static long
903 have_no_write( Sockbuf *sb, void *buf, long len )
904 {
905    lber_log_printf( LDAP_DEBUG_ANY, lber_int_debug,
906                    "warning: writing to uninitialized sockbuf\n");
907    errno =  EBADF;
908    return -1;
909 }
910
911 static int 
912 have_no_close( Sockbuf *sb )
913 {   
914    assert( 0 );
915    return -1;
916 }