Browse Source

add iob_write (send io batch through callback, e.g. for SSL)

master
Felix von Leitner 17 years ago
parent
commit
f2d7a6b264
  1. 1
      CHANGES
  2. 89
      io/io_mmapwritefile.c
  3. 27
      io/iob_write.3
  4. 36
      io/iob_write.c

1
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

89
io/io_mmapwritefile.c

@ -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;
}

27
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 <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)

36
io/iob_write.c

@ -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;
}
Loading…
Cancel
Save