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.

FdOutStream.cxx 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011 Pierre Ossman for Cendio AB
  3. * Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
  4. *
  5. * This is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This software is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this software; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  18. * USA.
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. #include <config.h>
  22. #endif
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <errno.h>
  26. #ifdef _WIN32
  27. #include <winsock2.h>
  28. #undef errno
  29. #define errno WSAGetLastError()
  30. #include <os/winerrno.h>
  31. #else
  32. #include <sys/types.h>
  33. #include <unistd.h>
  34. #include <sys/time.h>
  35. #include <sys/socket.h>
  36. #endif
  37. /* Old systems have select() in sys/time.h */
  38. #ifdef HAVE_SYS_SELECT_H
  39. #include <sys/select.h>
  40. #endif
  41. #include <rdr/FdOutStream.h>
  42. #include <rdr/Exception.h>
  43. #include <rfb/util.h>
  44. using namespace rdr;
  45. enum { DEFAULT_BUF_SIZE = 16384 };
  46. FdOutStream::FdOutStream(int fd_, bool blocking_, int timeoutms_, size_t bufSize_)
  47. : fd(fd_), blocking(blocking_), timeoutms(timeoutms_),
  48. bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
  49. {
  50. ptr = start = sentUpTo = new U8[bufSize];
  51. end = start + bufSize;
  52. gettimeofday(&lastWrite, NULL);
  53. }
  54. FdOutStream::~FdOutStream()
  55. {
  56. try {
  57. blocking = true;
  58. flush();
  59. } catch (Exception&) {
  60. }
  61. delete [] start;
  62. }
  63. void FdOutStream::setTimeout(int timeoutms_) {
  64. timeoutms = timeoutms_;
  65. }
  66. void FdOutStream::setBlocking(bool blocking_) {
  67. blocking = blocking_;
  68. }
  69. size_t FdOutStream::length()
  70. {
  71. return offset + ptr - sentUpTo;
  72. }
  73. int FdOutStream::bufferUsage()
  74. {
  75. return ptr - sentUpTo;
  76. }
  77. unsigned FdOutStream::getIdleTime()
  78. {
  79. return rfb::msSince(&lastWrite);
  80. }
  81. void FdOutStream::flush()
  82. {
  83. while (sentUpTo < ptr) {
  84. size_t n = writeWithTimeout((const void*) sentUpTo,
  85. ptr - sentUpTo,
  86. blocking? timeoutms : 0);
  87. // Timeout?
  88. if (n == 0) {
  89. // If non-blocking then we're done here
  90. if (!blocking)
  91. break;
  92. throw TimedOut();
  93. }
  94. sentUpTo += n;
  95. offset += n;
  96. }
  97. // Managed to flush everything?
  98. if (sentUpTo == ptr)
  99. ptr = sentUpTo = start;
  100. }
  101. size_t FdOutStream::overrun(size_t itemSize, size_t nItems)
  102. {
  103. if (itemSize > bufSize)
  104. throw Exception("FdOutStream overrun: max itemSize exceeded");
  105. // First try to get rid of the data we have
  106. flush();
  107. // Still not enough space?
  108. if (itemSize > (size_t)(end - ptr)) {
  109. // Can we shuffle things around?
  110. // (don't do this if it gains us less than 25%)
  111. if (((size_t)(sentUpTo - start) > bufSize / 4) &&
  112. (itemSize < bufSize - (ptr - sentUpTo))) {
  113. memmove(start, sentUpTo, ptr - sentUpTo);
  114. ptr = start + (ptr - sentUpTo);
  115. sentUpTo = start;
  116. } else {
  117. // Have to get rid of more data, so turn off non-blocking
  118. // for a bit...
  119. bool realBlocking;
  120. realBlocking = blocking;
  121. blocking = true;
  122. flush();
  123. blocking = realBlocking;
  124. }
  125. }
  126. // Can we fit all the items asked for?
  127. if (itemSize * nItems > (size_t)(end - ptr))
  128. nItems = (end - ptr) / itemSize;
  129. return nItems;
  130. }
  131. //
  132. // writeWithTimeout() writes up to the given length in bytes from the given
  133. // buffer to the file descriptor. If there is a timeout set and that timeout
  134. // expires, it throws a TimedOut exception. Otherwise it returns the number of
  135. // bytes written. It never attempts to send() unless select() indicates that
  136. // the fd is writable - this means it can be used on an fd which has been set
  137. // non-blocking. It also has to cope with the annoying possibility of both
  138. // select() and send() returning EINTR.
  139. //
  140. size_t FdOutStream::writeWithTimeout(const void* data, size_t length, int timeoutms)
  141. {
  142. int n;
  143. do {
  144. fd_set fds;
  145. struct timeval tv;
  146. struct timeval* tvp = &tv;
  147. if (timeoutms != -1) {
  148. tv.tv_sec = timeoutms / 1000;
  149. tv.tv_usec = (timeoutms % 1000) * 1000;
  150. } else {
  151. tvp = NULL;
  152. }
  153. FD_ZERO(&fds);
  154. FD_SET(fd, &fds);
  155. n = select(fd+1, 0, &fds, 0, tvp);
  156. } while (n < 0 && errno == EINTR);
  157. if (n < 0)
  158. throw SystemException("select", errno);
  159. if (n == 0)
  160. return 0;
  161. do {
  162. // select only guarantees that you can write SO_SNDLOWAT without
  163. // blocking, which is normally 1. Use MSG_DONTWAIT to avoid
  164. // blocking, when possible.
  165. #ifndef MSG_DONTWAIT
  166. n = ::send(fd, (const char*)data, length, 0);
  167. #else
  168. n = ::send(fd, (const char*)data, length, MSG_DONTWAIT);
  169. #endif
  170. } while (n < 0 && (errno == EINTR));
  171. if (n < 0)
  172. throw SystemException("write", errno);
  173. gettimeofday(&lastWrite, NULL);
  174. return n;
  175. }