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.6KB

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