URI: 
       optimize binary file transfers: use sendfile(2) syscall if supported - geomyidae - A small C-based gopherd.
  HTML git clone git://bitreich.org/geomyidae/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/geomyidae/
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
   DIR LICENSE
       ---
   DIR commit d8b18c7bfa0d75f38bbceefde217c83813473e5f
   DIR parent 1c6dfdef1faabdb80161e5490526491e2a02c28c
  HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       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 <20h@r-36.net>
       
       Diffstat:
         M handlr.c                            |      14 +++-----------
         M ind.c                               |      68 +++++++++++++++++++++++++++++++
         M ind.h                               |       1 +
       
       3 files changed, 72 insertions(+), 11 deletions(-)
       ---
   DIR 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, char *args,
        
                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);
                }
        }
   DIR 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)
        {
   DIR 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);