1#include "network_backends.h" 2 3#if defined(USE_WRITEV) 4 5#include "network.h" 6#include "log.h" 7 8#if defined(HAVE_SYS_UIO_H) 9# include <sys/uio.h> 10#endif 11 12#include <errno.h> 13#include <string.h> 14#include <stdlib.h> 15 16#if defined(UIO_MAXIOV) 17# define SYS_MAX_CHUNKS UIO_MAXIOV 18#elif defined(IOV_MAX) 19/* new name for UIO_MAXIOV since IEEE Std 1003.1-2001 */ 20# define SYS_MAX_CHUNKS IOV_MAX 21#elif defined(_XOPEN_IOV_MAX) 22/* minimum value for sysconf(_SC_IOV_MAX); posix requires this to be at least 16, which is good enough - no need to call sysconf() */ 23# define SYS_MAX_CHUNKS _XOPEN_IOV_MAX 24#else 25# error neither UIO_MAXIOV nor IOV_MAX nor _XOPEN_IOV_MAX are defined 26#endif 27 28/* allocate iovec[MAX_CHUNKS] on stack, so pick a sane limit: 29 * - each entry will use 1 pointer + 1 size_t 30 * - 32 chunks -> 256 / 512 bytes (32-bit/64-bit pointers) 31 */ 32#define STACK_MAX_ALLOC_CHUNKS 32 33#if SYS_MAX_CHUNKS > STACK_MAX_ALLOC_CHUNKS 34# define MAX_CHUNKS STACK_MAX_ALLOC_CHUNKS 35#else 36# define MAX_CHUNKS SYS_MAX_CHUNKS 37#endif 38 39#define DBE 0 40 41int network_writev_mem_chunks(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) { 42 struct iovec chunks[MAX_CHUNKS]; 43 size_t num_chunks; 44 off_t max_bytes = *p_max_bytes; 45 off_t toSend; 46 ssize_t r; 47 UNUSED(con); 48 49 force_assert(NULL != cq->first); 50 force_assert(MEM_CHUNK == cq->first->type); 51 52 { 53 chunk const *c; 54 55 toSend = 0; 56 num_chunks = 0; 57 for (c = cq->first; NULL != c && MEM_CHUNK == c->type && num_chunks < MAX_CHUNKS && toSend < max_bytes; c = c->next) { 58 size_t c_len; 59 60 force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem)); 61 c_len = buffer_string_length(c->mem) - c->offset; 62 if (c_len > 0) { 63 toSend += c_len; 64 65 chunks[num_chunks].iov_base = c->mem->ptr + c->offset; 66 chunks[num_chunks].iov_len = c_len; 67 68 ++num_chunks; 69 } 70 } 71 } 72 73 if (0 == num_chunks) { 74 chunkqueue_remove_finished_chunks(cq); 75 return 0; 76 } 77 78 r = writev(fd, chunks, num_chunks); 79 80 if (r < 0) switch (errno) { 81 case EAGAIN: 82 case EINTR: 83 break; 84 case EPIPE: 85 case ECONNRESET: 86 return -2; 87 default: 88 log_error_write(srv, __FILE__, __LINE__, "ssd", 89 "writev failed:", strerror(errno), fd); 90 return -1; 91 } 92 93 if (r >= 0) { 94 *p_max_bytes -= r; 95 chunkqueue_mark_written(cq, r); 96 } 97 98 return (r > 0 && r == toSend) ? 0 : -3; 99} 100 101#endif /* USE_WRITEV */ 102 103int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { 104 while (max_bytes > 0 && NULL != cq->first) { 105 int r = -1; 106 107 switch (cq->first->type) { 108 case MEM_CHUNK: 109 r = network_writev_mem_chunks(srv, con, fd, cq, &max_bytes); 110 break; 111 case FILE_CHUNK: 112 r = network_write_file_chunk_mmap(srv, con, fd, cq, &max_bytes); 113 break; 114 case SMB_CHUNK: 115 r = network_write_smbfile_chunk_mmap(srv, con, fd, cq, &max_bytes); 116 break; 117 } 118 119 if (-3 == r) return 0; 120 if (0 != r) return r; 121 } 122 123 return 0; 124} 125