/[Apache-SVN]/httpd/flood/trunk/flood_net_ssl.c
ViewVC logotype

Contents of /httpd/flood/trunk/flood_net_ssl.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 698796 - (show annotations) (download)
Thu Sep 25 01:47:23 2008 UTC (15 years, 10 months ago) by jerenkrantz
File MIME type: text/plain
File size: 9067 byte(s)
Fix HTTP keepalives over SSL.

* flood_net_ssl.c
  (ssl_check_socket): Implement.
* flood_net_ssl.h
  (ssl_check_socket): Declare.
* flood_socket_keepalive.c
  (ksock_check_socket, ksock_close_socket): Declare helper macros.
  (keepalive_begin_conn): Use helper function to call appropriate checker.
  (keepalive_end_conn): Use helper to close socket.

1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
17 */
18
19 #include <apr_portable.h>
20 #include <apr_strings.h>
21
22 #if APR_HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #include "config.h"
27 #include "flood_profile.h"
28 #include "flood_net.h"
29 #include "flood_net_ssl.h"
30
31 #if FLOOD_HAS_OPENSSL
32
33 #define OPENSSL_THREAD_DEFINES
34 #include <openssl/ssl.h>
35 #include <openssl/err.h>
36 #include <openssl/rand.h>
37
38 struct ssl_socket_t {
39 SSL_CTX *ssl_context;
40 SSL *ssl_connection;
41 flood_socket_t *socket;
42 };
43
44 apr_pool_t *ssl_pool;
45
46 #if APR_HAS_THREADS
47 apr_thread_mutex_t **ssl_locks;
48
49 typedef struct CRYPTO_dynlock_value {
50 apr_thread_mutex_t *lock;
51 } CRYPTO_dynlock_value;
52
53 static CRYPTO_dynlock_value *ssl_dyn_create(const char* file, int line)
54 {
55 CRYPTO_dynlock_value *l;
56 apr_status_t rv;
57
58 l = apr_palloc(ssl_pool, sizeof(CRYPTO_dynlock_value));
59 rv = apr_thread_mutex_create(&l->lock, APR_THREAD_MUTEX_DEFAULT, ssl_pool);
60 if (rv != APR_SUCCESS) {
61 /* FIXME: return error here */
62 }
63 return l;
64 }
65
66 static void ssl_dyn_lock(int mode, CRYPTO_dynlock_value *l, const char *file,
67 int line)
68 {
69 if (mode & CRYPTO_LOCK) {
70 apr_thread_mutex_lock(l->lock);
71 }
72 else if (mode & CRYPTO_UNLOCK) {
73 apr_thread_mutex_unlock(l->lock);
74 }
75 }
76
77 static void ssl_dyn_destroy(CRYPTO_dynlock_value *l, const char *file,
78 int line)
79 {
80 apr_thread_mutex_destroy(l->lock);
81 }
82
83 static void ssl_lock(int mode, int n, const char *file, int line)
84 {
85 if (mode & CRYPTO_LOCK) {
86 apr_thread_mutex_lock(ssl_locks[n]);
87 }
88 else if (mode & CRYPTO_UNLOCK) {
89 apr_thread_mutex_unlock(ssl_locks[n]);
90 }
91 }
92
93 static unsigned long ssl_id(void)
94 {
95 /* FIXME: This is lame and not portable. -aaron */
96 return (unsigned long) apr_os_thread_current();
97 }
98 #endif
99
100 /* borrowed from mod_ssl */
101 static int ssl_rand_choosenum(int l, int h)
102 {
103 int i;
104 char buf[50];
105
106 srand((unsigned int)time(NULL));
107 apr_snprintf(buf, sizeof(buf), "%.0f",
108 (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
109 i = atoi(buf)+1;
110 if (i < l) i = l;
111 if (i > h) i = h;
112 return i;
113 }
114
115 static void load_rand(void)
116 {
117 unsigned char stackdata[256];
118 time_t tt;
119 pid_t pid;
120 int l, n;
121
122 tt = time(NULL);
123 l = sizeof(time_t);
124 RAND_seed((unsigned char *)&tt, l);
125
126 pid = (pid_t)getpid();
127 l = sizeof(pid_t);
128 RAND_seed((unsigned char *)&pid, l);
129
130 n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
131 RAND_seed(stackdata+n, 128);
132 }
133
134 apr_status_t ssl_init_socket(apr_pool_t *pool)
135 {
136 #if APR_HAS_THREADS
137 int i, numlocks;
138 #endif
139
140 ssl_pool = pool;
141
142 SSL_library_init();
143 OpenSSL_add_ssl_algorithms();
144 SSL_load_error_strings();
145 ERR_load_crypto_strings();
146 #if ! FLOOD_HAS_DEVRAND
147 load_rand();
148 #endif
149
150 #if APR_HAS_THREADS
151 numlocks = CRYPTO_num_locks();
152 ssl_locks = apr_palloc(pool, sizeof(apr_thread_mutex_t*)*numlocks);
153 for (i = 0; i < numlocks; i++) {
154 apr_status_t rv;
155
156 /* Intraprocess locks don't /need/ a filename... */
157 rv = apr_thread_mutex_create(&ssl_locks[i], APR_THREAD_MUTEX_DEFAULT,
158 ssl_pool);
159 if (rv != APR_SUCCESS) {
160 /* FIXME: error out here */
161 }
162 }
163
164 CRYPTO_set_locking_callback(ssl_lock);
165 CRYPTO_set_id_callback(ssl_id);
166
167 CRYPTO_set_dynlock_create_callback(ssl_dyn_create);
168 CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock);
169 CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy);
170 #endif
171
172 return APR_SUCCESS;
173 }
174
175 void ssl_read_socket_handshake(ssl_socket_t *s);
176
177 ssl_socket_t* ssl_open_socket(apr_pool_t *pool, request_t *r,
178 apr_status_t *status)
179 {
180 apr_os_sock_t ossock;
181 int e, sslError;
182
183 ssl_socket_t *ssl_socket = apr_pcalloc(pool, sizeof(ssl_socket_t));
184
185 /* Open our TCP-based connection */
186 ssl_socket->socket = open_socket(pool, r, status);
187
188 if (!ssl_socket->socket)
189 return NULL;
190
191 /* Get the native OS socket. */
192 apr_os_sock_get(&ossock, ssl_socket->socket->socket);
193
194 /* Create a local context */
195 ssl_socket->ssl_context = SSL_CTX_new(SSLv23_client_method());
196 SSL_CTX_set_options(ssl_socket->ssl_context, SSL_OP_ALL);
197 #ifdef SSL_MODE_AUTO_RETRY
198 /* Not all OpenSSL versions support this. */
199 SSL_CTX_set_options(ssl_socket->ssl_context, SSL_MODE_AUTO_RETRY);
200 #endif
201 /*SSL_CTX_set_default_verify_paths(ssl_socket->ssl_context);*/
202 SSL_CTX_load_verify_locations(ssl_socket->ssl_context, NULL, CAPATH);
203
204 /* Initialize the SSL connection */
205 ssl_socket->ssl_connection = SSL_new(ssl_socket->ssl_context);
206 SSL_set_connect_state(ssl_socket->ssl_connection);
207
208 /* Set the descriptors */
209 SSL_set_fd(ssl_socket->ssl_connection, ossock);
210 e = SSL_connect(ssl_socket->ssl_connection);
211
212 if (e)
213 {
214 sslError = SSL_get_error(ssl_socket->ssl_connection, e);
215
216 switch (sslError)
217 {
218 case SSL_ERROR_NONE:
219 case SSL_ERROR_WANT_READ:
220 case SSL_ERROR_WANT_WRITE:
221 /* Treat as okay. */
222 break;
223 default:
224 ERR_print_errors_fp(stderr);
225 return NULL;
226 }
227 }
228
229 return ssl_socket;
230 }
231
232 /* close down TCP socket */
233 void ssl_close_socket(ssl_socket_t *s)
234 {
235 SSL_free(s->ssl_connection);
236 SSL_CTX_free(s->ssl_context);
237 close_socket(s->socket);
238 }
239
240 apr_status_t ssl_read_socket(ssl_socket_t *s, char *buf, apr_size_t *buflen)
241 {
242 apr_status_t e;
243 int sslError;
244 apr_int32_t socketsRead;
245
246 /* Wait until there is something to read. */
247 if (SSL_pending(s->ssl_connection) < *buflen) {
248 e = apr_poll(&s->socket->read_pollset, 1, &socketsRead,
249 LOCAL_SOCKET_TIMEOUT);
250
251 if (socketsRead != 1)
252 return APR_TIMEUP;
253 }
254
255 e = SSL_read(s->ssl_connection, buf, *buflen);
256 sslError = SSL_get_error(s->ssl_connection, e);
257
258 switch (sslError)
259 {
260 case SSL_ERROR_NONE:
261 *buflen = e;
262 break;
263 case SSL_ERROR_WANT_READ:
264 ssl_read_socket(s, buf, buflen);
265 break;
266 case SSL_ERROR_ZERO_RETURN: /* Peer closed connection. */
267 return APR_EOF;
268 case SSL_ERROR_SYSCALL: /* Look at errno. */
269 if (errno == 0)
270 return APR_EOF;
271 /* Continue through with the error case. */
272 case SSL_ERROR_WANT_WRITE: /* Technically, not an error. */
273 default:
274 ERR_print_errors_fp(stderr);
275 return APR_EGENERAL;
276 }
277
278 return APR_SUCCESS;
279 }
280
281 void ssl_read_socket_handshake(ssl_socket_t *s)
282 {
283 char buf[1];
284 int buflen = 1;
285 /* Wait until there is something to read. */
286 apr_int32_t socketsRead;
287 apr_status_t e;
288 e = apr_poll(&s->socket->read_pollset, 1, &socketsRead,
289 LOCAL_SOCKET_TIMEOUT);
290 e = SSL_read(s->ssl_connection, buf, buflen);
291 }
292
293 /* Write to the socket */
294 apr_status_t ssl_write_socket(ssl_socket_t *s, request_t *r)
295 {
296 apr_status_t e;
297 int sslError;
298
299 /* Returns an error. */
300 e = SSL_write(s->ssl_connection, r->rbuf, r->rbufsize);
301
302 sslError = SSL_get_error(s->ssl_connection, e);
303 switch (sslError)
304 {
305 case SSL_ERROR_NONE:
306 break;
307 case SSL_ERROR_WANT_READ:
308 ssl_read_socket_handshake(s);
309 ssl_write_socket(s, r);
310 break;
311 case SSL_ERROR_WANT_WRITE:
312 break;
313 default:
314 ERR_print_errors_fp(stderr);
315 return APR_EGENERAL;
316 }
317
318 return APR_SUCCESS;
319 }
320
321 apr_status_t ssl_check_socket(ssl_socket_t *s, apr_pool_t *pool)
322 {
323 return check_socket(s->socket, pool);
324 }
325
326 #else /* FLOOD_HAS_OPENSSL */
327
328 apr_status_t ssl_init_socket(apr_pool_t *pool)
329 {
330 return APR_ENOTIMPL;
331 }
332
333 ssl_socket_t* ssl_open_socket(apr_pool_t *pool, request_t *r,
334 apr_status_t *status)
335 {
336 return NULL;
337 }
338
339 void ssl_close_socket(ssl_socket_t *s)
340 {
341 }
342
343 apr_status_t ssl_write_socket(ssl_socket_t *s, request_t *r)
344 {
345 return APR_ENOTIMPL;
346 }
347
348 apr_status_t ssl_read_socket(ssl_socket_t *s, char *buf, apr_size_t *buflen)
349 {
350 return APR_ENOTIMPL;
351 }
352
353 apr_status_t ssl_check_socket(ssl_socket_t *s, apr_pool_t *pool)
354 {
355 return APR_ENOTIMPL;
356 }
357
358 #endif /* FLOOD_HAS_OPENSSL */

Properties

Name Value
svn:eol-style native

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26