1: #include "first.h"
2:
3: #include "network_backends.h"
4:
5: #if defined(USE_OPENSSL)
6:
7: #include "network.h"
8: #include "log.h"
9:
10: #include <unistd.h>
11: #include <stdlib.h>
12:
13: #include <errno.h>
14: #include <string.h>
15:
16: # include <openssl/ssl.h>
17: # include <openssl/err.h>
18:
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;
21:
22: #define LOCAL_SEND_BUFSIZE (64 * 1024)
23: /* this is a 64k sendbuffer
24: *
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
27: *
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;
32:
33: force_assert(NULL != c);
34:
35: switch (c->type) {
36: case MEM_CHUNK:
37: {
38: size_t have;
39:
40: force_assert(c->offset >= 0 && c->offset <= (off_t)buffer_string_length(c->mem));
41:
42: have = buffer_string_length(c->mem) - c->offset;
43: if ((off_t) have > max_bytes) have = max_bytes;
44:
45: *data = c->mem->ptr + c->offset;
46: *data_len = have;
47: }
48: return 0;
49:
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);
54: }
55:
56: if (0 != network_open_file_chunk(srv, con, cq)) return -1;
57:
58: {
59: off_t offset, toSend;
60:
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;
64:
65: if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
66: if (toSend > max_bytes) toSend = max_bytes;
67:
68: if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
69: log_error_write(srv, __FILE__, __LINE__, "ss", "lseek: ", strerror(errno));
70: return -1;
71: }
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;
75: }
76:
77: *data = local_send_buffer;
78: *data_len = toSend;
79: }
80: return 0;
81: }
82:
83: return -1;
84: }
85:
86:
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 */
92:
93: if (con->keep_alive == 0) {
94: SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
95: }
96:
97: chunkqueue_remove_finished_chunks(cq);
98:
99: while (max_bytes > 0 && NULL != cq->first) {
100: const char *data;
101: size_t data_len;
102: int r;
103:
104: if (0 != load_next_chunk(srv, con, cq, max_bytes, &data, &data_len)) return -1;
105:
106: /**
107: * SSL_write man-page
108: *
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.
113: */
114:
115: ERR_clear_error();
116: r = SSL_write(ssl, data, data_len);
117:
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;
121: }
122:
123: if (r <= 0) {
124: int ssl_r;
125: unsigned long err;
126:
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;
153: }
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));
159: }
160: break;
161:
162: case SSL_ERROR_ZERO_RETURN:
163: /* clean shutdown on the remote side */
164:
165: if (r == 0) return -2;
166:
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));
173: }
174: break;
175: }
176: return -1;
177: }
178:
179: chunkqueue_mark_written(cq, r);
180: max_bytes -= r;
181:
182: if ((size_t) r < data_len) break; /* try again later */
183: }
184:
185: return 0;
186: }
187: #endif /* USE_OPENSSL */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>