StreamPeerIO.c 23 KB

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