BSSLConnection.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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. #define THREADWORK_STATE_NONE 0
  38. #define THREADWORK_STATE_HANDSHAKE 1
  39. #define THREADWORK_STATE_READ 2
  40. #define THREADWORK_STATE_WRITE 3
  41. static void backend_threadwork_start (struct BSSLConnection_backend *b, int op);
  42. static int backend_threadwork_do_io (struct BSSLConnection_backend *b);
  43. static void connection_init_job_handler (BSSLConnection *o);
  44. static void connection_init_up (BSSLConnection *o);
  45. static void connection_try_io (BSSLConnection *o);
  46. static void connection_threadwork_func_work (void *user);
  47. static void connection_threadwork_handler_done (void *user);
  48. static void connection_recv_job_handler (BSSLConnection *o);
  49. static void connection_try_handshake (BSSLConnection *o);
  50. static void connection_try_send (BSSLConnection *o);
  51. static void connection_try_recv (BSSLConnection *o);
  52. static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len);
  53. static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len);
  54. int bprconnection_initialized = 0;
  55. PRDescIdentity bprconnection_identity;
  56. static PRFileDesc * get_bottom (PRFileDesc *layer)
  57. {
  58. while (layer->lower) {
  59. layer = layer->lower;
  60. }
  61. return layer;
  62. }
  63. static PRStatus method_close (PRFileDesc *fd)
  64. {
  65. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  66. ASSERT(!b->con)
  67. ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
  68. // free mutexes
  69. if ((b->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
  70. BMutex_Free(&b->recv_buf_mutex);
  71. BMutex_Free(&b->send_buf_mutex);
  72. }
  73. // free backend
  74. free(b);
  75. // set no secret
  76. fd->secret = NULL;
  77. return PR_SUCCESS;
  78. }
  79. static PRInt32 method_read (PRFileDesc *fd, void *buf, PRInt32 amount)
  80. {
  81. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  82. ASSERT(amount > 0)
  83. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  84. BMutex_Lock(&b->recv_buf_mutex);
  85. }
  86. // if we are receiving into buffer or buffer has no data left, refuse recv
  87. if (b->recv_busy || b->recv_pos == b->recv_len) {
  88. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  89. b->threadwork_want_recv = 1;
  90. BMutex_Unlock(&b->recv_buf_mutex);
  91. } else {
  92. // start receiving if not already
  93. if (!b->recv_busy) {
  94. // set recv busy
  95. b->recv_busy = 1;
  96. // receive into buffer
  97. StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE);
  98. }
  99. }
  100. PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
  101. return -1;
  102. }
  103. // limit amount to available data
  104. if (amount > b->recv_len - b->recv_pos) {
  105. amount = b->recv_len - b->recv_pos;
  106. }
  107. // copy data
  108. memcpy(buf, b->recv_buf + b->recv_pos, amount);
  109. // update buffer
  110. b->recv_pos += amount;
  111. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  112. BMutex_Unlock(&b->recv_buf_mutex);
  113. }
  114. return amount;
  115. }
  116. static PRInt32 method_write (PRFileDesc *fd, const void *buf, PRInt32 amount)
  117. {
  118. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret;
  119. ASSERT(amount > 0)
  120. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  121. BMutex_Lock(&b->send_buf_mutex);
  122. }
  123. ASSERT(!b->send_busy || b->send_pos < b->send_len)
  124. // if there is data in buffer, refuse send
  125. if (b->send_pos < b->send_len) {
  126. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  127. b->threadwork_want_send = 1;
  128. BMutex_Unlock(&b->send_buf_mutex);
  129. }
  130. PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
  131. return -1;
  132. }
  133. // limit amount to buffer size
  134. if (amount > BSSLCONNECTION_BUF_SIZE) {
  135. amount = BSSLCONNECTION_BUF_SIZE;
  136. }
  137. // init buffer
  138. memcpy(b->send_buf, buf, amount);
  139. b->send_pos = 0;
  140. b->send_len = amount;
  141. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  142. BMutex_Unlock(&b->send_buf_mutex);
  143. } else {
  144. // start sending
  145. b->send_busy = 1;
  146. StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
  147. }
  148. return amount;
  149. }
  150. static PRStatus method_shutdown (PRFileDesc *fd, PRIntn how)
  151. {
  152. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  153. return PR_FAILURE;
  154. }
  155. static PRInt32 method_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
  156. {
  157. ASSERT(flags == 0)
  158. return method_read(fd, buf, amount);
  159. }
  160. static PRInt32 method_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
  161. {
  162. ASSERT(flags == 0)
  163. return method_write(fd, buf, amount);
  164. }
  165. static PRInt16 method_poll (PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  166. {
  167. *out_flags = 0;
  168. return in_flags;
  169. }
  170. static PRStatus method_getpeername (PRFileDesc *fd, PRNetAddr *addr)
  171. {
  172. memset(addr, 0, sizeof(*addr));
  173. addr->raw.family = PR_AF_INET;
  174. return PR_SUCCESS;
  175. }
  176. static PRStatus method_getsocketoption (PRFileDesc *fd, PRSocketOptionData *data)
  177. {
  178. switch (data->option) {
  179. case PR_SockOpt_Nonblocking:
  180. data->value.non_blocking = PR_TRUE;
  181. return PR_SUCCESS;
  182. }
  183. PR_SetError(PR_UNKNOWN_ERROR, 0);
  184. return PR_FAILURE;
  185. }
  186. static PRStatus method_setsocketoption (PRFileDesc *fd, const PRSocketOptionData *data)
  187. {
  188. PR_SetError(PR_UNKNOWN_ERROR, 0);
  189. return PR_FAILURE;
  190. }
  191. static PRIntn _PR_InvalidIntn (void)
  192. {
  193. ASSERT(0)
  194. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  195. return -1;
  196. }
  197. static PRInt32 _PR_InvalidInt32 (void)
  198. {
  199. ASSERT(0)
  200. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  201. return -1;
  202. }
  203. static PRInt64 _PR_InvalidInt64 (void)
  204. {
  205. ASSERT(0)
  206. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  207. return -1;
  208. }
  209. static PROffset32 _PR_InvalidOffset32 (void)
  210. {
  211. ASSERT(0)
  212. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  213. return -1;
  214. }
  215. static PROffset64 _PR_InvalidOffset64 (void)
  216. {
  217. ASSERT(0)
  218. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  219. return -1;
  220. }
  221. static PRStatus _PR_InvalidStatus (void)
  222. {
  223. ASSERT(0)
  224. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  225. return PR_FAILURE;
  226. }
  227. static PRFileDesc *_PR_InvalidDesc (void)
  228. {
  229. ASSERT(0)
  230. PR_SetError(PR_INVALID_METHOD_ERROR, 0);
  231. return NULL;
  232. }
  233. static PRIOMethods methods = {
  234. (PRDescType)0,
  235. method_close,
  236. method_read,
  237. method_write,
  238. (PRAvailableFN)_PR_InvalidInt32,
  239. (PRAvailable64FN)_PR_InvalidInt64,
  240. (PRFsyncFN)_PR_InvalidStatus,
  241. (PRSeekFN)_PR_InvalidOffset32,
  242. (PRSeek64FN)_PR_InvalidOffset64,
  243. (PRFileInfoFN)_PR_InvalidStatus,
  244. (PRFileInfo64FN)_PR_InvalidStatus,
  245. (PRWritevFN)_PR_InvalidInt32,
  246. (PRConnectFN)_PR_InvalidStatus,
  247. (PRAcceptFN)_PR_InvalidDesc,
  248. (PRBindFN)_PR_InvalidStatus,
  249. (PRListenFN)_PR_InvalidStatus,
  250. method_shutdown,
  251. method_recv,
  252. method_send,
  253. (PRRecvfromFN)_PR_InvalidInt32,
  254. (PRSendtoFN)_PR_InvalidInt32,
  255. method_poll,
  256. (PRAcceptreadFN)_PR_InvalidInt32,
  257. (PRTransmitfileFN)_PR_InvalidInt32,
  258. (PRGetsocknameFN)_PR_InvalidStatus,
  259. method_getpeername,
  260. (PRReservedFN)_PR_InvalidIntn,
  261. (PRReservedFN)_PR_InvalidIntn,
  262. method_getsocketoption,
  263. method_setsocketoption,
  264. (PRSendfileFN)_PR_InvalidInt32,
  265. (PRConnectcontinueFN)_PR_InvalidStatus,
  266. (PRReservedFN)_PR_InvalidIntn,
  267. (PRReservedFN)_PR_InvalidIntn,
  268. (PRReservedFN)_PR_InvalidIntn,
  269. (PRReservedFN)_PR_InvalidIntn
  270. };
  271. static void backend_send_if_handler_done (struct BSSLConnection_backend *b, int data_len)
  272. {
  273. ASSERT(b->send_busy)
  274. ASSERT(b->send_len > 0)
  275. ASSERT(b->send_pos < b->send_len)
  276. ASSERT(data_len > 0)
  277. ASSERT(data_len <= b->send_len - b->send_pos)
  278. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  279. BMutex_Lock(&b->send_buf_mutex);
  280. }
  281. // update buffer
  282. b->send_pos += data_len;
  283. // send more if needed
  284. if (b->send_pos < b->send_len) {
  285. StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
  286. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  287. BMutex_Unlock(&b->send_buf_mutex);
  288. }
  289. return;
  290. }
  291. // set send not busy
  292. b->send_busy = 0;
  293. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  294. BMutex_Unlock(&b->send_buf_mutex);
  295. }
  296. // notify connection
  297. if (b->con && !b->con->have_error) {
  298. connection_try_io(b->con);
  299. return;
  300. }
  301. }
  302. static void backend_recv_if_handler_done (struct BSSLConnection_backend *b, int data_len)
  303. {
  304. ASSERT(b->recv_busy)
  305. ASSERT(data_len > 0)
  306. ASSERT(data_len <= BSSLCONNECTION_BUF_SIZE)
  307. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  308. BMutex_Lock(&b->recv_buf_mutex);
  309. }
  310. // init buffer
  311. b->recv_busy = 0;
  312. b->recv_pos = 0;
  313. b->recv_len = data_len;
  314. if (b->threadwork_state != THREADWORK_STATE_NONE) {
  315. BMutex_Unlock(&b->recv_buf_mutex);
  316. }
  317. // notify connection
  318. if (b->con && !b->con->have_error) {
  319. connection_try_io(b->con);
  320. return;
  321. }
  322. }
  323. static void backend_threadwork_start (struct BSSLConnection_backend *b, int op)
  324. {
  325. ASSERT(b->con)
  326. ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
  327. ASSERT(op == THREADWORK_STATE_HANDSHAKE || op == THREADWORK_STATE_READ || op == THREADWORK_STATE_WRITE)
  328. b->threadwork_state = op;
  329. b->threadwork_want_recv = 0;
  330. b->threadwork_want_send = 0;
  331. BThreadWork_Init(&b->threadwork, b->twd, connection_threadwork_handler_done, b->con, connection_threadwork_func_work, b->con);
  332. }
  333. static int backend_threadwork_do_io (struct BSSLConnection_backend *b)
  334. {
  335. ASSERT(b->con)
  336. ASSERT(b->threadwork_state == THREADWORK_STATE_NONE)
  337. int io_ready = (b->threadwork_want_recv && !b->recv_busy && b->recv_pos < b->recv_len) ||
  338. (b->threadwork_want_send && b->send_pos == b->send_len);
  339. if (b->threadwork_want_recv && b->recv_pos == b->recv_len && !b->recv_busy) {
  340. b->recv_busy = 1;
  341. StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE);
  342. }
  343. if (b->send_pos < b->send_len && !b->send_busy) {
  344. b->send_busy = 1;
  345. StreamPassInterface_Sender_Send(b->send_if, b->send_buf + b->send_pos, b->send_len - b->send_pos);
  346. }
  347. return io_ready;
  348. }
  349. static void connection_report_error (BSSLConnection *o)
  350. {
  351. ASSERT(!o->have_error)
  352. // set error
  353. o->have_error = 1;
  354. // report error
  355. DEBUGERROR(&o->d_err, o->handler(o->user, BSSLCONNECTION_EVENT_ERROR));
  356. }
  357. static void connection_init_job_handler (BSSLConnection *o)
  358. {
  359. DebugObject_Access(&o->d_obj);
  360. ASSERT(!o->have_error)
  361. ASSERT(!o->up)
  362. connection_try_handshake(o);
  363. }
  364. static void connection_init_up (BSSLConnection *o)
  365. {
  366. // unset init job
  367. // (just in the impossible case that handshake completed before the init job executed)
  368. BPending_Unset(&o->init_job);
  369. // init send interface
  370. StreamPassInterface_Init(&o->send_if, (StreamPassInterface_handler_send)connection_send_if_handler_send, o, o->pg);
  371. // init recv interface
  372. StreamRecvInterface_Init(&o->recv_if, (StreamRecvInterface_handler_recv)connection_recv_if_handler_recv, o, o->pg);
  373. // init recv job
  374. BPending_Init(&o->recv_job, o->pg, (BPending_handler)connection_recv_job_handler, o);
  375. // set no send data
  376. o->send_len = -1;
  377. // set no recv data
  378. o->recv_avail = -1;
  379. // set up
  380. o->up = 1;
  381. }
  382. static void connection_try_io (BSSLConnection *o)
  383. {
  384. DebugObject_Access(&o->d_obj);
  385. ASSERT(!o->have_error)
  386. if (!o->up) {
  387. connection_try_handshake(o);
  388. return;
  389. }
  390. if (o->send_len > 0) {
  391. if (o->recv_avail > 0) {
  392. BPending_Set(&o->recv_job);
  393. }
  394. connection_try_send(o);
  395. return;
  396. }
  397. if (o->recv_avail > 0) {
  398. connection_try_recv(o);
  399. return;
  400. }
  401. }
  402. static void connection_threadwork_func_work (void *user)
  403. {
  404. BSSLConnection *o = user;
  405. struct BSSLConnection_backend *b = o->backend;
  406. ASSERT(b->threadwork_state != THREADWORK_STATE_NONE)
  407. switch (b->threadwork_state) {
  408. case THREADWORK_STATE_HANDSHAKE:
  409. b->threadwork_result_sec = SSL_ForceHandshake(o->prfd);
  410. break;
  411. case THREADWORK_STATE_WRITE:
  412. b->threadwork_result_pr = PR_Write(o->prfd, o->send_data, o->send_len);
  413. break;
  414. case THREADWORK_STATE_READ:
  415. b->threadwork_result_pr = PR_Read(o->prfd, o->recv_data, o->recv_avail);
  416. break;
  417. default:
  418. ASSERT(0);
  419. }
  420. b->threadwork_error = PR_GetError();
  421. }
  422. static void connection_threadwork_handler_done (void *user)
  423. {
  424. BSSLConnection *o = user;
  425. struct BSSLConnection_backend *b = o->backend;
  426. ASSERT(b->threadwork_state != THREADWORK_STATE_NONE)
  427. // remember what operation the threadwork was performing
  428. int op = b->threadwork_state;
  429. // free threadwork
  430. BThreadWork_Free(&b->threadwork);
  431. b->threadwork_state = THREADWORK_STATE_NONE;
  432. // start any necessary backend I/O operations, and determine if any of the requested
  433. // backend I/O that was not available at the time is now available
  434. int io_ready = backend_threadwork_do_io(b);
  435. switch (op) {
  436. case THREADWORK_STATE_HANDSHAKE: {
  437. ASSERT(!o->up)
  438. ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE))
  439. if (b->threadwork_result_sec == SECFailure) {
  440. if (b->threadwork_error == PR_WOULD_BLOCK_ERROR) {
  441. if (io_ready) {
  442. // requested backend I/O got ready, try again
  443. backend_threadwork_start(o->backend, THREADWORK_STATE_HANDSHAKE);
  444. }
  445. return;
  446. }
  447. BLog(BLOG_ERROR, "SSL_ForceHandshake failed (%"PRIi32")", b->threadwork_error);
  448. connection_report_error(o);
  449. return;
  450. }
  451. // init up
  452. connection_init_up(o);
  453. // report up
  454. o->handler(o->user, BSSLCONNECTION_EVENT_UP);
  455. return;
  456. } break;
  457. case THREADWORK_STATE_WRITE: {
  458. ASSERT(o->up)
  459. ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO))
  460. ASSERT(o->send_len > 0)
  461. PRInt32 result = b->threadwork_result_pr;
  462. PRErrorCode error = b->threadwork_error;
  463. if (result < 0) {
  464. if (error == PR_WOULD_BLOCK_ERROR) {
  465. if (io_ready) {
  466. // requested backend I/O got ready, try again
  467. backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
  468. } else if (o->recv_avail > 0) {
  469. // don't forget about receiving
  470. backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
  471. }
  472. return;
  473. }
  474. BLog(BLOG_ERROR, "PR_Write failed (%"PRIi32")", error);
  475. connection_report_error(o);
  476. return;
  477. }
  478. ASSERT(result > 0)
  479. ASSERT(result <= o->send_len)
  480. // set no send data
  481. o->send_len = -1;
  482. // don't forget about receiving
  483. if (o->recv_avail > 0) {
  484. backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
  485. }
  486. // finish send operation
  487. StreamPassInterface_Done(&o->send_if, result);
  488. } break;
  489. case THREADWORK_STATE_READ: {
  490. ASSERT(o->up)
  491. ASSERT((b->flags & BSSLCONNECTION_FLAG_THREADWORK_IO))
  492. ASSERT(o->recv_avail > 0)
  493. PRInt32 result = b->threadwork_result_pr;
  494. PRErrorCode error = b->threadwork_error;
  495. if (result < 0) {
  496. if (error == PR_WOULD_BLOCK_ERROR) {
  497. if (io_ready) {
  498. // requested backend I/O got ready, try again
  499. backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
  500. } else if (o->send_len > 0) {
  501. // don't forget about sending
  502. backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
  503. }
  504. return;
  505. }
  506. BLog(BLOG_ERROR, "PR_Read failed (%"PRIi32")", error);
  507. connection_report_error(o);
  508. return;
  509. }
  510. if (result == 0) {
  511. BLog(BLOG_ERROR, "PR_Read returned 0");
  512. connection_report_error(o);
  513. return;
  514. }
  515. ASSERT(result > 0)
  516. ASSERT(result <= o->recv_avail)
  517. // set no recv data
  518. o->recv_avail = -1;
  519. // don't forget about sending
  520. if (o->send_len > 0) {
  521. backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
  522. }
  523. // finish receive operation
  524. StreamRecvInterface_Done(&o->recv_if, result);
  525. } break;
  526. default:
  527. ASSERT(0);
  528. }
  529. return;
  530. }
  531. static void connection_recv_job_handler (BSSLConnection *o)
  532. {
  533. DebugObject_Access(&o->d_obj);
  534. ASSERT(!o->have_error)
  535. ASSERT(o->up)
  536. ASSERT(o->recv_avail > 0)
  537. connection_try_recv(o);
  538. return;
  539. }
  540. static void connection_try_handshake (BSSLConnection *o)
  541. {
  542. ASSERT(!o->have_error)
  543. ASSERT(!o->up)
  544. // continue in threadwork if requested
  545. if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE)) {
  546. if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
  547. backend_threadwork_start(o->backend, THREADWORK_STATE_HANDSHAKE);
  548. }
  549. return;
  550. }
  551. // try handshake
  552. SECStatus res = SSL_ForceHandshake(o->prfd);
  553. if (res == SECFailure) {
  554. PRErrorCode error = PR_GetError();
  555. if (error == PR_WOULD_BLOCK_ERROR) {
  556. return;
  557. }
  558. BLog(BLOG_ERROR, "SSL_ForceHandshake failed (%"PRIi32")", error);
  559. connection_report_error(o);
  560. return;
  561. }
  562. // init up
  563. connection_init_up(o);
  564. // report up
  565. o->handler(o->user, BSSLCONNECTION_EVENT_UP);
  566. return;
  567. }
  568. static void connection_try_send (BSSLConnection *o)
  569. {
  570. ASSERT(!o->have_error)
  571. ASSERT(o->up)
  572. ASSERT(o->send_len > 0)
  573. // continue in threadwork if requested
  574. if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
  575. if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
  576. backend_threadwork_start(o->backend, THREADWORK_STATE_WRITE);
  577. }
  578. return;
  579. }
  580. // send
  581. PRInt32 res = PR_Write(o->prfd, o->send_data, o->send_len);
  582. if (res < 0) {
  583. PRErrorCode error = PR_GetError();
  584. if (error == PR_WOULD_BLOCK_ERROR) {
  585. return;
  586. }
  587. BLog(BLOG_ERROR, "PR_Write failed (%"PRIi32")", error);
  588. connection_report_error(o);
  589. return;
  590. }
  591. ASSERT(res > 0)
  592. ASSERT(res <= o->send_len)
  593. // set no send data
  594. o->send_len = -1;
  595. // done
  596. StreamPassInterface_Done(&o->send_if, res);
  597. }
  598. static void connection_try_recv (BSSLConnection *o)
  599. {
  600. ASSERT(!o->have_error)
  601. ASSERT(o->up)
  602. ASSERT(o->recv_avail > 0)
  603. // unset recv job
  604. BPending_Unset(&o->recv_job);
  605. // continue in threadwork if requested
  606. if ((o->backend->flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
  607. if (o->backend->threadwork_state == THREADWORK_STATE_NONE) {
  608. backend_threadwork_start(o->backend, THREADWORK_STATE_READ);
  609. }
  610. return;
  611. }
  612. // recv
  613. PRInt32 res = PR_Read(o->prfd, o->recv_data, o->recv_avail);
  614. if (res < 0) {
  615. PRErrorCode error = PR_GetError();
  616. if (error == PR_WOULD_BLOCK_ERROR) {
  617. return;
  618. }
  619. BLog(BLOG_ERROR, "PR_Read failed (%"PRIi32")", error);
  620. connection_report_error(o);
  621. return;
  622. }
  623. if (res == 0) {
  624. BLog(BLOG_ERROR, "PR_Read returned 0");
  625. connection_report_error(o);
  626. return;
  627. }
  628. ASSERT(res > 0)
  629. ASSERT(res <= o->recv_avail)
  630. // set no recv data
  631. o->recv_avail = -1;
  632. // done
  633. StreamRecvInterface_Done(&o->recv_if, res);
  634. }
  635. static void connection_send_if_handler_send (BSSLConnection *o, uint8_t *data, int data_len)
  636. {
  637. DebugObject_Access(&o->d_obj);
  638. ASSERT(!o->have_error)
  639. ASSERT(o->up)
  640. ASSERT(o->send_len == -1)
  641. ASSERT(data_len > 0)
  642. #ifndef NDEBUG
  643. ASSERT(!o->releasebuffers_called)
  644. o->user_io_started = 1;
  645. #endif
  646. // limit amount for PR_Write
  647. if (data_len > INT32_MAX) {
  648. data_len = INT32_MAX;
  649. }
  650. // set send data
  651. o->send_data = data;
  652. o->send_len = data_len;
  653. // start sending
  654. connection_try_send(o);
  655. }
  656. static void connection_recv_if_handler_recv (BSSLConnection *o, uint8_t *data, int data_len)
  657. {
  658. DebugObject_Access(&o->d_obj);
  659. ASSERT(!o->have_error)
  660. ASSERT(o->up)
  661. ASSERT(o->recv_avail == -1)
  662. ASSERT(data_len > 0)
  663. #ifndef NDEBUG
  664. ASSERT(!o->releasebuffers_called)
  665. o->user_io_started = 1;
  666. #endif
  667. // limit amount for PR_Read
  668. if (data_len > INT32_MAX) {
  669. data_len = INT32_MAX;
  670. }
  671. // set recv data
  672. o->recv_data = data;
  673. o->recv_avail = data_len;
  674. // start receiving
  675. connection_try_recv(o);
  676. }
  677. int BSSLConnection_GlobalInit (void)
  678. {
  679. ASSERT(!bprconnection_initialized)
  680. if ((bprconnection_identity = PR_GetUniqueIdentity("BSSLConnection")) == PR_INVALID_IO_LAYER) {
  681. BLog(BLOG_ERROR, "PR_GetUniqueIdentity failed");
  682. return 0;
  683. }
  684. bprconnection_initialized = 1;
  685. return 1;
  686. }
  687. int BSSLConnection_MakeBackend (PRFileDesc *prfd, StreamPassInterface *send_if, StreamRecvInterface *recv_if, BThreadWorkDispatcher *twd, int flags)
  688. {
  689. ASSERT(bprconnection_initialized)
  690. ASSERT(!(flags & ~(BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE | BSSLCONNECTION_FLAG_THREADWORK_IO)))
  691. ASSERT(!(flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || twd)
  692. ASSERT(!(flags & BSSLCONNECTION_FLAG_THREADWORK_IO) || twd)
  693. // don't do stuff in threads if threads aren't available
  694. if (((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) &&
  695. !BThreadWorkDispatcher_UsingThreads(twd)
  696. ) {
  697. BLog(BLOG_WARNING, "SSL operations in threads requested but threads are not available");
  698. flags &= ~(BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE | BSSLCONNECTION_FLAG_THREADWORK_IO);
  699. }
  700. // allocate backend
  701. struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)malloc(sizeof(*b));
  702. if (!b) {
  703. BLog(BLOG_ERROR, "malloc failed");
  704. goto fail0;
  705. }
  706. // init mutexes
  707. if ((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
  708. if (!BMutex_Init(&b->send_buf_mutex)) {
  709. BLog(BLOG_ERROR, "BMutex_Init failed");
  710. goto fail1;
  711. }
  712. if (!BMutex_Init(&b->recv_buf_mutex)) {
  713. BLog(BLOG_ERROR, "BMutex_Init failed");
  714. goto fail2;
  715. }
  716. }
  717. // init arguments
  718. b->send_if = send_if;
  719. b->recv_if = recv_if;
  720. b->twd = twd;
  721. b->flags = flags;
  722. // init interfaces
  723. StreamPassInterface_Sender_Init(b->send_if, (StreamPassInterface_handler_done)backend_send_if_handler_done, b);
  724. StreamRecvInterface_Receiver_Init(b->recv_if, (StreamRecvInterface_handler_done)backend_recv_if_handler_done, b);
  725. // set no connection
  726. b->con = NULL;
  727. // init send buffer
  728. b->send_busy = 0;
  729. b->send_len = 0;
  730. b->send_pos = 0;
  731. // init recv buffer
  732. b->recv_busy = 0;
  733. b->recv_pos = 0;
  734. b->recv_len = 0;
  735. // set threadwork state
  736. b->threadwork_state = THREADWORK_STATE_NONE;
  737. // init prfd
  738. memset(prfd, 0, sizeof(*prfd));
  739. prfd->methods = &methods;
  740. prfd->secret = (PRFilePrivate *)b;
  741. prfd->identity = bprconnection_identity;
  742. return 1;
  743. if ((flags & BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE) || (flags & BSSLCONNECTION_FLAG_THREADWORK_IO)) {
  744. fail2:
  745. BMutex_Free(&b->send_buf_mutex);
  746. }
  747. fail1:
  748. free(b);
  749. fail0:
  750. return 0;
  751. }
  752. void BSSLConnection_Init (BSSLConnection *o, PRFileDesc *prfd, int force_handshake, BPendingGroup *pg, void *user,
  753. BSSLConnection_handler handler)
  754. {
  755. ASSERT(force_handshake == 0 || force_handshake == 1)
  756. ASSERT(handler)
  757. ASSERT(bprconnection_initialized)
  758. ASSERT(get_bottom(prfd)->identity == bprconnection_identity)
  759. ASSERT(!((struct BSSLConnection_backend *)(get_bottom(prfd)->secret))->con)
  760. // init arguments
  761. o->prfd = prfd;
  762. o->pg = pg;
  763. o->user = user;
  764. o->handler = handler;
  765. // set backend
  766. o->backend = (struct BSSLConnection_backend *)(get_bottom(prfd)->secret);
  767. ASSERT(!o->backend->con)
  768. ASSERT(o->backend->threadwork_state == THREADWORK_STATE_NONE)
  769. // set have no error
  770. o->have_error = 0;
  771. // init init job
  772. BPending_Init(&o->init_job, o->pg, (BPending_handler)connection_init_job_handler, o);
  773. if (force_handshake) {
  774. // set not up
  775. o->up = 0;
  776. // set init job
  777. BPending_Set(&o->init_job);
  778. } else {
  779. // init up
  780. connection_init_up(o);
  781. }
  782. // set backend connection
  783. o->backend->con = o;
  784. #ifndef NDEBUG
  785. o->user_io_started = 0;
  786. o->releasebuffers_called = 0;
  787. #endif
  788. DebugError_Init(&o->d_err, o->pg);
  789. DebugObject_Init(&o->d_obj);
  790. }
  791. void BSSLConnection_Free (BSSLConnection *o)
  792. {
  793. DebugObject_Free(&o->d_obj);
  794. DebugError_Free(&o->d_err);
  795. #ifndef NDEBUG
  796. ASSERT(o->releasebuffers_called || !o->user_io_started)
  797. #endif
  798. ASSERT(o->backend->threadwork_state == THREADWORK_STATE_NONE)
  799. if (o->up) {
  800. // free recv job
  801. BPending_Free(&o->recv_job);
  802. // free recv interface
  803. StreamRecvInterface_Free(&o->recv_if);
  804. // free send interface
  805. StreamPassInterface_Free(&o->send_if);
  806. }
  807. // free init job
  808. BPending_Free(&o->init_job);
  809. // unset backend connection
  810. o->backend->con = NULL;
  811. }
  812. void BSSLConnection_ReleaseBuffers (BSSLConnection *o)
  813. {
  814. DebugObject_Access(&o->d_obj);
  815. #ifndef NDEBUG
  816. ASSERT(!o->releasebuffers_called)
  817. #endif
  818. // wait for threadwork to finish
  819. if (o->backend->threadwork_state != THREADWORK_STATE_NONE) {
  820. BThreadWork_Free(&o->backend->threadwork);
  821. o->backend->threadwork_state = THREADWORK_STATE_NONE;
  822. }
  823. #ifndef NDEBUG
  824. o->releasebuffers_called = 1;
  825. #endif
  826. }
  827. StreamPassInterface * BSSLConnection_GetSendIf (BSSLConnection *o)
  828. {
  829. DebugObject_Access(&o->d_obj);
  830. ASSERT(o->up)
  831. return &o->send_if;
  832. }
  833. StreamRecvInterface * BSSLConnection_GetRecvIf (BSSLConnection *o)
  834. {
  835. DebugObject_Access(&o->d_obj);
  836. ASSERT(o->up)
  837. return &o->recv_if;
  838. }