Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

FdInStream.cxx 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <sys/time.h>
  25. #ifdef _WIN32
  26. #include <winsock2.h>
  27. #define close closesocket
  28. #undef errno
  29. #define errno WSAGetLastError()
  30. #include <os/winerrno.h>
  31. #else
  32. #include <sys/types.h>
  33. #include <sys/socket.h>
  34. #include <unistd.h>
  35. #endif
  36. #ifndef vncmin
  37. #define vncmin(a,b) (((a) < (b)) ? (a) : (b))
  38. #endif
  39. #ifndef vncmax
  40. #define vncmax(a,b) (((a) > (b)) ? (a) : (b))
  41. #endif
  42. /* Old systems have select() in sys/time.h */
  43. #ifdef HAVE_SYS_SELECT_H
  44. #include <sys/select.h>
  45. #endif
  46. #include <rdr/FdInStream.h>
  47. #include <rdr/Exception.h>
  48. using namespace rdr;
  49. enum { DEFAULT_BUF_SIZE = 8192,
  50. MIN_BULK_SIZE = 1024 };
  51. FdInStream::FdInStream(int fd_, int timeoutms_, int bufSize_,
  52. bool closeWhenDone_)
  53. : fd(fd_), closeWhenDone(closeWhenDone_),
  54. timeoutms(timeoutms_), blockCallback(0),
  55. timing(false), timeWaitedIn100us(5), timedKbits(0),
  56. bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
  57. {
  58. ptr = end = start = new U8[bufSize];
  59. }
  60. FdInStream::FdInStream(int fd_, FdInStreamBlockCallback* blockCallback_,
  61. int bufSize_)
  62. : fd(fd_), timeoutms(0), blockCallback(blockCallback_),
  63. timing(false), timeWaitedIn100us(5), timedKbits(0),
  64. bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
  65. {
  66. ptr = end = start = new U8[bufSize];
  67. }
  68. FdInStream::~FdInStream()
  69. {
  70. delete [] start;
  71. if (closeWhenDone) close(fd);
  72. }
  73. void FdInStream::setTimeout(int timeoutms_) {
  74. timeoutms = timeoutms_;
  75. }
  76. void FdInStream::setBlockCallback(FdInStreamBlockCallback* blockCallback_)
  77. {
  78. blockCallback = blockCallback_;
  79. timeoutms = 0;
  80. }
  81. int FdInStream::pos()
  82. {
  83. return offset + ptr - start;
  84. }
  85. void FdInStream::readBytes(void* data, int length)
  86. {
  87. if (length < MIN_BULK_SIZE) {
  88. InStream::readBytes(data, length);
  89. return;
  90. }
  91. U8* dataPtr = (U8*)data;
  92. int n = end - ptr;
  93. if (n > length) n = length;
  94. memcpy(dataPtr, ptr, n);
  95. dataPtr += n;
  96. length -= n;
  97. ptr += n;
  98. while (length > 0) {
  99. n = readWithTimeoutOrCallback(dataPtr, length);
  100. dataPtr += n;
  101. length -= n;
  102. offset += n;
  103. }
  104. }
  105. int FdInStream::overrun(int itemSize, int nItems, bool wait)
  106. {
  107. if (itemSize > bufSize)
  108. throw Exception("FdInStream overrun: max itemSize exceeded");
  109. if (end - ptr != 0)
  110. memmove(start, ptr, end - ptr);
  111. offset += ptr - start;
  112. end -= ptr - start;
  113. ptr = start;
  114. int bytes_to_read;
  115. while (end < start + itemSize) {
  116. bytes_to_read = start + bufSize - end;
  117. if (!timing) {
  118. // When not timing, we must be careful not to read too much
  119. // extra data into the buffer. Otherwise, the line speed
  120. // estimation might stay at zero for a long time: All reads
  121. // during timing=1 can be satisfied without calling
  122. // readWithTimeoutOrCallback. However, reading only 1 or 2 bytes
  123. // bytes is ineffecient.
  124. bytes_to_read = vncmin(bytes_to_read, vncmax(itemSize*nItems, 8));
  125. }
  126. int n = readWithTimeoutOrCallback((U8*)end, bytes_to_read, wait);
  127. if (n == 0) return 0;
  128. end += n;
  129. }
  130. if (itemSize * nItems > end - ptr)
  131. nItems = (end - ptr) / itemSize;
  132. return nItems;
  133. }
  134. //
  135. // readWithTimeoutOrCallback() reads up to the given length in bytes from the
  136. // file descriptor into a buffer. If the wait argument is false, then zero is
  137. // returned if no bytes can be read without blocking. Otherwise if a
  138. // blockCallback is set, it will be called (repeatedly) instead of blocking.
  139. // If alternatively there is a timeout set and that timeout expires, it throws
  140. // a TimedOut exception. Otherwise it returns the number of bytes read. It
  141. // never attempts to recv() unless select() indicates that the fd is readable -
  142. // this means it can be used on an fd which has been set non-blocking. It also
  143. // has to cope with the annoying possibility of both select() and recv()
  144. // returning EINTR.
  145. //
  146. int FdInStream::readWithTimeoutOrCallback(void* buf, int len, bool wait)
  147. {
  148. struct timeval before, after;
  149. if (timing)
  150. gettimeofday(&before, 0);
  151. int n;
  152. while (true) {
  153. do {
  154. fd_set fds;
  155. struct timeval tv;
  156. struct timeval* tvp = &tv;
  157. if (!wait) {
  158. tv.tv_sec = tv.tv_usec = 0;
  159. } else 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. n = select(fd+1, &fds, 0, 0, tvp);
  168. } while (n < 0 && errno == EINTR);
  169. if (n > 0) break;
  170. if (n < 0) throw SystemException("select",errno);
  171. if (!wait) return 0;
  172. if (!blockCallback) throw TimedOut();
  173. blockCallback->blockCallback();
  174. }
  175. do {
  176. n = ::recv(fd, (char*)buf, len, 0);
  177. } while (n < 0 && errno == EINTR);
  178. if (n < 0) throw SystemException("read",errno);
  179. if (n == 0) throw EndOfStream();
  180. if (timing) {
  181. gettimeofday(&after, 0);
  182. int newTimeWaited = ((after.tv_sec - before.tv_sec) * 10000 +
  183. (after.tv_usec - before.tv_usec) / 100);
  184. int newKbits = n * 8 / 1000;
  185. // limit rate to between 10kbit/s and 40Mbit/s
  186. if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
  187. if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
  188. timeWaitedIn100us += newTimeWaited;
  189. timedKbits += newKbits;
  190. }
  191. return n;
  192. }
  193. void FdInStream::startTiming()
  194. {
  195. timing = true;
  196. // Carry over up to 1s worth of previous rate for smoothing.
  197. if (timeWaitedIn100us > 10000) {
  198. timedKbits = timedKbits * 10000 / timeWaitedIn100us;
  199. timeWaitedIn100us = 10000;
  200. }
  201. }
  202. void FdInStream::stopTiming()
  203. {
  204. timing = false;
  205. if (timeWaitedIn100us < timedKbits/2)
  206. timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
  207. }
  208. unsigned int FdInStream::kbitsPerSecond()
  209. {
  210. // The following calculation will overflow 32-bit arithmetic if we have
  211. // received more than about 50Mbytes (400Mbits) since we started timing, so
  212. // it should be OK for a single RFB update.
  213. return timedKbits * 10000 / timeWaitedIn100us;
  214. }