Leaked source code of windows server 2003
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.

411 lines
18 KiB

  1. /****************************************************************************/
  2. // wtdapi.c
  3. //
  4. // Transport driver - Windows specific API
  5. //
  6. // Copyright(C) 1997-1999 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. extern "C" {
  10. #define TRC_FILE "wtdapi"
  11. #define TRC_GROUP TRC_GROUP_NETWORK
  12. #include <atrcapi.h>
  13. #include <adcgfsm.h>
  14. }
  15. #include "autil.h"
  16. #include "td.h"
  17. #include "nl.h"
  18. /****************************************************************************/
  19. /* Name: TD_Recv */
  20. /* */
  21. /* Purpose: Called to receive X bytes from WinSock and store them in the */
  22. /* buffer pointed to by pData. */
  23. /* */
  24. /* Returns: The number of bytes received. */
  25. /* */
  26. /* Params: IN pData - pointer to buffer to receive the data. */
  27. /* IN size - number of bytes to receive. */
  28. /****************************************************************************/
  29. DCUINT DCAPI CTD::TD_Recv(PDCUINT8 pData,
  30. DCUINT size)
  31. {
  32. unsigned bytesToRecv;
  33. unsigned bytesCopied;
  34. unsigned BytesRecv;
  35. unsigned BytesToCopy;
  36. DC_BEGIN_FN("TD_Recv");
  37. /************************************************************************/
  38. /* Check that we're being asked to receive some data, that the pointer */
  39. /* is not NULL, that the memory range to receive the data into is */
  40. /* writable by us and that there is data available. */
  41. /************************************************************************/
  42. TRC_ASSERT((pData != NULL), (TB, _T("Data pointer is NULL")));
  43. TRC_ASSERT((size != 0), (TB, _T("No data to receive")));
  44. TRC_ASSERT((0 == IsBadWritePtr(pData, size)),
  45. (TB, _T("Don't have write access to memory %p (size %u)"),
  46. pData,
  47. size));
  48. TRC_ASSERT((_TD.dataInTD), (TB, _T("TD_Recv called when dataInTD is FALSE")));
  49. TRC_DBG((TB, _T("Request for %u bytes"), size));
  50. /************************************************************************/
  51. /* TD has a recv buffer into which it attempts to receive sufficient */
  52. /* data to fill the buffer. */
  53. /* Initially this buffer is empty. On a call to TD_Recv, the following */
  54. /* sequence occurs. */
  55. /* Data is copied from the recv buffer to the caller's buffer. If this */
  56. /* satisfies the caller's request, no further action is needed. */
  57. /* If this does not satisfy the caller, ie the recv buffer was empty or */
  58. /* had less data then requested (so is now empty), another call is made */
  59. /* to WinSock. */
  60. /* The buffer used for this recv is the recv buffer is the caller */
  61. /* requires fewer bytes than the recv buffer holds, the caller's buffer */
  62. /* otherwise. */
  63. /* Whenever the recv buffer is used, WinSock is asked for as many bytes */
  64. /* as the buffer holds (rather than the number of bytes the caller */
  65. /* wants). This means there may be some data left in the recv buffer */
  66. /* ready for the next call to TD_Recv. */
  67. /************************************************************************/
  68. bytesToRecv = size;
  69. /************************************************************************/
  70. /* Copy as much data as possible from the recv buffer. */
  71. /************************************************************************/
  72. // If the recv buffer contains data then copy up to bytesToCopy to the
  73. // caller's buffer, otherwise just quit.
  74. if (_TD.recvBuffer.dataLength == 0) {
  75. // The recv buffer is empty, so zero bytes copied.
  76. TRC_DBG((TB, _T("recv buffer is empty, need to go to WinSock")));
  77. bytesCopied = 0;
  78. }
  79. else {
  80. // Copy the lesser of the number of bytes requested and the number of
  81. // bytes in the buffer.
  82. bytesCopied = DC_MIN(bytesToRecv, _TD.recvBuffer.dataLength);
  83. TRC_ASSERT(((bytesCopied + _TD.recvBuffer.dataStart) <=
  84. _TD.recvBuffer.size),
  85. (TB, _T("Want %u bytes from buffer, but start %u, size %u"),
  86. bytesCopied,
  87. _TD.recvBuffer.dataStart,
  88. _TD.recvBuffer.size));
  89. memcpy(pData, &_TD.recvBuffer.pData[_TD.recvBuffer.dataStart],
  90. bytesCopied);
  91. TRC_DBG((TB, _T("Copied %u bytes from recv buffer"), bytesCopied));
  92. // Update the recv buffer to take account of the data copied.
  93. _TD.recvBuffer.dataLength -= bytesCopied;
  94. if (0 == _TD.recvBuffer.dataLength)
  95. // Used all the data from the recv buffer so reset the start pos.
  96. _TD.recvBuffer.dataStart = 0;
  97. else
  98. // Still some data left in recv buffer.
  99. _TD.recvBuffer.dataStart += bytesCopied;
  100. TRC_DBG((TB, _T("recv buffer now has %u bytes starting at %u"),
  101. _TD.recvBuffer.dataLength, _TD.recvBuffer.dataStart));
  102. // Update the number of bytes still to receive.
  103. bytesToRecv -= bytesCopied;
  104. if (0 == bytesToRecv) {
  105. TRC_DBG((TB, _T("Received all necessary data")));
  106. DC_QUIT;
  107. }
  108. }
  109. /************************************************************************/
  110. /* Now try to get any data which may still be required by recv'ing from */
  111. /* WinSock. Offset the address of the caller's buffer by the amount of */
  112. /* data copied from the recv buffer. */
  113. /************************************************************************/
  114. TRC_ASSERT(((_TD.recvBuffer.dataStart == 0) &&
  115. (_TD.recvBuffer.dataLength == 0)),
  116. (TB, _T("About to recv into buffer, but existing recv ")
  117. _T("length %u, start %u"), _TD.recvBuffer.dataStart,
  118. _TD.recvBuffer.dataLength));
  119. // Select the buffer into which we recv the data. This is the recv
  120. // buffer if all the data required fits into it, the caller's buffer
  121. // otherwise.
  122. if (bytesToRecv < _TD.recvBuffer.size) {
  123. // Caller requires less than the recv buffer size, so attempt to
  124. // have Winsock fill the recv buffer and copy to the caller's
  125. // buffer.
  126. BytesRecv = TDDoWinsockRecv(_TD.recvBuffer.pData, _TD.recvBuffer.size);
  127. if (BytesRecv != 0) {
  128. // Successful WinSock recv. Copy data from the recv buffer to the
  129. // caller's buffer (offset by bytesCopied, the end of the recv
  130. // buffer copy).
  131. BytesToCopy = DC_MIN(bytesToRecv, BytesRecv);
  132. memcpy(pData + bytesCopied, _TD.recvBuffer.pData, BytesToCopy);
  133. bytesCopied = BytesToCopy;
  134. // If we copied less than we recv'ed then there is some data left
  135. // in the recv buffer for next time.
  136. if (BytesRecv > bytesCopied) {
  137. _TD.recvBuffer.dataLength = BytesRecv - bytesCopied;
  138. _TD.recvBuffer.dataStart = bytesCopied;
  139. TRC_DBG((TB, _T("recv buffer now has %u bytes starting %u"),
  140. _TD.recvBuffer.dataLength, _TD.recvBuffer.dataStart));
  141. }
  142. TRC_DBG((TB, _T("%u bytes read to recv buffer, %u copied to caller ")
  143. _T("still need %u"), BytesRecv, bytesCopied,
  144. bytesToRecv - bytesCopied));
  145. }
  146. else {
  147. TRC_DBG((TB, _T("Didn't receive any data")));
  148. bytesCopied = 0;
  149. }
  150. TRC_DBG((TB, _T("%u bytes in recv buffer starting %u"),
  151. _TD.recvBuffer.dataLength, _TD.recvBuffer.dataStart));
  152. }
  153. else {
  154. // Caller requires more than the recv buffer size, so attempt to
  155. // have Winsock fill the caller's buffer.
  156. bytesCopied = TDDoWinsockRecv(pData + bytesCopied, bytesToRecv);
  157. TRC_DBG((TB, _T("Read %u bytes to caller's buffer, still need %u"),
  158. bytesCopied, bytesToRecv - bytesCopied));
  159. }
  160. /************************************************************************/
  161. /* Update the number of bytes to receive. */
  162. /************************************************************************/
  163. bytesToRecv -= bytesCopied;
  164. DC_EXIT_POINT:
  165. /************************************************************************/
  166. /* If we have received more than the maximum we allow without resetting */
  167. /* the data available flag OR we didn't get all the bytes we requested */
  168. /* then we can't allow TD to continue reporting data available. */
  169. /************************************************************************/
  170. if (bytesToRecv != 0 || _TD.recvByteCount >= TD_MAX_UNINTERRUPTED_RECV) {
  171. // We didn't get all the bytes that we wanted, or we have received
  172. // more than TD_MAX_UNINTERRUPTED_RECV so need to get back to the
  173. // message loop. So, update our global data available flag and
  174. // reset the per-FD_READ byte count.
  175. TRC_DBG((TB, _T("Only got %u bytes of %u requested, total %u"),
  176. size - bytesToRecv, size, _TD.recvByteCount));
  177. _TD.dataInTD = FALSE;
  178. _TD.recvByteCount = 0;
  179. }
  180. DC_END_FN();
  181. return (size - bytesToRecv);
  182. } /* TD_Recv */
  183. /****************************************************************************/
  184. /* Name: TDDoWinsockRecv */
  185. /* */
  186. /* Purpose: Wrapper round the WinSock recv function which handles any */
  187. /* errors returned. */
  188. /* */
  189. /* Returns: The number of bytes copied. */
  190. /* */
  191. /* Params: IN pData - pointer to buffer to receive the data. */
  192. /* IN bytesToRecv - number of bytes to receive. */
  193. /****************************************************************************/
  194. unsigned DCINTERNAL CTD::TDDoWinsockRecv(BYTE FAR *pData, unsigned bytesToRecv)
  195. {
  196. unsigned bytesReceived;
  197. int WSAErr;
  198. DC_BEGIN_FN("TDDoWinsockRecv");
  199. // Check that we are requesting some bytes. This will work if we ask
  200. // for zero bytes, but it implies there is a flaw in the logic.
  201. TRC_ASSERT((bytesToRecv != 0), (TB, _T("Requesting recv of 0 bytes")));
  202. // In the debug build we can constrain the amount of data received,
  203. // to simulate low-bandwidth scenarios.
  204. #ifdef DC_NLTEST
  205. #pragma message("NL Test code compiled in")
  206. bytesToRecv = 1;
  207. #elif DC_DEBUG
  208. // Calculate how many bytes we can receive and then decrement the count
  209. // of bytes left to send in this period.
  210. if (0 != _TD.hThroughputTimer) {
  211. bytesToRecv = (unsigned)DC_MIN(bytesToRecv, _TD.periodRecvBytesLeft);
  212. _TD.periodRecvBytesLeft -= bytesToRecv;
  213. if (0 == bytesToRecv) {
  214. // We won't recv any data, but still need to make the call to
  215. // ensure the FD_READ messages keep flowing.
  216. TRC_ALT((TB, _T("constrained READ bytes")));
  217. }
  218. TRC_DBG((TB, _T("periodRecvBytesLeft:%u"), _TD.periodRecvBytesLeft));
  219. }
  220. #endif
  221. #ifdef OS_WINCE
  222. // Check to see we already called WinSock recv() for this FD_READ.
  223. if (_TD.enableWSRecv) {
  224. // set enableWSRecv to FALSE to indicate that we performed a recv()
  225. // call for this FD_READ.
  226. _TD.enableWSRecv = FALSE;
  227. #endif // OS_WINCE
  228. //
  229. // Try to get bytesToRecv bytes from WinSock.
  230. //
  231. bytesReceived = (unsigned)recv(_TD.hSocket, (char *)pData,
  232. (int)bytesToRecv, 0);
  233. // Do any necessary error handling. We are OK if no error or if the
  234. // error is WOULDBLOCK (or INPROGRESS on CE).
  235. if (bytesReceived != SOCKET_ERROR) {
  236. // Successful WinSock recv.
  237. TRC_DBG((TB, _T("Requested %d bytes, got %d"),
  238. bytesToRecv, bytesReceived));
  239. // Update the performance counter.
  240. PRF_ADD_COUNTER(PERF_BYTES_RECV, bytesReceived);
  241. // Add this lot of data to the total amount received since last
  242. // resetting the counter, ie since we last returned to the
  243. // message loop.
  244. _TD.recvByteCount += bytesReceived;
  245. }
  246. else {
  247. WSAErr = WSAGetLastError();
  248. #ifndef OS_WINCE
  249. if (WSAErr == WSAEWOULDBLOCK) {
  250. #else
  251. if (WSAErr == WSAEWOULDBLOCK || WSAErr == WSAEINPROGRESS) {
  252. #endif
  253. // On a blocking call, we simply set received length to zero and
  254. // continue.
  255. bytesReceived = 0;
  256. }
  257. else {
  258. // Zero bytes received on error.
  259. bytesReceived = 0;
  260. // Call the FSM to begin disconnect processing.
  261. TRC_ERR((TB, _T("Error on call to recv, rc:%d"), WSAErr));
  262. TDConnectFSMProc(TD_EVT_ERROR,
  263. NL_MAKE_DISCONNECT_ERR(NL_ERR_TDONCALLTORECV));
  264. TRC_ALT((TB, _T("WinSock recv error")));
  265. }
  266. }
  267. #ifdef OS_WINCE
  268. }
  269. else {
  270. // recv is called once for this FD_READ.
  271. TRC_DBG((TB, _T("recv() already called.")));
  272. bytesReceived = 0;
  273. }
  274. #endif // OS_WINCE
  275. DC_END_FN();
  276. return bytesReceived;
  277. }
  278. #ifdef DC_DEBUG
  279. /****************************************************************************/
  280. /* Name: TD_GetNetworkThroughput */
  281. /* */
  282. /* Purpose: Get the current network throughput setting. */
  283. /* */
  284. /* Returns: Current network throughput. */
  285. /****************************************************************************/
  286. DCUINT32 DCAPI CTD::TD_GetNetworkThroughput(DCVOID)
  287. {
  288. DCUINT32 retVal;
  289. DC_BEGIN_FN("TD_GetNetworkThroughput");
  290. /************************************************************************/
  291. /* Calculate the actual throughput. This is the */
  292. /************************************************************************/
  293. retVal = _TD.currentThroughput * (1000 / TD_THROUGHPUTINTERVAL);
  294. TRC_NRM((TB, _T("Returning network throughput of:%lu"), retVal));
  295. DC_END_FN();
  296. return(retVal);
  297. } /* TD_GetNetworkThroughput */
  298. /****************************************************************************/
  299. /* Name: TD_SetNetworkThroughput */
  300. /* */
  301. /* Purpose: Sets the network throughput. This is the number of bytes */
  302. /* that can be passed into or out of the network layer per */
  303. /* second. For example setting this to 3000 is roughly */
  304. /* equivalent to a 24000bps modem connection. */
  305. /* */
  306. /* Params: throughput - the number of bytes to be allowed into and out */
  307. /* of the network layer per second. */
  308. /****************************************************************************/
  309. DCVOID DCAPI CTD::TD_SetNetworkThroughput(DCUINT32 throughput)
  310. {
  311. DC_BEGIN_FN("TD_SetNetworkThroughput");
  312. /************************************************************************/
  313. /* Check to determine if the throughput throttling has been enabled */
  314. /* or disabled. */
  315. /************************************************************************/
  316. if (0 == throughput)
  317. {
  318. /********************************************************************/
  319. /* Throughput throttling has been disabled so kill the throughput */
  320. /* timer. */
  321. /********************************************************************/
  322. TRC_ALT((TB, _T("Throughput throttling disabled")));
  323. if (_TD.hThroughputTimer != 0)
  324. {
  325. TRC_NRM((TB, _T("Kill throttling timer")));
  326. KillTimer(_TD.hWnd, TD_THROUGHPUTTIMERID);
  327. _TD.hThroughputTimer = 0;
  328. }
  329. _TD.currentThroughput = 0;
  330. }
  331. else
  332. {
  333. /********************************************************************/
  334. /* Throughput throttling has been enabled so update the throughput */
  335. /* byte counts and set the timer. */
  336. /********************************************************************/
  337. _TD.currentThroughput = (throughput * TD_THROUGHPUTINTERVAL) / 1000;
  338. _TD.periodSendBytesLeft = _TD.currentThroughput;
  339. _TD.periodRecvBytesLeft = _TD.currentThroughput;
  340. _TD.hThroughputTimer = SetTimer(_TD.hWnd,
  341. TD_THROUGHPUTTIMERID,
  342. TD_THROUGHPUTINTERVAL,
  343. NULL);
  344. TRC_ALT((TB, _T("Throughput throttling enabled interval:%u"),
  345. throughput));
  346. }
  347. DC_END_FN();
  348. } /* TD_SetNetworkThroughput */
  349. #endif /* DC_DEBUG */