You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TLSOutStream.cxx 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2005 Martin Koegler
  3. * Copyright (C) 2010 TigerVNC Team
  4. * Copyright (C) 2012-2021 Pierre Ossman for Cendio AB
  5. *
  6. * This is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This software is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this software; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  19. * USA.
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <rdr/Exception.h>
  25. #include <rdr/TLSException.h>
  26. #include <rdr/TLSOutStream.h>
  27. #include <rfb/LogWriter.h>
  28. #include <errno.h>
  29. #ifdef HAVE_GNUTLS
  30. using namespace rdr;
  31. static rfb::LogWriter vlog("TLSOutStream");
  32. enum { DEFAULT_BUF_SIZE = 16384 };
  33. ssize_t TLSOutStream::push(gnutls_transport_ptr_t str, const void* data,
  34. size_t size)
  35. {
  36. TLSOutStream* self= (TLSOutStream*) str;
  37. OutStream *out = self->out;
  38. delete self->saved_exception;
  39. self->saved_exception = NULL;
  40. try {
  41. out->writeBytes(data, size);
  42. out->flush();
  43. } catch (SystemException &e) {
  44. vlog.error("Failure sending TLS data: %s", e.str());
  45. gnutls_transport_set_errno(self->session, e.err);
  46. self->saved_exception = new SystemException(e);
  47. return -1;
  48. } catch (Exception& e) {
  49. vlog.error("Failure sending TLS data: %s", e.str());
  50. gnutls_transport_set_errno(self->session, EINVAL);
  51. self->saved_exception = new Exception(e);
  52. return -1;
  53. }
  54. return size;
  55. }
  56. TLSOutStream::TLSOutStream(OutStream* _out, gnutls_session_t _session)
  57. : session(_session), out(_out), bufSize(DEFAULT_BUF_SIZE), offset(0),
  58. saved_exception(NULL)
  59. {
  60. gnutls_transport_ptr_t recv, send;
  61. ptr = start = new U8[bufSize];
  62. end = start + bufSize;
  63. gnutls_transport_set_push_function(session, push);
  64. gnutls_transport_get_ptr2(session, &recv, &send);
  65. gnutls_transport_set_ptr2(session, recv, this);
  66. }
  67. TLSOutStream::~TLSOutStream()
  68. {
  69. #if 0
  70. try {
  71. // flush();
  72. } catch (Exception&) {
  73. }
  74. #endif
  75. gnutls_transport_set_push_function(session, NULL);
  76. delete [] start;
  77. delete saved_exception;
  78. }
  79. size_t TLSOutStream::length()
  80. {
  81. return offset + ptr - start;
  82. }
  83. void TLSOutStream::flush()
  84. {
  85. U8* sentUpTo;
  86. // Only give GnuTLS larger chunks if corked to minimize overhead
  87. if (corked && ((ptr - start) < 1024))
  88. return;
  89. sentUpTo = start;
  90. while (sentUpTo < ptr) {
  91. size_t n = writeTLS(sentUpTo, ptr - sentUpTo);
  92. sentUpTo += n;
  93. offset += n;
  94. }
  95. ptr = start;
  96. out->flush();
  97. }
  98. void TLSOutStream::cork(bool enable)
  99. {
  100. OutStream::cork(enable);
  101. out->cork(enable);
  102. }
  103. void TLSOutStream::overrun(size_t needed)
  104. {
  105. bool oldCorked;
  106. if (needed > bufSize)
  107. throw Exception("TLSOutStream overrun: buffer size exceeded");
  108. // A cork might prevent the flush, so disable it temporarily
  109. oldCorked = corked;
  110. corked = false;
  111. flush();
  112. corked = oldCorked;
  113. }
  114. size_t TLSOutStream::writeTLS(const U8* data, size_t length)
  115. {
  116. int n;
  117. n = gnutls_record_send(session, data, length);
  118. if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
  119. return 0;
  120. if (n == GNUTLS_E_PUSH_ERROR)
  121. throw *saved_exception;
  122. if (n < 0)
  123. throw TLSException("writeTLS", n);
  124. return n;
  125. }
  126. #endif