BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file StreamPeerIO.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 <stdlib.h>
31  
32 #include <nss/ssl.h>
33 #include <nss/sslerr.h>
34  
35 #include <misc/offset.h>
36 #include <misc/byteorder.h>
37  
38 #include <client/StreamPeerIO.h>
39  
40 #include <generated/blog_channel_StreamPeerIO.h>
41  
42 #define MODE_NONE 0
43 #define MODE_CONNECT 1
44 #define MODE_LISTEN 2
45  
46 #define CONNECT_STATE_CONNECTING 0
47 #define CONNECT_STATE_HANDSHAKE 1
48 #define CONNECT_STATE_SENDING 2
49 #define CONNECT_STATE_SENT 3
50 #define CONNECT_STATE_FINISHED 4
51  
52 #define LISTEN_STATE_LISTENER 0
53 #define LISTEN_STATE_GOTCLIENT 1
54 #define LISTEN_STATE_FINISHED 2
55  
56 #define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
57  
58 static void decoder_handler_error (StreamPeerIO *pio);
59 static void connector_handler (StreamPeerIO *pio, int is_error);
60 static void connection_handler (StreamPeerIO *pio, int event);
61 static void connect_sslcon_handler (StreamPeerIO *pio, int event);
62 static void pwsender_handler (StreamPeerIO *pio);
63 static void listener_handler_client (StreamPeerIO *pio, sslsocket *sock);
64 static int init_io (StreamPeerIO *pio, sslsocket *sock);
65 static void free_io (StreamPeerIO *pio);
66 static void sslcon_handler (StreamPeerIO *pio, int event);
67 static SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer);
68 static SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey);
69 static int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert);
70 static void reset_state (StreamPeerIO *pio);
71 static void reset_and_report_error (StreamPeerIO *pio);
72  
73 void decoder_handler_error (StreamPeerIO *pio)
74 {
75 DebugObject_Access(&pio->d_obj);
76  
77 PeerLog(pio, BLOG_ERROR, "decoder error");
78  
79 reset_and_report_error(pio);
80 return;
81 }
82  
83 void connector_handler (StreamPeerIO *pio, int is_error)
84 {
85 DebugObject_Access(&pio->d_obj);
86 ASSERT(pio->mode == MODE_CONNECT)
87 ASSERT(pio->connect.state == CONNECT_STATE_CONNECTING)
88  
89 // check connection result
90 if (is_error) {
91 PeerLog(pio, BLOG_NOTICE, "connection failed");
92 goto fail0;
93 }
94  
95 // init connection
96 if (!BConnection_Init(&pio->connect.sock.con, BConnection_source_connector(&pio->connect.connector), pio->reactor, pio, (BConnection_handler)connection_handler)) {
97 PeerLog(pio, BLOG_ERROR, "BConnection_Init failed");
98 goto fail0;
99 }
100  
101 if (pio->ssl) {
102 // init connection interfaces
103 BConnection_SendAsync_Init(&pio->connect.sock.con);
104 BConnection_RecvAsync_Init(&pio->connect.sock.con);
105  
106 // create bottom NSPR file descriptor
107 if (!BSSLConnection_MakeBackend(&pio->connect.sock.bottom_prfd, BConnection_SendAsync_GetIf(&pio->connect.sock.con), BConnection_RecvAsync_GetIf(&pio->connect.sock.con), pio->twd, pio->ssl_flags)) {
108 PeerLog(pio, BLOG_ERROR, "BSSLConnection_MakeBackend failed");
109 goto fail1;
110 }
111  
112 // create SSL file descriptor from the bottom NSPR file descriptor
113 if (!(pio->connect.sock.ssl_prfd = SSL_ImportFD(NULL, &pio->connect.sock.bottom_prfd))) {
114 ASSERT_FORCE(PR_Close(&pio->connect.sock.bottom_prfd) == PR_SUCCESS)
115 goto fail1;
116 }
117  
118 // set client mode
119 if (SSL_ResetHandshake(pio->connect.sock.ssl_prfd, PR_FALSE) != SECSuccess) {
120 PeerLog(pio, BLOG_ERROR, "SSL_ResetHandshake failed");
121 goto fail2;
122 }
123  
124 // set verify peer certificate hook
125 if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, (SSLAuthCertificate)client_auth_certificate_callback, pio) != SECSuccess) {
126 PeerLog(pio, BLOG_ERROR, "SSL_AuthCertificateHook failed");
127 goto fail2;
128 }
129  
130 // set client certificate callback
131 if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, (SSLGetClientAuthData)client_client_auth_data_callback, pio) != SECSuccess) {
132 PeerLog(pio, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
133 goto fail2;
134 }
135  
136 // init BSSLConnection
137 BSSLConnection_Init(&pio->connect.sslcon, pio->connect.sock.ssl_prfd, 1, BReactor_PendingGroup(pio->reactor), pio, (BSSLConnection_handler)connect_sslcon_handler);
138  
139 // change state
140 pio->connect.state = CONNECT_STATE_HANDSHAKE;
141 } else {
142 // init connection send interface
143 BConnection_SendAsync_Init(&pio->connect.sock.con);
144  
145 // init password sender
146 SingleStreamSender_Init(&pio->connect.pwsender, (uint8_t *)&pio->connect.password, sizeof(pio->connect.password), BConnection_SendAsync_GetIf(&pio->connect.sock.con), BReactor_PendingGroup(pio->reactor), pio, (SingleStreamSender_handler)pwsender_handler);
147  
148 // change state
149 pio->connect.state = CONNECT_STATE_SENDING;
150 }
151  
152 return;
153  
154 if (pio->ssl) {
155 fail2:
156 ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
157 fail1:
158 BConnection_RecvAsync_Free(&pio->connect.sock.con);
159 BConnection_SendAsync_Free(&pio->connect.sock.con);
160 }
161 BConnection_Free(&pio->connect.sock.con);
162 fail0:
163 reset_and_report_error(pio);
164 return;
165 }
166  
167 void connection_handler (StreamPeerIO *pio, int event)
168 {
169 DebugObject_Access(&pio->d_obj);
170 ASSERT(pio->mode == MODE_CONNECT || pio->mode == MODE_LISTEN)
171 ASSERT(!(pio->mode == MODE_CONNECT) || pio->connect.state >= CONNECT_STATE_HANDSHAKE)
172 ASSERT(!(pio->mode == MODE_LISTEN) || pio->listen.state >= LISTEN_STATE_FINISHED)
173  
174 if (event == BCONNECTION_EVENT_RECVCLOSED) {
175 PeerLog(pio, BLOG_NOTICE, "connection closed");
176 } else {
177 PeerLog(pio, BLOG_NOTICE, "connection error");
178 }
179  
180 reset_and_report_error(pio);
181 return;
182 }
183  
184 void connect_sslcon_handler (StreamPeerIO *pio, int event)
185 {
186 DebugObject_Access(&pio->d_obj);
187 ASSERT(pio->ssl)
188 ASSERT(pio->mode == MODE_CONNECT)
189 ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE || pio->connect.state == CONNECT_STATE_SENDING)
190 ASSERT(event == BSSLCONNECTION_EVENT_UP || event == BSSLCONNECTION_EVENT_ERROR)
191  
192 if (event == BSSLCONNECTION_EVENT_ERROR) {
193 PeerLog(pio, BLOG_NOTICE, "SSL error");
194  
195 reset_and_report_error(pio);
196 return;
197 }
198  
199 // handshake complete
200 ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
201  
202 // remove client certificate callback
203 if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
204 PeerLog(pio, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
205 goto fail0;
206 }
207  
208 // remove verify peer certificate callback
209 if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
210 PeerLog(pio, BLOG_ERROR, "SSL_AuthCertificateHook failed");
211 goto fail0;
212 }
213  
214 // init password sender
215 SingleStreamSender_Init(&pio->connect.pwsender, (uint8_t *)&pio->connect.password, sizeof(pio->connect.password), BSSLConnection_GetSendIf(&pio->connect.sslcon), BReactor_PendingGroup(pio->reactor), pio, (SingleStreamSender_handler)pwsender_handler);
216  
217 // change state
218 pio->connect.state = CONNECT_STATE_SENDING;
219  
220 return;
221  
222 fail0:
223 reset_and_report_error(pio);
224 return;
225 }
226  
227 void pwsender_handler (StreamPeerIO *pio)
228 {
229 DebugObject_Access(&pio->d_obj);
230 ASSERT(pio->mode == MODE_CONNECT)
231 ASSERT(pio->connect.state == CONNECT_STATE_SENDING)
232  
233 // stop using any buffers before they get freed
234 if (pio->ssl) {
235 BSSLConnection_ReleaseBuffers(&pio->connect.sslcon);
236 }
237  
238 // free password sender
239 SingleStreamSender_Free(&pio->connect.pwsender);
240  
241 if (pio->ssl) {
242 // free BSSLConnection (we used the send interface)
243 BSSLConnection_Free(&pio->connect.sslcon);
244 } else {
245 // init connection send interface
246 BConnection_SendAsync_Free(&pio->connect.sock.con);
247 }
248  
249 // change state
250 pio->connect.state = CONNECT_STATE_SENT;
251  
252 // setup i/o
253 if (!init_io(pio, &pio->connect.sock)) {
254 goto fail0;
255 }
256  
257 // change state
258 pio->connect.state = CONNECT_STATE_FINISHED;
259  
260 return;
261  
262 fail0:
263 reset_and_report_error(pio);
264 return;
265 }
266  
267 void listener_handler_client (StreamPeerIO *pio, sslsocket *sock)
268 {
269 DebugObject_Access(&pio->d_obj);
270 ASSERT(pio->mode == MODE_LISTEN)
271 ASSERT(pio->listen.state == LISTEN_STATE_LISTENER)
272  
273 // remember socket
274 pio->listen.sock = sock;
275  
276 // set connection handler
277 BConnection_SetHandlers(&pio->listen.sock->con, pio, (BConnection_handler)connection_handler);
278  
279 // change state
280 pio->listen.state = LISTEN_STATE_GOTCLIENT;
281  
282 // check ceritficate
283 if (pio->ssl) {
284 CERTCertificate *peer_cert = SSL_PeerCertificate(pio->listen.sock->ssl_prfd);
285 if (!peer_cert) {
286 PeerLog(pio, BLOG_ERROR, "SSL_PeerCertificate failed");
287 goto fail0;
288 }
289  
290 // compare certificate to the one provided by the server
291 if (!compare_certificate(pio, peer_cert)) {
292 CERT_DestroyCertificate(peer_cert);
293 goto fail0;
294 }
295  
296 CERT_DestroyCertificate(peer_cert);
297 }
298  
299 // setup i/o
300 if (!init_io(pio, pio->listen.sock)) {
301 goto fail0;
302 }
303  
304 // change state
305 pio->listen.state = LISTEN_STATE_FINISHED;
306  
307 return;
308  
309 fail0:
310 reset_and_report_error(pio);
311 return;
312 }
313  
314 int init_io (StreamPeerIO *pio, sslsocket *sock)
315 {
316 ASSERT(!pio->sock)
317  
318 // limit socket send buffer, else our scheduling is pointless
319 if (pio->sock_sndbuf > 0) {
320 if (!BConnection_SetSendBuffer(&sock->con, pio->sock_sndbuf)) {
321 PeerLog(pio, BLOG_WARNING, "BConnection_SetSendBuffer failed");
322 }
323 }
324  
325 if (pio->ssl) {
326 // init BSSLConnection
327 BSSLConnection_Init(&pio->sslcon, sock->ssl_prfd, 0, BReactor_PendingGroup(pio->reactor), pio, (BSSLConnection_handler)sslcon_handler);
328 } else {
329 // init connection interfaces
330 BConnection_SendAsync_Init(&sock->con);
331 BConnection_RecvAsync_Init(&sock->con);
332 }
333  
334 StreamPassInterface *send_if = (pio->ssl ? BSSLConnection_GetSendIf(&pio->sslcon) : BConnection_SendAsync_GetIf(&sock->con));
335 StreamRecvInterface *recv_if = (pio->ssl ? BSSLConnection_GetRecvIf(&pio->sslcon) : BConnection_RecvAsync_GetIf(&sock->con));
336  
337 // init receiving
338 StreamRecvConnector_ConnectInput(&pio->input_connector, recv_if);
339  
340 // init sending
341 PacketStreamSender_Init(&pio->output_pss, send_if, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
342 PacketPassConnector_ConnectOutput(&pio->output_connector, PacketStreamSender_GetInput(&pio->output_pss));
343  
344 pio->sock = sock;
345  
346 return 1;
347 }
348  
349 void free_io (StreamPeerIO *pio)
350 {
351 ASSERT(pio->sock)
352  
353 // stop using any buffers before they get freed
354 if (pio->ssl) {
355 BSSLConnection_ReleaseBuffers(&pio->sslcon);
356 }
357  
358 // reset decoder
359 PacketProtoDecoder_Reset(&pio->input_decoder);
360  
361 // free sending
362 PacketPassConnector_DisconnectOutput(&pio->output_connector);
363 PacketStreamSender_Free(&pio->output_pss);
364  
365 // free receiving
366 StreamRecvConnector_DisconnectInput(&pio->input_connector);
367  
368 if (pio->ssl) {
369 // free BSSLConnection
370 BSSLConnection_Free(&pio->sslcon);
371 } else {
372 // free connection interfaces
373 BConnection_RecvAsync_Free(&pio->sock->con);
374 BConnection_SendAsync_Free(&pio->sock->con);
375 }
376  
377 pio->sock = NULL;
378 }
379  
380 void sslcon_handler (StreamPeerIO *pio, int event)
381 {
382 DebugObject_Access(&pio->d_obj);
383 ASSERT(pio->ssl)
384 ASSERT(pio->mode == MODE_CONNECT || pio->mode == MODE_LISTEN)
385 ASSERT(!(pio->mode == MODE_CONNECT) || pio->connect.state == CONNECT_STATE_FINISHED)
386 ASSERT(!(pio->mode == MODE_LISTEN) || pio->listen.state == LISTEN_STATE_FINISHED)
387 ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
388  
389 PeerLog(pio, BLOG_NOTICE, "SSL error");
390  
391 reset_and_report_error(pio);
392 return;
393 }
394  
395 SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
396 {
397 ASSERT(pio->ssl)
398 ASSERT(pio->mode == MODE_CONNECT)
399 ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
400 DebugObject_Access(&pio->d_obj);
401  
402 // This callback is used to bypass checking the server's domain name, as peers
403 // don't have domain names. We byte-compare the certificate to the one reported
404 // by the server anyway.
405  
406 SECStatus ret = SECFailure;
407  
408 CERTCertificate *server_cert = SSL_PeerCertificate(pio->connect.sock.ssl_prfd);
409 if (!server_cert) {
410 PeerLog(pio, BLOG_ERROR, "SSL_PeerCertificate failed");
411 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
412 goto fail1;
413 }
414  
415 if (CERT_VerifyCertNow(CERT_GetDefaultCertDB(), server_cert, PR_TRUE, certUsageSSLServer, SSL_RevealPinArg(pio->connect.sock.ssl_prfd)) != SECSuccess) {
416 goto fail2;
417 }
418  
419 // compare to certificate provided by the server
420 if (!compare_certificate(pio, server_cert)) {
421 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
422 goto fail2;
423 }
424  
425 ret = SECSuccess;
426  
427 fail2:
428 CERT_DestroyCertificate(server_cert);
429 fail1:
430 return ret;
431 }
432  
433 SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
434 {
435 ASSERT(pio->ssl)
436 ASSERT(pio->mode == MODE_CONNECT)
437 ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
438 DebugObject_Access(&pio->d_obj);
439  
440 CERTCertificate *cert = CERT_DupCertificate(pio->connect.ssl_cert);
441 if (!cert) {
442 PeerLog(pio, BLOG_ERROR, "CERT_DupCertificate failed");
443 goto fail0;
444 }
445  
446 SECKEYPrivateKey *key = SECKEY_CopyPrivateKey(pio->connect.ssl_key);
447 if (!key) {
448 PeerLog(pio, BLOG_ERROR, "SECKEY_CopyPrivateKey failed");
449 goto fail1;
450 }
451  
452 *pRetCert = cert;
453 *pRetKey = key;
454 return SECSuccess;
455  
456 fail1:
457 CERT_DestroyCertificate(cert);
458 fail0:
459 return SECFailure;
460 }
461  
462 int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert)
463 {
464 ASSERT(pio->ssl)
465  
466 SECItem der = cert->derCert;
467 if (der.len != pio->ssl_peer_cert_len || memcmp(der.data, pio->ssl_peer_cert, der.len)) {
468 PeerLog(pio, BLOG_NOTICE, "Client certificate doesn't match");
469 return 0;
470 }
471  
472 return 1;
473 }
474  
475 void reset_state (StreamPeerIO *pio)
476 {
477 // free resources
478 switch (pio->mode) {
479 case MODE_NONE:
480 break;
481 case MODE_LISTEN:
482 switch (pio->listen.state) {
483 case LISTEN_STATE_FINISHED:
484 free_io(pio);
485 case LISTEN_STATE_GOTCLIENT:
486 if (pio->ssl) {
487 ASSERT_FORCE(PR_Close(pio->listen.sock->ssl_prfd) == PR_SUCCESS)
488 BConnection_RecvAsync_Free(&pio->listen.sock->con);
489 BConnection_SendAsync_Free(&pio->listen.sock->con);
490 }
491 BConnection_Free(&pio->listen.sock->con);
492 free(pio->listen.sock);
493 case LISTEN_STATE_LISTENER:
494 if (pio->listen.state == LISTEN_STATE_LISTENER) {
495 PasswordListener_RemoveEntry(pio->listen.listener, &pio->listen.pwentry);
496 }
497 break;
498 default:
499 ASSERT(0);
500 }
501 break;
502 case MODE_CONNECT:
503 switch (pio->connect.state) {
504 case CONNECT_STATE_FINISHED:
505 free_io(pio);
506 case CONNECT_STATE_SENT:
507 case CONNECT_STATE_SENDING:
508 if (pio->connect.state == CONNECT_STATE_SENDING) {
509 if (pio->ssl) {
510 BSSLConnection_ReleaseBuffers(&pio->connect.sslcon);
511 }
512 SingleStreamSender_Free(&pio->connect.pwsender);
513 if (!pio->ssl) {
514 BConnection_SendAsync_Free(&pio->connect.sock.con);
515 }
516 }
517 case CONNECT_STATE_HANDSHAKE:
518 if (pio->ssl) {
519 if (pio->connect.state == CONNECT_STATE_HANDSHAKE || pio->connect.state == CONNECT_STATE_SENDING) {
520 BSSLConnection_Free(&pio->connect.sslcon);
521 }
522 ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
523 BConnection_RecvAsync_Free(&pio->connect.sock.con);
524 BConnection_SendAsync_Free(&pio->connect.sock.con);
525 }
526 BConnection_Free(&pio->connect.sock.con);
527 case CONNECT_STATE_CONNECTING:
528 BConnector_Free(&pio->connect.connector);
529 break;
530 default:
531 ASSERT(0);
532 }
533 break;
534 default:
535 ASSERT(0);
536 }
537  
538 // set mode none
539 pio->mode = MODE_NONE;
540  
541 ASSERT(!pio->sock)
542 }
543  
544 void reset_and_report_error (StreamPeerIO *pio)
545 {
546 reset_state(pio);
547  
548 pio->handler_error(pio->user);
549 return;
550 }
551  
552 int StreamPeerIO_Init (
553 StreamPeerIO *pio,
554 BReactor *reactor,
555 BThreadWorkDispatcher *twd,
556 int ssl,
557 int ssl_flags,
558 uint8_t *ssl_peer_cert,
559 int ssl_peer_cert_len,
560 int payload_mtu,
561 int sock_sndbuf,
562 PacketPassInterface *user_recv_if,
563 BLog_logfunc logfunc,
564 StreamPeerIO_handler_error handler_error,
565 void *user
566 )
567 {
568 ASSERT(ssl == 0 || ssl == 1)
569 ASSERT(payload_mtu >= 0)
570 ASSERT(PacketPassInterface_GetMTU(user_recv_if) >= payload_mtu)
571 ASSERT(handler_error)
572  
573 // init arguments
574 pio->reactor = reactor;
575 pio->twd = twd;
576 pio->ssl = ssl;
577 if (pio->ssl) {
578 pio->ssl_flags = ssl_flags;
579 pio->ssl_peer_cert = ssl_peer_cert;
580 pio->ssl_peer_cert_len = ssl_peer_cert_len;
581 }
582 pio->payload_mtu = payload_mtu;
583 pio->sock_sndbuf = sock_sndbuf;
584 pio->logfunc = logfunc;
585 pio->handler_error = handler_error;
586 pio->user = user;
587  
588 // check payload MTU
589 if (pio->payload_mtu > PACKETPROTO_MAXPAYLOAD) {
590 PeerLog(pio, BLOG_ERROR, "payload MTU is too large");
591 goto fail0;
592 }
593  
594 // init receiveing objects
595 StreamRecvConnector_Init(&pio->input_connector, BReactor_PendingGroup(pio->reactor));
596 if (!PacketProtoDecoder_Init(&pio->input_decoder, StreamRecvConnector_GetOutput(&pio->input_connector), user_recv_if, BReactor_PendingGroup(pio->reactor), pio,
597 (PacketProtoDecoder_handler_error)decoder_handler_error
598 )) {
599 PeerLog(pio, BLOG_ERROR, "FlowErrorDomain_Init failed");
600 goto fail1;
601 }
602  
603 // init sending objects
604 PacketCopier_Init(&pio->output_user_copier, pio->payload_mtu, BReactor_PendingGroup(pio->reactor));
605 PacketProtoEncoder_Init(&pio->output_user_ppe, PacketCopier_GetOutput(&pio->output_user_copier), BReactor_PendingGroup(pio->reactor));
606 PacketPassConnector_Init(&pio->output_connector, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
607 if (!SinglePacketBuffer_Init(&pio->output_user_spb, PacketProtoEncoder_GetOutput(&pio->output_user_ppe), PacketPassConnector_GetInput(&pio->output_connector), BReactor_PendingGroup(pio->reactor))) {
608 PeerLog(pio, BLOG_ERROR, "SinglePacketBuffer_Init failed");
609 goto fail2;
610 }
611  
612 // set mode none
613 pio->mode = MODE_NONE;
614  
615 // set no socket
616 pio->sock = NULL;
617  
618 DebugObject_Init(&pio->d_obj);
619 return 1;
620  
621 fail2:
622 PacketPassConnector_Free(&pio->output_connector);
623 PacketProtoEncoder_Free(&pio->output_user_ppe);
624 PacketCopier_Free(&pio->output_user_copier);
625 PacketProtoDecoder_Free(&pio->input_decoder);
626 fail1:
627 StreamRecvConnector_Free(&pio->input_connector);
628 fail0:
629 return 0;
630 }
631  
632 void StreamPeerIO_Free (StreamPeerIO *pio)
633 {
634 DebugObject_Free(&pio->d_obj);
635  
636 // reset state
637 reset_state(pio);
638  
639 // free sending objects
640 SinglePacketBuffer_Free(&pio->output_user_spb);
641 PacketPassConnector_Free(&pio->output_connector);
642 PacketProtoEncoder_Free(&pio->output_user_ppe);
643 PacketCopier_Free(&pio->output_user_copier);
644  
645 // free receiveing objects
646 PacketProtoDecoder_Free(&pio->input_decoder);
647 StreamRecvConnector_Free(&pio->input_connector);
648 }
649  
650 PacketPassInterface * StreamPeerIO_GetSendInput (StreamPeerIO *pio)
651 {
652 DebugObject_Access(&pio->d_obj);
653  
654 return PacketCopier_GetInput(&pio->output_user_copier);
655 }
656  
657 int StreamPeerIO_Connect (StreamPeerIO *pio, BAddr addr, uint64_t password, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key)
658 {
659 DebugObject_Access(&pio->d_obj);
660  
661 // reset state
662 reset_state(pio);
663  
664 // check address
665 if (!BConnection_AddressSupported(addr)) {
666 PeerLog(pio, BLOG_ERROR, "BConnection_AddressSupported failed");
667 goto fail0;
668 }
669  
670 // init connector
671 if (!BConnector_Init(&pio->connect.connector, addr, pio->reactor, pio, (BConnector_handler)connector_handler)) {
672 PeerLog(pio, BLOG_ERROR, "BConnector_Init failed");
673 goto fail0;
674 }
675  
676 // remember data
677 if (pio->ssl) {
678 pio->connect.ssl_cert = ssl_cert;
679 pio->connect.ssl_key = ssl_key;
680 }
681 pio->connect.password = htol64(password);
682  
683 // set state
684 pio->mode = MODE_CONNECT;
685 pio->connect.state = CONNECT_STATE_CONNECTING;
686  
687 return 1;
688  
689 fail0:
690 return 0;
691 }
692  
693 void StreamPeerIO_Listen (StreamPeerIO *pio, PasswordListener *listener, uint64_t *password)
694 {
695 DebugObject_Access(&pio->d_obj);
696 ASSERT(listener->ssl == pio->ssl)
697  
698 // reset state
699 reset_state(pio);
700  
701 // add PasswordListener entry
702 uint64_t newpass = PasswordListener_AddEntry(listener, &pio->listen.pwentry, (PasswordListener_handler_client)listener_handler_client, pio);
703  
704 // remember data
705 pio->listen.listener = listener;
706  
707 // set state
708 pio->mode = MODE_LISTEN;
709 pio->listen.state = LISTEN_STATE_LISTENER;
710  
711 *password = newpass;
712 }