| 32 | | |
| | 33 | |
| | 34 | /* this is a 64k sendbuffer |
| | 35 | * |
| | 36 | * it has to stay at the same location all the time to satisfy the needs |
| | 37 | * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE |
| | 38 | * |
| | 39 | * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown |
| | 40 | * -> we expect a 64k block to 'leak' in valgrind |
| | 41 | * |
| | 42 | * |
| | 43 | * In reality we would like to use mmap() but we don't have a guarantee that |
| | 44 | * we get the same mmap() address for each call. On openbsd the mmap() address |
| | 45 | * even randomized. |
| | 46 | * That means either we keep the mmap() open or we do a read() into a |
| | 47 | * constant buffer |
| | 48 | * */ |
| | 49 | #define LOCAL_SEND_BUFSIZE (64 * 1024) |
| | 50 | static char *local_send_buffer = NULL; |
| | 51 | |
| 114 | | |
| 115 | | offset = c->data.file.offset + c->offset; |
| 116 | | toSend = c->data.file.length - c->offset; |
| 117 | | |
| 118 | | if (-1 == (ifd = open(c->data.file.name->ptr, O_RDONLY))) { |
| 119 | | log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); |
| | 132 | |
| | 133 | if (NULL == local_send_buffer) { |
| | 134 | local_send_buffer = malloc(LOCAL_SEND_BUFSIZE); |
| | 135 | assert(local_send_buffer); |
| | 136 | } |
| | 137 | |
| | 138 | do { |
| | 139 | |
| | 140 | offset = c->data.file.offset + c->offset; |
| | 141 | toSend = c->data.file.length - c->offset; |
| | 142 | |
| | 143 | if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; |
| | 144 | |
| | 145 | if (-1 == (ifd = open(c->data.file.name->ptr, O_RDONLY))) { |
| | 146 | log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); |
| 121 | | return -1; |
| 122 | | } |
| 123 | | |
| 124 | | |
| 125 | | if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) { |
| 126 | | log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno)); |
| 127 | | |
| | 148 | return -1; |
| | 149 | } |
| | 150 | |
| | 151 | |
| | 152 | lseek(ifd, offset, SEEK_SET); |
| | 153 | if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) { |
| | 154 | log_error_write(srv, __FILE__, __LINE__, "ss", "read failed: ", strerror(errno)); |
| | 155 | return -1; |
| | 156 | } |
| | 157 | |
| | 158 | s = local_send_buffer; |
| | 159 | |
| 129 | | |
| 130 | | return -1; |
| 131 | | } |
| 132 | | |
| 133 | | close(ifd); |
| 134 | | |
| 135 | | s = p + offset; |
| 136 | | |
| 137 | | if ((r = SSL_write(con->ssl, s, toSend)) <= 0) { |
| 138 | | switch ((ssl_r = SSL_get_error(con->ssl, r))) { |
| 139 | | case SSL_ERROR_WANT_WRITE: |
| 140 | | break; |
| 141 | | case SSL_ERROR_SYSCALL: |
| 142 | | switch(errno) { |
| 143 | | case EPIPE: |
| 144 | | return -2; |
| | 161 | |
| | 162 | if ((r = SSL_write(con->ssl, s, toSend)) <= 0) { |
| | 163 | switch ((ssl_r = SSL_get_error(con->ssl, r))) { |
| | 164 | case SSL_ERROR_WANT_WRITE: |
| | 165 | break; |
| | 166 | case SSL_ERROR_SYSCALL: |
| | 167 | switch(errno) { |
| | 168 | case EPIPE: |
| | 169 | return -2; |
| | 170 | default: |
| | 171 | log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", |
| | 172 | ssl_r, r, errno, |
| | 173 | strerror(errno)); |
| | 174 | break; |
| | 175 | } |
| | 176 | |
| | 177 | return -1; |
| | 178 | case SSL_ERROR_ZERO_RETURN: |
| | 179 | /* clean shutdown on the remote side */ |
| | 180 | |
| | 181 | if (r == 0) return -2; |
| | 182 | |
| | 183 | /* fall thourgh */ |
| 151 | | |
| 152 | | return -1; |
| 153 | | case SSL_ERROR_ZERO_RETURN: |
| 154 | | /* clean shutdown on the remote side */ |
| 155 | | |
| 156 | | if (r == 0) { |
| 157 | | munmap(p, c->data.file.length); |
| 158 | | return -2; |
| 159 | | } |
| 160 | | |
| 161 | | /* fall thourgh */ |
| 162 | | default: |
| 163 | | log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", |
| 164 | | ssl_r, r, |
| 165 | | ERR_error_string(ERR_get_error(), NULL)); |
| 166 | | |
| 167 | | munmap(p, c->data.file.length); |
| 168 | | return -1; |
| 169 | | } |
| 170 | | } else { |
| 171 | | c->offset += r; |
| 172 | | con->bytes_written += r; |
| 173 | | } |
| 174 | | |
| 175 | | munmap(p, c->data.file.length); |
| 176 | | |
| 177 | | if (c->offset == c->data.file.length) { |
| 178 | | chunk_finished = 1; |
| 179 | | } |
| | 191 | } else { |
| | 192 | c->offset += r; |
| | 193 | con->bytes_written += r; |
| | 194 | } |
| | 195 | |
| | 196 | if (c->offset == c->data.file.length) { |
| | 197 | chunk_finished = 1; |
| | 198 | } |
| | 199 | } while(!chunk_finished); |