Annotation of embedaddon/lighttpd/src/network_solaris_sendfilev.c, revision 1.1
1.1 ! misho 1: #include "network_backends.h"
! 2:
! 3: #ifdef USE_SOLARIS_SENDFILEV
! 4:
! 5: #include "network.h"
! 6: #include "fdevent.h"
! 7: #include "log.h"
! 8: #include "stat_cache.h"
! 9:
! 10: #include <sys/types.h>
! 11: #include <sys/socket.h>
! 12: #include <sys/stat.h>
! 13: #include <sys/time.h>
! 14: #include <sys/resource.h>
! 15:
! 16: #include <netinet/in.h>
! 17: #include <netinet/tcp.h>
! 18:
! 19: #include <errno.h>
! 20: #include <fcntl.h>
! 21: #include <unistd.h>
! 22: #include <netdb.h>
! 23: #include <string.h>
! 24: #include <stdlib.h>
! 25: #include <limits.h>
! 26:
! 27: #ifndef UIO_MAXIOV
! 28: # define UIO_MAXIOV IOV_MAX
! 29: #endif
! 30:
! 31: /**
! 32: * a very simple sendfilev() interface for solaris which can be optimised a lot more
! 33: * as solaris sendfilev() supports 'sending everythin in one syscall()'
! 34: *
! 35: * If you want such an interface and need the performance, just give me an account on
! 36: * a solaris box.
! 37: * - jan@kneschke.de
! 38: */
! 39:
! 40:
! 41: int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
! 42: chunk *c;
! 43:
! 44: for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
! 45: int chunk_finished = 0;
! 46:
! 47: switch(c->type) {
! 48: case MEM_CHUNK: {
! 49: char * offset;
! 50: off_t toSend;
! 51: ssize_t r;
! 52:
! 53: size_t num_chunks, i;
! 54: struct iovec chunks[UIO_MAXIOV];
! 55: chunk *tc;
! 56:
! 57: size_t num_bytes = 0;
! 58:
! 59: /* we can't send more then SSIZE_MAX bytes in one chunk */
! 60:
! 61: /* build writev list
! 62: *
! 63: * 1. limit: num_chunks < UIO_MAXIOV
! 64: * 2. limit: num_bytes < SSIZE_MAX
! 65: */
! 66: for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
! 67:
! 68: for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
! 69: if (tc->mem->used == 0) {
! 70: chunks[i].iov_base = tc->mem->ptr;
! 71: chunks[i].iov_len = 0;
! 72: } else {
! 73: offset = tc->mem->ptr + tc->offset;
! 74: toSend = tc->mem->used - 1 - tc->offset;
! 75:
! 76: chunks[i].iov_base = offset;
! 77:
! 78: /* protect the return value of writev() */
! 79: if (toSend > max_bytes ||
! 80: (off_t) num_bytes + toSend > max_bytes) {
! 81: chunks[i].iov_len = max_bytes - num_bytes;
! 82:
! 83: num_chunks = i + 1;
! 84: break;
! 85: } else {
! 86: chunks[i].iov_len = toSend;
! 87: }
! 88:
! 89: num_bytes += toSend;
! 90: }
! 91: }
! 92:
! 93: if ((r = writev(fd, chunks, num_chunks)) < 0) {
! 94: switch (errno) {
! 95: case EAGAIN:
! 96: case EINTR:
! 97: r = 0;
! 98: break;
! 99: case EPIPE:
! 100: case ECONNRESET:
! 101: return -2;
! 102: default:
! 103: log_error_write(srv, __FILE__, __LINE__, "ssd",
! 104: "writev failed:", strerror(errno), fd);
! 105:
! 106: return -1;
! 107: }
! 108: }
! 109:
! 110: /* check which chunks have been written */
! 111: cq->bytes_out += r;
! 112:
! 113: for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
! 114: if (r >= (ssize_t)chunks[i].iov_len) {
! 115: /* written */
! 116: r -= chunks[i].iov_len;
! 117: tc->offset += chunks[i].iov_len;
! 118:
! 119: if (chunk_finished) {
! 120: /* skip the chunks from further touches */
! 121: c = c->next;
! 122: } else {
! 123: /* chunks_written + c = c->next is done in the for()*/
! 124: chunk_finished = 1;
! 125: }
! 126: } else {
! 127: /* partially written */
! 128:
! 129: tc->offset += r;
! 130: chunk_finished = 0;
! 131:
! 132: break;
! 133: }
! 134: }
! 135:
! 136: break;
! 137: }
! 138: case FILE_CHUNK: {
! 139: ssize_t r;
! 140: off_t offset, toSend;
! 141: size_t written;
! 142: sendfilevec_t fvec;
! 143: stat_cache_entry *sce = NULL;
! 144: int ifd;
! 145:
! 146: if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
! 147: log_error_write(srv, __FILE__, __LINE__, "sb",
! 148: strerror(errno), c->file.name);
! 149: return -1;
! 150: }
! 151:
! 152: offset = c->file.start + c->offset;
! 153: toSend = c->file.length - c->offset;
! 154: if (toSend > max_bytes) toSend = max_bytes;
! 155:
! 156: if (offset > sce->st.st_size) {
! 157: log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
! 158:
! 159: return -1;
! 160: }
! 161:
! 162: if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
! 163: log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
! 164:
! 165: return -1;
! 166: }
! 167:
! 168: fvec.sfv_fd = ifd;
! 169: fvec.sfv_flag = 0;
! 170: fvec.sfv_off = offset;
! 171: fvec.sfv_len = toSend;
! 172:
! 173: /* Solaris sendfilev() */
! 174: if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
! 175: if (errno != EAGAIN) {
! 176: log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
! 177:
! 178: close(ifd);
! 179: return -1;
! 180: }
! 181:
! 182: r = 0;
! 183: }
! 184:
! 185: close(ifd);
! 186: c->offset += written;
! 187: cq->bytes_out += written;
! 188: max_bytes -= written;
! 189:
! 190: if (c->offset == c->file.length) {
! 191: chunk_finished = 1;
! 192: }
! 193:
! 194: break;
! 195: }
! 196: default:
! 197:
! 198: log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
! 199:
! 200: return -1;
! 201: }
! 202:
! 203: if (!chunk_finished) {
! 204: /* not finished yet */
! 205:
! 206: break;
! 207: }
! 208: }
! 209:
! 210: return 0;
! 211: }
! 212:
! 213: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>