#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #define BSD_SENDFILE #endif #include #include #include #include #include #include #ifdef __linux__ #include #endif #include "iob_internal.h" int64 iob_send(int64 s,io_batch* b) { io_entry* e,* last; struct iovec* v; int64 total,sent; long i; long headers; #ifdef BSD_SENDFILE long trailers; #endif if (b->bytesleft==0) return 0; last=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(io_entry),b->next))) return -3; /* can't happen error */ #ifdef BSD_SENDFILE /* 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; else sent=-3; } else { sent=writev(s,v,headers); if (sent==-1 && errno!=EAGAIN) sent=-3; } #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) { sent=writev(s,v,headers); if (sent==-1 && errno==EAGAIN) 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) { b->bytesleft=0; #ifdef TCP_CORK if (b->bufs && b->files) { static int zero=0; setsockopt(s,IPPROTO_TCP,TCP_CORK,&zero,sizeof(zero)); } #endif break; } else if (sent>0) { int64 rest=sent; b->bytesleft-=rest; for (i=0; e+inext; if (!rest) break; } else { e[i].offset+=rest; goto abort; } } } else break; } abort: return total; }