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.

657 lines
18 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: reliable.c
  6. * Content: stream communication related routines
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 01-29-98 sohailm initial implementation
  11. * 02-15-98 a-peterz Remove unused SetMessageHeader
  12. * 02-10-00 aarono only allow one enum per socket then turf it.
  13. *
  14. ***************************************************************************/
  15. #include "dphelp.h"
  16. /*
  17. * Globals
  18. */
  19. FDS gReadfds; // fd set to receive data
  20. RECEIVELIST gReceiveList; // list of connections + listener
  21. /*
  22. * Externs
  23. */
  24. extern SOCKET gsStreamListener; // we listen for tcp connections on this socket
  25. extern gbReceiveShutdown; // receive thread will exit when TRUE
  26. extern LPSPNODE gNodeList;
  27. #undef DPF_MODNAME
  28. #define DPF_MODNAME "MakeBufferSpace"
  29. // make sure the buffer is big enough to fit the message size
  30. HRESULT MakeBufferSpace(LPBYTE * ppBuffer,LPDWORD pdwBufferSize,DWORD dwMessageSize)
  31. {
  32. HRESULT hr = DP_OK;
  33. ASSERT(ppBuffer);
  34. ASSERT(pdwBufferSize);
  35. ENTER_DPLAYSVR();
  36. if (!*ppBuffer)
  37. {
  38. DPF(9, "Allocating space for message of size %d", dwMessageSize);
  39. // need to alloc receive buffer?
  40. *ppBuffer = MemAlloc(dwMessageSize);
  41. if (!*ppBuffer)
  42. {
  43. DPF_ERR("could not alloc stream receive buffer - out of memory");
  44. hr = E_OUTOFMEMORY;
  45. goto CLEANUP_EXIT;
  46. }
  47. *pdwBufferSize = dwMessageSize;
  48. }
  49. // make sure receive buffer can hold data
  50. else if (dwMessageSize > *pdwBufferSize)
  51. {
  52. LPVOID pvTemp;
  53. DPF(9, "ReAllocating space for message of size %d", dwMessageSize);
  54. // realloc buffer to hold data
  55. pvTemp = MemReAlloc(*ppBuffer,dwMessageSize);
  56. if (!pvTemp)
  57. {
  58. DPF_ERR("could not realloc stream receive buffer - out of memory");
  59. hr = E_OUTOFMEMORY;
  60. goto CLEANUP_EXIT;
  61. }
  62. *ppBuffer = pvTemp;
  63. *pdwBufferSize = dwMessageSize;
  64. }
  65. // fall through
  66. CLEANUP_EXIT:
  67. LEAVE_DPLAYSVR();
  68. return hr;
  69. } // MakeBufferSpace
  70. #undef DPF_MODNAME
  71. #define DPF_MODNAME "AddSocketToReceiveList"
  72. HRESULT AddSocketToReceiveList(SOCKET sSocket)
  73. {
  74. UINT i = 0;
  75. UINT err, iNewSlot;
  76. BOOL bFoundSlot = FALSE;
  77. HRESULT hr = DP_OK;
  78. INT addrlen=sizeof(SOCKADDR);
  79. LPCONNECTION pNewConnection;
  80. ENTER_DPLAYSVR();
  81. // look for an empty slot
  82. while ( (i < gReceiveList.nConnections) && !bFoundSlot)
  83. {
  84. if (INVALID_SOCKET == gReceiveList.pConnection[i].socket)
  85. {
  86. bFoundSlot = TRUE;
  87. iNewSlot = i;
  88. }
  89. else
  90. {
  91. i++;
  92. }
  93. }
  94. if (!bFoundSlot)
  95. {
  96. DWORD dwCurrentSize,dwNewSize;
  97. // allocate space for list of connections
  98. dwCurrentSize = gReceiveList.nConnections * sizeof(CONNECTION);
  99. dwNewSize = dwCurrentSize + INITIAL_RECEIVELIST_SIZE * sizeof(CONNECTION);
  100. hr = MakeBufferSpace((LPBYTE *)&(gReceiveList.pConnection),&dwCurrentSize,dwNewSize);
  101. if (FAILED(hr))
  102. {
  103. ASSERT(FALSE);
  104. goto CLEANUP_EXIT;
  105. }
  106. ASSERT(dwCurrentSize == dwNewSize);
  107. // set all the new entries to INVALID
  108. for (i = gReceiveList.nConnections + 1;
  109. i < gReceiveList.nConnections + INITIAL_RECEIVELIST_SIZE; i++ )
  110. {
  111. gReceiveList.pConnection[i].socket = INVALID_SOCKET;
  112. }
  113. // store the new socket in the 1st new spot
  114. iNewSlot = gReceiveList.nConnections;
  115. // allocate space for an fd set (fd_count + fd_array)
  116. if (gReceiveList.nConnections)
  117. {
  118. dwCurrentSize = sizeof(u_int) + gReceiveList.nConnections * sizeof(SOCKET);
  119. dwNewSize = dwCurrentSize + INITIAL_RECEIVELIST_SIZE * sizeof(SOCKET);
  120. }
  121. else
  122. {
  123. dwCurrentSize = 0;
  124. dwNewSize = sizeof(u_int) + INITIAL_RECEIVELIST_SIZE * sizeof(SOCKET);
  125. }
  126. hr = MakeBufferSpace((LPBYTE *)&(gReadfds.pfdbigset),&dwCurrentSize,dwNewSize);
  127. if (FAILED(hr))
  128. {
  129. ASSERT(FALSE);
  130. goto CLEANUP_EXIT;
  131. }
  132. ASSERT(dwCurrentSize == dwNewSize);
  133. // update the # of connections
  134. gReceiveList.nConnections += INITIAL_RECEIVELIST_SIZE;
  135. // update the fd_array buffer size
  136. gReadfds.dwArraySize = gReceiveList.nConnections;
  137. } // !bFoundSlot
  138. // Initialize new connection
  139. pNewConnection = &(gReceiveList.pConnection[iNewSlot]);
  140. pNewConnection->socket = sSocket;
  141. // allocate a default receive buffer
  142. pNewConnection->pDefaultBuffer = MemAlloc(DEFAULT_RECEIVE_BUFFERSIZE);
  143. if (NULL == pNewConnection->pDefaultBuffer)
  144. {
  145. DPF_ERR("could not alloc default receive buffer - out of memory");
  146. hr = E_OUTOFMEMORY;
  147. goto CLEANUP_EXIT;
  148. }
  149. // receive buffer initially points to our default buffer
  150. pNewConnection->pBuffer = pNewConnection->pDefaultBuffer;
  151. // remember the address we are connected to
  152. err = g_getpeername(pNewConnection->socket, &(pNewConnection->sockAddr), &addrlen);
  153. if (SOCKET_ERROR == err)
  154. {
  155. err = g_WSAGetLastError();
  156. DPF(1,"could not getpeername err = %d\n",err);
  157. }
  158. DPF(9, "Added new socket at index %d", iNewSlot);
  159. CLEANUP_EXIT:
  160. LEAVE_DPLAYSVR();
  161. return hr;
  162. } // AddSocketToReceiveList
  163. #undef DPF_MODNAME
  164. #define DPF_MODNAME "KillSocket"
  165. HRESULT KillSocket(SOCKET sSocket,BOOL fStream,BOOL fHard)
  166. {
  167. UINT err;
  168. if (INVALID_SOCKET == sSocket)
  169. {
  170. return E_FAIL;
  171. }
  172. if (!fStream)
  173. {
  174. if (SOCKET_ERROR == g_closesocket(sSocket))
  175. {
  176. err = g_WSAGetLastError();
  177. DPF(0,"killsocket - dgram close err = %d\n",err);
  178. return E_FAIL;
  179. }
  180. }
  181. else
  182. {
  183. LINGER Linger;
  184. if (fHard)
  185. {
  186. Linger.l_onoff=TRUE; // turn linger on
  187. Linger.l_linger=0; // nice small time out
  188. if( SOCKET_ERROR == g_setsockopt( sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,
  189. sizeof(Linger) ) )
  190. {
  191. err = g_WSAGetLastError();
  192. DPF(0,"killsocket - stream setopt err = %d\n",err);
  193. }
  194. }
  195. #if 0
  196. // DON'T DO SHUTDOWN! It leads to TIME_WAIT on sockets.
  197. if (SOCKET_ERROR == g_shutdown(sSocket,2))
  198. {
  199. // this may well fail, if e.g. no one is using this socket right now...
  200. // the error would be wsaenotconn
  201. err = g_WSAGetLastError();
  202. DPF(5,"killsocket - stream shutdown err = %d\n",err);
  203. }
  204. #endif
  205. if (SOCKET_ERROR == g_closesocket(sSocket))
  206. {
  207. err = g_WSAGetLastError();
  208. DPF(0,"killsocket - stream close err = %d\n",err);
  209. return E_FAIL;
  210. }
  211. }
  212. return DP_OK;
  213. }// KillSocket
  214. void FreeConnection(LPCONNECTION pConnection)
  215. {
  216. DEBUGPRINTSOCK(5,"Freeing connection - ",&pConnection->socket);
  217. // Kill them all hard so they don't wind up in TIME_WAIT state.
  218. KillSocket(pConnection->socket,TRUE,TRUE);
  219. if (pConnection->pBuffer && (pConnection->pBuffer != pConnection->pDefaultBuffer))
  220. {
  221. MemFree(pConnection->pBuffer);
  222. pConnection->pBuffer = NULL;
  223. }
  224. if (pConnection->pDefaultBuffer)
  225. {
  226. MemFree(pConnection->pDefaultBuffer);
  227. pConnection->pDefaultBuffer = NULL;
  228. }
  229. // initialize connection
  230. pConnection->socket = INVALID_SOCKET; // this tells us if connection is valid
  231. pConnection->dwCurMessageSize = 0;
  232. pConnection->dwTotalMessageSize = 0;
  233. }
  234. #undef DPF_MODNAME
  235. #define DPF_MODNAME "RemoveSocketFromList"
  236. void RemoveSocketFromList(SOCKET socket)
  237. {
  238. UINT i = 0;
  239. BOOL bFound = FALSE;
  240. ENTER_DPLAYSVR();
  241. // look for the corresponding connection
  242. while ( (i < gReceiveList.nConnections) && !bFound)
  243. {
  244. if (gReceiveList.pConnection[i].socket == socket)
  245. {
  246. bFound = TRUE;
  247. FreeConnection(&gReceiveList.pConnection[i]);
  248. }
  249. else
  250. {
  251. i++;
  252. }
  253. } // while
  254. LEAVE_DPLAYSVR();
  255. return ;
  256. }
  257. #undef DPF_MODNAME
  258. #define DPF_MODNAME "EmptyConnectionList"
  259. void EmptyConnectionList(void)
  260. {
  261. UINT i;
  262. DPF(5, "Emptying connection list");
  263. ENTER_DPLAYSVR();
  264. for (i=0;i<gReceiveList.nConnections ;i++ )
  265. {
  266. if (INVALID_SOCKET != gReceiveList.pConnection[i].socket)
  267. {
  268. FreeConnection(&(gReceiveList.pConnection[i]));
  269. }
  270. }
  271. LEAVE_DPLAYSVR();
  272. return ;
  273. } // EmptyConnectionList
  274. #undef DPF_MODNAME
  275. #define DPF_MODNAME "StreamReceive"
  276. /*
  277. ** StreamReceive
  278. *
  279. * CALLED BY: StreamReceiveThreadProc
  280. *
  281. * PARAMETERS:
  282. * sSocket - socket to receive on
  283. * ppBuffer - buffer to receive into - alloc'ed / realloc'ed as necessary
  284. * pdwBuffersize - size of pBuffer
  285. *
  286. * DESCRIPTION:
  287. * pull the bytes out of sSocket until no more bytes
  288. *
  289. * RETURNS: E_FAIL on sockerr, or DP_OK.
  290. *
  291. */
  292. HRESULT StreamReceive(LPCONNECTION pConnection)
  293. {
  294. HRESULT hr = DP_OK;
  295. UINT err;
  296. DWORD dwBytesReceived=0;
  297. DWORD dwMessageSize;
  298. LPBYTE pReceiveBuffer=NULL;
  299. DWORD dwReceiveBufferSize;
  300. // is it a new message ?
  301. if (pConnection->dwCurMessageSize == 0)
  302. {
  303. // receive the header first
  304. pConnection->dwTotalMessageSize = SPMESSAGEHEADERLEN;
  305. }
  306. // continue receiving message
  307. pReceiveBuffer = pConnection->pBuffer + pConnection->dwCurMessageSize;
  308. dwReceiveBufferSize = pConnection->dwTotalMessageSize - pConnection->dwCurMessageSize;
  309. DPF(9,"Attempting to receive %d bytes", dwReceiveBufferSize);
  310. DEBUGPRINTSOCK(9,">>> receiving data on socket - ",&pConnection->socket);
  311. // receive data from socket
  312. // note - make exactly one call to recv after select otherwise we'll hang
  313. dwBytesReceived = g_recv(pConnection->socket, (LPBYTE)pReceiveBuffer, dwReceiveBufferSize, 0);
  314. DEBUGPRINTSOCK(9,"<<< received data on socket - ",&pConnection->socket);
  315. DPF(5, "received %d bytes", dwBytesReceived);
  316. if (0 == dwBytesReceived)
  317. {
  318. // remote side has shutdown connection gracefully
  319. hr = DP_OK;
  320. DPF(5,"Remote side has shutdown connection gracefully");
  321. goto CLEANUP_EXIT;
  322. }
  323. else if (SOCKET_ERROR == dwBytesReceived)
  324. {
  325. err = g_WSAGetLastError();
  326. DPF(0,"STREAMRECEIVEE: receive error - err = %d",err);
  327. hr = E_UNEXPECTED;
  328. goto CLEANUP_EXIT;
  329. }
  330. // we have received this much message so far
  331. pConnection->dwCurMessageSize += dwBytesReceived;
  332. if (pConnection->dwCurMessageSize == SPMESSAGEHEADERLEN)
  333. {
  334. // we just completed receiving message header
  335. if (VALID_DPLAYSVR_MESSAGE(pConnection->pDefaultBuffer))
  336. {
  337. dwMessageSize = SP_MESSAGE_SIZE(pConnection->pDefaultBuffer); // total message size
  338. // SECURITY: limit message size for enum.
  339. if(dwMessageSize > 8192)
  340. {
  341. hr=E_UNEXPECTED;
  342. goto CLEANUP_EXIT;
  343. }
  344. }
  345. else
  346. {
  347. DPF(2,"got invalid message");
  348. ASSERT(FALSE);
  349. hr = E_UNEXPECTED;
  350. goto CLEANUP_EXIT;
  351. }
  352. // prepare to receive the rest of the message (after token)
  353. if (dwMessageSize)
  354. {
  355. pConnection->dwTotalMessageSize = dwMessageSize;
  356. // which buffer to receive message in ?
  357. if (dwMessageSize > DEFAULT_RECEIVE_BUFFERSIZE)
  358. {
  359. ASSERT(pConnection->pBuffer == pConnection->pDefaultBuffer);
  360. // get a new buffer to fit the message
  361. pConnection->pBuffer = MemAlloc(dwMessageSize);
  362. if (!pConnection->pBuffer)
  363. {
  364. DPF(0,"Failed to allocate receive buffer for message - out of memory");
  365. goto CLEANUP_EXIT;
  366. }
  367. // copy header into new message buffer
  368. memcpy(pConnection->pBuffer, pConnection->pDefaultBuffer, SPMESSAGEHEADERLEN);
  369. }
  370. }
  371. }
  372. // did we receive a complete message ?
  373. if (pConnection->dwCurMessageSize == pConnection->dwTotalMessageSize)
  374. {
  375. // received a complete message - process it
  376. if (TOKEN == SP_MESSAGE_TOKEN(pConnection->pBuffer))
  377. {
  378. DEBUGPRINTADDR(9,"dplay helper :: received reliable enum request from ",(SOCKADDR *)&pConnection->sockAddr);
  379. // take the dplay lock so no one messes w/ our list of registered serves while we're
  380. // trying to send to them...
  381. ENTER_DPLAYSVR();
  382. HandleIncomingMessage(pConnection->pBuffer, pConnection->dwTotalMessageSize,
  383. (SOCKADDR_IN *)&pConnection->sockAddr);
  384. // give up the lock
  385. LEAVE_DPLAYSVR();
  386. }
  387. // cleanup up new receive buffer if any
  388. if (pConnection->dwTotalMessageSize > DEFAULT_RECEIVE_BUFFERSIZE)
  389. {
  390. DPF(9, "Releasing receive buffer of size %d", pConnection->dwTotalMessageSize);
  391. if (pConnection->pBuffer) MemFree(pConnection->pBuffer);
  392. }
  393. // initialize message information
  394. pConnection->dwCurMessageSize = 0;
  395. pConnection->dwTotalMessageSize = 0;
  396. pConnection->pBuffer = pConnection->pDefaultBuffer;
  397. // new... only allow one enum per socket, then turf it.... AO 2/10/2000
  398. //goto CLEANUP_EXIT;
  399. }
  400. // all done
  401. return DP_OK;
  402. CLEANUP_EXIT:
  403. RemoveSocketFromList(pConnection->socket);
  404. return hr;
  405. } // StreamReceive
  406. #undef DPF_MODNAME
  407. #define DPF_MODNAME "StreamReceiveThreadProc"
  408. // watch our list of sockets, waiting for one to have data to be received, or to be closed
  409. DWORD WINAPI StreamReceiveThreadProc(LPVOID pvCast)
  410. {
  411. HRESULT hr;
  412. INT_PTR rval;
  413. UINT i = 0;
  414. UINT err;
  415. DWORD dwBufferSize = 0;
  416. UINT nSelected;
  417. SOCKADDR sockaddr; // socket we receive from
  418. INT addrlen=sizeof(sockaddr);
  419. SOCKET sSocket;
  420. BOOL bTrue = TRUE;
  421. // add listener socket to receive list
  422. // listener socket should be the first socket in the receive list
  423. hr = AddSocketToReceiveList(gsStreamListener);
  424. if (FAILED(hr))
  425. {
  426. DPF(0, "Failed to add TCP listener to receive list");
  427. return hr;
  428. }
  429. while (1)
  430. {
  431. ENTER_DPLAYSVR();
  432. ASSERT(gReadfds.pfdbigset);
  433. // add all sockets in our recv list to readfds
  434. FD_ZERO(gReadfds.pfdbigset);
  435. nSelected = 0;
  436. for (i=0;i < gReceiveList.nConnections ; i++)
  437. {
  438. if (INVALID_SOCKET != gReceiveList.pConnection[i].socket)
  439. {
  440. FD_BIG_SET(gReceiveList.pConnection[i].socket,&gReadfds);
  441. nSelected++;
  442. }
  443. }
  444. LEAVE_DPLAYSVR();
  445. if (0 == nSelected)
  446. {
  447. if (gbReceiveShutdown)
  448. {
  449. DPF(2,"stream receive thread proc detected shutdown - bailing");
  450. goto CLEANUP_EXIT;
  451. }
  452. // we should have at least one?
  453. DPF_ERR("No sockets in receive list - missing listener socket? bailing!");
  454. ASSERT(FALSE);
  455. goto CLEANUP_EXIT;
  456. }
  457. // now, we wait for something to happen w/ our socket set
  458. rval = g_select(0,(fd_set *)(gReadfds.pfdbigset),NULL,NULL,NULL);
  459. if (SOCKET_ERROR == rval)
  460. {
  461. err = g_WSAGetLastError();
  462. if (WSAEINTR != err)
  463. {
  464. // WSAEINTR is what winsock uses to break a blocking socket out of
  465. // its wait. it means someone killed this socket.
  466. // if it's not that, then it's a real error.
  467. DPF(0,"\n select error = %d socket - trying again",err);
  468. }
  469. else
  470. {
  471. DPF(9,"\n select error = %d socket - trying again",err);
  472. }
  473. rval = 0;
  474. }
  475. // shut 'em down?
  476. if (gbReceiveShutdown)
  477. {
  478. DPF(2,"receive thread proc detected bShutdown - bailing");
  479. goto CLEANUP_EXIT;
  480. }
  481. DPF(5,"receive thread proc - events on %d sockets",rval);
  482. i = 0;
  483. ENTER_DPLAYSVR();
  484. while (rval>0)
  485. {
  486. // walk the receive list, dealing w/ all new sockets
  487. if (i >= gReceiveList.nConnections)
  488. {
  489. rval = 0; // just to be safe, reset
  490. }
  491. if (gReceiveList.pConnection[i].socket != INVALID_SOCKET)
  492. {
  493. // see if it's in the set
  494. if (g_WSAFDIsSet(gReceiveList.pConnection[i].socket,(fd_set *)gReadfds.pfdbigset))
  495. {
  496. if (0==i)
  497. // we got a new connection
  498. {
  499. // accept any incoming connection
  500. sSocket = g_accept(gReceiveList.pConnection[i].socket,&sockaddr,&addrlen);
  501. if (INVALID_SOCKET == sSocket)
  502. {
  503. err = g_WSAGetLastError();
  504. DPF(0,"\n stream accept error - err = %d socket = %d BAILING",err,(DWORD)sSocket);
  505. DPF(0, "\n !!! stream accept thread is going away - won't get reliable enum sessions anymore !!!");
  506. ASSERT(FALSE);
  507. LEAVE_DPLAYSVR();
  508. goto CLEANUP_EXIT;
  509. }
  510. DEBUGPRINTADDR(5,"stream - accepted connection from",&sockaddr);
  511. // Turn on KEEPALIVE for the socket.
  512. if (SOCKET_ERROR == g_setsockopt(sSocket, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  513. {
  514. err = g_WSAGetLastError();
  515. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  516. }
  517. // add the new socket to our receive list
  518. hr = AddSocketToReceiveList(sSocket);
  519. if (FAILED(hr))
  520. {
  521. ASSERT(FALSE);
  522. }
  523. }
  524. else
  525. // socket has new data
  526. {
  527. DPF(9, "Receiving on socket %d from ReceiveList", i);
  528. // got one! this socket has something going on...
  529. hr = StreamReceive(&(gReceiveList.pConnection[i]));
  530. if (FAILED(hr))
  531. {
  532. DPF(1,"Stream Receive failed - hr = 0x%08lx\n",hr);
  533. }
  534. }
  535. rval--; // one less to hunt for
  536. } // IS_SET
  537. } // != INVALID_SOCKET
  538. i++;
  539. } // while rval
  540. LEAVE_DPLAYSVR();
  541. } // while 1
  542. CLEANUP_EXIT:
  543. EmptyConnectionList();
  544. DPF(5, "Stream receive thread exiting");
  545. return 0;
  546. } // ReceiveThreadProc
  547.