Browse Source

open files only once for chunk, cache mmap and let the chunk itself close the fd (fixed #261, #257)

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@703 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.6
Jan Kneschke 17 years ago
parent
commit
63dceeb0c6
  1. 66
      src/chunk.c
  2. 30
      src/chunk.h
  3. 54
      src/connections.c
  4. 19
      src/mod_fastcgi.c
  5. 39
      src/network_linux_sendfile.c
  6. 22
      src/network_write.c
  7. 110
      src/network_writev.c

66
src/chunk.c

@ -6,6 +6,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
@ -35,8 +36,10 @@ static chunk *chunk_init(void) {
c = calloc(1, sizeof(*c));
/* c->mem overlaps with c->data.file.name */
c->data.mem = buffer_init();
c->mem = buffer_init();
c->file.name = buffer_init();
c->file.fd = -1;
c->file.mmap.start = MAP_FAILED;
c->next = NULL;
return c;
@ -45,24 +48,25 @@ static chunk *chunk_init(void) {
static void chunk_free(chunk *c) {
if (!c) return;
/* c->data.mem overlaps with c->data.file.name */
switch (c->type) {
case MEM_CHUNK: buffer_free(c->data.mem); break;
case FILE_CHUNK: buffer_free(c->data.file.name); break;
default: break;
}
buffer_free(c->mem);
buffer_free(c->file.name);
free(c);
}
static void chunk_reset(chunk *c) {
if (!c) return;
/* c->data.mem overlaps with c->data.file.name */
switch (c->type) {
case MEM_CHUNK: buffer_reset(c->data.mem); break;
case FILE_CHUNK: buffer_reset(c->data.file.name); break;
default: break;
buffer_reset(c->mem);
buffer_reset(c->file.name);
if (c->file.fd != -1) {
close(c->file.fd);
c->file.fd = -1;
}
if (MAP_FAILED != c->file.mmap.start) {
munmap(c->file.mmap.start, c->file.mmap.length);
c->file.mmap.start = MAP_FAILED;
}
}
@ -136,10 +140,10 @@ void chunkqueue_reset(chunkqueue *cq) {
for (c = cq->first; c; c = c->next) {
switch(c->type) {
case MEM_CHUNK:
c->offset = c->data.mem->used - 1;
c->offset = c->mem->used - 1;
break;
case FILE_CHUNK:
c->offset = c->data.file.length;
c->offset = c->file.length;
break;
default:
break;
@ -147,6 +151,8 @@ void chunkqueue_reset(chunkqueue *cq) {
}
chunkqueue_remove_finished_chunks(cq);
cq->bytes_in = 0;
cq->bytes_out = 0;
}
int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
@ -158,9 +164,9 @@ int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len)
c->type = FILE_CHUNK;
buffer_copy_string_buffer(c->data.file.name, fn);
c->data.file.offset = offset;
c->data.file.length = len;
buffer_copy_string_buffer(c->file.name, fn);
c->file.offset = offset;
c->file.length = len;
c->offset = 0;
chunkqueue_append_chunk(cq, c);
@ -176,7 +182,7 @@ int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_buffer(c->data.mem, mem);
buffer_copy_string_buffer(c->mem, mem);
chunkqueue_append_chunk(cq, c);
@ -191,7 +197,7 @@ int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_buffer(c->data.mem, mem);
buffer_copy_string_buffer(c->mem, mem);
chunkqueue_prepend_chunk(cq, c);
@ -206,7 +212,7 @@ int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_len(c->data.mem, mem, len - 1);
buffer_copy_string_len(c->mem, mem, len - 1);
chunkqueue_append_chunk(cq, c);
@ -220,11 +226,11 @@ buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
c->type = MEM_CHUNK;
c->offset = 0;
buffer_reset(c->data.mem);
buffer_reset(c->mem);
chunkqueue_prepend_chunk(cq, c);
return c->data.mem;
return c->mem;
}
buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
@ -234,11 +240,11 @@ buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
c->type = MEM_CHUNK;
c->offset = 0;
buffer_reset(c->data.mem);
buffer_reset(c->mem);
chunkqueue_append_chunk(cq, c);
return c->data.mem;
return c->mem;
}
off_t chunkqueue_length(chunkqueue *cq) {
@ -248,10 +254,10 @@ off_t chunkqueue_length(chunkqueue *cq) {
for (c = cq->first; c; c = c->next) {
switch (c->type) {
case MEM_CHUNK:
len += c->data.mem->used ? c->data.mem->used - 1 : 0;
len += c->mem->used ? c->mem->used - 1 : 0;
break;
case FILE_CHUNK:
len += c->data.file.length;
len += c->file.length;
break;
default:
break;
@ -291,10 +297,10 @@ int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
switch (c->type) {
case MEM_CHUNK:
if (c->offset == (off_t)c->data.mem->used - 1) is_finished = 1;
if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
break;
case FILE_CHUNK:
if (c->offset == c->data.file.length) is_finished = 1;
if (c->offset == c->file.length) is_finished = 1;
break;
default:
break;

30
src/chunk.h

@ -4,8 +4,7 @@
#include "buffer.h"
typedef struct chunk {
/* ok, this one is tricky:
*
/*
* MEM_CHUNK
* b: the chunk it self
* FILE_CHUNK
@ -14,18 +13,25 @@ typedef struct chunk {
enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
union {
buffer *mem;
struct {
buffer *name;
off_t offset;
off_t length;
} file;
} data;
/* memchunk */
buffer *mem; /* it might be large */
struct {
/* filechunk */
buffer *name;
off_t offset;
off_t length;
int fd;
struct {
char *start;
size_t length;
} mmap;
} file;
/* how many bytes are already handled */
off_t offset;
off_t offset;
struct chunk *next;
} chunk;
@ -36,6 +42,8 @@ typedef struct {
chunk *unused;
size_t unused_chunks;
off_t bytes_in, bytes_out;
} chunkqueue;
chunkqueue *chunkqueue_init(void);

54
src/connections.c

@ -805,7 +805,7 @@ int connection_handle_read_state(server *srv, connection *con) {
for (c = cq->first; c; c = cq->first) {
assert(c != c->next);
if (c->data.mem->used == 0) {
if (c->mem->used == 0) {
cq->first = c->next;
c->next = cq->unused;
cq->unused = c;
@ -830,8 +830,8 @@ int connection_handle_read_state(server *srv, connection *con) {
if (con->request.request->used == 0) {
buffer b;
b.ptr = c->data.mem->ptr + c->offset;
b.used = c->data.mem->used - c->offset;
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
if (NULL != (h_term = buffer_search_rnrn(&b))) {
/* \r\n\r\n found
@ -846,8 +846,8 @@ int connection_handle_read_state(server *srv, connection *con) {
c->offset += h_term - b.ptr + 4;
} else {
/* not found, copy everything */
buffer_copy_string_len(con->request.request, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1);
c->offset = c->data.mem->used - 1;
buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
c->offset = c->mem->used - 1;
}
} else {
/* have to take care of overlapping header terminators */
@ -856,36 +856,36 @@ int connection_handle_read_state(server *srv, connection *con) {
char *s = con->request.request->ptr;
buffer b;
b.ptr = c->data.mem->ptr + c->offset;
b.used = c->data.mem->used - c->offset;
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
if (con->request.request->used - 1 > 3 &&
c->data.mem->used > 1 &&
c->mem->used > 1 &&
s[l-2] == '\r' &&
s[l-1] == '\n' &&
s[l-0] == '\r' &&
c->data.mem->ptr[0] == '\n') {
buffer_append_string_len(con->request.request, c->data.mem->ptr + c->offset, 1);
c->mem->ptr[0] == '\n') {
buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
c->offset += 1;
h_term = con->request.request->ptr;
} else if (con->request.request->used - 1 > 2 &&
c->data.mem->used > 2 &&
c->mem->used > 2 &&
s[l-1] == '\r' &&
s[l-0] == '\n' &&
c->data.mem->ptr[0] == '\r' &&
c->data.mem->ptr[1] == '\n') {
buffer_append_string_len(con->request.request, c->data.mem->ptr + c->offset, 2);
c->mem->ptr[0] == '\r' &&
c->mem->ptr[1] == '\n') {
buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
c->offset += 2;
h_term = con->request.request->ptr;
} else if (con->request.request->used - 1 > 1 &&
c->data.mem->used > 3 &&
c->mem->used > 3 &&
s[l-0] == '\r' &&
c->data.mem->ptr[0] == '\n' &&
c->data.mem->ptr[1] == '\r' &&
c->data.mem->ptr[2] == '\n') {
buffer_append_string_len(con->request.request, c->data.mem->ptr + c->offset, 3);
c->mem->ptr[0] == '\n' &&
c->mem->ptr[1] == '\r' &&
c->mem->ptr[2] == '\n') {
buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
c->offset += 3;
h_term = con->request.request->ptr;
@ -895,19 +895,19 @@ int connection_handle_read_state(server *srv, connection *con) {
*/
buffer_append_string_len(con->request.request,
c->data.mem->ptr + c->offset,
c->mem->ptr + c->offset,
c->offset + h_term - b.ptr + 4);
/* the buffer has been read up to the terminator */
c->offset += h_term - b.ptr + 4;
} else {
/* not found, copy everything */
buffer_append_string_len(con->request.request, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1);
c->offset = c->data.mem->used - 1;
buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
c->offset = c->mem->used - 1;
}
}
if (c->offset + 1 == c->data.mem->used) {
if (c->offset + 1 == c->mem->used) {
/* chunk is empty, move it to unused */
cq->first = c->next;
c->next = cq->unused;
@ -933,17 +933,17 @@ int connection_handle_read_state(server *srv, connection *con) {
weWant = con->request.content_length - (con->request.content->used ? con->request.content->used - 1 : 0);
/* without the terminating \0 */
assert(c->data.mem->used);
assert(c->mem->used);
weHave = c->data.mem->used - c->offset - 1;
weHave = c->mem->used - c->offset - 1;
toRead = weHave > weWant ? weWant : weHave;
buffer_append_string_len(con->request.content, c->data.mem->ptr + c->offset, toRead);
buffer_append_string_len(con->request.content, c->mem->ptr + c->offset, toRead);
c->offset += toRead;
if (c->offset + 1 >= c->data.mem->used) {
if (c->offset + 1 >= c->mem->used) {
/* chunk is empty, move it to unused */
cq->first = c->next;

19
src/mod_fastcgi.c

@ -1951,9 +1951,9 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* get at least the FastCGI header */
for (c = hctx->rb->first; c; c = c->next) {
if (packet->b->used == 0) {
buffer_copy_string_len(packet->b, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1);
buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
} else {
buffer_append_string_len(packet->b, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1);
buffer_append_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
}
if (packet->b->used >= sizeof(*header) + 1) break;
@ -1979,25 +1979,20 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* the first bytes in packet->b are the header */
offset = sizeof(*header);
log_error_write(srv, __FILE__, __LINE__, "sddd", "FastCGI: got header:", packet->len, packet->request_id, packet->type);
/* ->b should only be the content */
buffer_reset(packet->b);
if (packet->len) {
/* copy the content */
for (; c && (packet->b->used < packet->len + 1); c = c->next) {
toread = c->data.mem->used - c->offset - offset - 1 > packet->len ? packet->len : c->data.mem->used - c->offset - offset - 1;
toread = c->mem->used - c->offset - offset - 1 > packet->len ? packet->len : c->mem->used - c->offset - offset - 1;
log_error_write(srv, __FILE__, __LINE__, "sdd", "FastCGI: reading content:", packet->b->used, toread);
buffer_append_string_len(packet->b, c->data.mem->ptr + c->offset + offset, toread);
buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, toread);
offset = 0;
}
if (packet->b->used < packet->len + 1) {
/* we didn't got the full packet */
log_error_write(srv, __FILE__, __LINE__, "sdd", "FastCGI: not the full packet", packet->b->used, packet->len);
buffer_free(packet->b);
return -1;
@ -2010,10 +2005,10 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* tag the chunks as read */
toread = packet->len + sizeof(FCGI_Header);
for (c = hctx->rb->first; c && toread; c = c->next) {
if (c->data.mem->used - c->offset - 1 <= toread) {
if (c->mem->used - c->offset - 1 <= toread) {
/* we read this whole buffer, move it to unused */
toread -= c->data.mem->used - c->offset - 1;
c->offset = c->data.mem->used - 1; /* everthing has been written */
toread -= c->mem->used - c->offset - 1;
c->offset = c->mem->used - 1; /* everthing has been written */
} else {
c->offset += toread;
toread = 0;

39
src/network_linux_sendfile.c

@ -53,12 +53,12 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, chunkqu
tc = tc->next, num_chunks++);
for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->data.mem->used == 0) {
chunks[i].iov_base = tc->data.mem->ptr;
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
chunks[i].iov_len = 0;
} else {
offset = tc->data.mem->ptr + tc->offset;
toSend = tc->data.mem->used - 1 - tc->offset;
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
chunks[i].iov_base = offset;
@ -101,7 +101,6 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, chunkqu
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
con->bytes_written += chunks[i].iov_len;
if (chunk_finished) {
/* skip the chunks from further touches */
@ -115,12 +114,13 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, chunkqu
/* partially written */
tc->offset += r;
con->bytes_written += r;
chunk_finished = 0;
break;
}
}
cq->bytes_out += r;
con->bytes_written += r;
break;
}
@ -129,33 +129,34 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, chunkqu
off_t offset;
size_t toSend;
stat_cache_entry *sce = NULL;
int ifd;
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->data.file.name, &sce)) {
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->data.file.name);
strerror(errno), c->file.name);
return -1;
}
offset = c->data.file.offset + c->offset;
offset = c->file.offset + c->offset;
/* limit the toSend to 2^31-1 bytes in a chunk */
toSend = c->data.file.length - c->offset > ((1 << 30) - 1) ?
((1 << 30) - 1) : c->data.file.length - c->offset;
toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
((1 << 30) - 1) : c->file.length - c->offset;
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->data.file.name);
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
return -1;
}
if (-1 == (ifd = open(c->data.file.name->ptr, O_RDONLY))) {
/* open file if not already opened */
if (-1 == c->file.fd &&
-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
return -1;
}
/* Linux sendfile() */
if (-1 == (r = sendfile(fd, ifd, &offset, toSend))) {
if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
switch (errno) {
case EAGAIN:
case EINTR:
@ -163,21 +164,19 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, chunkqu
break;
case EPIPE:
case ECONNRESET:
close(ifd);
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd",
"sendfile failed:", strerror(errno), fd);
close(ifd);
return -1;
}
}
close(ifd);
c->offset += r;
con->bytes_written += r;
cq->bytes_out += r;
if (c->offset == c->data.file.length) {
if (c->offset == c->file.length) {
chunk_finished = 1;
}

22
src/network_write.c

@ -38,13 +38,13 @@ int network_write_chunkqueue_write(server *srv, connection *con, chunkqueue *cq)
size_t toSend;
ssize_t r;
if (c->data.mem->used == 0) {
if (c->mem->used == 0) {
chunk_finished = 1;
break;
}
offset = c->data.mem->ptr + c->offset;
toSend = c->data.mem->used - 1 - c->offset;
offset = c->mem->ptr + c->offset;
toSend = c->mem->used - 1 - c->offset;
#ifdef __WIN32
if ((r = send(fd, offset, toSend, 0)) < 0) {
log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
@ -62,7 +62,7 @@ int network_write_chunkqueue_write(server *srv, connection *con, chunkqueue *cq)
c->offset += r;
con->bytes_written += r;
if (c->offset == (off_t)c->data.mem->used - 1) {
if (c->offset == (off_t)c->mem->used - 1) {
chunk_finished = 1;
}
@ -78,22 +78,22 @@ int network_write_chunkqueue_write(server *srv, connection *con, chunkqueue *cq)
stat_cache_entry *sce = NULL;
int ifd;
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->data.file.name, &sce)) {
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->data.file.name);
strerror(errno), c->file.name);
return -1;
}
offset = c->data.file.offset + c->offset;
toSend = c->data.file.length - c->offset;
offset = c->file.offset + c->offset;
toSend = c->file.length - c->offset;
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->data.file.name);
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
return -1;
}
if (-1 == (ifd = open(c->data.file.name->ptr, O_RDONLY))) {
if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
return -1;
@ -137,7 +137,7 @@ int network_write_chunkqueue_write(server *srv, connection *con, chunkqueue *cq)
c->offset += r;
con->bytes_written += r;
if (c->offset == c->data.file.length) {
if (c->offset == c->file.length) {
chunk_finished = 1;
}

110
src/network_writev.c

@ -75,12 +75,12 @@ int network_write_chunkqueue_writev(server *srv, connection *con, chunkqueue *cq
for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->data.mem->used == 0) {
chunks[i].iov_base = tc->data.mem->ptr;
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
chunks[i].iov_len = 0;
} else {
offset = tc->data.mem->ptr + tc->offset;
toSend = tc->data.mem->used - 1 - tc->offset;
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
chunks[i].iov_base = offset;
@ -123,7 +123,6 @@ int network_write_chunkqueue_writev(server *srv, connection *con, chunkqueue *cq
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
con->bytes_written += chunks[i].iov_len;
if (chunk_finished) {
/* skip the chunks from further touches */
@ -137,89 +136,82 @@ int network_write_chunkqueue_writev(server *srv, connection *con, chunkqueue *cq
/* partially written */
tc->offset += r;
con->bytes_written += r;
chunk_finished = 0;
#if 0
log_error_write(srv, __FILE__, __LINE__, "sdd",
"(debug) partially write: ", r, fd);
#endif
break;
}
}
cq->bytes_out += r;
con->bytes_written += r;
break;
}
case FILE_CHUNK: {
#ifdef USE_MMAP
char *p = NULL;
#endif
ssize_t r;
off_t offset;
size_t toSend;
stat_cache_entry *sce = NULL;
int ifd;
switch (stat_cache_get_entry(srv, con, c->data.file.name, &sce)) {
case HANDLER_COMEBACK:
case HANDLER_GO_ON:
offset = c->data.file.offset + c->offset;
toSend = c->data.file.length - c->offset;
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.offset + c->offset;
toSend = c->file.length - c->offset;
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"file was shrinked:", c->data.file.name);
return -1;
}
if (-1 == (ifd = open(c->data.file.name->ptr, O_RDONLY))) {
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"file was shrinked:", c->file.name);
return -1;
}
if (c->file.mmap.start == MAP_FAILED) {
if (-1 == c->file.fd && /* open the file if not already open */
-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
return -1;
}
if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
if (MAP_FAILED == (c->file.mmap.start = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
strerror(errno), c->data.file.name, ifd);
strerror(errno), c->file.name, c->file.fd);
close(ifd);
return -1;
}
close(ifd);
if ((r = write(fd, p + offset, toSend)) <= 0) {
switch (errno) {
case EAGAIN:
case EINTR:
r = 0;
break;
case EPIPE:
case ECONNRESET:
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd",
"write failed:", strerror(errno), fd);
return -1;
}
}
munmap(p, sce->st.st_size);
break;
default:
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->data.file.name);
return -1;
close(c->file.fd);
c->file.fd = -1;
/* chunk_reset() or chunk_free() will cleanup for us */
}
if ((r = write(fd, c->file.mmap.start + offset, toSend)) < 0) {
switch (errno) {
case EAGAIN:
case EINTR:
r = 0;
break;
case EPIPE:
case ECONNRESET:
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd",
"write failed:", strerror(errno), fd);
return -1;
}
}
c->offset += r;
con->bytes_written += r;
cq->bytes_out += r;
if (c->offset == c->data.file.length) {
if (c->offset == c->file.length) {
chunk_finished = 1;
}

Loading…
Cancel
Save