From 86cfc33dab72e45526e5b93a48143e627162aa59 Mon Sep 17 00:00:00 2001 From: leitner Date: Thu, 25 Nov 2004 23:01:44 +0000 Subject: [PATCH] add iob_write (send io batch through callback, e.g. for SSL) --- CHANGES | 1 + io/io_mmapwritefile.c | 89 +++++++++++++++++++++++++++++++++++++++++++ io/iob_write.3 | 27 +++++++++++++ io/iob_write.c | 36 +++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 io/io_mmapwritefile.c create mode 100644 io/iob_write.3 create mode 100644 io/iob_write.c diff --git a/CHANGES b/CHANGES index 79f047f..da3ba21 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ int -> long for sizes char -> unsigned char for strings buffer_getline is now a function, not a macro + add iob_write (send io batch through callback, e.g. for SSL) 0.20: add errmsg API diff --git a/io/io_mmapwritefile.c b/io/io_mmapwritefile.c new file mode 100644 index 0000000..9b0d62a --- /dev/null +++ b/io/io_mmapwritefile.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include + +#define BUFSIZE 16384 + +int64 io_mmapwritefile(int64 out,int64 in,uint64 off,uint64 bytes,io_write_callback writecb) { + char buf[BUFSIZE]; + int n,m; + uint64 sent=0; + io_entry* e=array_get(&io_fds,sizeof(io_entry),out); + if (e) { + const char* c; + long left; + do { + if (e->mmapped) { + /* did we already map the right chunk? */ + if (off>=e->mapofs && offmapofs+e->maplen) + goto mapok; /* ok; mmapped the right chunk*/ + munmap(e->mmapped,e->maplen); + } + e->mapofs=off&0xffffffffffff0000ull; + if (e->mapofs+0x10000>off+bytes) + e->maplen=off+bytes-e->mapofs; + else + e->maplen=0x10000; + if ((e->mmapped=mmap(0,e->maplen,PROT_READ,MAP_SHARED,in,e->mapofs))==MAP_FAILED) { + e->mmapped=0; + goto readwrite; + } + mapok: + c=(const char*)(e->mmapped)+(off&0xffff); + left=e->maplen-(off&0xffff); + if (left>bytes) left=bytes; + while (left>0) { + m=writecb(out,c,left); + if (m==-1) { + e->canwrite=0; + e->next_write=-1; + if (errno!=EAGAIN) { + munmap(e->mmapped,e->maplen); + e->mmapped=0; + return -3; + } + return sent?sent:-1; + } + if (m==0) return sent; + sent+=m; + left-=m; + bytes-=m; + off+=m; + c+=m; + } + } while (bytes); + if (e->mmapped) { + munmap(e->mmapped,e->maplen); + e->mmapped=0; + } + return sent; + } +readwrite: + if (lseek(in,off,SEEK_SET) != off) + return -1; + while (bytes>0) { + char* tmp=buf; + if ((n=read(in,tmp,(bytes0) { + if ((m=writecb(out,tmp,n))<0) { + if (m==-1) { + if (e) { + e->canwrite=0; + e->next_write=-1; + } + return errno==EAGAIN?(sent?sent:-1):-3; + } + goto abort; + } + sent+=m; + n-=m; + bytes-=m; + tmp+=m; + } + } +abort: + return sent; +} diff --git a/io/iob_write.3 b/io/iob_write.3 new file mode 100644 index 0000000..56161cd --- /dev/null +++ b/io/iob_write.3 @@ -0,0 +1,27 @@ +.TH iob_write 3 +.SH NAME +iob_write \- send I/O batch through callback +.SH SYNTAX +.B #include + +int64 \fBiob_write\fR(int64 s,io_batch* b,io_write_callback cb); +.SH DESCRIPTION +iob_write sends the (rest of) \fIb\fR through the callback \fIcb\fR, +passing \fIs\fR as first argument. \fIcb\fR is expected to behave like +io_trywrite(2). + +This interface is intended to send an I/O batch through a filter, for +example to encrypt or compress it. If you just want to send an I/O +batch to a socket, use iob_send instead. + +iob_write returns the number of bytes written, 0 if there were no more +bytes to be written in the batch, -1 for EAGAIN, or -3 for a permanent +error (for example "connection reset by peer"). + +The normal usage pattern is using io_wait to know when a descriptor is +writable, and then calling iob_write until it returns 0, -1 or -3. + +If it returns 0, terminate the loop (everything was written OK). If it +returns -1, call io_wait again. If it returned -3, signal an error. +.SH "SEE ALSO" +iob_send(3) diff --git a/io/iob_write.c b/io/iob_write.c new file mode 100644 index 0000000..025762d --- /dev/null +++ b/io/iob_write.c @@ -0,0 +1,36 @@ +#include + +int64 iob_write(int64 s,io_batch* b,io_write_callback cb) { + iob_entry* e,* last; + int64 total,sent; + long i; + int thatsit; + + if (b->bytesleft==0) return 0; + last=(iob_entry*)(((char*)array_start(&b->b))+array_bytes(&b->b)); + total=0; + if (!(e=array_get(&b->b,sizeof(iob_entry),b->next))) + return -3; /* can't happen error */ + thatsit=0; + for (i=0; e+i e[i].n) sent=e[i].n; /* can't happen */ + thatsit=(sent != e[i].n); + if (sent==-1 && errno!=EAGAIN) + sent=-3; + if (sent>0) { + e[i].offset+=sent; + e[i].n-=sent; + total+=sent; + } else + return total?total:sent; + if (thatsit) break; + } + if (total == b->bytesleft) + iob_reset(b); + return total; +}