1 #include "network_backends.h" 2 3 #include "network.h" 4 #include "fdevent.h" 5 #include "log.h" 6 #include "stat_cache.h" 7 8 #include "sys-socket.h" 9 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <sys/time.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <unistd.h> 16 #include <string.h> 17 #include <stdlib.h> 18 19 #ifdef HAVE_SYS_FILIO_H 20 # include <sys/filio.h> 21 #endif 22 23 #ifdef HAVE_SYS_RESOURCE_H 24 # include <sys/resource.h> 25 #endif 26 27 int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) { 28 chunk *c; 29 size_t chunks_written = 0; 30 31 for(c = cq->first; c; c = c->next) { 32 int chunk_finished = 0; 33 34 switch(c->type) { 35 case MEM_CHUNK: { 36 char * offset; 37 size_t toSend; 38 ssize_t r; 39 40 if (c->mem->used == 0) { 41 chunk_finished = 1; 42 break; 43 } 44 45 offset = c->mem->ptr + c->offset; 46 toSend = c->mem->used - 1 - c->offset; 47 #ifdef __WIN32 48 if ((r = send(fd, offset, toSend, 0)) < 0) { 49 /* no error handling for windows... */ 50 log_error_write(srv, __FILE__, __LINE__, "ssd", "send failed: ", strerror(errno), fd); 51 52 return -1; 53 } 54 #else 55 if ((r = write(fd, offset, toSend)) < 0) { 56 switch (errno) { 57 case EAGAIN: 58 case EINTR: 59 r = 0; 60 break; 61 case EPIPE: 62 case ECONNRESET: 63 return -2; 64 default: 65 log_error_write(srv, __FILE__, __LINE__, "ssd", 66 "write failed:", strerror(errno), fd); 67 68 return -1; 69 } 70 } 71 #endif 72 73 c->offset += r; 74 cq->bytes_out += r; 75 76 if (c->offset == (off_t)c->mem->used - 1) { 77 chunk_finished = 1; 78 } 79 80 break; 81 } 82 case FILE_CHUNK: { 83 #ifdef USE_MMAP 84 char *p = NULL; 85 #endif 86 ssize_t r; 87 off_t offset; 88 size_t toSend; 89 stat_cache_entry *sce = NULL; 90 int ifd; 91 92 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { 93 log_error_write(srv, __FILE__, __LINE__, "sb", 94 strerror(errno), c->file.name); 95 return -1; 96 } 97 98 offset = c->file.start + c->offset; 99 toSend = c->file.length - c->offset; 100 101 if (offset > sce->st.st_size) { 102 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); 103 104 return -1; 105 } 106 107 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { 108 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); 109 110 return -1; 111 } 112 113 #ifdef USE_MMAP 114 if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) { 115 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno)); 116 117 close(ifd); 118 119 return -1; 120 } 121 close(ifd); 122 123 if ((r = write(fd, p + offset, toSend)) <= 0) { 124 switch (errno) { 125 case EAGAIN: 126 case EINTR: 127 r = 0; 128 break; 129 case EPIPE: 130 case ECONNRESET: 131 munmap(p, sce->st.st_size); 132 return -2; 133 default: 134 log_error_write(srv, __FILE__, __LINE__, "ssd", 135 "write failed:", strerror(errno), fd); 136 munmap(p, sce->st.st_size); 137 138 return -1; 139 } 140 } 141 142 munmap(p, sce->st.st_size); 143 #else /* USE_MMAP */ 144 buffer_prepare_copy(srv->tmp_buf, toSend); 145 146 lseek(ifd, offset, SEEK_SET); 147 if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) { 148 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno)); 149 close(ifd); 150 151 return -1; 152 } 153 close(ifd); 154 155 #ifdef __WIN32 156 if ((r = send(fd, srv->tmp_buf->ptr, toSend, 0)) < 0) { 157 /* no error handling for windows... */ 158 log_error_write(srv, __FILE__, __LINE__, "ssd", "send failed: ", strerror(errno), fd); 159 160 return -1; 161 } 162 #else /* __WIN32 */ 163 if ((r = write(fd, srv->tmp_buf->ptr, toSend)) < 0) { 164 switch (errno) { 165 case EAGAIN: 166 case EINTR: 167 r = 0; 168 break; 169 case EPIPE: 170 case ECONNRESET: 171 return -2; 172 default: 173 log_error_write(srv, __FILE__, __LINE__, "ssd", 174 "write failed:", strerror(errno), fd); 175 176 return -1; 177 } 178 } 179 #endif /* __WIN32 */ 180 #endif /* USE_MMAP */ 181 182 c->offset += r; 183 cq->bytes_out += r; 184 185 if (c->offset == c->file.length) { 186 chunk_finished = 1; 187 } 188 189 break; 190 } 191 default: 192 193 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); 194 195 return -1; 196 } 197 198 if (!chunk_finished) { 199 /* not finished yet */ 200 201 break; 202 } 203 204 chunks_written++; 205 } 206 207 return chunks_written; 208 } 209 210 #if 0 211 network_write_init(void) { 212 p->write = network_write_write_chunkset; 213 } 214 #endif 215