|
|
|
@ -67,6 +67,7 @@
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__attribute_cold__ |
|
|
|
|
static int network_write_error(int fd, log_error_st *errh) { |
|
|
|
|
#if defined(__WIN32) |
|
|
|
|
int lastError = WSAGetLastError(); |
|
|
|
@ -88,7 +89,7 @@ static int network_write_error(int fd, log_error_st *errh) {
|
|
|
|
|
case EINTR: |
|
|
|
|
return -3; |
|
|
|
|
case EPIPE: |
|
|
|
|
case ECONNRESET: |
|
|
|
|
case ECONNRESET: |
|
|
|
|
return -2; |
|
|
|
|
default: |
|
|
|
|
log_perror(errh,__FILE__,__LINE__,"write failed: %d",fd); |
|
|
|
@ -97,6 +98,13 @@ static int network_write_error(int fd, log_error_st *errh) {
|
|
|
|
|
#endif /* __WIN32 */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
__attribute_cold__ |
|
|
|
|
static int network_remove_finished_chunks(chunkqueue * const cq, const off_t len) { |
|
|
|
|
force_assert(len >= 0); |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline |
|
|
|
|
static ssize_t network_write_data_len(int fd, const char *data, off_t len) { |
|
|
|
|
#if defined(__WIN32) |
|
|
|
@ -106,33 +114,31 @@ static ssize_t network_write_data_len(int fd, const char *data, off_t len) {
|
|
|
|
|
#endif /* __WIN32 */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int network_write_accounting(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh, const ssize_t wr, const off_t toSend) { |
|
|
|
|
if (wr >= 0) { |
|
|
|
|
*p_max_bytes -= wr;/*(toSend > 0 if we reach this func)*/ |
|
|
|
|
const int rc = (wr == toSend && *p_max_bytes > 0) ? 0 : -3; |
|
|
|
|
chunkqueue_mark_written(cq, wr); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
return network_write_error(fd, errh); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* write next chunk(s); finished chunks are removed afterwards after successful writes.
|
|
|
|
|
* return values: similar as backends (0 success, -1 error, -2 remote close, -3 try again later (EINTR/EAGAIN)) */ |
|
|
|
|
/* next chunk must be MEM_CHUNK. use write()/send() */ |
|
|
|
|
static int network_write_mem_chunk(int fd, chunkqueue *cq, off_t *p_max_bytes, log_error_st *errh) { |
|
|
|
|
static int network_write_mem_chunk(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh) { |
|
|
|
|
chunk* const c = cq->first; |
|
|
|
|
ssize_t wr; |
|
|
|
|
off_t c_len = (off_t)buffer_string_length(c->mem); |
|
|
|
|
force_assert(c->offset >= 0 && c->offset <= c_len); |
|
|
|
|
c_len -= c->offset; |
|
|
|
|
off_t c_len = (off_t)buffer_string_length(c->mem) - c->offset; |
|
|
|
|
if (c_len > *p_max_bytes) c_len = *p_max_bytes; |
|
|
|
|
if (c_len <= 0) return network_remove_finished_chunks(cq, c_len); |
|
|
|
|
|
|
|
|
|
if (0 == c_len) { |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
wr = network_write_data_len(fd, c->mem->ptr + c->offset, c_len); |
|
|
|
|
if (wr >= 0) { |
|
|
|
|
*p_max_bytes -= wr; |
|
|
|
|
chunkqueue_mark_written(cq, wr); |
|
|
|
|
return (wr > 0 && wr == c_len) ? 0 : -3; |
|
|
|
|
} else { |
|
|
|
|
return network_write_error(fd, errh); |
|
|
|
|
} |
|
|
|
|
ssize_t wr = network_write_data_len(fd, c->mem->ptr + c->offset, c_len); |
|
|
|
|
return network_write_accounting(fd, cq, p_max_bytes, errh, wr, c_len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -140,22 +146,15 @@ static int network_write_mem_chunk(int fd, chunkqueue *cq, off_t *p_max_bytes, l
|
|
|
|
|
|
|
|
|
|
#if !defined(NETWORK_WRITE_USE_MMAP) |
|
|
|
|
|
|
|
|
|
static int network_write_file_chunk_no_mmap(int fd, chunkqueue *cq, off_t *p_max_bytes, log_error_st *errh) { |
|
|
|
|
static int network_write_file_chunk_no_mmap(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh) { |
|
|
|
|
chunk* const c = cq->first; |
|
|
|
|
off_t offset, toSend; |
|
|
|
|
ssize_t wr; |
|
|
|
|
char buf[16384]; /* max read 16kb in one step */ |
|
|
|
|
|
|
|
|
|
force_assert(c->offset >= 0 && c->offset <= c->file.length); |
|
|
|
|
|
|
|
|
|
offset = c->offset; |
|
|
|
|
toSend = c->file.length - c->offset; |
|
|
|
|
if (toSend > *p_max_bytes) toSend = *p_max_bytes; |
|
|
|
|
|
|
|
|
|
if (0 == toSend) { |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (toSend <= 0) return network_remove_finished_chunks(cq, toSend); |
|
|
|
|
|
|
|
|
|
if (c->file.fd < 0 && 0 != chunkqueue_open_file_chunk(cq, errh)) return -1; |
|
|
|
|
|
|
|
|
@ -170,14 +169,8 @@ static int network_write_file_chunk_no_mmap(int fd, chunkqueue *cq, off_t *p_max
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
wr = network_write_data_len(fd, buf, toSend); |
|
|
|
|
if (wr >= 0) { |
|
|
|
|
*p_max_bytes -= wr; |
|
|
|
|
chunkqueue_mark_written(cq, wr); |
|
|
|
|
return (wr > 0 && wr == toSend) ? 0 : -3; |
|
|
|
|
} else { |
|
|
|
|
return network_write_error(fd, errh); |
|
|
|
|
} |
|
|
|
|
ssize_t wr = network_write_data_len(fd, buf, toSend); |
|
|
|
|
return network_write_accounting(fd, cq, p_max_bytes, errh, wr, toSend); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
@ -214,24 +207,17 @@ static void sigbus_handler(int sig) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* next chunk must be FILE_CHUNK. send mmap()ed file with write() */ |
|
|
|
|
static int network_write_file_chunk_mmap(int fd, chunkqueue *cq, off_t *p_max_bytes, log_error_st *errh) { |
|
|
|
|
static int network_write_file_chunk_mmap(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh) { |
|
|
|
|
chunk* const c = cq->first; |
|
|
|
|
off_t offset, toSend, file_end; |
|
|
|
|
ssize_t wr; |
|
|
|
|
size_t mmap_offset, mmap_avail; |
|
|
|
|
const char *data; |
|
|
|
|
|
|
|
|
|
force_assert(c->offset >= 0 && c->offset <= c->file.length); |
|
|
|
|
|
|
|
|
|
file_end = c->file.length; /*file end offset in this chunk*/ |
|
|
|
|
offset = c->offset; |
|
|
|
|
toSend = c->file.length - c->offset; |
|
|
|
|
if (toSend > *p_max_bytes) toSend = *p_max_bytes; |
|
|
|
|
file_end = c->file.length; /*file end offset in this chunk*/ |
|
|
|
|
|
|
|
|
|
if (0 == toSend) { |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (toSend <= 0) return network_remove_finished_chunks(cq, toSend); |
|
|
|
|
|
|
|
|
|
if (c->file.fd < 0 && 0 != chunkqueue_open_file_chunk(cq, errh)) return -1; |
|
|
|
|
|
|
|
|
@ -309,8 +295,9 @@ static int network_write_file_chunk_mmap(int fd, chunkqueue *cq, off_t *p_max_by
|
|
|
|
|
signal(SIGBUS, sigbus_handler); |
|
|
|
|
|
|
|
|
|
sigbus_jmp_valid = 1; |
|
|
|
|
wr = network_write_data_len(fd, data, toSend); |
|
|
|
|
ssize_t wr = network_write_data_len(fd, data, toSend); |
|
|
|
|
sigbus_jmp_valid = 0; |
|
|
|
|
return network_write_accounting(fd, cq, p_max_bytes, errh, wr, toSend); |
|
|
|
|
} else { |
|
|
|
|
sigbus_jmp_valid = 0; |
|
|
|
|
|
|
|
|
@ -322,13 +309,6 @@ static int network_write_file_chunk_mmap(int fd, chunkqueue *cq, off_t *p_max_by
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (wr >= 0) { |
|
|
|
|
*p_max_bytes -= wr; |
|
|
|
|
chunkqueue_mark_written(cq, wr); |
|
|
|
|
return (wr > 0 && wr == toSend) ? 0 : -3; |
|
|
|
|
} else { |
|
|
|
|
return network_write_error(fd, errh); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* NETWORK_WRITE_USE_MMAP */ |
|
|
|
@ -366,55 +346,28 @@ static int network_write_file_chunk_mmap(int fd, chunkqueue *cq, off_t *p_max_by
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* next chunk must be MEM_CHUNK. send multiple mem chunks using writev() */ |
|
|
|
|
static int network_writev_mem_chunks(int fd, chunkqueue *cq, off_t *p_max_bytes, log_error_st *errh) { |
|
|
|
|
struct iovec chunks[MAX_CHUNKS]; |
|
|
|
|
static int network_writev_mem_chunks(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh) { |
|
|
|
|
size_t num_chunks = 0; |
|
|
|
|
off_t max_bytes = *p_max_bytes; |
|
|
|
|
off_t toSend = 0; |
|
|
|
|
ssize_t wr; |
|
|
|
|
struct iovec chunks[MAX_CHUNKS]; |
|
|
|
|
|
|
|
|
|
for (const chunk *c = cq->first; |
|
|
|
|
NULL != c && MEM_CHUNK == c->type |
|
|
|
|
&& num_chunks < MAX_CHUNKS && toSend < max_bytes; |
|
|
|
|
c = c->next) { |
|
|
|
|
size_t c_len = buffer_string_length(c->mem); |
|
|
|
|
force_assert(c->offset >= 0 && c->offset <= (off_t)c_len); |
|
|
|
|
c_len -= c->offset; |
|
|
|
|
for (const chunk *c = cq->first; c && MEM_CHUNK == c->type; c = c->next) { |
|
|
|
|
const off_t c_len = (off_t)buffer_string_length(c->mem) - c->offset; |
|
|
|
|
if (c_len > 0) { |
|
|
|
|
toSend += c_len; |
|
|
|
|
|
|
|
|
|
chunks[num_chunks].iov_base = c->mem->ptr + c->offset; |
|
|
|
|
chunks[num_chunks].iov_len = c_len; |
|
|
|
|
chunks[num_chunks].iov_len = (size_t)c_len; |
|
|
|
|
|
|
|
|
|
++num_chunks; |
|
|
|
|
if (++num_chunks == MAX_CHUNKS || toSend >= *p_max_bytes) break; |
|
|
|
|
} |
|
|
|
|
else if (c_len < 0) /*(should not happen; trigger assert)*/ |
|
|
|
|
return network_remove_finished_chunks(cq, c_len); |
|
|
|
|
} |
|
|
|
|
if (0 == num_chunks) return network_remove_finished_chunks(cq, 0); |
|
|
|
|
|
|
|
|
|
if (0 == num_chunks) { |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
wr = writev(fd, chunks, num_chunks); |
|
|
|
|
|
|
|
|
|
if (wr < 0) switch (errno) { |
|
|
|
|
case EAGAIN: |
|
|
|
|
case EINTR: |
|
|
|
|
break; |
|
|
|
|
case EPIPE: |
|
|
|
|
case ECONNRESET: |
|
|
|
|
return -2; |
|
|
|
|
default: |
|
|
|
|
log_perror(errh, __FILE__, __LINE__, "writev failed: %d", fd); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (wr >= 0) { |
|
|
|
|
*p_max_bytes -= wr; |
|
|
|
|
chunkqueue_mark_written(cq, wr); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return (wr > 0 && wr == toSend) ? 0 : -3; |
|
|
|
|
ssize_t wr = writev(fd, chunks, num_chunks); |
|
|
|
|
return network_write_accounting(fd, cq, p_max_bytes, errh, wr, toSend); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#endif /* NETWORK_WRITE_USE_WRITEV */ |
|
|
|
@ -434,23 +387,17 @@ static int network_writev_mem_chunks(int fd, chunkqueue *cq, off_t *p_max_bytes,
|
|
|
|
|
#include <sys/uio.h> |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int network_write_file_chunk_sendfile(int fd, chunkqueue *cq, off_t *p_max_bytes, log_error_st *errh) { |
|
|
|
|
static int network_write_file_chunk_sendfile(const int fd, chunkqueue * const cq, off_t * const p_max_bytes, log_error_st * const errh) { |
|
|
|
|
chunk * const c = cq->first; |
|
|
|
|
ssize_t wr; |
|
|
|
|
off_t offset; |
|
|
|
|
off_t toSend; |
|
|
|
|
off_t written = 0; |
|
|
|
|
|
|
|
|
|
force_assert(c->offset >= 0 && c->offset <= c->file.length); |
|
|
|
|
|
|
|
|
|
offset = c->offset; |
|
|
|
|
toSend = c->file.length - c->offset; |
|
|
|
|
if (toSend > *p_max_bytes) toSend = *p_max_bytes; |
|
|
|
|
|
|
|
|
|
if (0 == toSend) { |
|
|
|
|
chunkqueue_remove_finished_chunks(cq); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (toSend <= 0) return network_remove_finished_chunks(cq, toSend); |
|
|
|
|
|
|
|
|
|
if (c->file.fd < 0 && 0 != chunkqueue_open_file_chunk(cq, errh)) return -1; |
|
|
|
|
|
|
|
|
@ -529,6 +476,7 @@ static int network_write_file_chunk_sendfile(int fd, chunkqueue *cq, off_t *p_ma
|
|
|
|
|
if (written > 0) { |
|
|
|
|
chunkqueue_mark_written(cq, written); |
|
|
|
|
*p_max_bytes -= written; |
|
|
|
|
if (__builtin_expect( (*p_max_bytes <= 0), 0)) return -3; |
|
|
|
|
} |
|
|
|
|
else if (0 == wr) { /*(-1 != wr && 0 == written)*/ |
|
|
|
|
log_error(errh, __FILE__, __LINE__, |
|
|
|
@ -550,8 +498,8 @@ static int network_write_file_chunk_sendfile(int fd, chunkqueue *cq, off_t *p_ma
|
|
|
|
|
* -2 : remote close |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static int network_write_chunkqueue_write(int fd, chunkqueue *cq, off_t max_bytes, log_error_st *errh) { |
|
|
|
|
while (max_bytes > 0 && NULL != cq->first) { |
|
|
|
|
static int network_write_chunkqueue_write(const int fd, chunkqueue * const cq, off_t max_bytes, log_error_st * const errh) { |
|
|
|
|
while (NULL != cq->first) { |
|
|
|
|
int rc = -1; |
|
|
|
|
|
|
|
|
|
switch (cq->first->type) { |
|
|
|
@ -567,16 +515,15 @@ static int network_write_chunkqueue_write(int fd, chunkqueue *cq, off_t max_byte
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (-3 == rc) return 0; |
|
|
|
|
if (0 != rc) return rc; |
|
|
|
|
if (__builtin_expect( (0 != rc), 0)) return (-3 == rc) ? 0 : rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if defined(NETWORK_WRITE_USE_WRITEV) |
|
|
|
|
static int network_write_chunkqueue_writev(int fd, chunkqueue *cq, off_t max_bytes, log_error_st *errh) { |
|
|
|
|
while (max_bytes > 0 && NULL != cq->first) { |
|
|
|
|
static int network_write_chunkqueue_writev(const int fd, chunkqueue * const cq, off_t max_bytes, log_error_st * const errh) { |
|
|
|
|
while (NULL != cq->first) { |
|
|
|
|
int rc = -1; |
|
|
|
|
|
|
|
|
|
switch (cq->first->type) { |
|
|
|
@ -596,8 +543,7 @@ static int network_write_chunkqueue_writev(int fd, chunkqueue *cq, off_t max_byt
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (-3 == rc) return 0; |
|
|
|
|
if (0 != rc) return rc; |
|
|
|
|
if (__builtin_expect( (0 != rc), 0)) return (-3 == rc) ? 0 : rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
@ -605,8 +551,8 @@ static int network_write_chunkqueue_writev(int fd, chunkqueue *cq, off_t max_byt
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if defined(NETWORK_WRITE_USE_SENDFILE) |
|
|
|
|
static int network_write_chunkqueue_sendfile(int fd, chunkqueue *cq, off_t max_bytes, log_error_st *errh) { |
|
|
|
|
while (max_bytes > 0 && NULL != cq->first) { |
|
|
|
|
static int network_write_chunkqueue_sendfile(const int fd, chunkqueue * const cq, off_t max_bytes, log_error_st * const errh) { |
|
|
|
|
while (NULL != cq->first) { |
|
|
|
|
int rc = -1; |
|
|
|
|
|
|
|
|
|
switch (cq->first->type) { |
|
|
|
@ -628,8 +574,7 @@ static int network_write_chunkqueue_sendfile(int fd, chunkqueue *cq, off_t max_b
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (-3 == rc) return 0; |
|
|
|
|
if (0 != rc) return rc; |
|
|
|
|
if (__builtin_expect( (0 != rc), 0)) return (-3 == rc) ? 0 : rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|