#include "havebsdsf.h" #ifdef HAVE_BSDSENDFILE /* for MacOS X. Yep, they blew it again. */ #define SENDFILE 1 #endif #include #include #include #include #include #include #include #include #include "havealloca.h" #include "iob_internal.h" int64 iob_send(int64 s,io_batch* b) { iob_entry* e,* last; struct iovec* v; int64 total,sent; long i; long headers; #ifdef HAVE_BSDSENDFILE long trailers; #endif if (b->bytesleft==0) return 0; last=(iob_entry*)(((char*)array_start(&b->b))+array_bytes(&b->b)); v=alloca(b->bufs*sizeof(struct iovec)); total=0; for (;;) { if (!(e=array_get(&b->b,sizeof(iob_entry),b->next))) return -3; /* can't happen error */ #ifdef HAVE_BSDSENDFILE /* BSD sendfile can send headers and trailers. If we run on BSD, we * should try to exploit this. */ headers=trailers=0; #endif for (i=0; e+ibytesleft; else if (r==-1 && errno==EAGAIN) { if (!(sent=sbytes)) { sent=-1; goto eagain; } } else sent=-3; } else { if (headers==1) /* cosmetics for strace */ sent=write(s,v[0].iov_base,v[0].iov_len); else sent=writev(s,v,headers); if (sent==-1) { if (errno!=EAGAIN) sent=-3; else { eagain: io_eagain(s); return -1; } } } #else #ifdef TCP_CORK if (b->bufs && b->files && !b->next) { static int one=1; setsockopt(s,IPPROTO_TCP,TCP_CORK,&one,sizeof(one)); } #endif if (headers) { if (headers==1) /* cosmetics for strace */ sent=write(s,v[0].iov_base,v[0].iov_len); else sent=writev(s,v,headers); if (sent==-1) { if (errno==EAGAIN) { io_eagain(s); return -1; } sent=-3; } } else sent=io_sendfile(s,e->fd,e->offset,e->n); #endif if (sent>0) total+=sent; else return total?total:sent; if (sent==b->bytesleft) { #ifdef TCP_CORK if (b->bufs && b->files) { static int zero=0; setsockopt(s,IPPROTO_TCP,TCP_CORK,&zero,sizeof(zero)); } #endif iob_reset(b); break; } else if (sent>0) { int64 rest=sent; b->bytesleft-=rest; for (i=0; e+inext; if (!rest) break; } else { e[i].offset+=rest; e[i].n-=rest; goto abort; } } } else break; } abort: return total; }