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 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* Copyright (C) 2002-2003 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. #include <stdio.h>
  19. #include <string.h>
  20. #ifdef _WIN32
  21. #include <winsock2.h>
  22. #define write(s,b,l) send(s,(const char*)b,l,0)
  23. #define EWOULDBLOCK WSAEWOULDBLOCK
  24. #undef errno
  25. #define errno WSAGetLastError()
  26. #undef EINTR
  27. #define EINTR WSAEINTR
  28. #else
  29. #include <sys/types.h>
  30. #include <errno.h>
  31. #include <unistd.h>
  32. #include <sys/time.h>
  33. #endif
  34. #include <rdr/FdOutStream.h>
  35. #include <rdr/Exception.h>
  36. using namespace rdr;
  37. enum { DEFAULT_BUF_SIZE = 16384,
  38. MIN_BULK_SIZE = 1024 };
  39. FdOutStream::FdOutStream(int fd_, int timeoutms_, int bufSize_)
  40. : fd(fd_), timeoutms(timeoutms_),
  41. bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
  42. {
  43. ptr = start = new U8[bufSize];
  44. end = start + bufSize;
  45. }
  46. FdOutStream::~FdOutStream()
  47. {
  48. try {
  49. flush();
  50. } catch (Exception&) {
  51. }
  52. delete [] start;
  53. }
  54. void FdOutStream::setTimeout(int timeoutms_) {
  55. timeoutms = timeoutms_;
  56. }
  57. void FdOutStream::writeBytes(const void* data, int length)
  58. {
  59. if (length < MIN_BULK_SIZE) {
  60. OutStream::writeBytes(data, length);
  61. return;
  62. }
  63. const U8* dataPtr = (const U8*)data;
  64. flush();
  65. while (length > 0) {
  66. int n = writeWithTimeout(dataPtr, length);
  67. length -= n;
  68. dataPtr += n;
  69. offset += n;
  70. }
  71. }
  72. int FdOutStream::length()
  73. {
  74. return offset + ptr - start;
  75. }
  76. void FdOutStream::flush()
  77. {
  78. U8* sentUpTo = start;
  79. while (sentUpTo < ptr) {
  80. int n = writeWithTimeout((const void*) sentUpTo, ptr - sentUpTo);
  81. sentUpTo += n;
  82. offset += n;
  83. }
  84. ptr = start;
  85. }
  86. int FdOutStream::overrun(int itemSize, int nItems)
  87. {
  88. if (itemSize > bufSize)
  89. throw Exception("FdOutStream overrun: max itemSize exceeded");
  90. flush();
  91. if (itemSize * nItems > end - ptr)
  92. nItems = (end - ptr) / itemSize;
  93. return nItems;
  94. }
  95. //
  96. // writeWithTimeout() writes up to the given length in bytes from the given
  97. // buffer to the file descriptor. If there is a timeout set and that timeout
  98. // expires, it throws a TimedOut exception. Otherwise it returns the number of
  99. // bytes written. It never attempts to write() unless select() indicates that
  100. // the fd is writable - this means it can be used on an fd which has been set
  101. // non-blocking. It also has to cope with the annoying possibility of both
  102. // select() and write() returning EINTR.
  103. //
  104. int FdOutStream::writeWithTimeout(const void* data, int length)
  105. {
  106. int n;
  107. do {
  108. do {
  109. fd_set fds;
  110. struct timeval tv;
  111. struct timeval* tvp = &tv;
  112. if (timeoutms != -1) {
  113. tv.tv_sec = timeoutms / 1000;
  114. tv.tv_usec = (timeoutms % 1000) * 1000;
  115. } else {
  116. tvp = 0;
  117. }
  118. FD_ZERO(&fds);
  119. FD_SET(fd, &fds);
  120. #ifdef _WIN32_WCE
  121. // NB: This fixes a broken Winsock2 select() behaviour. select()
  122. // never returns for non-blocking sockets, unless they're already
  123. // ready to be written to...
  124. u_long zero = 0; ioctlsocket(fd, FIONBIO, &zero);
  125. #endif
  126. n = select(fd+1, 0, &fds, 0, tvp);
  127. #ifdef _WIN32_WCE
  128. u_long one = 0; ioctlsocket(fd, FIONBIO, &one);
  129. #endif
  130. } while (n < 0 && errno == EINTR);
  131. if (n < 0) throw SystemException("select",errno);
  132. if (n == 0) throw TimedOut();
  133. do {
  134. n = ::write(fd, data, length);
  135. } while (n < 0 && (errno == EINTR));
  136. // NB: This outer loop simply fixes a broken Winsock2 EWOULDBLOCK
  137. // condition, found only under Win98 (first edition), with slow
  138. // network connections. Should in fact never ever happen...
  139. } while (n < 0 && (errno == EWOULDBLOCK));
  140. if (n < 0) throw SystemException("write",errno);
  141. return n;
  142. }