StreamPeerIO.c 23 KB

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