BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file BSSLConnection.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <prerror.h>
31 #include <nss/ssl.h>
32  
33 #include <string.h>
34 #include <stdlib.h>
35  
36 #include <misc/print_macros.h>
37 #include <base/BLog.h>
38  
39 #include "BSSLConnection.h"
40  
41 #include <generated/blog_channel_BSSLConnection.h>
42  
43 #define THREADWORK_STATE_NONE 0
44 #define THREADWORK_STATE_HANDSHAKE 1
45 #define THREADWORK_STATE_READ 2
46 #define THREADWORK_STATE_WRITE 3
47  
48 static void backend_threadwork_start (struct BSSLConnection_backend *b, int op);
49 static int backend_threadwork_do_io (struct BSSLConnection_backend *b);
50 static void connection_init_job_handler (BSSLConnection *o);
51 static void connection_init_up (BSSLConnection *o);
52 static void connection_try_io (BSSLConnection *o);
53 static void connection_threadwork_func_work (void *user);
54 static void connection_threadwork_handler_done (void *user);
55 static void connection_recv_job_handler (BSSLConnection *o);
56 static void connection_try_handshake (BSSLConnection *o);
57 static void connection_try_send (BSSLConnection *o);
58 static void connection_try_recv (BSSLConnection *o);
59 static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len);
60 static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len);
61  
62 int bprconnection_initialized = 0;
63 PRDescIdentity bprconnection_identity;
64  
65 static PRFileDesc * get_bottom (PRFileDesc *layer)
66 {
67 while (layer->lower) {
68 layer = layer->lower;
69 }
70  
71 return layer;
72 }
73  
74 static PRStatus method_close (PRFileDesc *fd)
75 {
76 struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
77 ASSERT(!b->con)
78 ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
79  
80 // free mutexes
81 if ((b->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
82 BMutex_Free(&b->recv_buf_mutex);
83 BMutex_Free(&b->send_buf_mutex);
84 }
85  
86 // free backend
87 free(b);
88  
89 // set no secret
90 fd->secret = NULL;
91  
92 return PR_SUCCESS;
93 }
94  
95 static PRInt32 method_read (PRFileDesc *fd, void *buf, PRInt32 amount)
96 {
97 struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
98 ASSERT(amount > 0)
99  
100 if (b->threadwork_state != THREADWORK_STATE_NONE) {
101 BMutex_Lock(&b->recv_buf_mutex);
102 }
103  
104 // if we are receiving into buffer or buffer has no data left, refuse recv
105 if (b->recv_busy || b->recv_pos == b->recv_len) {
106 if (b->threadwork_state != THREADWORK_STATE_NONE) {
107 b->threadwork_want_recv = 1;
108 BMutex_Unlock(&b->recv_buf_mutex);
109 } else {
110 // start receiving if not already
111 if (!b->recv_busy) {
112 // set recv busy
113 b->recv_busy = 1;
114  
115 // receive into buffer
116 StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE);
117 }
118 }
119 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
120 return -1;
121 }
122  
123 // limit amount to available data
124 if (amount > b->recv_len - b->recv_pos) {
125 amount = b->recv_len - b->recv_pos;
126 }
127  
128 // copy data
129 memcpy(buf, b->recv_buf + b->recv_pos, amount);
130  
131 // update buffer
132 b->recv_pos += amount;
133  
134 if (b->threadwork_state != THREADWORK_STATE_NONE) {
135 BMutex_Unlock(&b->recv_buf_mutex);
136 }
137  
138 return amount;
139 }
140  
141 static PRInt32 method_write (PRFileDesc *fd, const void *buf, PRInt32 amount)
142 {
143 struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
144 ASSERT(amount > 0)
145  
146 if (b->threadwork_state != THREADWORK_STATE_NONE) {
147 BMutex_Lock(&b->send_buf_mutex);
148 }
149  
150 ASSERT(!b->send_busy || b->send_pos < b->send_len)
151  
152 // if there is data in buffer, refuse send
153 if (b->send_pos < b->send_len) {
154 if (b->threadwork_state != THREADWORK_STATE_NONE) {
155 b->threadwork_want_send = 1;
156 BMutex_Unlock(&b->send_buf_mutex);
157 }
158 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
159 return -1;
160 }
161  
162 // limit amount to buffer size
163 if (amount > BSSLCONNECTION_BUF_SIZE) {
164 amount = BSSLCONNECTION_BUF_SIZE;
165 }
166  
167 // init buffer
168 memcpy(b->send_buf, buf, amount);
169 b->send_pos = 0;
170 b->send_len = amount;
171  
172 if (b->threadwork_state != THREADWORK_STATE_NONE) {
173 BMutex_Unlock(&b->send_buf_mutex);
174 } else {
175 // start sending
176 b->send_busy = 1;
177 StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
178 }
179  
180 return amount;
181 }
182  
183 static PRStatus method_shutdown (PRFileDesc *fd, PRIntn how)
184 {
185 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
186 return PR_FAILURE;
187 }
188  
189 static PRInt32 method_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
190 {
191 ASSERT(flags == 0)
192  
193 return method_read(fd, buf, amount);
194 }
195  
196 static PRInt32 method_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
197 {
198 ASSERT(flags == 0)
199  
200 return method_write(fd, buf, amount);
201 }
202  
203 static PRInt16 method_poll (PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
204 {
205 *out_flags = 0;
206 return in_flags;
207 }
208  
209 static PRStatus method_getpeername (PRFileDesc *fd, PRNetAddr *addr)
210 {
211 memset(addr, 0, sizeof(*addr));
212 addr->raw.family = PR_AF_INET;
213 return PR_SUCCESS;
214 }
215  
216 static PRStatus method_getsocketoption (PRFileDesc *fd, PRSocketOptionData *data)
217 {
218 switch (data->option) {
219 case PR_SockOpt_Nonblocking:
220 data->value.non_blocking = PR_TRUE;
221 return PR_SUCCESS;
222 }
223  
224 PR_SetError(PR_UNKNOWN_ERROR, 0);
225 return PR_FAILURE;
226 }
227  
228 static PRStatus method_setsocketoption (PRFileDesc *fd, const PRSocketOptionData *data)
229 {
230 PR_SetError(PR_UNKNOWN_ERROR, 0);
231 return PR_FAILURE;
232 }
233  
234 static PRIntn _PR_InvalidIntn (void)
235 {
236 ASSERT(0)
237 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
238 return -1;
239 }
240  
241 static PRInt32 _PR_InvalidInt32 (void)
242 {
243 ASSERT(0)
244 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
245 return -1;
246 }
247  
248 static PRInt64 _PR_InvalidInt64 (void)
249 {
250 ASSERT(0)
251 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
252 return -1;
253 }
254  
255 static PROffset32 _PR_InvalidOffset32 (void)
256 {
257 ASSERT(0)
258 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
259 return -1;
260 }
261  
262 static PROffset64 _PR_InvalidOffset64 (void)
263 {
264 ASSERT(0)
265 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
266 return -1;
267 }
268  
269 static PRStatus _PR_InvalidStatus (void)
270 {
271 ASSERT(0)
272 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
273 return PR_FAILURE;
274 }
275  
276 static PRFileDesc *_PR_InvalidDesc (void)
277 {
278 ASSERT(0)
279 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
280 return NULL;
281 }
282  
283 static PRIOMethods methods = {
284 (PRDescType)0,
285 method_close,
286 method_read,
287 method_write,
288 (PRAvailableFN)_PR_InvalidInt32,
289 (PRAvailable64FN)_PR_InvalidInt64,
290 (PRFsyncFN)_PR_InvalidStatus,
291 (PRSeekFN)_PR_InvalidOffset32,
292 (PRSeek64FN)_PR_InvalidOffset64,
293 (PRFileInfoFN)_PR_InvalidStatus,
294 (PRFileInfo64FN)_PR_InvalidStatus,
295 (PRWritevFN)_PR_InvalidInt32,
296 (PRConnectFN)_PR_InvalidStatus,
297 (PRAcceptFN)_PR_InvalidDesc,
298 (PRBindFN)_PR_InvalidStatus,
299 (PRListenFN)_PR_InvalidStatus,
300 method_shutdown,
301 method_recv,
302 method_send,
303 (PRRecvfromFN)_PR_InvalidInt32,
304 (PRSendtoFN)_PR_InvalidInt32,
305 method_poll,
306 (PRAcceptreadFN)_PR_InvalidInt32,
307 (PRTransmitfileFN)_PR_InvalidInt32,
308 (PRGetsocknameFN)_PR_InvalidStatus,
309 method_getpeername,
310 (PRReservedFN)_PR_InvalidIntn,
311 (PRReservedFN)_PR_InvalidIntn,
312 method_getsocketoption,
313 method_setsocketoption,
314 (PRSendfileFN)_PR_InvalidInt32,
315 (PRConnectcontinueFN)_PR_InvalidStatus,
316 (PRReservedFN)_PR_InvalidIntn,
317 (PRReservedFN)_PR_InvalidIntn,
318 (PRReservedFN)_PR_InvalidIntn,
319 (PRReservedFN)_PR_InvalidIntn
320 };
321  
322 static void backend_send_if_handler_done (struct BSSLConnection_backend *b, int data_len)
323 {
324 ASSERT(b->send_busy)
325 ASSERT(b->send_len > 0)
326 ASSERT(b->send_pos < b->send_len)
327 ASSERT(data_len > 0)
328 ASSERT(data_len <= b->send_len - b->send_pos)
329  
330 if (b->threadwork_state != THREADWORK_STATE_NONE) {
331 BMutex_Lock(&b->send_buf_mutex);
332 }
333  
334 // update buffer
335 b->send_pos += data_len;
336  
337 // send more if needed
338 if (b->send_pos < b->send_len) {
339 StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
340 if (b->threadwork_state != THREADWORK_STATE_NONE) {
341 BMutex_Unlock(&b->send_buf_mutex);
342 }
343 return;
344 }
345  
346 // set send not busy
347 b->send_busy = 0;
348  
349 if (b->threadwork_state != THREADWORK_STATE_NONE) {
350 BMutex_Unlock(&b->send_buf_mutex);
351 }
352  
353 // notify connection
354 if (b->con && !b->con->have_error) {
355 connection_try_io(b->con);
356 return;
357 }
358 }
359  
360 static void backend_recv_if_handler_done (struct BSSLConnection_backend *b, int data_len)
361 {
362 ASSERT(b->recv_busy)
363 ASSERT(data_len > 0)
364 ASSERT(data_len <= BSSLCONNECTION_BUF_SIZE)
365  
366 if (b->threadwork_state != THREADWORK_STATE_NONE) {
367 BMutex_Lock(&b->recv_buf_mutex);
368 }
369  
370 // init buffer
371 b->recv_busy = 0;
372 b->recv_pos = 0;
373 b->recv_len = data_len;
374  
375 if (b->threadwork_state != THREADWORK_STATE_NONE) {
376 BMutex_Unlock(&b->recv_buf_mutex);
377 }
378  
379 // notify connection
380 if (b->con && !b->con->have_error) {
381 connection_try_io(b->con);
382 return;
383 }
384 }
385  
386 static void backend_threadwork_start (struct BSSLConnection_backend *b, int op)
387 {
388 ASSERT(b->con)
389 ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
390 ASSERT(op == THREADWORK_STATE_HANDSHAKE || op == THREADWORK_STATE_READ || op == THREADWORK_STATE_WRITE)
391  
392 b->threadwork_state = op;
393 b->threadwork_want_recv = 0;
394 b->threadwork_want_send = 0;
395 BThreadWork_Init(&b->threadwork, b->twd, connection_threadwork_handler_done, b->con, connection_threadwork_func_work, b->con);
396 }
397  
398 static int backend_threadwork_do_io (struct BSSLConnection_backend *b)
399 {
400 ASSERT(b->con)
401 ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
402  
403 int io_ready = (b->threadwork_want_recv && !b->recv_busy && b->recv_pos < b->recv_len) ||
404 (b->threadwork_want_send && b->send_pos == b->send_len);
405  
406 if (b->threadwork_want_recv && b->recv_pos == b->recv_len && !b->recv_busy) {
407 b->recv_busy = 1;
408 StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE);
409 }
410  
411 if (b->send_pos < b->send_len && !b->send_busy) {
412 b->send_busy = 1;
413 StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
414 }
415  
416 return io_ready;
417 }
418  
419 static void connection_report_error (BSSLConnection *o)
420 {
421 ASSERT(!o->have_error)
422  
423 // set error
424 o->have_error = 1;
425  
426 // report error
427 DEBUGERROR(&o->d_err, o->handler(o->user, BSSLCONNECTION_EVENT_ERROR));
428 }
429  
430 static void connection_init_job_handler (BSSLConnection *o)
431 {
432 DebugObject_Access(&o->d_obj);
433 ASSERT(!o->have_error)
434 ASSERT(!o->up)
435  
436 connection_try_handshake(o);
437 }
438  
439 static void connection_init_up (BSSLConnection *o)
440 {
441 // unset init job
442 // (just in the impossible case that handshake completed before the init job executed)
443 BPending_Unset(&o->init_job);
444  
445 // init send interface
446 StreamPassInterface_Init(&o->send_if, (StreamPassInterface_handler_send)connection_send_if_handler_send, o, o->pg);
447  
448 // init recv interface
449 StreamRecvInterface_Init(&o->recv_if, (StreamRecvInterface_handler_recv)connection_recv_if_handler_recv, o, o->pg);
450  
451 // init recv job
452 BPending_Init(&o->recv_job, o->pg, (BPending_handler)connection_recv_job_handler, o);
453  
454 // set no send data
455 o->send_len = -1;
456  
457 // set no recv data
458 o->recv_avail = -1;
459  
460 // set up
461 o->up = 1;
462 }
463  
464 static void connection_try_io (BSSLConnection *o)
465 {
466 DebugObject_Access(&o->d_obj);
467 ASSERT(!o->have_error)
468  
469 if (!o->up) {
470 connection_try_handshake(o);
471 return;
472 }
473  
474 if (o->send_len > 0) {
475 if (o->recv_avail > 0) {
476 BPending_Set(&o->recv_job);
477 }
478  
479 connection_try_send(o);
480 return;
481 }
482  
483 if (o->recv_avail > 0) {
484 connection_try_recv(o);
485 return;
486 }
487 }
488  
489 static void connection_threadwork_func_work (void *user)
490 {
491 BSSLConnection *o = (BSSLConnection *)user;
492 struct BSSLConnection_backend *b = o->backend;
493 ASSERT(b->threadwork_state != THREADWORK_STATE_NONE)
494  
495 switch (b->threadwork_state) {
496 case THREADWORK_STATE_HANDSHAKE:
497 b->threadwork_result_sec = SSL_ForceHandshake(o->prfd);
498 break;
499 case THREADWORK_STATE_WRITE:
500 b->threadwork_result_pr = PR_Write(o->prfd, o->send_data, o->send_len);
501 break;
502 case THREADWORK_STATE_READ:
503 b->threadwork_result_pr = PR_Read(o->prfd, o->recv_data, o->recv_avail);
504 break;
505 default:
506 ASSERT(0);
507 }
508  
509 b->threadwork_error = PR_GetError();
510 }
511  
512 static void connection_threadwork_handler_done (void *user)
513 {
514 BSSLConnection *o = (BSSLConnection *)user;
515 struct BSSLConnection_backend *b = o->backend;
516 ASSERT(b->threadwork_state != THREADWORK_STATE_NONE)
517  
518 // remember what operation the threadwork was performing
519 int op = b->threadwork_state;
520  
521 // free threadwork
522 BThreadWork_Free(&b->threadwork);
523 b->threadwork_state = THREADWORK_STATE_NONE;
524  
525 // start any necessary backend I/O operations, and determine if any of the requested
526 // backend I/O that was not available at the time is now available
527 int io_ready = backend_threadwork_do_io(b);
528  
529 switch (op) {
530 case THREADWORK_STATE_HANDSHAKE: {
531 ASSERT(!o->up)
532 ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE))
533  
534 if (b->threadwork_result_sec == SECFailure) {
535 if (b->threadwork_error == PR_WOULD_BLOCK_ERROR) {
536 if (io_ready) {
537 // requested backend I/O got ready, try again
538 backend_threadwork_start(o->backend, THREADWORK_STATE_HANDSHAKE);
539 }
540 return;
541 }
542 BLog(BLOG_ERROR, "SSL_ForceHandshake failed (%"PRIi32")", b->threadwork_error);
543 connection_report_error(o);
544 return;
545 }
546  
547 // init up
548 connection_init_up(o);
549  
550 // report up
551 o->handler(o->user, BSSLCONNECTION_EVENT_UP);
552 return;
553 } break;
554  
555 case THREADWORK_STATE_WRITE: {
556 ASSERT(o->up)
557 ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO))
558 ASSERT(o->send_len > 0)
559  
560 PRInt32 result = b->threadwork_result_pr;
561 PRErrorCode error = b->threadwork_error;
562  
563 if (result < 0) {
564 if (error == PR_WOULD_BLOCK_ERROR) {
565 if (io_ready) {
566 // requested backend I/O got ready, try again
567 backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
568 } else if (o->recv_avail > 0) {
569 // don't forget about receiving
570 backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
571 }
572 return;
573 }
574 BLog(BLOG_ERROR, "PR_Write failed (%"PRIi32")", error);
575 connection_report_error(o);
576 return;
577 }
578  
579 ASSERT(result > 0)
580 ASSERT(result <= o->send_len)
581  
582 // set no send data
583 o->send_len = -1;
584  
585 // don't forget about receiving
586 if (o->recv_avail > 0) {
587 backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
588 }
589  
590 // finish send operation
591 StreamPassInterface_Done(&o->send_if, result);
592 } break;
593  
594 case THREADWORK_STATE_READ: {
595 ASSERT(o->up)
596 ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO))
597 ASSERT(o->recv_avail > 0)
598  
599 PRInt32 result = b->threadwork_result_pr;
600 PRErrorCode error = b->threadwork_error;
601  
602 if (result < 0) {
603 if (error == PR_WOULD_BLOCK_ERROR) {
604 if (io_ready) {
605 // requested backend I/O got ready, try again
606 backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
607 } else if (o->send_len > 0) {
608 // don't forget about sending
609 backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
610 }
611 return;
612 }
613 BLog(BLOG_ERROR, "PR_Read failed (%"PRIi32")", error);
614 connection_report_error(o);
615 return;
616 }
617  
618 if (result == 0) {
619 BLog(BLOG_ERROR, "PR_Read returned 0");
620 connection_report_error(o);
621 return;
622 }
623  
624 ASSERT(result > 0)
625 ASSERT(result <= o->recv_avail)
626  
627 // set no recv data
628 o->recv_avail = -1;
629  
630 // don't forget about sending
631 if (o->send_len > 0) {
632 backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
633 }
634  
635 // finish receive operation
636 StreamRecvInterface_Done(&o->recv_if, result);
637 } break;
638  
639 default:
640 ASSERT(0);
641 }
642  
643 return;
644 }
645  
646 static void connection_recv_job_handler (BSSLConnection *o)
647 {
648 DebugObject_Access(&o->d_obj);
649 ASSERT(!o->have_error)
650 ASSERT(o->up)
651 ASSERT(o->recv_avail > 0)
652  
653 connection_try_recv(o);
654 return;
655 }
656  
657 static void connection_try_handshake (BSSLConnection *o)
658 {
659 ASSERT(!o->have_error)
660 ASSERT(!o->up)
661  
662 // continue in threadwork if requested
663 if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE)) {
664 if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
665 backend_threadwork_start(o->backend, THREADWORK_STATE_HANDSHAKE);
666 }
667 return;
668 }
669  
670 // try handshake
671 SECStatus res = SSL_ForceHandshake(o->prfd);
672 if (res == SECFailure) {
673 PRErrorCode error = PR_GetError();
674 if (error == PR_WOULD_BLOCK_ERROR) {
675 return;
676 }
677 BLog(BLOG_ERROR, "SSL_ForceHandshake failed (%"PRIi32")", error);
678 connection_report_error(o);
679 return;
680 }
681  
682 // init up
683 connection_init_up(o);
684  
685 // report up
686 o->handler(o->user, BSSLCONNECTION_EVENT_UP);
687 return;
688 }
689  
690 static void connection_try_send (BSSLConnection *o)
691 {
692 ASSERT(!o->have_error)
693 ASSERT(o->up)
694 ASSERT(o->send_len > 0)
695  
696 // continue in threadwork if requested
697 if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
698 if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
699 backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
700 }
701 return;
702 }
703  
704 // send
705 PRInt32 res = PR_Write(o->prfd, o->send_data, o->send_len);
706 if (res < 0) {
707 PRErrorCode error = PR_GetError();
708 if (error == PR_WOULD_BLOCK_ERROR) {
709 return;
710 }
711 BLog(BLOG_ERROR, "PR_Write failed (%"PRIi32")", error);
712 connection_report_error(o);
713 return;
714 }
715  
716 ASSERT(res > 0)
717 ASSERT(res <= o->send_len)
718  
719 // set no send data
720 o->send_len = -1;
721  
722 // done
723 StreamPassInterface_Done(&o->send_if, res);
724 }
725  
726 static void connection_try_recv (BSSLConnection *o)
727 {
728 ASSERT(!o->have_error)
729 ASSERT(o->up)
730 ASSERT(o->recv_avail > 0)
731  
732 // unset recv job
733 BPending_Unset(&o->recv_job);
734  
735 // continue in threadwork if requested
736 if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
737 if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
738 backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
739 }
740 return;
741 }
742  
743 // recv
744 PRInt32 res = PR_Read(o->prfd, o->recv_data, o->recv_avail);
745 if (res < 0) {
746 PRErrorCode error = PR_GetError();
747 if (error == PR_WOULD_BLOCK_ERROR) {
748 return;
749 }
750 BLog(BLOG_ERROR, "PR_Read failed (%"PRIi32")", error);
751 connection_report_error(o);
752 return;
753 }
754  
755 if (res == 0) {
756 BLog(BLOG_ERROR, "PR_Read returned 0");
757 connection_report_error(o);
758 return;
759 }
760  
761 ASSERT(res > 0)
762 ASSERT(res <= o->recv_avail)
763  
764 // set no recv data
765 o->recv_avail = -1;
766  
767 // done
768 StreamRecvInterface_Done(&o->recv_if, res);
769 }
770  
771 static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len)
772 {
773 DebugObject_Access(&o->d_obj);
774 ASSERT(!o->have_error)
775 ASSERT(o->up)
776 ASSERT(o->send_len == -1)
777 ASSERT(data_len > 0)
778  
779 #ifndef NDEBUG
780 ASSERT(!o->releasebuffers_called)
781 o->user_io_started = 1;
782 #endif
783  
784 // limit amount for PR_Write
785 if (data_len > INT32_MAX) {
786 data_len = INT32_MAX;
787 }
788  
789 // set send data
790 o->send_data = data;
791 o->send_len = data_len;
792  
793 // start sending
794 connection_try_send(o);
795 }
796  
797 static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len)
798 {
799 DebugObject_Access(&o->d_obj);
800 ASSERT(!o->have_error)
801 ASSERT(o->up)
802 ASSERT(o->recv_avail == -1)
803 ASSERT(data_len > 0)
804  
805 #ifndef NDEBUG
806 ASSERT(!o->releasebuffers_called)
807 o->user_io_started = 1;
808 #endif
809  
810 // limit amount for PR_Read
811 if (data_len > INT32_MAX) {
812 data_len = INT32_MAX;
813 }
814  
815 // set recv data
816 o->recv_data = data;
817 o->recv_avail = data_len;
818  
819 // start receiving
820 connection_try_recv(o);
821 }
822  
823 int BSSLConnection_GlobalInit (void)
824 {
825 ASSERT(!bprconnection_initialized)
826  
827 if ((bprconnection_identity = PR_GetUniqueIdentity("BSSLConnection")) == PR_INVALID_IO_LAYER) {
828 BLog(BLOG_ERROR, "PR_GetUniqueIdentity failed");
829 return 0;
830 }
831  
832 bprconnection_initialized = 1;
833  
834 return 1;
835 }
836  
837 int BSSLConnection_MakeBackend (PRFileDesc *prfd, StreamPassInterface *send_if, StreamRecvInterface *recv_if, BThreadWorkDispatcher *twd, int flags)
838 {
839 ASSERT(bprconnection_initialized)
840 ASSERT(!(flags & ~(BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE | BSSLCONNECTION_FLAG_THREADWORK_IO)))
841 ASSERT(!(flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || twd)
842 ASSERT(!(flags & BSSLCONNECTION_FLAG_THREADWORK_IO) || twd)
843  
844 // don't do stuff in threads if threads aren't available
845 if (((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) &&
846 !BThreadWorkDispatcher_UsingThreads(twd)
847 ) {
848 BLog(BLOG_WARNING, "SSL operations in threads requested but threads are not available");
849 flags &= ~(BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE | BSSLCONNECTION_FLAG_THREADWORK_IO);
850 }
851  
852 // allocate backend
853 struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)malloc(sizeof(*b));
854 if (!b) {
855 BLog(BLOG_ERROR, "malloc failed");
856 goto fail0;
857 }
858  
859 // init mutexes
860 if ((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
861 if (!BMutex_Init(&b->send_buf_mutex)) {
862 BLog(BLOG_ERROR, "BMutex_Init failed");
863 goto fail1;
864 }
865  
866 if (!BMutex_Init(&b->recv_buf_mutex)) {
867 BLog(BLOG_ERROR, "BMutex_Init failed");
868 goto fail2;
869 }
870 }
871  
872 // init arguments
873 b->send_if = send_if;
874 b->recv_if = recv_if;
875 b->twd = twd;
876 b->flags = flags;
877  
878 // init interfaces
879 StreamPassInterface_Sender_Init(b->send_if, (StreamPassInterface_handler_done)backend_send_if_handler_done, b);
880 StreamRecvInterface_Receiver_Init(b->recv_if, (StreamRecvInterface_handler_done)backend_recv_if_handler_done, b);
881  
882 // set no connection
883 b->con = NULL;
884  
885 // init send buffer
886 b->send_busy = 0;
887 b->send_len = 0;
888 b->send_pos = 0;
889  
890 // init recv buffer
891 b->recv_busy = 0;
892 b->recv_pos = 0;
893 b->recv_len = 0;
894  
895 // set threadwork state
896 b->threadwork_state = THREADWORK_STATE_NONE;
897  
898 // init prfd
899 memset(prfd, 0, sizeof(*prfd));
900 prfd->methods = &methods;
901 prfd->secret = (PRFilePrivate *)b;
902 prfd->identity = bprconnection_identity;
903  
904 return 1;
905  
906 if ((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
907 fail2:
908 BMutex_Free(&b->send_buf_mutex);
909 }
910 fail1:
911 free(b);
912 fail0:
913 return 0;
914 }
915  
916 void BSSLConnection_Init (BSSLConnection *o, PRFileDesc *prfd, int force_handshake, BPendingGroup *pg, void *user,
917 BSSLConnection_handler handler)
918 {
919 ASSERT(force_handshake == 0 || force_handshake == 1)
920 ASSERT(handler)
921 ASSERT(bprconnection_initialized)
922 ASSERT(get_bottom(prfd)->identity == bprconnection_identity)
923 ASSERT(!((struct BSSLConnection_backend *)(get_bottom(prfd)->secret))->con)
924  
925 // init arguments
926 o->prfd = prfd;
927 o->pg = pg;
928 o->user = user;
929 o->handler = handler;
930  
931 // set backend
932 o->backend = (struct BSSLConnection_backend *)(get_bottom(prfd)->secret);
933 ASSERT(!o->backend->con)
934 ASSERT(o->backend->threadwork_state == THREADWORK_STATE_NONE)
935  
936 // set have no error
937 o->have_error = 0;
938  
939 // init init job
940 BPending_Init(&o->init_job, o->pg, (BPending_handler)connection_init_job_handler, o);
941  
942 if (force_handshake) {
943 // set not up
944 o->up = 0;
945  
946 // set init job
947 BPending_Set(&o->init_job);
948 } else {
949 // init up
950 connection_init_up(o);
951 }
952  
953 // set backend connection
954 o->backend->con = o;
955  
956 #ifndef NDEBUG
957 o->user_io_started = 0;
958 o->releasebuffers_called = 0;
959 #endif
960  
961 DebugError_Init(&o->d_err, o->pg);
962 DebugObject_Init(&o->d_obj);
963 }
964  
965 void BSSLConnection_Free (BSSLConnection *o)
966 {
967 DebugObject_Free(&o->d_obj);
968 DebugError_Free(&o->d_err);
969 #ifndef NDEBUG
970 ASSERT(o->releasebuffers_called || !o->user_io_started)
971 #endif
972 ASSERT(o->backend->threadwork_state == THREADWORK_STATE_NONE)
973  
974 if (o->up) {
975 // free recv job
976 BPending_Free(&o->recv_job);
977  
978 // free recv interface
979 StreamRecvInterface_Free(&o->recv_if);
980  
981 // free send interface
982 StreamPassInterface_Free(&o->send_if);
983 }
984  
985 // free init job
986 BPending_Free(&o->init_job);
987  
988 // unset backend connection
989 o->backend->con = NULL;
990 }
991  
992 void BSSLConnection_ReleaseBuffers (BSSLConnection *o)
993 {
994 DebugObject_Access(&o->d_obj);
995 #ifndef NDEBUG
996 ASSERT(!o->releasebuffers_called)
997 #endif
998  
999 // wait for threadwork to finish
1000 if (o->backend->threadwork_state != THREADWORK_STATE_NONE) {
1001 BThreadWork_Free(&o->backend->threadwork);
1002 o->backend->threadwork_state = THREADWORK_STATE_NONE;
1003 }
1004  
1005 #ifndef NDEBUG
1006 o->releasebuffers_called = 1;
1007 #endif
1008 }
1009  
1010 StreamPassInterface * BSSLConnection_GetSendIf (BSSLConnection *o)
1011 {
1012 DebugObject_Access(&o->d_obj);
1013 ASSERT(o->up)
1014  
1015 return &o->send_if;
1016 }
1017  
1018 StreamRecvInterface * BSSLConnection_GetRecvIf (BSSLConnection *o)
1019 {
1020 DebugObject_Access(&o->d_obj);
1021 ASSERT(o->up)
1022  
1023 return &o->recv_if;
1024 }