| optimize binary file transfers: use sendfile(2) syscall if supported - geomyida… | |
| git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfri… | |
| Log | |
| Files | |
| Refs | |
| Tags | |
| README | |
| LICENSE | |
| --- | |
| commit d8b18c7bfa0d75f38bbceefde217c83813473e5f | |
| parent 1c6dfdef1faabdb80161e5490526491e2a02c28c | |
| Author: Hiltjo Posthuma <[email protected]> | |
| Date: Sat, 23 Sep 2017 16:08:28 +0200 | |
| optimize binary file transfers: use sendfile(2) syscall if supported | |
| The OS supporting sendfile(2) are (for now): Linux, FreeBSD, DragonFlyBSD. | |
| When the file is empty or has no filesize information (such as block, | |
| character devices etc) fallback to the normal read/write loop in userland. | |
| A platform with no sendfile(2) support always uses this loop. | |
| Optimize the buffer size in the normal read/write loop by using the block size | |
| information, fallback to BUFSIZ. | |
| Set socket options TCP_CORK (Linux), TCP_NOPUSH (BSDs) and TCP_NODELAY to | |
| optimize packet transfers for large file transfers. | |
| Tested on Linux (glibc and musl), FreeBSD, DragonFlyBSD and OpenBSD. | |
| Signed-off-by: Christoph Lohmann <[email protected]> | |
| Diffstat: | |
| M handlr.c | 14 +++----------- | |
| M ind.c | 68 +++++++++++++++++++++++++++++… | |
| M ind.h | 1 + | |
| 3 files changed, 72 insertions(+), 11 deletions(-) | |
| --- | |
| diff --git a/handlr.c b/handlr.c | |
| @@ -104,8 +104,7 @@ void | |
| handlebin(int sock, char *file, char *port, char *base, char *args, | |
| char *sear, char *ohost) | |
| { | |
| - char sendb[1024]; | |
| - int len, fd, sent; | |
| + int fd; | |
| USED(port); | |
| USED(base); | |
| @@ -115,15 +114,8 @@ handlebin(int sock, char *file, char *port, char *base, ch… | |
| fd = open(file, O_RDONLY); | |
| if(fd >= 0) { | |
| - while((len = read(fd, sendb, sizeof(sendb))) > 0) { | |
| - while(len > 0) { | |
| - if ((sent = send(sock, sendb, len, 0)) < 0) { | |
| - close(fd); | |
| - return; | |
| - } | |
| - len -= sent; | |
| - } | |
| - } | |
| + if(xsendfile(fd, sock) < 0) | |
| + perror("sendfile"); | |
| close(fd); | |
| } | |
| } | |
| diff --git a/ind.c b/ind.c | |
| @@ -12,9 +12,19 @@ | |
| #include <stdlib.h> | |
| #include <netdb.h> | |
| #include <sys/socket.h> | |
| +#include <sys/stat.h> | |
| #include <netinet/in.h> | |
| +#include <netinet/tcp.h> | |
| #include <arpa/inet.h> | |
| +/* for sendfile(2) */ | |
| +#ifdef __linux__ | |
| +#include <sys/sendfile.h> | |
| +#elif defined(__FreeBSD__) || defined(__DragonFly__) | |
| +#include <sys/types.h> | |
| +#include <sys/uio.h> | |
| +#endif | |
| + | |
| #include "ind.h" | |
| #include "handlr.h" | |
| @@ -42,6 +52,64 @@ filetype type[] = { | |
| {nil, nil, nil}, | |
| }; | |
| +int | |
| +xsendfile(int fd, int sock) | |
| +{ | |
| + struct stat st; | |
| + char *sendb; | |
| + size_t bufsiz = BUFSIZ, count = 0; | |
| + int len, sent, optval; | |
| + | |
| +#ifdef TCP_CORK | |
| + optval = 1; | |
| + setsockopt(sock, IPPROTO_TCP, TCP_CORK, &optval, sizeof(int)); | |
| +#endif | |
| + | |
| +#ifdef TCP_NOPUSH | |
| + optval = 1; | |
| + setsockopt(sock, IPPROTO_TCP, TCP_NOPUSH, &optval, sizeof(int)); | |
| +#endif | |
| + | |
| +#ifdef TCP_NODELAY | |
| + optval = 0; | |
| + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(int)); | |
| +#endif | |
| + | |
| + if(fstat(fd, &st) >= 0) { | |
| + if((bufsiz = st.st_blksize) < BUFSIZ) | |
| + bufsiz = BUFSIZ; | |
| + count = st.st_size; | |
| + } | |
| + | |
| +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__DragonFly__) | |
| + count = 0; | |
| +#endif | |
| + | |
| + if (count == 0) { | |
| + sendb = xmalloc(bufsiz); | |
| + while((len = read(fd, sendb, bufsiz)) > 0) { | |
| + while(len > 0) { | |
| + if ((sent = send(sock, sendb, len, 0)) < 0) { | |
| + close(fd); | |
| + free(sendb); | |
| + return -1; | |
| + } | |
| + len -= sent; | |
| + } | |
| + } | |
| + free(sendb); | |
| + return 0; | |
| + } | |
| + | |
| +#ifdef __linux__ | |
| + return sendfile(sock, fd, NULL, count); | |
| +#endif | |
| +#if defined(__FreeBSD__) || defined(__DragonFly__) | |
| + return sendfile(fd, sock, 0, count, NULL, NULL, 0); | |
| +#endif | |
| + return -1; | |
| +} | |
| + | |
| void * | |
| xcalloc(size_t nmemb, size_t size) | |
| { | |
| diff --git a/ind.h b/ind.h | |
| @@ -35,6 +35,7 @@ void *xcalloc(size_t, size_t); | |
| void *xmalloc(size_t); | |
| void *xrealloc(void *, size_t); | |
| char *xstrdup(const char *str); | |
| +int xsendfile(int, int); | |
| Indexs *scanfile(char *fname); | |
| Elems *getadv(char *str); | |
| int printelem(int fd, Elems *el, char *addr, char *port); |