Diff for /embedaddon/lighttpd/src/network_solaris_sendfilev.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2013/10/14 10:32:48 version 1.1.1.2, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "network_backends.h"  #include "network_backends.h"
   
#ifdef USE_SOLARIS_SENDFILEV#if defined(USE_SOLARIS_SENDFILEV)
   
 #include "network.h"  #include "network.h"
 #include "fdevent.h"  
 #include "log.h"  #include "log.h"
 #include "stat_cache.h"  
   
#include <sys/types.h>#include <sys/sendfile.h>
#include <sys/socket.h> 
#include <sys/stat.h> 
#include <sys/time.h> 
#include <sys/resource.h> 
   
 #include <netinet/in.h>  
 #include <netinet/tcp.h>  
   
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  
 #include <unistd.h>  
 #include <netdb.h>  
 #include <string.h>  #include <string.h>
 #include <stdlib.h>  
 #include <limits.h>  
   
 #ifndef UIO_MAXIOV  
 # define UIO_MAXIOV IOV_MAX  
 #endif  
   
 /**  /**
  * a very simple sendfilev() interface for solaris which can be optimised a lot more   * a very simple sendfilev() interface for solaris which can be optimised a lot more
  * as solaris sendfilev() supports 'sending everythin in one syscall()'   * as solaris sendfilev() supports 'sending everythin in one syscall()'
  *  
  * If you want such an interface and need the performance, just give me an account on  
  * a solaris box.  
  *   - jan@kneschke.de  
  */   */
   
   int network_write_file_chunk_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) {
           chunk* const c = cq->first;
           off_t offset;
           off_t toSend;
           size_t written = 0;
           int r;
           sendfilevec_t fvec;
   
int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {        force_assert(NULL != c);
        chunk *c;        force_assert(FILE_CHUNK == c->type);
         force_assert(c->offset >= 0 && c->offset <= c->file.length);
   
        for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {        offset = c->file.start + c->offset;
                int chunk_finished = 0;        toSend = c->file.length - c->offset;
         if (toSend > *p_max_bytes) toSend = *p_max_bytes;
   
                switch(c->type) {        if (0 == toSend) {
                case MEM_CHUNK: {                chunkqueue_remove_finished_chunks(cq);
                        char * offset;                return 0;
                        off_t toSend;        }
                        ssize_t r; 
   
                        size_t num_chunks, i;        if (0 != network_open_file_chunk(srv, con, cq)) return -1;
                        struct iovec chunks[UIO_MAXIOV]; 
                        chunk *tc; 
   
                        size_t num_bytes = 0;        fvec.sfv_fd = c->file.fd;
         fvec.sfv_flag = 0;
         fvec.sfv_off = offset;
         fvec.sfv_len = toSend;
   
                        /* we can't send more then SSIZE_MAX bytes in one chunk */        /* Solaris sendfilev() */
   
                        /* build writev list        if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
                         *                switch(errno) {
                         * 1. limit: num_chunks < UIO_MAXIOV                case EAGAIN:
                         * 2. limit: num_bytes < SSIZE_MAX                case EINTR:
                         */                        /* for EAGAIN/EINTR written still contains the sent bytes */
                        for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);                        break; /* try again later */
                case EPIPE:
                        for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {                case ENOTCONN:
                                if (tc->mem->used == 0) {                        return -2;
                                        chunks[i].iov_base = tc->mem->ptr;                case EINVAL:
                                        chunks[i].iov_len  = 0;                case ENOSYS:
                                } else {              #if defined(ENOTSUP) \
                                        offset = tc->mem->ptr + tc->offset;                && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP)
                                        toSend = tc->mem->used - 1 - tc->offset;                case ENOTSUP:
              #endif
                                        chunks[i].iov_base = offset;              #ifdef EOPNOTSUPP
                case EOPNOTSUPP:
                                        /* protect the return value of writev() */              #endif
                                        if (toSend > max_bytes ||              #ifdef ESOCKTNOSUPPORT
                                            (off_t) num_bytes + toSend > max_bytes) {                case ESOCKTNOSUPPORT:
                                                chunks[i].iov_len = max_bytes - num_bytes;              #endif
              #ifdef EAFNOSUPPORT
                                                num_chunks = i + 1;                case EAFNOSUPPORT:
                                                break;              #endif
                                        } else {                      #ifdef USE_MMAP
                                                chunks[i].iov_len = toSend;                        return network_write_file_chunk_mmap(srv, con, fd, cq, p_max_bytes);
                                        }                      #else
                        return network_write_file_chunk_no_mmap(srv, con, fd, cq, p_max_bytes);
                                        num_bytes += toSend;                      #endif
                                } 
                        } 
 
                        if ((r = writev(fd, chunks, num_chunks)) < 0) { 
                                switch (errno) { 
                                case EAGAIN: 
                                case EINTR: 
                                        r = 0; 
                                        break; 
                                case EPIPE: 
                                case ECONNRESET: 
                                        return -2; 
                                default: 
                                        log_error_write(srv, __FILE__, __LINE__, "ssd", 
                                                        "writev failed:", strerror(errno), fd); 
 
                                        return -1; 
                                } 
                        } 
 
                        /* check which chunks have been written */ 
                        cq->bytes_out += r; 
 
                        for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { 
                                if (r >= (ssize_t)chunks[i].iov_len) { 
                                        /* written */ 
                                        r -= chunks[i].iov_len; 
                                        tc->offset += chunks[i].iov_len; 
 
                                        if (chunk_finished) { 
                                                /* skip the chunks from further touches */ 
                                                c = c->next; 
                                        } else { 
                                                /* chunks_written + c = c->next is done in the for()*/ 
                                                chunk_finished = 1; 
                                        } 
                                } else { 
                                        /* partially written */ 
 
                                        tc->offset += r; 
                                        chunk_finished = 0; 
 
                                        break; 
                                } 
                        } 
 
                        break; 
                } 
                case FILE_CHUNK: { 
                        ssize_t r; 
                        off_t offset, toSend; 
                        size_t written; 
                        sendfilevec_t fvec; 
                        stat_cache_entry *sce = NULL; 
                        int ifd; 
 
                        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { 
                                log_error_write(srv, __FILE__, __LINE__, "sb", 
                                                strerror(errno), c->file.name); 
                                return -1; 
                        } 
 
                        offset = c->file.start + c->offset; 
                        toSend = c->file.length - c->offset; 
                        if (toSend > max_bytes) toSend = max_bytes; 
 
                        if (offset > sce->st.st_size) { 
                                log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); 
 
                                return -1; 
                        } 
 
                        if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { 
                                log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); 
 
                                return -1; 
                        } 
 
                        fvec.sfv_fd = ifd; 
                        fvec.sfv_flag = 0; 
                        fvec.sfv_off = offset; 
                        fvec.sfv_len = toSend; 
 
                        /* Solaris sendfilev() */ 
                        if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) { 
                                if (errno != EAGAIN) { 
                                        log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno); 
 
                                        close(ifd); 
                                        return -1; 
                                } 
 
                                r = 0; 
                        } 
 
                        close(ifd); 
                        c->offset += written; 
                        cq->bytes_out += written; 
                        max_bytes -= written; 
 
                        if (c->offset == c->file.length) { 
                                chunk_finished = 1; 
                        } 
 
                        break; 
                } 
                 default:                  default:
                        log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
                        log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); 
 
                         return -1;                          return -1;
                 }                  }
           }
   
                if (!chunk_finished) {        if (written >= 0) {
                        /* not finished yet */                chunkqueue_mark_written(cq, written);
                *p_max_bytes -= written;
                        break; 
                } 
         }          }
   
        return 0;        return (r >= 0 && (off_t) written == toSend) ? 0 : -3;
 }  }
   
#endif#endif /* USE_SOLARIS_SENDFILEV */

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>