[core] consolidate duplicated read-to-close code
[lighttpd.git] / src / network_openssl.c
blob9a9138edbf9d42271cd55f37c0a1933e67e26f6e
1 #include "first.h"
3 #include "network_backends.h"
5 #if defined(USE_OPENSSL)
7 #include "network.h"
8 #include "log.h"
10 #include <unistd.h>
11 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
16 # include <openssl/ssl.h>
17 # include <openssl/err.h>
19 static int load_next_chunk(server *srv, connection *con, chunkqueue *cq, off_t max_bytes, const char **data, size_t *data_len) {
20 chunk * const c = cq->first;
22 #define LOCAL_SEND_BUFSIZE (64 * 1024)
23 /* this is a 64k sendbuffer
25 * it has to stay at the same location all the time to satisfy the needs
26 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
28 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
29 * -> we expect a 64k block to 'leak' in valgrind
30 * */
31 static char *local_send_buffer = NULL;
33 force_assert(NULL != c);
35 switch (c->type) {
36 case MEM_CHUNK:
38 size_t have;
40 force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
42 have = buffer_string_length(c->mem) - c->offset;
43 if ((off_t) have > max_bytes) have = max_bytes;
45 *data = c->mem->ptr + c->offset;
46 *data_len = have;
48 return 0;
50 case FILE_CHUNK:
51 if (NULL == local_send_buffer) {
52 local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
53 force_assert(NULL != local_send_buffer);
56 if (0 != network_open_file_chunk(srv, con, cq)) return -1;
59 off_t offset, toSend;
61 force_assert(c->offset >= 0 && c->offset <= c->file.length);
62 offset = c->file.start + c->offset;
63 toSend = c->file.length - c->offset;
65 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
66 if (toSend > max_bytes) toSend = max_bytes;
68 if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
69 log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
70 return -1;
72 if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
73 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
74 return -1;
77 *data = local_send_buffer;
78 *data_len = toSend;
80 return 0;
83 return -1;
87 int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
88 /* the remote side closed the connection before without shutdown request
89 * - IE
90 * - wget
91 * if keep-alive is disabled */
93 if (con->keep_alive == 0) {
94 SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
97 chunkqueue_remove_finished_chunks(cq);
99 while (max_bytes > 0 && NULL != cq->first) {
100 const char *data;
101 size_t data_len;
102 int r;
104 if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
107 * SSL_write man-page
109 * WARNING
110 * When an SSL_write() operation has to be repeated because of
111 * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
112 * repeated with the same arguments.
115 ERR_clear_error();
116 r = SSL_write(ssl, data, data_len);
118 if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
119 log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
120 return -1;
123 if (r <= 0) {
124 int ssl_r;
125 unsigned long err;
127 switch ((ssl_r = SSL_get_error(ssl, r))) {
128 case SSL_ERROR_WANT_READ:
129 con->is_readable = -1;
130 return 0; /* try again later */
131 case SSL_ERROR_WANT_WRITE:
132 con->is_writable = -1;
133 return 0; /* try again later */
134 case SSL_ERROR_SYSCALL:
135 /* perhaps we have error waiting in our error-queue */
136 if (0 != (err = ERR_get_error())) {
137 do {
138 log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
139 ssl_r, r,
140 ERR_error_string(err, NULL));
141 } while((err = ERR_get_error()));
142 } else if (r == -1) {
143 /* no, but we have errno */
144 switch(errno) {
145 case EPIPE:
146 case ECONNRESET:
147 return -2;
148 default:
149 log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
150 ssl_r, r, errno,
151 strerror(errno));
152 break;
154 } else {
155 /* neither error-queue nor errno ? */
156 log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
157 ssl_r, r, errno,
158 strerror(errno));
160 break;
162 case SSL_ERROR_ZERO_RETURN:
163 /* clean shutdown on the remote side */
165 if (r == 0) return -2;
167 /* fall through */
168 default:
169 while((err = ERR_get_error())) {
170 log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
171 ssl_r, r,
172 ERR_error_string(err, NULL));
174 break;
176 return -1;
179 chunkqueue_mark_written(cq, r);
180 max_bytes -= r;
182 if ((size_t) r < data_len) break; /* try again later */
185 return 0;
187 #endif /* USE_OPENSSL */