StreamPeerIO.c 22 KB

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