Source code of Windows XP (NT5)
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.

185 lines
4.0 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // udpsock.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class UDPSocket.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/06/2000 Original version.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <proxypch.h>
  19. #include <malloc.h>
  20. #include <udpsock.h>
  21. inline BOOL UDPSocket::createReceiveThread()
  22. {
  23. return IASRequestThread(this) ? TRUE : (SetEvent(idle), FALSE);
  24. }
  25. UDPSocket::UDPSocket() throw ()
  26. : receiver(NULL),
  27. sock(INVALID_SOCKET),
  28. closing(FALSE),
  29. idle(NULL)
  30. {
  31. CallbackRoutine = startRoutine;
  32. }
  33. UDPSocket::~UDPSocket() throw ()
  34. {
  35. if (idle) { CloseHandle(idle); }
  36. if (sock != INVALID_SOCKET) { closesocket(sock); }
  37. }
  38. BOOL UDPSocket::open(
  39. PacketReceiver* sink,
  40. ULONG_PTR recvKey,
  41. const SOCKADDR_IN* address
  42. ) throw ()
  43. {
  44. receiver = sink;
  45. key = recvKey;
  46. if (address)
  47. {
  48. localAddress = *address;
  49. }
  50. sock = WSASocket(
  51. AF_INET,
  52. SOCK_DGRAM,
  53. 0,
  54. NULL,
  55. 0,
  56. WSA_FLAG_OVERLAPPED
  57. );
  58. if (sock == INVALID_SOCKET) { return FALSE; }
  59. int error = bind(
  60. sock,
  61. localAddress,
  62. sizeof(localAddress)
  63. );
  64. if (error) { return FALSE; }
  65. idle = CreateEventW(
  66. NULL,
  67. TRUE,
  68. FALSE,
  69. NULL
  70. );
  71. if (!idle) { return FALSE; }
  72. return createReceiveThread();
  73. }
  74. void UDPSocket::close() throw ()
  75. {
  76. if (sock != INVALID_SOCKET)
  77. {
  78. closing = TRUE;
  79. closesocket(sock);
  80. sock = INVALID_SOCKET;
  81. WaitForSingleObject(idle, INFINITE);
  82. }
  83. if (idle)
  84. {
  85. CloseHandle(idle);
  86. idle = NULL;
  87. }
  88. }
  89. BOOL UDPSocket::send(
  90. const SOCKADDR_IN& to,
  91. const BYTE* buf,
  92. ULONG buflen
  93. ) throw ()
  94. {
  95. WSABUF wsabuf = { buflen, (CHAR*)buf };
  96. ULONG bytesSent;
  97. return !WSASendTo(
  98. sock,
  99. &wsabuf,
  100. 1,
  101. &bytesSent,
  102. 0,
  103. (const SOCKADDR*)&to,
  104. sizeof(to),
  105. NULL,
  106. NULL
  107. );
  108. }
  109. void UDPSocket::receive() throw ()
  110. {
  111. WSABUF wsabuf = { sizeof(buffer), (CHAR*)buffer };
  112. ULONG bytesReceived;
  113. ULONG flags = 0;
  114. SOCKADDR_IN remoteAddress;
  115. int remoteAddressLength;
  116. remoteAddressLength = sizeof(remoteAddress);
  117. int error = WSARecvFrom(
  118. sock,
  119. &wsabuf,
  120. 1,
  121. &bytesReceived,
  122. &flags,
  123. (SOCKADDR*)&remoteAddress,
  124. &remoteAddressLength,
  125. NULL,
  126. NULL
  127. );
  128. if (error)
  129. {
  130. error = WSAGetLastError();
  131. if (error == WSAECONNRESET)
  132. {
  133. // Ignore WSAECONNRESET since this doesn't effect listening on the
  134. // port. We'll get a replacement instead of looping because it's
  135. // easier and this situation shouldn't happen often.
  136. createReceiveThread();
  137. }
  138. else
  139. {
  140. // Don't report errors while closing.
  141. if (!closing)
  142. {
  143. receiver->onReceiveError(*this, key, error);
  144. }
  145. // There's no point getting another thread if the socket's no good, so
  146. // we'll just exit.
  147. SetEvent(idle);
  148. }
  149. }
  150. else
  151. {
  152. // Save the buffer locally.
  153. PBYTE packet = (PBYTE)_alloca(bytesReceived);
  154. memcpy(packet, buffer, bytesReceived);
  155. // Get a replacement.
  156. createReceiveThread();
  157. // Invoke the callback.
  158. receiver->onReceive(*this, key, remoteAddress, packet, bytesReceived);
  159. }
  160. }
  161. void UDPSocket::startRoutine(PIAS_CALLBACK This) throw ()
  162. {
  163. static_cast<UDPSocket*>(This)->receive();
  164. }