Annotation of embedaddon/lighttpd/src/network_solaris_sendfilev.c, revision 1.1.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>