PageRenderTime 342ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/libmicrohttpd/src/daemon/https/tls/gnutls_buffers.c

https://github.com/MaDDoGo/xbmc
C | 1111 lines | 772 code | 175 blank | 164 comment | 165 complexity | a2bc5ebcd50730007c290af332517e67 MD5 | raw file
  1. /*
  2. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
  3. *
  4. * Author: Nikos Mavrogiannopoulos
  5. *
  6. * This file is part of GNUTLS.
  7. *
  8. * The GNUTLS library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  21. * USA
  22. *
  23. */
  24. /* This is the only file that uses the berkeley sockets API.
  25. *
  26. * Also holds all the buffering code used in gnutls.
  27. * The buffering code works as:
  28. *
  29. * RECORD LAYER:
  30. * 1. uses a buffer to hold data (application/handshake),
  31. * we got but they were not requested, yet.
  32. * (see MHD_gnutls_record_buffer_put(), MHD_gnutls_record_buffer_get_size() etc.)
  33. *
  34. * 2. uses a buffer to hold data that were incomplete (ie the read/write
  35. * was interrupted)
  36. * (see MHD_gtls_io_read_buffered(), MHD_gtls_io_write_buffered() etc.)
  37. *
  38. * HANDSHAKE LAYER:
  39. * 1. Uses a buffer to hold data that was not sent or received
  40. * complete. (E.g. sent 10 bytes of a handshake packet that is 20 bytes
  41. * long).
  42. * (see MHD__gnutls_handshake_send_int(), MHD__gnutls_handshake_recv_int())
  43. *
  44. * 2. Uses buffer to hold the last received handshake message.
  45. * (see MHD_gtls_handshake_buffer_put() etc.)
  46. *
  47. */
  48. #include <gnutls_int.h>
  49. #include <gnutls_errors.h>
  50. #include <gnutls_num.h>
  51. #include <gnutls_record.h>
  52. #include <gnutls_buffers.h>
  53. #include <errno.h>
  54. #ifdef _WIN32
  55. # include <winsock2.h>
  56. #endif
  57. #ifndef EAGAIN
  58. # define EAGAIN EWOULDBLOCK
  59. #endif
  60. /* Buffers received packets of type APPLICATION DATA and
  61. * HANDSHAKE DATA.
  62. */
  63. int
  64. MHD_gnutls_record_buffer_put (content_type_t type,
  65. MHD_gtls_session_t session, opaque * data,
  66. size_t length)
  67. {
  68. MHD_gtls_buffer *buf;
  69. if (length == 0)
  70. return 0;
  71. switch (type)
  72. {
  73. case GNUTLS_APPLICATION_DATA:
  74. buf = &session->internals.application_data_buffer;
  75. MHD__gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
  76. length, type);
  77. break;
  78. case GNUTLS_HANDSHAKE:
  79. buf = &session->internals.handshake_data_buffer;
  80. MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
  81. length, type);
  82. break;
  83. case GNUTLS_INNER_APPLICATION:
  84. buf = &session->internals.ia_data_buffer;
  85. MHD__gnutls_buffers_log ("BUF[IA]: Inserted %d bytes of Data(%d)\n",
  86. length, type);
  87. break;
  88. default:
  89. MHD_gnutls_assert ();
  90. return GNUTLS_E_INVALID_REQUEST;
  91. }
  92. if (MHD_gtls_buffer_append (buf, data, length) < 0)
  93. {
  94. MHD_gnutls_assert ();
  95. return GNUTLS_E_MEMORY_ERROR;
  96. }
  97. return 0;
  98. }
  99. int
  100. MHD_gnutls_record_buffer_get_size (content_type_t type,
  101. MHD_gtls_session_t session)
  102. {
  103. switch (type)
  104. {
  105. case GNUTLS_APPLICATION_DATA:
  106. return session->internals.application_data_buffer.length;
  107. case GNUTLS_HANDSHAKE:
  108. return session->internals.handshake_data_buffer.length;
  109. case GNUTLS_INNER_APPLICATION:
  110. return session->internals.ia_data_buffer.length;
  111. default:
  112. return GNUTLS_E_INVALID_REQUEST;
  113. }
  114. }
  115. int
  116. MHD_gtls_record_buffer_get (content_type_t type, MHD_gtls_session_t session,
  117. opaque * data, size_t length)
  118. {
  119. if (length == 0 || data == NULL)
  120. {
  121. MHD_gnutls_assert ();
  122. return GNUTLS_E_INVALID_REQUEST;
  123. }
  124. switch (type)
  125. {
  126. case GNUTLS_APPLICATION_DATA:
  127. if (length > session->internals.application_data_buffer.length)
  128. {
  129. length = session->internals.application_data_buffer.length;
  130. }
  131. MHD__gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n",
  132. length, type);
  133. session->internals.application_data_buffer.length -= length;
  134. memcpy (data, session->internals.application_data_buffer.data, length);
  135. /* overwrite buffer */
  136. memmove (session->internals.application_data_buffer.data,
  137. &session->internals.application_data_buffer.data[length],
  138. session->internals.application_data_buffer.length);
  139. /* we do no longer realloc the application_data_buffer.data,
  140. * since it serves no practical reason. It also decreases
  141. * performance.
  142. */
  143. break;
  144. case GNUTLS_HANDSHAKE:
  145. if (length > session->internals.handshake_data_buffer.length)
  146. {
  147. length = session->internals.handshake_data_buffer.length;
  148. }
  149. MHD__gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n",
  150. length, type);
  151. session->internals.handshake_data_buffer.length -= length;
  152. memcpy (data, session->internals.handshake_data_buffer.data, length);
  153. /* overwrite buffer */
  154. memmove (session->internals.handshake_data_buffer.data,
  155. &session->internals.handshake_data_buffer.data[length],
  156. session->internals.handshake_data_buffer.length);
  157. break;
  158. case GNUTLS_INNER_APPLICATION:
  159. if (length > session->internals.ia_data_buffer.length)
  160. length = session->internals.ia_data_buffer.length;
  161. MHD__gnutls_buffers_log ("BUF[REC][IA]: Read %d bytes of Data(%d)\n",
  162. length, type);
  163. session->internals.ia_data_buffer.length -= length;
  164. memcpy (data, session->internals.ia_data_buffer.data, length);
  165. /* overwrite buffer */
  166. memmove (session->internals.ia_data_buffer.data,
  167. &session->internals.ia_data_buffer.data[length],
  168. session->internals.ia_data_buffer.length);
  169. break;
  170. default:
  171. MHD_gnutls_assert ();
  172. return GNUTLS_E_INVALID_REQUEST;
  173. }
  174. return length;
  175. }
  176. /* This function is like read. But it does not return -1 on error.
  177. * It does return MHD_gnutls_errno instead.
  178. *
  179. * Flags are only used if the default recv() function is being used.
  180. */
  181. static ssize_t
  182. MHD__gnutls_read (MHD_gtls_session_t session, void *iptr,
  183. size_t sizeOfPtr, int flags)
  184. {
  185. size_t left;
  186. ssize_t i = 0;
  187. char *ptr = iptr;
  188. MHD_gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
  189. session->internals.direction = 0;
  190. left = sizeOfPtr;
  191. while (left > 0)
  192. {
  193. session->internals.errnum = 0;
  194. if (session->internals.MHD__gnutls_pull_func == NULL)
  195. {
  196. i =
  197. recv (GNUTLS_POINTER_TO_INT (fd), &ptr[sizeOfPtr - left], left,
  198. flags);
  199. #if HAVE_WINSOCK
  200. if (i < 0)
  201. {
  202. int tmperr = WSAGetLastError ();
  203. switch (tmperr)
  204. {
  205. case WSAEWOULDBLOCK:
  206. session->internals.errnum = EAGAIN;
  207. break;
  208. case WSAEINTR:
  209. session->internals.errnum = EINTR;
  210. break;
  211. default:
  212. session->internals.errnum = EIO;
  213. break;
  214. }
  215. WSASetLastError (tmperr);
  216. }
  217. #endif
  218. }
  219. else
  220. i = session->internals.MHD__gnutls_pull_func (fd,
  221. &ptr[sizeOfPtr - left],
  222. left);
  223. if (i < 0)
  224. {
  225. int err = session->internals.errnum ? session->internals.errnum
  226. : errno;
  227. if ( (err == EAGAIN) || (err == EINTR) )
  228. {
  229. if (sizeOfPtr - left > 0)
  230. goto finish;
  231. MHD_gnutls_assert ();
  232. if (err == EAGAIN)
  233. return GNUTLS_E_AGAIN;
  234. return GNUTLS_E_INTERRUPTED;
  235. }
  236. else
  237. {
  238. MHD_gnutls_assert ();
  239. return GNUTLS_E_PULL_ERROR;
  240. }
  241. }
  242. else
  243. {
  244. if (i == 0)
  245. break; /* EOF */
  246. }
  247. left -= i;
  248. }
  249. finish:
  250. return (sizeOfPtr - left);
  251. }
  252. #define RCVLOWAT session->internals.lowat
  253. /* This function is only used with berkeley style sockets.
  254. * Clears the peeked data (read with MSG_PEEK).
  255. */
  256. int
  257. MHD_gtls_io_clear_peeked_data (MHD_gtls_session_t session)
  258. {
  259. char *peekdata;
  260. int ret, sum;
  261. if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
  262. return 0;
  263. peekdata = MHD_gnutls_alloca (RCVLOWAT);
  264. if (peekdata == NULL)
  265. {
  266. MHD_gnutls_assert ();
  267. return GNUTLS_E_MEMORY_ERROR;
  268. }
  269. /* this was already read by using MSG_PEEK - so it shouldn't fail */
  270. sum = 0;
  271. do
  272. { /* we need this to finish now */
  273. ret = MHD__gnutls_read (session, peekdata, RCVLOWAT - sum, 0);
  274. if (ret > 0)
  275. sum += ret;
  276. }
  277. while ( (ret == GNUTLS_E_INTERRUPTED) ||
  278. (ret == GNUTLS_E_AGAIN) ||
  279. (sum < RCVLOWAT) );
  280. MHD_gnutls_afree (peekdata);
  281. if (ret < 0)
  282. {
  283. MHD_gnutls_assert ();
  284. return ret;
  285. }
  286. session->internals.have_peeked_data = 0;
  287. return 0;
  288. }
  289. void
  290. MHD_gtls_io_clear_read_buffer (MHD_gtls_session_t session)
  291. {
  292. session->internals.record_recv_buffer.length = 0;
  293. }
  294. /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
  295. * It does return MHD_gnutls_errno instead.
  296. * This function reads data from the socket and keeps them in a buffer, of up to
  297. * MAX_RECV_SIZE.
  298. *
  299. * This is not a general purpose function. It returns EXACTLY the data requested,
  300. * which are stored in a local (in the session) buffer. A pointer (iptr) to this buffer is returned.
  301. *
  302. */
  303. ssize_t
  304. MHD_gtls_io_read_buffered (MHD_gtls_session_t session, opaque ** iptr,
  305. size_t sizeOfPtr, content_type_t recv_type)
  306. {
  307. ssize_t ret = 0, ret2 = 0;
  308. size_t min;
  309. int buf_pos;
  310. opaque *buf;
  311. int recvlowat;
  312. int recvdata, alloc_size;
  313. *iptr = session->internals.record_recv_buffer.data;
  314. if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0)
  315. {
  316. MHD_gnutls_assert (); /* internal error */
  317. return GNUTLS_E_INVALID_REQUEST;
  318. }
  319. /* If an external pull function is used, then do not leave
  320. * any data into the kernel buffer.
  321. */
  322. if (session->internals.MHD__gnutls_pull_func != NULL)
  323. {
  324. recvlowat = 0;
  325. }
  326. else
  327. {
  328. /* leave peeked data to the kernel space only if application data
  329. * is received and we don't have any peeked
  330. * data in gnutls session.
  331. */
  332. if (recv_type != GNUTLS_APPLICATION_DATA
  333. && session->internals.have_peeked_data == 0)
  334. recvlowat = 0;
  335. else
  336. recvlowat = RCVLOWAT;
  337. }
  338. /* calculate the actual size, ie. get the minimum of the
  339. * buffered data and the requested data.
  340. */
  341. min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr);
  342. if (min > 0)
  343. {
  344. /* if we have enough buffered data
  345. * then just return them.
  346. */
  347. if (min == sizeOfPtr)
  348. {
  349. return min;
  350. }
  351. }
  352. /* min is over zero. recvdata is the data we must
  353. * receive in order to return the requested data.
  354. */
  355. recvdata = sizeOfPtr - min;
  356. /* Check if the previously read data plus the new data to
  357. * receive are longer than the maximum receive buffer size.
  358. */
  359. if ((session->internals.record_recv_buffer.length + recvdata)
  360. > MAX_RECV_SIZE)
  361. {
  362. MHD_gnutls_assert (); /* internal error */
  363. return GNUTLS_E_INVALID_REQUEST;
  364. }
  365. /* Allocate the data required to store the new packet.
  366. */
  367. alloc_size = recvdata + session->internals.record_recv_buffer.length;
  368. session->internals.record_recv_buffer.data =
  369. MHD_gtls_realloc_fast (session->internals.record_recv_buffer.data,
  370. alloc_size);
  371. if (session->internals.record_recv_buffer.data == NULL)
  372. {
  373. MHD_gnutls_assert ();
  374. return GNUTLS_E_MEMORY_ERROR;
  375. }
  376. buf_pos = session->internals.record_recv_buffer.length;
  377. buf = session->internals.record_recv_buffer.data;
  378. *iptr = buf;
  379. /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */
  380. if (recvdata - recvlowat > 0)
  381. {
  382. ret =
  383. MHD__gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 0);
  384. /* return immediately if we got an interrupt or eagain
  385. * error.
  386. */
  387. if (ret < 0 && MHD_gtls_error_is_fatal (ret) == 0)
  388. {
  389. return ret;
  390. }
  391. }
  392. /* copy fresh data to our buffer.
  393. */
  394. if (ret > 0)
  395. {
  396. MHD__gnutls_read_log
  397. ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
  398. session->internals.record_recv_buffer.length, ret);
  399. MHD__gnutls_read_log ("RB: Requested %d bytes\n", sizeOfPtr);
  400. session->internals.record_recv_buffer.length += ret;
  401. }
  402. buf_pos = session->internals.record_recv_buffer.length;
  403. /* This is a hack placed in order for select to work. Just leave recvlowat data,
  404. * into the kernel buffer (using a read with MSG_PEEK), thus making
  405. * select think, that the socket is ready for reading.
  406. * MSG_PEEK is only used with berkeley style sockets.
  407. */
  408. if (ret == (recvdata - recvlowat) && recvlowat > 0)
  409. {
  410. ret2 = MHD__gnutls_read (session, &buf[buf_pos], recvlowat, MSG_PEEK);
  411. if (ret2 < 0 && MHD_gtls_error_is_fatal (ret2) == 0)
  412. {
  413. return ret2;
  414. }
  415. if (ret2 > 0)
  416. {
  417. MHD__gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n",
  418. ret2);
  419. MHD__gnutls_read_log
  420. ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
  421. session->internals.record_recv_buffer.length, ret2, sizeOfPtr);
  422. session->internals.have_peeked_data = 1;
  423. session->internals.record_recv_buffer.length += ret2;
  424. }
  425. }
  426. if (ret < 0 || ret2 < 0)
  427. {
  428. MHD_gnutls_assert ();
  429. /* that's because they are initialized to 0 */
  430. return MIN (ret, ret2);
  431. }
  432. ret += ret2;
  433. if (ret > 0 && ret < recvlowat)
  434. {
  435. MHD_gnutls_assert ();
  436. return GNUTLS_E_AGAIN;
  437. }
  438. if (ret == 0)
  439. { /* EOF */
  440. MHD_gnutls_assert ();
  441. return 0;
  442. }
  443. ret = session->internals.record_recv_buffer.length;
  444. if ((ret > 0) && ((size_t) ret < sizeOfPtr))
  445. {
  446. /* Short Read */
  447. MHD_gnutls_assert ();
  448. return GNUTLS_E_AGAIN;
  449. }
  450. else
  451. {
  452. return ret;
  453. }
  454. }
  455. /* These two functions are used to insert data to the send buffer of the handshake or
  456. * record protocol. The send buffer is kept if a send is interrupted and we need to keep
  457. * the data left to sent, in order to send them later.
  458. */
  459. #define MEMSUB(x,y) ((ssize_t)((ptrdiff_t)x-(ptrdiff_t)y))
  460. inline static int
  461. MHD__gnutls_buffer_insert (MHD_gtls_buffer * buffer,
  462. const opaque * _data, size_t data_size)
  463. {
  464. if ((MEMSUB (_data, buffer->data) >= 0)
  465. && (MEMSUB (_data, buffer->data) < (ssize_t) buffer->length))
  466. {
  467. /* the given _data is part of the buffer.
  468. */
  469. if (data_size > buffer->length)
  470. {
  471. MHD_gnutls_assert ();
  472. /* this shouldn't have happened */
  473. return GNUTLS_E_INTERNAL_ERROR;
  474. }
  475. if (_data == buffer->data)
  476. { /* then don't even memmove */
  477. buffer->length = data_size;
  478. return 0;
  479. }
  480. memmove (buffer->data, _data, data_size);
  481. buffer->length = data_size;
  482. return 0;
  483. }
  484. if (MHD_gtls_buffer_append (buffer, _data, data_size) < 0)
  485. {
  486. MHD_gnutls_assert ();
  487. return GNUTLS_E_MEMORY_ERROR;
  488. }
  489. return 0;
  490. }
  491. inline static int
  492. MHD__gnutls_buffer_get (MHD_gtls_buffer * buffer,
  493. const opaque ** ptr, size_t * ptr_size)
  494. {
  495. *ptr_size = buffer->length;
  496. *ptr = buffer->data;
  497. return 0;
  498. }
  499. /* This function is like write. But it does not return -1 on error.
  500. * It does return MHD_gnutls_errno instead.
  501. *
  502. * In case of E_AGAIN and E_INTERRUPTED errors, you must call MHD_gnutls_write_flush(),
  503. * until it returns ok (0).
  504. *
  505. * We need to push exactly the data in n, since we cannot send less
  506. * data. In TLS the peer must receive the whole packet in order
  507. * to decrypt and verify the integrity.
  508. *
  509. */
  510. ssize_t
  511. MHD_gtls_io_write_buffered (MHD_gtls_session_t session,
  512. const void *iptr, size_t n)
  513. {
  514. size_t left;
  515. unsigned j, x, sum = 0;
  516. ssize_t retval, i;
  517. const opaque *ptr;
  518. int ret;
  519. MHD_gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
  520. /* to know where the procedure was interrupted.
  521. */
  522. session->internals.direction = 1;
  523. ptr = iptr;
  524. /* In case the previous write was interrupted, check if the
  525. * iptr != NULL and we have data in the buffer.
  526. * If this is true then return an error.
  527. */
  528. if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
  529. {
  530. MHD_gnutls_assert ();
  531. return GNUTLS_E_INVALID_REQUEST;
  532. }
  533. /* If data in the buffer exist
  534. */
  535. if (iptr == NULL)
  536. {
  537. /* checking is handled above */
  538. ret =
  539. MHD__gnutls_buffer_get (&session->internals.record_send_buffer, &ptr,
  540. &n);
  541. if (ret < 0)
  542. {
  543. MHD_gnutls_assert ();
  544. return ret;
  545. }
  546. MHD__gnutls_write_log
  547. ("WRITE: Restoring old write. (%d bytes to send)\n", n);
  548. }
  549. MHD__gnutls_write_log ("WRITE: Will write %d bytes to %d.\n", n, fd);
  550. i = 0;
  551. left = n;
  552. while (left > 0)
  553. {
  554. session->internals.errnum = 0;
  555. if (session->internals.MHD__gnutls_push_func == NULL)
  556. {
  557. i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0);
  558. #if HAVE_WINSOCK
  559. if (i < 0)
  560. {
  561. int tmperr = WSAGetLastError ();
  562. switch (tmperr)
  563. {
  564. case WSAEWOULDBLOCK:
  565. session->internals.errnum = EAGAIN;
  566. break;
  567. case WSAEINTR:
  568. session->internals.errnum = EINTR;
  569. break;
  570. default:
  571. session->internals.errnum = EIO;
  572. break;
  573. }
  574. WSASetLastError (tmperr);
  575. }
  576. #endif
  577. }
  578. else
  579. i = session->internals.MHD__gnutls_push_func (fd, &ptr[n - left], left);
  580. if (i == -1)
  581. {
  582. int err = session->internals.errnum ? session->internals.errnum
  583. : errno;
  584. if ( (err == EAGAIN) || (err == EINTR) )
  585. {
  586. session->internals.record_send_buffer_prev_size += n - left;
  587. retval =
  588. MHD__gnutls_buffer_insert (&session->
  589. internals.record_send_buffer,
  590. &ptr[n - left], left);
  591. if (retval < 0)
  592. {
  593. MHD_gnutls_assert ();
  594. return retval;
  595. }
  596. if (err == EAGAIN)
  597. return GNUTLS_E_AGAIN;
  598. return GNUTLS_E_INTERRUPTED;
  599. }
  600. else
  601. {
  602. MHD_gnutls_assert ();
  603. return GNUTLS_E_PUSH_ERROR;
  604. }
  605. }
  606. left -= i;
  607. if (MHD__gnutls_log_level >= 7)
  608. {
  609. char line[128];
  610. char tmp[16];
  611. MHD__gnutls_write_log
  612. ("WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n",
  613. i, fd, left, n);
  614. for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
  615. {
  616. line[0] = 0;
  617. if (sum > n - left)
  618. break;
  619. sprintf (tmp, "%.4x - ", x);
  620. MHD_gtls_str_cat (line, sizeof (line), tmp);
  621. for (j = 0; j < 16; j++)
  622. {
  623. if (sum < n - left)
  624. {
  625. sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
  626. MHD_gtls_str_cat (line, sizeof (line), tmp);
  627. }
  628. else
  629. break;
  630. }
  631. MHD__gnutls_write_log ("%s\n", line);
  632. }
  633. }
  634. }
  635. retval = n + session->internals.record_send_buffer_prev_size;
  636. session->internals.record_send_buffer.length = 0;
  637. session->internals.record_send_buffer_prev_size = 0;
  638. return retval;
  639. }
  640. /* This function writes the data that are left in the
  641. * TLS write buffer (ie. because the previous write was
  642. * interrupted.
  643. */
  644. ssize_t
  645. MHD_gtls_io_write_flush (MHD_gtls_session_t session)
  646. {
  647. ssize_t ret;
  648. if (session->internals.record_send_buffer.length == 0)
  649. return 0; /* done */
  650. ret = MHD_gtls_io_write_buffered (session, NULL, 0);
  651. MHD__gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", ret,
  652. session->internals.record_send_buffer.length);
  653. return ret;
  654. }
  655. /* This function writes the data that are left in the
  656. * Handshake write buffer (ie. because the previous write was
  657. * interrupted.
  658. */
  659. ssize_t
  660. MHD_gtls_handshake_io_write_flush (MHD_gtls_session_t session)
  661. {
  662. ssize_t ret;
  663. ret = MHD_gtls_handshake_io_send_int (session, 0, 0, NULL, 0);
  664. if (ret < 0)
  665. {
  666. MHD_gnutls_assert ();
  667. return ret;
  668. }
  669. MHD__gnutls_write_log ("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret);
  670. if (session->internals.handshake_send_buffer.length == 0)
  671. {
  672. ret = session->internals.handshake_send_buffer_prev_size; /* done */
  673. session->internals.handshake_send_buffer_prev_size = 0;
  674. }
  675. return ret;
  676. }
  677. /* This is a send function for the gnutls handshake
  678. * protocol. Just makes sure that all data have been sent.
  679. */
  680. ssize_t
  681. MHD_gtls_handshake_io_send_int (MHD_gtls_session_t session,
  682. content_type_t type,
  683. MHD_gnutls_handshake_description_t htype,
  684. const void *iptr, size_t n)
  685. {
  686. size_t left;
  687. ssize_t ret = 0;
  688. const opaque *ptr;
  689. ssize_t retval = 0;
  690. ptr = iptr;
  691. if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL && n
  692. == 0)
  693. {
  694. /* resuming previously interrupted write
  695. */
  696. MHD_gnutls_assert ();
  697. ret = MHD__gnutls_buffer_get (&session->internals.handshake_send_buffer,
  698. &ptr, &n);
  699. if (ret < 0)
  700. {
  701. MHD_gnutls_assert ();
  702. return retval;
  703. }
  704. type = session->internals.handshake_send_buffer_type;
  705. htype = session->internals.handshake_send_buffer_htype;
  706. }
  707. else if (session->internals.handshake_send_buffer.length > 0)
  708. {
  709. MHD_gnutls_assert ();
  710. return GNUTLS_E_INTERNAL_ERROR;
  711. }
  712. #ifdef WRITE_DEBUG
  713. else
  714. {
  715. size_t sum = 0, x, j;
  716. MHD__gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
  717. MHD_gnutls_transport_get_ptr (session));
  718. for (x = 0; x < ((n) / 16) + 1; x++)
  719. {
  720. if (sum > n)
  721. break;
  722. MHD__gnutls_write_log ("%.4x - ", x);
  723. for (j = 0; j < 16; j++)
  724. {
  725. if (sum < n)
  726. {
  727. MHD__gnutls_write_log ("%.2x ",
  728. ((unsigned char *) ptr)[sum++]);
  729. }
  730. else
  731. break;
  732. }
  733. MHD__gnutls_write_log ("\n");
  734. }
  735. MHD__gnutls_write_log ("\n");
  736. }
  737. #endif
  738. if (n == 0)
  739. { /* if we have no data to send */
  740. MHD_gnutls_assert ();
  741. return 0;
  742. }
  743. else if (ptr == NULL)
  744. {
  745. MHD_gnutls_assert ();
  746. return GNUTLS_E_INTERNAL_ERROR;
  747. }
  748. left = n;
  749. while (left > 0)
  750. {
  751. ret = MHD_gtls_send_int (session, type, htype, &ptr[n - left], left);
  752. if (ret <= 0)
  753. {
  754. if (ret == 0)
  755. {
  756. MHD_gnutls_assert ();
  757. ret = GNUTLS_E_INTERNAL_ERROR;
  758. }
  759. if (left > 0 && (ret == GNUTLS_E_INTERRUPTED || ret
  760. == GNUTLS_E_AGAIN))
  761. {
  762. MHD_gnutls_assert ();
  763. retval =
  764. MHD__gnutls_buffer_insert (&session->internals.
  765. handshake_send_buffer,
  766. &ptr[n - left], left);
  767. if (retval < 0)
  768. {
  769. MHD_gnutls_assert ();
  770. return retval;
  771. }
  772. session->internals.handshake_send_buffer_prev_size += n - left;
  773. session->internals.handshake_send_buffer_type = type;
  774. session->internals.handshake_send_buffer_htype = htype;
  775. }
  776. else
  777. {
  778. session->internals.handshake_send_buffer_prev_size = 0;
  779. session->internals.handshake_send_buffer.length = 0;
  780. }
  781. MHD_gnutls_assert ();
  782. return ret;
  783. }
  784. left -= ret;
  785. }
  786. retval = n + session->internals.handshake_send_buffer_prev_size;
  787. session->internals.handshake_send_buffer.length = 0;
  788. session->internals.handshake_send_buffer_prev_size = 0;
  789. return retval;
  790. }
  791. /* This is a receive function for the gnutls handshake
  792. * protocol. Makes sure that we have received all data.
  793. */
  794. ssize_t
  795. MHD_gtls_handshake_io_recv_int (MHD_gtls_session_t session,
  796. content_type_t type,
  797. MHD_gnutls_handshake_description_t htype,
  798. void *iptr, size_t sizeOfPtr)
  799. {
  800. size_t left;
  801. ssize_t i;
  802. opaque *ptr;
  803. size_t dsize;
  804. ptr = iptr;
  805. left = sizeOfPtr;
  806. if (sizeOfPtr == 0 || iptr == NULL)
  807. {
  808. MHD_gnutls_assert ();
  809. return GNUTLS_E_INVALID_REQUEST;
  810. }
  811. if (session->internals.handshake_recv_buffer.length > 0)
  812. {
  813. /* if we have already received some data */
  814. if (sizeOfPtr <= session->internals.handshake_recv_buffer.length)
  815. {
  816. /* if requested less data then return it.
  817. */
  818. MHD_gnutls_assert ();
  819. memcpy (iptr, session->internals.handshake_recv_buffer.data,
  820. sizeOfPtr);
  821. session->internals.handshake_recv_buffer.length -= sizeOfPtr;
  822. memmove (session->internals.handshake_recv_buffer.data,
  823. &session->internals.handshake_recv_buffer.data[sizeOfPtr],
  824. session->internals.handshake_recv_buffer.length);
  825. return sizeOfPtr;
  826. }
  827. MHD_gnutls_assert ();
  828. memcpy (iptr, session->internals.handshake_recv_buffer.data,
  829. session->internals.handshake_recv_buffer.length);
  830. htype = session->internals.handshake_recv_buffer_htype;
  831. type = session->internals.handshake_recv_buffer_type;
  832. left -= session->internals.handshake_recv_buffer.length;
  833. session->internals.handshake_recv_buffer.length = 0;
  834. }
  835. while (left > 0)
  836. {
  837. dsize = sizeOfPtr - left;
  838. i = MHD_gtls_recv_int (session, type, htype, &ptr[dsize], left);
  839. if (i < 0)
  840. {
  841. if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
  842. {
  843. MHD_gnutls_assert ();
  844. session->internals.handshake_recv_buffer.data
  845. =
  846. MHD_gtls_realloc_fast (session->internals.
  847. handshake_recv_buffer.data, dsize);
  848. if (session->internals.handshake_recv_buffer.data == NULL)
  849. {
  850. MHD_gnutls_assert ();
  851. return GNUTLS_E_MEMORY_ERROR;
  852. }
  853. memcpy (session->internals.handshake_recv_buffer.data, iptr,
  854. dsize);
  855. session->internals.handshake_recv_buffer_htype = htype;
  856. session->internals.handshake_recv_buffer_type = type;
  857. session->internals.handshake_recv_buffer.length = dsize;
  858. }
  859. else
  860. session->internals.handshake_recv_buffer.length = 0;
  861. MHD_gnutls_assert ();
  862. return i;
  863. }
  864. else
  865. {
  866. if (i == 0)
  867. break; /* EOF */
  868. }
  869. left -= i;
  870. }
  871. session->internals.handshake_recv_buffer.length = 0;
  872. return sizeOfPtr - left;
  873. }
  874. /* Buffer for handshake packets. Keeps the packets in order
  875. * for finished messages to use them. Used in HMAC calculation
  876. * and finished messages.
  877. */
  878. int
  879. MHD_gtls_handshake_buffer_put (MHD_gtls_session_t session, opaque * data,
  880. size_t length)
  881. {
  882. if (length == 0)
  883. return 0;
  884. if ((session->internals.max_handshake_data_buffer_size > 0) && ((length
  885. +
  886. session->
  887. internals.
  888. handshake_hash_buffer.
  889. length) >
  890. session->
  891. internals.
  892. max_handshake_data_buffer_size))
  893. {
  894. MHD_gnutls_assert ();
  895. return GNUTLS_E_MEMORY_ERROR;
  896. }
  897. MHD__gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", length);
  898. if (MHD_gtls_buffer_append (&session->internals.handshake_hash_buffer, data,
  899. length) < 0)
  900. {
  901. MHD_gnutls_assert ();
  902. return GNUTLS_E_MEMORY_ERROR;
  903. }
  904. return 0;
  905. }
  906. /* this function does not touch the buffer
  907. * and returns data from it (peek mode!)
  908. */
  909. int
  910. MHD_gtls_handshake_buffer_get_ptr (MHD_gtls_session_t session,
  911. opaque ** data_ptr, size_t * length)
  912. {
  913. if (length != NULL)
  914. *length = session->internals.handshake_hash_buffer.length;
  915. MHD__gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n",
  916. session->internals.handshake_hash_buffer.length);
  917. if (data_ptr != NULL)
  918. *data_ptr = session->internals.handshake_hash_buffer.data;
  919. return 0;
  920. }
  921. /* Does not free the buffer
  922. */
  923. int
  924. MHD_gtls_handshake_buffer_empty (MHD_gtls_session_t session)
  925. {
  926. MHD__gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n");
  927. session->internals.handshake_hash_buffer.length = 0;
  928. return 0;
  929. }
  930. int
  931. MHD_gtls_handshake_buffer_clear (MHD_gtls_session_t session)
  932. {
  933. MHD__gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
  934. MHD_gtls_buffer_clear (&session->internals.handshake_hash_buffer);
  935. return 0;
  936. }