@ -0,0 +1,89 @@ | |||
#include <io_internal.h> | |||
#include <iob.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <sys/mman.h> | |||
#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 && off<e->mapofs+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,(bytes<BUFSIZE)?bytes:BUFSIZE))<=0) | |||
return (sent?sent:-1); | |||
while (n>0) { | |||
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; | |||
} |
@ -0,0 +1,27 @@ | |||
.TH iob_write 3 | |||
.SH NAME | |||
iob_write \- send I/O batch through callback | |||
.SH SYNTAX | |||
.B #include <iob.h> | |||
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) |
@ -0,0 +1,36 @@ | |||
#include <iob_internal.h> | |||
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<last; ++i) { | |||
if (!e[i].n) continue; | |||
if (e[i].type==FROMFILE || e[i].type==FROMFILE_CLOSE) | |||
sent=io_mmapwritefile(s,e[i].fd,e[i].offset,e[i].n,cb); | |||
else | |||
sent=cb(s,e[i].buf+e[i].offset,e[i].n); | |||
if (sent > 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; | |||
} |