File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / network_solaris_sendfilev.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:48 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, v1_4_33, HEAD
1.4.33

    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>