Mercurial > hg > nginx-vendor-0-8
comparison src/event/ngx_event_openssl.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | cc9f381affaa |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 | |
11 | |
12 static ngx_int_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); | |
13 | |
14 | |
15 ngx_int_t ngx_ssl_init(ngx_log_t *log) | |
16 { | |
17 SSL_library_init(); | |
18 SSL_load_error_strings(); | |
19 | |
20 return NGX_OK; | |
21 } | |
22 | |
23 | |
24 ngx_int_t ngx_ssl_create_session(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c, | |
25 ngx_uint_t flags) | |
26 { | |
27 ngx_ssl_t *ssl; | |
28 | |
29 if (!(ssl = ngx_pcalloc(c->pool, sizeof(ngx_ssl_t)))) { | |
30 return NGX_ERROR; | |
31 } | |
32 | |
33 if (!(ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE))) { | |
34 return NGX_ERROR; | |
35 } | |
36 | |
37 if (flags & NGX_SSL_BUFFER) { | |
38 ssl->buffer = 1; | |
39 } | |
40 | |
41 ssl->ssl = SSL_new(ssl_ctx); | |
42 | |
43 if (ssl->ssl == NULL) { | |
44 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); | |
45 return NGX_ERROR; | |
46 } | |
47 | |
48 if (SSL_set_fd(ssl->ssl, c->fd) == 0) { | |
49 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed"); | |
50 return NGX_ERROR; | |
51 } | |
52 | |
53 SSL_set_accept_state(ssl->ssl); | |
54 | |
55 c->ssl = ssl; | |
56 | |
57 return NGX_OK; | |
58 } | |
59 | |
60 | |
61 ngx_int_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) | |
62 { | |
63 int n, sslerr; | |
64 ngx_err_t err; | |
65 char *handshake; | |
66 | |
67 n = SSL_read(c->ssl->ssl, buf, size); | |
68 | |
69 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); | |
70 | |
71 if (n > 0) { | |
72 return n; | |
73 } | |
74 | |
75 sslerr = SSL_get_error(c->ssl->ssl, n); | |
76 | |
77 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
78 | |
79 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
80 | |
81 if (sslerr == SSL_ERROR_WANT_READ) { | |
82 return NGX_AGAIN; | |
83 } | |
84 | |
85 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
86 ngx_log_error(NGX_LOG_ALERT, c->log, err, | |
87 "SSL wants to write%s", handshake); | |
88 return NGX_ERROR; | |
89 #if 0 | |
90 return NGX_AGAIN; | |
91 #endif | |
92 } | |
93 | |
94 if (!SSL_is_init_finished(c->ssl->ssl)) { | |
95 handshake = "in SSL handshake"; | |
96 | |
97 } else { | |
98 handshake = ""; | |
99 } | |
100 | |
101 c->ssl->no_rcv_shut = 1; | |
102 | |
103 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { | |
104 ngx_log_error(NGX_LOG_INFO, c->log, err, | |
105 "client closed connection%s", handshake); | |
106 | |
107 return NGX_ERROR; | |
108 } | |
109 | |
110 ngx_ssl_error(NGX_LOG_ALERT, c->log, err, | |
111 "SSL_read() failed%s", handshake); | |
112 | |
113 return NGX_ERROR; | |
114 } | |
115 | |
116 | |
117 /* | |
118 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer | |
119 * before SSL_write() call to decrease a SSL overhead. | |
120 * | |
121 * Besides for protocols such as HTTP it is possible to always buffer | |
122 * the output to decrease a SSL overhead some more. | |
123 */ | |
124 | |
125 ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, | |
126 off_t limit) | |
127 { | |
128 int n; | |
129 ngx_uint_t flush; | |
130 ssize_t send, size; | |
131 ngx_buf_t *buf; | |
132 | |
133 buf = c->ssl->buf; | |
134 | |
135 if (in && in->next == NULL && !c->buffered && !c->ssl->buffer) { | |
136 | |
137 /* | |
138 * we avoid a buffer copy if the incoming buf is a single, | |
139 * our buffer is empty, and we do not need to buffer the output | |
140 */ | |
141 | |
142 n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos); | |
143 | |
144 if (n == NGX_ERROR) { | |
145 return NGX_CHAIN_ERROR; | |
146 } | |
147 | |
148 if (n < 0) { | |
149 n = 0; | |
150 } | |
151 | |
152 in->buf->pos += n; | |
153 | |
154 return in; | |
155 } | |
156 | |
157 send = 0; | |
158 flush = (in == NULL) ? 1 : 0; | |
159 | |
160 for ( ;; ) { | |
161 | |
162 while (in && buf->last < buf->end) { | |
163 if (in->buf->last_buf) { | |
164 flush = 1; | |
165 } | |
166 | |
167 if (ngx_buf_special(in->buf)) { | |
168 in = in->next; | |
169 continue; | |
170 } | |
171 | |
172 size = in->buf->last - in->buf->pos; | |
173 | |
174 if (size > buf->end - buf->last) { | |
175 size = buf->end - buf->last; | |
176 } | |
177 | |
178 /* | |
179 * TODO: the taking in->buf->flush into account can be | |
180 * implemented using the limit on the higher level | |
181 */ | |
182 | |
183 if (send + size > limit) { | |
184 size = limit - send; | |
185 flush = 1; | |
186 } | |
187 | |
188 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
189 "SSL buf copy: %d", size); | |
190 | |
191 ngx_memcpy(buf->last, in->buf->pos, size); | |
192 | |
193 buf->last += size; | |
194 | |
195 in->buf->pos += size; | |
196 if (in->buf->pos == in->buf->last) { | |
197 in = in->next; | |
198 } | |
199 } | |
200 | |
201 size = buf->last - buf->pos; | |
202 | |
203 if (!flush && buf->last < buf->end && c->ssl->buffer) { | |
204 break; | |
205 } | |
206 | |
207 n = ngx_ssl_write(c, buf->pos, size); | |
208 | |
209 if (n == NGX_ERROR) { | |
210 return NGX_CHAIN_ERROR; | |
211 } | |
212 | |
213 if (n < 0) { | |
214 n = 0; | |
215 } | |
216 | |
217 buf->pos += n; | |
218 send += n; | |
219 c->sent += n; | |
220 | |
221 if (n < size) { | |
222 break; | |
223 } | |
224 | |
225 if (buf->pos == buf->last) { | |
226 buf->pos = buf->start; | |
227 buf->last = buf->start; | |
228 } | |
229 | |
230 if (in == NULL || send == limit) { | |
231 break; | |
232 } | |
233 } | |
234 | |
235 c->buffered = (buf->pos < buf->last) ? 1 : 0; | |
236 | |
237 return in; | |
238 } | |
239 | |
240 | |
241 static ngx_int_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) | |
242 { | |
243 int n, sslerr; | |
244 ngx_err_t err; | |
245 | |
246 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); | |
247 | |
248 n = SSL_write(c->ssl->ssl, data, size); | |
249 | |
250 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n); | |
251 | |
252 if (n > 0) { | |
253 return n; | |
254 } | |
255 | |
256 sslerr = SSL_get_error(c->ssl->ssl, n); | |
257 | |
258 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
259 | |
260 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
261 | |
262 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
263 c->write->ready = 0; | |
264 return NGX_AGAIN; | |
265 } | |
266 | |
267 if (sslerr == SSL_ERROR_WANT_READ) { | |
268 ngx_log_error(NGX_LOG_ALERT, c->log, err, | |
269 "SSL wants to read%s", handshake); | |
270 return NGX_ERROR; | |
271 #if 0 | |
272 return NGX_AGAIN; | |
273 } | |
274 #endif | |
275 | |
276 c->ssl->no_rcv_shut = 1; | |
277 | |
278 ngx_ssl_error(NGX_LOG_ALERT, c->log, err, "SSL_write() failed"); | |
279 | |
280 return NGX_ERROR; | |
281 } | |
282 | |
283 | |
284 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) | |
285 { | |
286 int n, sslerr; | |
287 ngx_uint_t again; | |
288 | |
289 if (c->timedout) { | |
290 SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN); | |
291 | |
292 } else { | |
293 if (c->ssl->no_rcv_shut) { | |
294 SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN); | |
295 } | |
296 | |
297 if (c->ssl->no_send_shut) { | |
298 SSL_set_shutdown(c->ssl->ssl, SSL_SENT_SHUTDOWN); | |
299 } | |
300 } | |
301 | |
302 again = 0; | |
303 | |
304 for ( ;; ) { | |
305 n = SSL_shutdown(c->ssl->ssl); | |
306 | |
307 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); | |
308 | |
309 if (n == 0) { | |
310 again = 1; | |
311 break; | |
312 } | |
313 | |
314 if (n == 1) { | |
315 SSL_free(c->ssl->ssl); | |
316 c->ssl = NULL; | |
317 return NGX_OK; | |
318 } | |
319 | |
320 break; | |
321 } | |
322 | |
323 if (!again) { | |
324 sslerr = SSL_get_error(c->ssl->ssl, n); | |
325 | |
326 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
327 "SSL_get_error: %d", sslerr); | |
328 } | |
329 | |
330 if (again || sslerr == SSL_ERROR_WANT_READ) { | |
331 | |
332 ngx_add_timer(c->read, 10000); | |
333 | |
334 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
335 return NGX_ERROR; | |
336 } | |
337 | |
338 return NGX_AGAIN; | |
339 } | |
340 | |
341 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
342 | |
343 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
344 return NGX_ERROR; | |
345 } | |
346 | |
347 return NGX_AGAIN; | |
348 } | |
349 | |
350 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); | |
351 | |
352 return NGX_ERROR; | |
353 } | |
354 | |
355 | |
356 void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, | |
357 char *fmt, ...) | |
358 { | |
359 int len; | |
360 char errstr[NGX_MAX_CONF_ERRSTR]; | |
361 va_list args; | |
362 | |
363 va_start(args, fmt); | |
364 len = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); | |
365 va_end(args); | |
366 | |
367 errstr[len++] = ' '; | |
368 errstr[len++] = '('; | |
369 errstr[len++] = 'S'; | |
370 errstr[len++] = 'S'; | |
371 errstr[len++] = 'L'; | |
372 errstr[len++] = ':'; | |
373 errstr[len++] = ' '; | |
374 | |
375 ERR_error_string_n(ERR_get_error(), errstr + len, sizeof(errstr) - len - 1); | |
376 | |
377 ngx_log_error(level, log, err, "%s)", errstr); | |
378 } |