StreamPeerIO.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /**
  2. * @file StreamPeerIO.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <stdlib.h>
  23. #include <ssl.h>
  24. #include <sslerr.h>
  25. #include <misc/offset.h>
  26. #include <misc/debug.h>
  27. #include <misc/byteorder.h>
  28. #include <system/BLog.h>
  29. #include <client/StreamPeerIO.h>
  30. #include <generated/blog_channel_StreamPeerIO.h>
  31. #define STREAMPEERIO_COMPONENT_SEND_SINK 0
  32. #define STREAMPEERIO_COMPONENT_RECEIVE_SOURCE 1
  33. #define STREAMPEERIO_COMPONENT_RECEIVE_DECODER 2
  34. #define MODE_NONE 0
  35. #define MODE_CONNECT 1
  36. #define MODE_LISTEN 2
  37. #define CONNECT_STATE_CONNECTING 0
  38. #define CONNECT_STATE_HANDSHAKE 1
  39. #define CONNECT_STATE_SENDING 2
  40. #define CONNECT_STATE_SENT 3
  41. #define CONNECT_STATE_FINISHED 4
  42. #define LISTEN_STATE_LISTENER 0
  43. #define LISTEN_STATE_GOTCLIENT 1
  44. #define LISTEN_STATE_FINISHED 2
  45. #define COMPONENT_SOURCE 1
  46. #define COMPONENT_SINK 2
  47. #define COMPONENT_DECODER 3
  48. static int init_persistent_io (StreamPeerIO *pio, PacketPassInterface *user_recv_if);
  49. static void free_persistent_io (StreamPeerIO *pio);
  50. static void connecting_connect_handler (StreamPeerIO *pio, int event);
  51. static SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer);
  52. static SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey);
  53. static void connecting_try_handshake (StreamPeerIO *pio);
  54. static void connecting_handshake_read_handler (StreamPeerIO *pio, PRInt16 event);
  55. static void connecting_pwsender_handler (StreamPeerIO *pio, int is_error);
  56. static void error_handler (StreamPeerIO *pio, int component, int code);
  57. static void listener_handler_client (StreamPeerIO *pio, sslsocket *sock);
  58. static int init_io (StreamPeerIO *pio, sslsocket *sock);
  59. static void free_io (StreamPeerIO *pio);
  60. static int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert);
  61. static void reset_state (StreamPeerIO *pio);
  62. static void cleanup_socket (sslsocket *sock, int ssl);
  63. static void reset_and_report_error (StreamPeerIO *pio);
  64. void connecting_connect_handler (StreamPeerIO *pio, int event)
  65. {
  66. ASSERT(event == BSOCKET_CONNECT)
  67. ASSERT(pio->mode == MODE_CONNECT)
  68. ASSERT(pio->connect.state == CONNECT_STATE_CONNECTING)
  69. DebugObject_Access(&pio->d_obj);
  70. // remove connect event handler
  71. BSocket_RemoveEventHandler(&pio->connect.sock.sock, BSOCKET_CONNECT);
  72. // check connection result
  73. int res = BSocket_GetConnectResult(&pio->connect.sock.sock);
  74. if (res != 0) {
  75. BLog(BLOG_NOTICE, "Connection failed (%d)", res);
  76. goto fail0;
  77. }
  78. if (pio->ssl) {
  79. // create BSocket NSPR file descriptor
  80. BSocketPRFileDesc_Create(&pio->connect.sock.bottom_prfd, &pio->connect.sock.sock);
  81. // create SSL file descriptor from the socket's BSocketPRFileDesc
  82. if (!(pio->connect.sock.ssl_prfd = SSL_ImportFD(NULL, &pio->connect.sock.bottom_prfd))) {
  83. ASSERT_FORCE(PR_Close(&pio->connect.sock.bottom_prfd) == PR_SUCCESS)
  84. goto fail0;
  85. }
  86. // set client mode
  87. if (SSL_ResetHandshake(pio->connect.sock.ssl_prfd, PR_FALSE) != SECSuccess) {
  88. BLog(BLOG_ERROR, "SSL_ResetHandshake failed");
  89. goto fail_ssl1;
  90. }
  91. // set verify peer certificate hook
  92. if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, (SSLAuthCertificate)client_auth_certificate_callback, pio) != SECSuccess) {
  93. BLog(BLOG_ERROR, "SSL_AuthCertificateHook failed");
  94. goto fail_ssl1;
  95. }
  96. // set client certificate callback
  97. if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, (SSLGetClientAuthData)client_client_auth_data_callback, pio) != SECSuccess) {
  98. BLog(BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
  99. goto fail_ssl1;
  100. }
  101. // initialize BPRFileDesc on SSL file descriptor
  102. BPRFileDesc_Init(&pio->connect.sock.ssl_bprfd, pio->connect.sock.ssl_prfd);
  103. // add event handler for driving handshake
  104. BPRFileDesc_AddEventHandler(&pio->connect.sock.ssl_bprfd, PR_POLL_READ, (BPRFileDesc_handler)connecting_handshake_read_handler, pio);
  105. // change state
  106. pio->connect.state = CONNECT_STATE_HANDSHAKE;
  107. // start handshake
  108. connecting_try_handshake(pio);
  109. return;
  110. } else {
  111. // init password sender
  112. PasswordSender_Init(&pio->connect.pwsender, pio->connect.password, 0, &pio->connect.sock.sock, NULL, (PasswordSender_handler)connecting_pwsender_handler, pio, pio->reactor);
  113. // change state
  114. pio->connect.state = CONNECT_STATE_SENDING;
  115. return;
  116. }
  117. // cleanup
  118. fail_ssl1:
  119. ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
  120. fail0:
  121. reset_and_report_error(pio);
  122. return;
  123. }
  124. SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
  125. {
  126. ASSERT(pio->ssl)
  127. ASSERT(pio->mode == MODE_CONNECT)
  128. ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
  129. DebugObject_Access(&pio->d_obj);
  130. // This callback is used to bypass checking the server's domain name, as peers
  131. // don't have domain names. We byte-compare the certificate to the one reported
  132. // by the server anyway.
  133. SECStatus ret = SECFailure;
  134. CERTCertificate *server_cert = SSL_PeerCertificate(pio->connect.sock.ssl_prfd);
  135. if (!server_cert) {
  136. BLog(BLOG_ERROR, "SSL_PeerCertificate failed");
  137. PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
  138. goto fail1;
  139. }
  140. if (CERT_VerifyCertNow(CERT_GetDefaultCertDB(), server_cert, PR_TRUE, certUsageSSLServer, SSL_RevealPinArg(pio->connect.sock.ssl_prfd)) != SECSuccess) {
  141. goto fail2;
  142. }
  143. // compare to certificate provided by the server
  144. if (!compare_certificate(pio, server_cert)) {
  145. PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
  146. goto fail2;
  147. }
  148. ret = SECSuccess;
  149. fail2:
  150. CERT_DestroyCertificate(server_cert);
  151. fail1:
  152. return ret;
  153. }
  154. SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
  155. {
  156. ASSERT(pio->ssl)
  157. ASSERT(pio->mode == MODE_CONNECT)
  158. ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
  159. DebugObject_Access(&pio->d_obj);
  160. CERTCertificate *cert = CERT_DupCertificate(pio->connect.ssl_cert);
  161. if (!cert) {
  162. BLog(BLOG_ERROR, "CERT_DupCertificate failed");
  163. goto fail0;
  164. }
  165. SECKEYPrivateKey *key = SECKEY_CopyPrivateKey(pio->connect.ssl_key);
  166. if (!key) {
  167. BLog(BLOG_ERROR, "SECKEY_CopyPrivateKey failed");
  168. goto fail1;
  169. }
  170. *pRetCert = cert;
  171. *pRetKey = key;
  172. return SECSuccess;
  173. fail1:
  174. CERT_DestroyCertificate(cert);
  175. fail0:
  176. return SECFailure;
  177. }
  178. void connecting_try_handshake (StreamPeerIO *pio)
  179. {
  180. ASSERT(pio->ssl)
  181. ASSERT(pio->mode == MODE_CONNECT)
  182. ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
  183. if (SSL_ForceHandshake(pio->connect.sock.ssl_prfd) != SECSuccess) {
  184. PRErrorCode error = PR_GetError();
  185. if (error == PR_WOULD_BLOCK_ERROR) {
  186. BPRFileDesc_EnableEvent(&pio->connect.sock.ssl_bprfd, PR_POLL_READ);
  187. return;
  188. }
  189. BLog(BLOG_NOTICE, "SSL_ForceHandshake failed (%d)", (int)error);
  190. goto fail0;
  191. }
  192. // remove client certificate callback
  193. if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
  194. BLog(BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
  195. goto fail0;
  196. }
  197. // remove verify peer certificate callback
  198. if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
  199. BLog(BLOG_ERROR, "SSL_AuthCertificateHook failed");
  200. goto fail0;
  201. }
  202. // remove read handler
  203. BPRFileDesc_RemoveEventHandler(&pio->connect.sock.ssl_bprfd, PR_POLL_READ);
  204. // init password sender
  205. PasswordSender_Init(&pio->connect.pwsender, pio->connect.password, 1, NULL, &pio->connect.sock.ssl_bprfd, (PasswordSender_handler)connecting_pwsender_handler, pio, pio->reactor);
  206. // change state
  207. pio->connect.state = CONNECT_STATE_SENDING;
  208. return;
  209. // cleanup
  210. fail0:
  211. reset_and_report_error(pio);
  212. return;
  213. }
  214. void connecting_handshake_read_handler (StreamPeerIO *pio, PRInt16 event)
  215. {
  216. ASSERT(pio->ssl)
  217. ASSERT(pio->mode == MODE_CONNECT)
  218. ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
  219. DebugObject_Access(&pio->d_obj);
  220. connecting_try_handshake(pio);
  221. return;
  222. }
  223. static void connecting_pwsender_handler (StreamPeerIO *pio, int is_error)
  224. {
  225. ASSERT(pio->mode == MODE_CONNECT)
  226. ASSERT(pio->connect.state == CONNECT_STATE_SENDING)
  227. DebugObject_Access(&pio->d_obj);
  228. if (is_error) {
  229. BLog(BLOG_NOTICE, "error sending password");
  230. goto fail0;
  231. }
  232. // free password sender
  233. PasswordSender_Free(&pio->connect.pwsender);
  234. // change state
  235. pio->connect.state = CONNECT_STATE_SENT;
  236. // setup i/o
  237. if (!init_io(pio, &pio->connect.sock)) {
  238. goto fail0;
  239. }
  240. // change state
  241. pio->connect.state = CONNECT_STATE_FINISHED;
  242. return;
  243. fail0:
  244. reset_and_report_error(pio);
  245. return;
  246. }
  247. void error_handler (StreamPeerIO *pio, int component, int code)
  248. {
  249. ASSERT(pio->sock)
  250. DebugObject_Access(&pio->d_obj);
  251. // cleanup
  252. reset_and_report_error(pio);
  253. return;
  254. }
  255. void listener_handler_client (StreamPeerIO *pio, sslsocket *sock)
  256. {
  257. ASSERT(pio->mode == MODE_LISTEN)
  258. ASSERT(pio->listen.state == LISTEN_STATE_LISTENER)
  259. DebugObject_Access(&pio->d_obj);
  260. // remember socket
  261. pio->listen.sock = sock;
  262. // change state
  263. pio->listen.state = LISTEN_STATE_GOTCLIENT;
  264. // check ceritficate
  265. if (pio->ssl) {
  266. CERTCertificate *peer_cert = SSL_PeerCertificate(pio->listen.sock->ssl_prfd);
  267. if (!peer_cert) {
  268. BLog(BLOG_ERROR, "SSL_PeerCertificate failed");
  269. goto fail0;
  270. }
  271. // compare certificate to the one provided by the server
  272. if (!compare_certificate(pio, peer_cert)) {
  273. CERT_DestroyCertificate(peer_cert);
  274. goto fail0;
  275. }
  276. CERT_DestroyCertificate(peer_cert);
  277. }
  278. // setup i/o
  279. if (!init_io(pio, pio->listen.sock)) {
  280. goto fail0;
  281. }
  282. // change state
  283. pio->listen.state = LISTEN_STATE_FINISHED;
  284. return;
  285. // cleanup
  286. fail0:
  287. reset_and_report_error(pio);
  288. return;
  289. }
  290. int init_persistent_io (StreamPeerIO *pio, PacketPassInterface *user_recv_if)
  291. {
  292. // init error domain
  293. FlowErrorDomain_Init(&pio->ioerrdomain, (FlowErrorDomain_handler)error_handler, pio);
  294. // init receiveing objects
  295. StreamRecvConnector_Init(&pio->input_connector, BReactor_PendingGroup(pio->reactor));
  296. if (!PacketProtoDecoder_Init(
  297. &pio->input_decoder, FlowErrorReporter_Create(&pio->ioerrdomain, COMPONENT_DECODER),
  298. StreamRecvConnector_GetOutput(&pio->input_connector), user_recv_if, BReactor_PendingGroup(pio->reactor)
  299. )) {
  300. goto fail1;
  301. }
  302. // init sending objects
  303. PacketCopier_Init(&pio->output_user_copier, pio->payload_mtu, BReactor_PendingGroup(pio->reactor));
  304. PacketProtoEncoder_Init(&pio->output_user_ppe, PacketCopier_GetOutput(&pio->output_user_copier), BReactor_PendingGroup(pio->reactor));
  305. PacketPassConnector_Init(&pio->output_connector, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
  306. if (!SinglePacketBuffer_Init(&pio->output_user_spb, PacketProtoEncoder_GetOutput(&pio->output_user_ppe), PacketPassConnector_GetInput(&pio->output_connector), BReactor_PendingGroup(pio->reactor))) {
  307. goto fail2;
  308. }
  309. return 1;
  310. fail2:
  311. PacketPassConnector_Free(&pio->output_connector);
  312. PacketProtoEncoder_Free(&pio->output_user_ppe);
  313. PacketCopier_Free(&pio->output_user_copier);
  314. PacketProtoDecoder_Free(&pio->input_decoder);
  315. fail1:
  316. StreamRecvConnector_Free(&pio->input_connector);
  317. return 0;
  318. }
  319. void free_persistent_io (StreamPeerIO *pio)
  320. {
  321. // free sending objects
  322. SinglePacketBuffer_Free(&pio->output_user_spb);
  323. PacketPassConnector_Free(&pio->output_connector);
  324. PacketProtoEncoder_Free(&pio->output_user_ppe);
  325. PacketCopier_Free(&pio->output_user_copier);
  326. // free receiveing objects
  327. PacketProtoDecoder_Free(&pio->input_decoder);
  328. StreamRecvConnector_Free(&pio->input_connector);
  329. }
  330. int init_io (StreamPeerIO *pio, sslsocket *sock)
  331. {
  332. ASSERT(!pio->sock)
  333. // limit socket send buffer, else our scheduling is pointless
  334. if (BSocket_SetSendBuffer(&sock->sock, STREAMPEERIO_SOCKET_SEND_BUFFER) < 0) {
  335. BLog(BLOG_WARNING, "BSocket_SetSendBuffer failed");
  336. }
  337. // init receiving
  338. StreamRecvInterface *source_interface;
  339. if (pio->ssl) {
  340. PRStreamSource_Init(
  341. &pio->input_source.ssl, FlowErrorReporter_Create(&pio->ioerrdomain, COMPONENT_SOURCE),
  342. &sock->ssl_bprfd, BReactor_PendingGroup(pio->reactor)
  343. );
  344. source_interface = PRStreamSource_GetOutput(&pio->input_source.ssl);
  345. } else {
  346. StreamSocketSource_Init(
  347. &pio->input_source.plain, FlowErrorReporter_Create(&pio->ioerrdomain, COMPONENT_SOURCE),
  348. &sock->sock, BReactor_PendingGroup(pio->reactor)
  349. );
  350. source_interface = StreamSocketSource_GetOutput(&pio->input_source.plain);
  351. }
  352. StreamRecvConnector_ConnectInput(&pio->input_connector, source_interface);
  353. // init sending
  354. StreamPassInterface *sink_interface;
  355. if (pio->ssl) {
  356. PRStreamSink_Init(
  357. &pio->output_sink.ssl, FlowErrorReporter_Create(&pio->ioerrdomain, COMPONENT_SINK),
  358. &sock->ssl_bprfd, BReactor_PendingGroup(pio->reactor)
  359. );
  360. sink_interface = PRStreamSink_GetInput(&pio->output_sink.ssl);
  361. } else {
  362. StreamSocketSink_Init(
  363. &pio->output_sink.plain, FlowErrorReporter_Create(&pio->ioerrdomain, COMPONENT_SINK),
  364. &sock->sock, BReactor_PendingGroup(pio->reactor)
  365. );
  366. sink_interface = StreamSocketSink_GetInput(&pio->output_sink.plain);
  367. }
  368. PacketStreamSender_Init(&pio->output_pss, sink_interface, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
  369. PacketPassConnector_ConnectOutput(&pio->output_connector, PacketStreamSender_GetInput(&pio->output_pss));
  370. pio->sock = sock;
  371. return 1;
  372. }
  373. void free_io (StreamPeerIO *pio)
  374. {
  375. ASSERT(pio->sock)
  376. // reset decoder
  377. PacketProtoDecoder_Reset(&pio->input_decoder);
  378. // free sending
  379. PacketPassConnector_DisconnectOutput(&pio->output_connector);
  380. PacketStreamSender_Free(&pio->output_pss);
  381. if (pio->ssl) {
  382. PRStreamSink_Free(&pio->output_sink.ssl);
  383. } else {
  384. StreamSocketSink_Free(&pio->output_sink.plain);
  385. }
  386. // free receiving
  387. StreamRecvConnector_DisconnectInput(&pio->input_connector);
  388. if (pio->ssl) {
  389. PRStreamSource_Free(&pio->input_source.ssl);
  390. } else {
  391. StreamSocketSource_Free(&pio->input_source.plain);
  392. }
  393. pio->sock = NULL;
  394. }
  395. int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert)
  396. {
  397. ASSERT(pio->ssl)
  398. SECItem der = cert->derCert;
  399. if (der.len != pio->ssl_peer_cert_len || memcmp(der.data, pio->ssl_peer_cert, der.len)) {
  400. BLog(BLOG_NOTICE, "Client certificate doesn't match");
  401. return 0;
  402. }
  403. return 1;
  404. }
  405. void reset_state (StreamPeerIO *pio)
  406. {
  407. // free resources
  408. switch (pio->mode) {
  409. case MODE_NONE:
  410. break;
  411. case MODE_LISTEN:
  412. switch (pio->listen.state) {
  413. case LISTEN_STATE_FINISHED:
  414. free_io(pio);
  415. case LISTEN_STATE_GOTCLIENT:
  416. cleanup_socket(pio->listen.sock, pio->ssl);
  417. free(pio->listen.sock);
  418. break;
  419. case LISTEN_STATE_LISTENER:
  420. PasswordListener_RemoveEntry(pio->listen.listener, &pio->listen.pwentry);
  421. break;
  422. default:
  423. ASSERT(0);
  424. }
  425. pio->mode = MODE_NONE;
  426. break;
  427. case MODE_CONNECT:
  428. switch (pio->connect.state) {
  429. case CONNECT_STATE_FINISHED:
  430. free_io(pio);
  431. case CONNECT_STATE_SENT:
  432. case CONNECT_STATE_SENDING:
  433. if (pio->connect.state == CONNECT_STATE_SENDING) {
  434. PasswordSender_Free(&pio->connect.pwsender);
  435. }
  436. case CONNECT_STATE_HANDSHAKE:
  437. if (pio->ssl) {
  438. BPRFileDesc_Free(&pio->connect.sock.ssl_bprfd);
  439. ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
  440. }
  441. case CONNECT_STATE_CONNECTING:
  442. BSocket_Free(&pio->connect.sock.sock);
  443. break;
  444. default:
  445. ASSERT(0);
  446. }
  447. pio->mode = MODE_NONE;
  448. break;
  449. default:
  450. ASSERT(0);
  451. }
  452. ASSERT(!pio->sock)
  453. }
  454. void cleanup_socket (sslsocket *sock, int ssl)
  455. {
  456. if (ssl) {
  457. // free BPRFileDesc
  458. BPRFileDesc_Free(&sock->ssl_bprfd);
  459. // free SSL NSPR file descriptor
  460. ASSERT_FORCE(PR_Close(sock->ssl_prfd) == PR_SUCCESS)
  461. }
  462. // free socket
  463. BSocket_Free(&sock->sock);
  464. }
  465. void reset_and_report_error (StreamPeerIO *pio)
  466. {
  467. reset_state(pio);
  468. pio->handler_error(pio->user);
  469. return;
  470. }
  471. int StreamPeerIO_Init (
  472. StreamPeerIO *pio,
  473. BReactor *reactor,
  474. int ssl,
  475. uint8_t *ssl_peer_cert,
  476. int ssl_peer_cert_len,
  477. int payload_mtu,
  478. PacketPassInterface *user_recv_if,
  479. StreamPeerIO_handler_error handler_error,
  480. void *user
  481. )
  482. {
  483. ASSERT(ssl == 0 || ssl == 1)
  484. ASSERT(payload_mtu >= 0)
  485. ASSERT(PacketPassInterface_GetMTU(user_recv_if) >= payload_mtu)
  486. // init arguments
  487. pio->reactor = reactor;
  488. pio->ssl = ssl;
  489. if (pio->ssl) {
  490. pio->ssl_peer_cert = ssl_peer_cert;
  491. pio->ssl_peer_cert_len = ssl_peer_cert_len;
  492. }
  493. pio->payload_mtu = payload_mtu;
  494. pio->handler_error = handler_error;
  495. pio->user = user;
  496. // check payload MTU
  497. if (pio->payload_mtu > PACKETPROTO_MAXPAYLOAD) {
  498. BLog(BLOG_ERROR, "payload MTU is too large");
  499. goto fail0;
  500. }
  501. // init persistent I/O modules
  502. if (!init_persistent_io(pio, user_recv_if)) {
  503. goto fail0;
  504. }
  505. // set mode none
  506. pio->mode = MODE_NONE;
  507. // set no socket
  508. pio->sock = NULL;
  509. DebugObject_Init(&pio->d_obj);
  510. return 1;
  511. fail0:
  512. return 0;
  513. }
  514. void StreamPeerIO_Free (StreamPeerIO *pio)
  515. {
  516. DebugObject_Free(&pio->d_obj);
  517. // reset state
  518. reset_state(pio);
  519. // free persistent I/O modules
  520. free_persistent_io(pio);
  521. }
  522. PacketPassInterface * StreamPeerIO_GetSendInput (StreamPeerIO *pio)
  523. {
  524. DebugObject_Access(&pio->d_obj);
  525. return PacketCopier_GetInput(&pio->output_user_copier);
  526. }
  527. int StreamPeerIO_Connect (StreamPeerIO *pio, BAddr addr, uint64_t password, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key)
  528. {
  529. ASSERT(!BAddr_IsInvalid(&addr))
  530. DebugObject_Access(&pio->d_obj);
  531. // reset state
  532. reset_state(pio);
  533. // create socket
  534. if (BSocket_Init(&pio->connect.sock.sock, pio->reactor, addr.type, BSOCKET_TYPE_STREAM) < 0) {
  535. BLog(BLOG_ERROR, "BSocket_Init failed");
  536. goto fail0;
  537. }
  538. // attempt connection
  539. if (BSocket_Connect(&pio->connect.sock.sock, &addr, 1) >= 0 || BSocket_GetError(&pio->connect.sock.sock) != BSOCKET_ERROR_IN_PROGRESS) {
  540. BLog(BLOG_NOTICE, "BSocket_Connect failed");
  541. goto fail1;
  542. }
  543. // waiting for connection result
  544. BSocket_AddEventHandler(&pio->connect.sock.sock, BSOCKET_CONNECT, (BSocket_handler)connecting_connect_handler, pio);
  545. BSocket_EnableEvent(&pio->connect.sock.sock, BSOCKET_CONNECT);
  546. // remember data
  547. if (pio->ssl) {
  548. pio->connect.ssl_cert = ssl_cert;
  549. pio->connect.ssl_key = ssl_key;
  550. }
  551. pio->connect.password = htol64(password);
  552. // set state
  553. pio->mode = MODE_CONNECT;
  554. pio->connect.state = CONNECT_STATE_CONNECTING;
  555. return 1;
  556. fail1:
  557. BSocket_Free(&pio->connect.sock.sock);
  558. fail0:
  559. return 0;
  560. }
  561. void StreamPeerIO_Listen (StreamPeerIO *pio, PasswordListener *listener, uint64_t *password)
  562. {
  563. ASSERT(listener->ssl == pio->ssl)
  564. DebugObject_Access(&pio->d_obj);
  565. // reset state
  566. reset_state(pio);
  567. // add PasswordListener entry
  568. uint64_t newpass = PasswordListener_AddEntry(listener, &pio->listen.pwentry, (PasswordListener_handler_client)listener_handler_client, pio);
  569. // remember data
  570. pio->listen.listener = listener;
  571. // set state
  572. pio->mode = MODE_LISTEN;
  573. pio->listen.state = LISTEN_STATE_LISTENER;
  574. *password = newpass;
  575. }