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.

383 lines
8.9 KiB

  1. #include "precomp.h"
  2. DEBUG_FILEZONE(ZONE_T120_MSMCSTCP);
  3. /* Socket.cpp
  4. *
  5. * Copyright (c) 1996 by Microsoft Corporation
  6. *
  7. * Abstract:
  8. * This is the implementation of our socket constructor/destructor functions.
  9. *
  10. */
  11. #include "socket.h"
  12. #include "plgxprt.h"
  13. /* Size of listen queue */
  14. #define LISTEN_QUEUE_SIZE 3
  15. /* External definitions */
  16. extern HWND TCP_Window_Handle;
  17. extern PTransportInterface g_Transport;
  18. /*
  19. * void CreateAndConfigureListenSocket (VOID)
  20. *
  21. * Functional Description
  22. * This function sets up a listening socket.
  23. * returns INVALID_SOCKET if there is any error.
  24. */
  25. SOCKET CreateAndConfigureListenSocket (VOID)
  26. {
  27. SOCKADDR_IN socket_control;
  28. SOCKET Socket;
  29. // Create the listening socket.
  30. Socket = socket (AF_INET, SOCK_STREAM, 0);
  31. if (Socket == INVALID_SOCKET) {
  32. WARNING_OUT (("Socket: error creating listening socket (errno = %d)", WSAGetLastError()));
  33. goto Error;
  34. }
  35. // The listen socket only waits for FD_ACCEPT msgs.
  36. ASSERT(TCP_Window_Handle);
  37. if (WSAAsyncSelect (Socket,
  38. TCP_Window_Handle,
  39. WM_SOCKET_NOTIFICATION,
  40. FD_ACCEPT) != 0) {
  41. WARNING_OUT (("CreateAndConfigureListenSocket: Error on WSAAsyncSelect = %d", WSAGetLastError()));
  42. goto Error;
  43. }
  44. /*
  45. * Load the socket control structure with the parameters necessary.
  46. * - Internet socket
  47. * - Let it assign any address to this socket
  48. * - Assign our port number
  49. */
  50. socket_control.sin_family = AF_INET;
  51. socket_control.sin_addr.s_addr = INADDR_ANY;
  52. socket_control.sin_port = htons ( TCP_PORT_NUMBER );
  53. /* Issue the bind call */
  54. if (bind (Socket, (LPSOCKADDR) &socket_control, sizeof(SOCKADDR_IN)) != 0) {
  55. WARNING_OUT (("Socket::Listen: bind failed: Unable to use WinSock"));
  56. goto Error;
  57. }
  58. /*
  59. * Issue a listen to WinSock to tell it we are willing to accept calls.
  60. * This is a non-blocking listen, therefore we will receive FD_ACCEPT
  61. * if someone is trying to call us.
  62. */
  63. if (listen (Socket, LISTEN_QUEUE_SIZE) != 0) {
  64. WARNING_OUT (("Socket::Listen: listen failed: Unable to use WinSock"));
  65. goto Error;
  66. }
  67. ASSERT(Socket != INVALID_SOCKET);
  68. return Socket;
  69. Error:
  70. if (INVALID_SOCKET != Socket)
  71. {
  72. ::closesocket(Socket);
  73. }
  74. return INVALID_SOCKET;
  75. }
  76. /*
  77. * PSocket newSocket (SOCKET socket_number)
  78. *
  79. * Functional Description:
  80. * This is a constructor for the Socket object. It allocates the
  81. * send and receive buffers and sets up internal variables.
  82. */
  83. PSocket newSocket(TransportConnection XprtConn, PSecurityContext pSC)
  84. {
  85. if (IS_SOCKET(XprtConn))
  86. {
  87. return ::newSocketEx(XprtConn, pSC);
  88. }
  89. return g_pSocketList->FindByTransportConnection(XprtConn, TRUE);
  90. }
  91. PSocket newPluggableSocket(TransportConnection XprtConn)
  92. {
  93. PSocket pSocket = ::newSocketEx(XprtConn, NULL);
  94. if (NULL != pSocket)
  95. {
  96. g_pSocketList->SafeAppend(pSocket);
  97. }
  98. return pSocket;
  99. }
  100. PSocket newSocketEx(TransportConnection XprtConn, PSecurityContext pSC)
  101. {
  102. BOOL fRet;
  103. DBG_SAVE_FILE_LINE
  104. PSocket pSocket = new CSocket(&fRet, XprtConn, pSC);
  105. if (NULL != pSocket)
  106. {
  107. if (fRet)
  108. {
  109. return pSocket;
  110. }
  111. pSocket->Release();
  112. }
  113. ERROR_OUT(("newSocket: Unable to allocate memory for Socket struct, pSocket=0x%x", pSocket));
  114. return NULL;
  115. }
  116. CSocket::CSocket(BOOL *_pfRet, TransportConnection _XprtConn, PSecurityContext _pSC)
  117. :
  118. CRefCount(MAKE_STAMP_ID('S','o','c','k')),
  119. State(IS_SOCKET(_XprtConn) ? NOT_CONNECTED : SOCKET_CONNECTED),
  120. SecState((NULL == _pSC) ? SC_UNDETERMINED : SC_SECURE),
  121. pSC(_pSC),
  122. Max_Packet_Length(DEFAULT_MAX_X224_SIZE),
  123. Current_Length(0),
  124. Data_Indication_Buffer(NULL),
  125. Data_Indication_Length(0),
  126. Read_State(READ_HEADER),
  127. X224_Length(0),
  128. bSpaceAllocated(FALSE),
  129. Data_Memory(NULL),
  130. fExtendedX224(FALSE),
  131. fIncomingSecure(FALSE),
  132. XprtConn(_XprtConn)
  133. {
  134. // assume failure
  135. *_pfRet = FALSE;
  136. // zero out sub structures
  137. ::ZeroMemory(&X224_Header, sizeof(X224_Header));
  138. ::ZeroMemory(&Retry_Info, sizeof(Retry_Info));
  139. Remote_Address[0] = '\0';
  140. if (IS_SOCKET(XprtConn))
  141. {
  142. if (INVALID_SOCKET == XprtConn.nLogicalHandle)
  143. {
  144. /* Create a STREAM socket (fully reliable, full duplex, and sequenced) */
  145. if ((XprtConn.nLogicalHandle = ::socket(AF_INET, SOCK_STREAM, 0))
  146. == INVALID_SOCKET)
  147. {
  148. ERROR_OUT (("CSocket: error acquiring INET socket # (errno = %d)", WSAGetLastError()));
  149. return;
  150. }
  151. }
  152. /* Enable Tx and Rx messages to the window */
  153. ASSERT(TCP_Window_Handle);
  154. if (::WSAAsyncSelect(XprtConn.nLogicalHandle, TCP_Window_Handle,
  155. WM_SOCKET_NOTIFICATION,
  156. FD_READ | FD_WRITE | FD_CLOSE | FD_CONNECT) != 0)
  157. {
  158. WARNING_OUT (("CSocket: Error on WSAAsyncSelect = %d", WSAGetLastError()));
  159. }
  160. }
  161. else
  162. {
  163. ASSERT(IS_PLUGGABLE(XprtConn));
  164. CPluggableConnection *p = ::GetPluggableConnection(this);
  165. if (NULL == p)
  166. {
  167. ERROR_OUT(("newSocket: Unable to find plugable transport (%d, %d)",
  168. XprtConn.eType, XprtConn.nLogicalHandle));
  169. return;
  170. }
  171. }
  172. // success
  173. *_pfRet = TRUE;
  174. }
  175. /*
  176. * void freeSocket (PSocket, TransportConnection)
  177. *
  178. * Functional Description:
  179. * This is a destructor for the Socket object. It frees the send
  180. * and receive buffers and connection structure.
  181. * It will also cleanup the listening socket. In this case,
  182. * "pSocket" is set to NULL and "trash_packets" should be set to TRUE.
  183. */
  184. void freeSocket(PSocket pSocket, TransportConnection XprtConn)
  185. {
  186. if (IS_SOCKET(XprtConn))
  187. {
  188. if (NULL != g_pSocketList)
  189. {
  190. g_pSocketList->SafeRemove(pSocket);
  191. }
  192. freeSocketEx(pSocket, XprtConn);
  193. }
  194. }
  195. void freeListenSocket(TransportConnection XprtConn)
  196. {
  197. ASSERT(IS_SOCKET(XprtConn));
  198. freeSocketEx(NULL, XprtConn);
  199. }
  200. void freePluggableSocket(PSocket pSocket)
  201. {
  202. freeSocketEx(pSocket, pSocket->XprtConn);
  203. if (NULL != g_pSocketList)
  204. {
  205. g_pSocketList->SafeRemove(pSocket);
  206. }
  207. }
  208. void freeSocketEx(PSocket pSocket, TransportConnection XprtConn)
  209. {
  210. // Either "pSocket" is NULL, or the socket is not invalid.
  211. #ifdef _DEBUG
  212. if (IS_SOCKET(XprtConn))
  213. {
  214. if (NULL != pSocket)
  215. {
  216. ASSERT(INVALID_SOCKET != pSocket->XprtConn.nLogicalHandle);
  217. }
  218. else
  219. {
  220. // it is a listen socket
  221. ASSERT(INVALID_SOCKET != XprtConn.nLogicalHandle);
  222. }
  223. }
  224. #endif
  225. // Determine the socket number to use... Either the socket is the
  226. // socket indicated in the PSocket structure, or it is a structure-less
  227. // listen socket. Note: both cannot be valid!
  228. if (IS_SOCKET(XprtConn))
  229. {
  230. SOCKET socket = (pSocket) ? pSocket->XprtConn.nLogicalHandle : XprtConn.nLogicalHandle;
  231. XprtConn.nLogicalHandle = socket;
  232. /* Disable notifications to our window */
  233. if (::IsWindow(TCP_Window_Handle))
  234. {
  235. ::WSAAsyncSelect(socket, TCP_Window_Handle, 0, 0);
  236. }
  237. }
  238. if (pSocket != NULL)
  239. {
  240. pSocket->Release();
  241. }
  242. else
  243. {
  244. // This is the listening socket
  245. ::ShutdownAndClose (XprtConn, FALSE, 0);
  246. }
  247. }
  248. CSocket::~CSocket(void)
  249. {
  250. switch (State)
  251. {
  252. case SOCKET_CONNECTED:
  253. // case WAITING_FOR_DISCONNECT:
  254. /* All physically connected states issue a shutdown() first */
  255. ::ShutdownAndClose(XprtConn, TRUE, SD_BOTH);
  256. break;
  257. case X224_CONNECTED:
  258. // Shutdown disable reception only.
  259. ::ShutdownAndClose(XprtConn, TRUE, SD_RECEIVE);
  260. break;
  261. default:
  262. ::ShutdownAndClose(XprtConn, FALSE, 0);
  263. break;
  264. }
  265. /* Free the structures */
  266. FreeTransportBuffer();
  267. delete pSC;
  268. }
  269. void CSocket::FreeTransportBuffer(void)
  270. {
  271. if (NULL != Data_Memory)
  272. {
  273. ::FreeMemory(Data_Memory);
  274. Data_Memory = NULL;
  275. Data_Indication_Buffer = NULL;
  276. }
  277. }
  278. void CSocketList::SafeAppend(PSocket pSocket)
  279. {
  280. ::EnterCriticalSection(&g_csTransport);
  281. if (! Find(pSocket))
  282. {
  283. Append(pSocket);
  284. }
  285. ::LeaveCriticalSection(&g_csTransport);
  286. }
  287. BOOL CSocketList::SafeRemove(PSocket pSocket)
  288. {
  289. ::EnterCriticalSection(&g_csTransport);
  290. BOOL fRet = Remove(pSocket);
  291. ::LeaveCriticalSection(&g_csTransport);
  292. return fRet;
  293. }
  294. PSocket CSocketList::FindByTransportConnection(TransportConnection XprtConn, BOOL fNoAddRef)
  295. {
  296. PSocket pSocket;
  297. ::EnterCriticalSection(&g_csTransport);
  298. Reset();
  299. while (NULL != (pSocket = Iterate()))
  300. {
  301. if (IS_SAME_TRANSPORT_CONNECTION(pSocket->XprtConn, XprtConn))
  302. {
  303. if (! fNoAddRef)
  304. {
  305. pSocket->AddRef();
  306. }
  307. break;
  308. }
  309. }
  310. ::LeaveCriticalSection(&g_csTransport);
  311. return pSocket;
  312. }
  313. PSocket CSocketList::RemoveByTransportConnection(TransportConnection XprtConn)
  314. {
  315. PSocket pSocket;
  316. ::EnterCriticalSection(&g_csTransport);
  317. Reset();
  318. while (NULL != (pSocket = Iterate()))
  319. {
  320. if (IS_SAME_TRANSPORT_CONNECTION(pSocket->XprtConn, XprtConn))
  321. {
  322. Remove(pSocket);
  323. break;
  324. }
  325. }
  326. ::LeaveCriticalSection(&g_csTransport);
  327. return pSocket;
  328. }