BSSLConnection.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /**
  2. * @file BSSLConnection.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 <prerror.h>
  30. #include <ssl.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <misc/print_macros.h>
  34. #include <base/BLog.h>
  35. #include "BSSLConnection.h"
  36. #include <generated/blog_channel_BSSLConnection.h>
  37. static void connection_init_job_handler (BSSLConnection *o);
  38. static void connection_init_up (BSSLConnection *o);
  39. static void connection_try_io (BSSLConnection *o);
  40. static void connection_recv_job_handler (BSSLConnection *o);
  41. static void connection_try_send (BSSLConnection *o);
  42. static void connection_try_recv (BSSLConnection *o);
  43. static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len);
  44. static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len);
  45. int bprconnection_initialized = 0;
  46. PRDescIdentity bprconnection_identity;
  47. static PRFileDesc * get_bottom (PRFileDesc *layer)
  48. {
  49. while (layer->lower) {
  50. layer = layer->lower;
  51. }
  52. return layer;
  53. }
  54. static PRStatus method_close (PRFileDesc *fd)
  55. {
  56. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  57. ASSERT(!b->con)
  58. // free backend
  59. free(b);
  60. // set no secret
  61. fd->secret = NULL;
  62. return PR_SUCCESS;
  63. }
  64. static PRInt32 method_read (PRFileDesc *fd, void *buf, PRInt32 amount)
  65. {
  66. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  67. ASSERT(amount > 0)
  68. // if we are receiving into buffer or buffer has no data left, refuse recv
  69. if (b->recv_busy || b->recv_pos == b->recv_len) {
  70. // start receiving if not already
  71. if (!b->recv_busy) {
  72. // set recv busy
  73. b->recv_busy = 1;
  74. // receive into buffer
  75. StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE);
  76. }
  77. PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
  78. return -1;
  79. }
  80. // limit amount to available data
  81. if (amount > b->recv_len - b->recv_pos) {
  82. amount = b->recv_len - b->recv_pos;
  83. }
  84. // copy data
  85. memcpy(buf, b->recv_buf + b->recv_pos, amount);
  86. // update buffer
  87. b->recv_pos += amount;
  88. return amount;
  89. }
  90. static PRInt32 method_write (PRFileDesc *fd, const void *buf, PRInt32 amount)
  91. {
  92. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  93. ASSERT(amount > 0)
  94. // if there is data in buffer, refuse send
  95. if (b->send_pos < b->send_len) {
  96. PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
  97. return -1;
  98. }
  99. // limit amount to buffer size
  100. if (amount > BSSLCONNECTION_BUF_SIZE) {
  101. amount = BSSLCONNECTION_BUF_SIZE;
  102. }
  103. // init buffer
  104. memcpy(b->send_buf, buf, amount);
  105. b->send_pos = 0;
  106. b->send_len = amount;
  107. // start sending
  108. StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
  109. return amount;
  110. }
  111. static PRStatus method_shutdown (PRFileDesc *fd, PRIntn how)
  112. {
  113. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  114. return PR_FAILURE;
  115. }
  116. static PRInt32 method_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
  117. {
  118. ASSERT(flags == 0)
  119. return method_read(fd, buf, amount);
  120. }
  121. static PRInt32 method_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
  122. {
  123. ASSERT(flags == 0)
  124. return method_write(fd, buf, amount);
  125. }
  126. static PRInt16 method_poll (PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  127. {
  128. *out_flags = 0;
  129. return in_flags;
  130. }
  131. static PRStatus method_getpeername (PRFileDesc *fd, PRNetAddr *addr)
  132. {
  133. memset(addr, 0, sizeof(*addr));
  134. addr->raw.family = PR_AF_INET;
  135. return PR_SUCCESS;
  136. }
  137. static PRStatus method_getsocketoption (PRFileDesc *fd, PRSocketOptionData *data)
  138. {
  139. switch (data->option) {
  140. case PR_SockOpt_Nonblocking:
  141. data->value.non_blocking = PR_TRUE;
  142. return PR_SUCCESS;
  143. }
  144. PR_SetError(PR_UNKNOWN_ERROR, 0);
  145. return PR_FAILURE;
  146. }
  147. static PRStatus method_setsocketoption (PRFileDesc *fd, const PRSocketOptionData *data)
  148. {
  149. PR_SetError(PR_UNKNOWN_ERROR, 0);
  150. return PR_FAILURE;
  151. }
  152. static PRIntn _PR_InvalidIntn (void)
  153. {
  154. ASSERT(0)
  155. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  156. return -1;
  157. }
  158. static PRInt32 _PR_InvalidInt32 (void)
  159. {
  160. ASSERT(0)
  161. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  162. return -1;
  163. }
  164. static PRInt64 _PR_InvalidInt64 (void)
  165. {
  166. ASSERT(0)
  167. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  168. return -1;
  169. }
  170. static PROffset32 _PR_InvalidOffset32 (void)
  171. {
  172. ASSERT(0)
  173. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  174. return -1;
  175. }
  176. static PROffset64 _PR_InvalidOffset64 (void)
  177. {
  178. ASSERT(0)
  179. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  180. return -1;
  181. }
  182. static PRStatus _PR_InvalidStatus (void)
  183. {
  184. ASSERT(0)
  185. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  186. return PR_FAILURE;
  187. }
  188. static PRFileDesc *_PR_InvalidDesc (void)
  189. {
  190. ASSERT(0)
  191. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  192. return NULL;
  193. }
  194. static PRIOMethods methods = {
  195. (PRDescType)0,
  196. method_close,
  197. method_read,
  198. method_write,
  199. (PRAvailableFN)_PR_InvalidInt32,
  200. (PRAvailable64FN)_PR_InvalidInt64,
  201. (PRFsyncFN)_PR_InvalidStatus,
  202. (PRSeekFN)_PR_InvalidOffset32,
  203. (PRSeek64FN)_PR_InvalidOffset64,
  204. (PRFileInfoFN)_PR_InvalidStatus,
  205. (PRFileInfo64FN)_PR_InvalidStatus,
  206. (PRWritevFN)_PR_InvalidInt32,
  207. (PRConnectFN)_PR_InvalidStatus,
  208. (PRAcceptFN)_PR_InvalidDesc,
  209. (PRBindFN)_PR_InvalidStatus,
  210. (PRListenFN)_PR_InvalidStatus,
  211. method_shutdown,
  212. method_recv,
  213. method_send,
  214. (PRRecvfromFN)_PR_InvalidInt32,
  215. (PRSendtoFN)_PR_InvalidInt32,
  216. method_poll,
  217. (PRAcceptreadFN)_PR_InvalidInt32,
  218. (PRTransmitfileFN)_PR_InvalidInt32,
  219. (PRGetsocknameFN)_PR_InvalidStatus,
  220. method_getpeername,
  221. (PRReservedFN)_PR_InvalidIntn,
  222. (PRReservedFN)_PR_InvalidIntn,
  223. method_getsocketoption,
  224. method_setsocketoption,
  225. (PRSendfileFN)_PR_InvalidInt32,
  226. (PRConnectcontinueFN)_PR_InvalidStatus,
  227. (PRReservedFN)_PR_InvalidIntn,
  228. (PRReservedFN)_PR_InvalidIntn,
  229. (PRReservedFN)_PR_InvalidIntn,
  230. (PRReservedFN)_PR_InvalidIntn
  231. };
  232. static void backend_send_if_handler_done (struct BSSLConnection_backend *b, int data_len)
  233. {
  234. ASSERT(b->send_len > 0)
  235. ASSERT(b->send_pos < b->send_len)
  236. ASSERT(data_len > 0)
  237. ASSERT(data_len <= b->send_len - b->send_pos)
  238. // update buffer
  239. b->send_pos += data_len;
  240. // send more if needed
  241. if (b->send_pos < b->send_len) {
  242. StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
  243. return;
  244. }
  245. // notify connection
  246. if (b->con && !b->con->have_error) {
  247. connection_try_io(b->con);
  248. return;
  249. }
  250. }
  251. static void backend_recv_if_handler_done (struct BSSLConnection_backend *b, int data_len)
  252. {
  253. ASSERT(b->recv_busy)
  254. ASSERT(data_len > 0)
  255. ASSERT(data_len <= BSSLCONNECTION_BUF_SIZE)
  256. // init buffer
  257. b->recv_busy = 0;
  258. b->recv_pos = 0;
  259. b->recv_len = data_len;
  260. // notify connection
  261. if (b->con && !b->con->have_error) {
  262. connection_try_io(b->con);
  263. return;
  264. }
  265. }
  266. static void connection_report_error (BSSLConnection *o)
  267. {
  268. ASSERT(!o->have_error)
  269. // set error
  270. o->have_error = 1;
  271. // report error
  272. DEBUGERROR(&o->d_err, o->handler(o->user, BSSLCONNECTION_EVENT_ERROR));
  273. }
  274. static void connection_init_job_handler (BSSLConnection *o)
  275. {
  276. DebugObject_Access(&o->d_obj);
  277. ASSERT(!o->have_error)
  278. ASSERT(!o->up)
  279. connection_try_io(o);
  280. return;
  281. }
  282. static void connection_init_up (BSSLConnection *o)
  283. {
  284. // init send interface
  285. StreamPassInterface_Init(&o->send_if, (StreamPassInterface_handler_send)connection_send_if_handler_send, o, o->pg);
  286. // init recv interface
  287. StreamRecvInterface_Init(&o->recv_if, (StreamRecvInterface_handler_recv)connection_recv_if_handler_recv, o, o->pg);
  288. // init recv job
  289. BPending_Init(&o->recv_job, o->pg, (BPending_handler)connection_recv_job_handler, o);
  290. // set no send data
  291. o->send_len = -1;
  292. // set no recv data
  293. o->recv_avail = -1;
  294. // set up
  295. o->up = 1;
  296. }
  297. static void connection_try_io (BSSLConnection *o)
  298. {
  299. DebugObject_Access(&o->d_obj);
  300. ASSERT(!o->have_error)
  301. if (!o->up) {
  302. // unset init job (in case backend called us before it executed)
  303. BPending_Unset(&o->init_job);
  304. // try handshake
  305. SECStatus res = SSL_ForceHandshake(o->prfd);
  306. if (res == SECFailure) {
  307. PRErrorCode error = PR_GetError();
  308. if (error == PR_WOULD_BLOCK_ERROR) {
  309. return;
  310. }
  311. BLog(BLOG_ERROR, "SSL_ForceHandshake failed (%"PRIi32")", error);
  312. connection_report_error(o);
  313. return;
  314. }
  315. // init up
  316. connection_init_up(o);
  317. // report up
  318. o->handler(o->user, BSSLCONNECTION_EVENT_UP);
  319. return;
  320. }
  321. if (o->send_len > 0) {
  322. if (o->recv_avail > 0) {
  323. BPending_Set(&o->recv_job);
  324. }
  325. connection_try_send(o);
  326. return;
  327. }
  328. if (o->recv_avail > 0) {
  329. connection_try_recv(o);
  330. return;
  331. }
  332. }
  333. static void connection_recv_job_handler (BSSLConnection *o)
  334. {
  335. DebugObject_Access(&o->d_obj);
  336. ASSERT(!o->have_error)
  337. ASSERT(o->up)
  338. ASSERT(o->recv_avail > 0)
  339. connection_try_recv(o);
  340. return;
  341. }
  342. static void connection_try_send (BSSLConnection *o)
  343. {
  344. ASSERT(!o->have_error)
  345. ASSERT(o->up)
  346. ASSERT(o->send_len > 0)
  347. // send
  348. PRInt32 res = PR_Write(o->prfd, o->send_data, o->send_len);
  349. if (res < 0) {
  350. PRErrorCode error = PR_GetError();
  351. if (error == PR_WOULD_BLOCK_ERROR) {
  352. return;
  353. }
  354. BLog(BLOG_ERROR, "PR_Write failed (%"PRIi32")", error);
  355. connection_report_error(o);
  356. return;
  357. }
  358. ASSERT(res > 0)
  359. ASSERT(res <= o->send_len)
  360. // set no send data
  361. o->send_len = -1;
  362. // done
  363. StreamPassInterface_Done(&o->send_if, res);
  364. }
  365. static void connection_try_recv (BSSLConnection *o)
  366. {
  367. ASSERT(!o->have_error)
  368. ASSERT(o->up)
  369. ASSERT(o->recv_avail > 0)
  370. // unset recv job
  371. BPending_Unset(&o->recv_job);
  372. // recv
  373. PRInt32 res = PR_Read(o->prfd, o->recv_data, o->recv_avail);
  374. if (res < 0) {
  375. PRErrorCode error = PR_GetError();
  376. if (error == PR_WOULD_BLOCK_ERROR) {
  377. return;
  378. }
  379. BLog(BLOG_ERROR, "PR_Read failed (%"PRIi32")", error);
  380. connection_report_error(o);
  381. return;
  382. }
  383. if (res == 0) {
  384. BLog(BLOG_ERROR, "PR_Read returned 0");
  385. connection_report_error(o);
  386. return;
  387. }
  388. ASSERT(res > 0)
  389. ASSERT(res <= o->recv_avail)
  390. // set no recv data
  391. o->recv_avail = -1;
  392. // done
  393. StreamRecvInterface_Done(&o->recv_if, res);
  394. }
  395. static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len)
  396. {
  397. DebugObject_Access(&o->d_obj);
  398. ASSERT(!o->have_error)
  399. ASSERT(o->up)
  400. ASSERT(o->send_len == -1)
  401. ASSERT(data_len > 0)
  402. // limit amount for PR_Write
  403. if (data_len > INT32_MAX) {
  404. data_len = INT32_MAX;
  405. }
  406. // set send data
  407. o->send_data = data;
  408. o->send_len = data_len;
  409. // start sending
  410. connection_try_send(o);
  411. return;
  412. }
  413. static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len)
  414. {
  415. DebugObject_Access(&o->d_obj);
  416. ASSERT(!o->have_error)
  417. ASSERT(o->up)
  418. ASSERT(o->recv_avail == -1)
  419. ASSERT(data_len > 0)
  420. // limit amount for PR_Read
  421. if (data_len > INT32_MAX) {
  422. data_len = INT32_MAX;
  423. }
  424. // set recv data
  425. o->recv_data = data;
  426. o->recv_avail = data_len;
  427. // start receiving
  428. connection_try_recv(o);
  429. return;
  430. }
  431. int BSSLConnection_GlobalInit (void)
  432. {
  433. ASSERT(!bprconnection_initialized)
  434. if ((bprconnection_identity = PR_GetUniqueIdentity("BSSLConnection")) == PR_INVALID_IO_LAYER) {
  435. BLog(BLOG_ERROR, "PR_GetUniqueIdentity failed");
  436. return 0;
  437. }
  438. bprconnection_initialized = 1;
  439. return 1;
  440. }
  441. int BSSLConnection_MakeBackend (PRFileDesc *prfd, StreamPassInterface *send_if, StreamRecvInterface *recv_if)
  442. {
  443. ASSERT(bprconnection_initialized)
  444. // allocate backend
  445. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)malloc(sizeof(*b));
  446. if (!b) {
  447. BLog(BLOG_ERROR, "malloc failed");
  448. return 0;
  449. }
  450. // init arguments
  451. b->send_if = send_if;
  452. b->recv_if = recv_if;
  453. // init interfaces
  454. StreamPassInterface_Sender_Init(b->send_if, (StreamPassInterface_handler_done)backend_send_if_handler_done, b);
  455. StreamRecvInterface_Receiver_Init(b->recv_if, (StreamRecvInterface_handler_done)backend_recv_if_handler_done, b);
  456. // set no connection
  457. b->con = NULL;
  458. // init send buffer
  459. b->send_len = 0;
  460. b->send_pos = 0;
  461. // init recv buffer
  462. b->recv_busy = 0;
  463. b->recv_pos = 0;
  464. b->recv_len = 0;
  465. // init prfd
  466. memset(prfd, 0, sizeof(*prfd));
  467. prfd->methods = &methods;
  468. prfd->secret = (PRFilePrivate *)b;
  469. prfd->identity = bprconnection_identity;
  470. return 1;
  471. }
  472. void BSSLConnection_Init (BSSLConnection *o, PRFileDesc *prfd, int force_handshake, BPendingGroup *pg, void *user,
  473. BSSLConnection_handler handler)
  474. {
  475. ASSERT(force_handshake == 0 || force_handshake == 1)
  476. ASSERT(handler)
  477. ASSERT(bprconnection_initialized)
  478. ASSERT(get_bottom(prfd)->identity == bprconnection_identity)
  479. ASSERT(!((struct BSSLConnection_backend *)(get_bottom(prfd)->secret))->con)
  480. // init arguments
  481. o->prfd = prfd;
  482. o->pg = pg;
  483. o->user = user;
  484. o->handler = handler;
  485. // set backend
  486. o->backend = (struct BSSLConnection_backend *)(get_bottom(prfd)->secret);
  487. // set have no error
  488. o->have_error = 0;
  489. // init init job
  490. BPending_Init(&o->init_job, o->pg, (BPending_handler)connection_init_job_handler, o);
  491. if (force_handshake) {
  492. // set not up
  493. o->up = 0;
  494. // set init job
  495. BPending_Set(&o->init_job);
  496. } else {
  497. // init up
  498. connection_init_up(o);
  499. }
  500. // set backend connection
  501. o->backend->con = o;
  502. DebugError_Init(&o->d_err, o->pg);
  503. DebugObject_Init(&o->d_obj);
  504. }
  505. void BSSLConnection_Free (BSSLConnection *o)
  506. {
  507. DebugObject_Free(&o->d_obj);
  508. DebugError_Free(&o->d_err);
  509. if (o->up) {
  510. // free recv job
  511. BPending_Free(&o->recv_job);
  512. // free recv interface
  513. StreamRecvInterface_Free(&o->recv_if);
  514. // free send interface
  515. StreamPassInterface_Free(&o->send_if);
  516. }
  517. // free init job
  518. BPending_Free(&o->init_job);
  519. // unset backend connection
  520. o->backend->con = NULL;
  521. }
  522. StreamPassInterface * BSSLConnection_GetSendIf (BSSLConnection *o)
  523. {
  524. DebugObject_Access(&o->d_obj);
  525. ASSERT(o->up)
  526. return &o->send_if;
  527. }
  528. StreamRecvInterface * BSSLConnection_GetRecvIf (BSSLConnection *o)
  529. {
  530. DebugObject_Access(&o->d_obj);
  531. ASSERT(o->up)
  532. return &o->recv_if;
  533. }