StreamPeerIO.c 22 KB

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