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.

3248 lines
87 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: fastsock.c
  6. * Content: new socket management to speed up massive multiplayer games
  7. * History:
  8. *
  9. * Date By Reason
  10. * ========== == ======
  11. * 01/23/2000 aarono created
  12. * 05/08/2000 aarono B#34466 Fix ordering problem in DecRefConnExist
  13. * 07/07/2000 aarono added WSAEHOSTUNREACH for disconnected links in GetPlayerConn
  14. * 08/30/2000 aarono workaround PAST bug MB#43599
  15. * fix MB#43586 Win2K stopping, not handling WSAEWOULDBLOCK on
  16. * receive properly (was dropping link).
  17. * 02/02/2001 aarono B#300219 STRESS: don't break on WSAENOBUFS from winsock
  18. * 02/21/2001 a-aogus don't allow large receives from untrusted sources.
  19. ***************************************************************************/
  20. #define INCL_WINSOCK_API_TYPEDEFS 1 // includes winsock 2 fn proto's, for getprocaddress
  21. #include <winsock2.h>
  22. #include "dpsp.h"
  23. #if USE_RSIP
  24. #include "rsip.h"
  25. #elif USE_NATHELP
  26. #include "nathelp.h"
  27. #endif
  28. #include "mmsystem.h"
  29. LPFN_WSAWAITFORMULTIPLEEVENTS g_WSAWaitForMultipleEvents;
  30. LPFN_WSASEND g_WSASend;
  31. LPFN_WSASENDTO g_WSASendTo;
  32. LPFN_WSACLOSEEVENT g_WSACloseEvent;
  33. LPFN_WSACREATEEVENT g_WSACreateEvent;
  34. LPFN_WSAENUMNETWORKEVENTS g_WSAEnumNetworkEvents;
  35. LPFN_WSAEVENTSELECT g_WSAEventSelect;
  36. LPFN_GETSOCKOPT g_getsockopt;
  37. HRESULT FastPlayerEventSelect(LPGLOBALDATA pgd, PPLAYERCONN pConn, BOOL bSelect);
  38. VOID FastAccept(LPGLOBALDATA pgd, LPWSANETWORKEVENTS pNetEvents);
  39. HRESULT ProcessConnEvents(
  40. LPGLOBALDATA pgd,
  41. PPLAYERCONN pConn,
  42. LPWSANETWORKEVENTS pSockEvents,
  43. LPWSANETWORKEVENTS pSockInEvents
  44. );
  45. extern DWORD wsaoDecRef(LPSENDINFO pSendInfo);
  46. PPLAYERCONN CleanPlayerConn(LPGLOBALDATA pgd, PPLAYERCONN pConn, BOOL bHard);
  47. PPLAYERCONN FastCombine(LPGLOBALDATA pgd, PPLAYERCONN pConn, SOCKADDR *psockaddr);
  48. VOID RemoveConnFromPendingList(LPGLOBALDATA pgd, PPLAYERCONN pConn);
  49. /*=============================================================================
  50. PlayerConnnection management:
  51. -----------------------------
  52. For datagram sends, there is one port on each machine used as a target,
  53. and since no connection is required, only 1 socket is used for datagram
  54. sends and receives. Since datagrams are allowed to be dropped, there is
  55. no race between sending from one side to the other until player creation
  56. since its ok to drop the receives that occure before player creation on
  57. this machine occurs. Actually there is a race, but we don't care.
  58. For reliable sends there are numerous race conditions that exist. First
  59. the actual creation of the link between this client and the remote
  60. machine is going to become a race. Since we are connecting to and from
  61. the same ports to create the link, only one link will get set up, either
  62. it will get set up due to a connect to us, or it will get set up by us
  63. connecting to them.
  64. They connect to us:
  65. In the case where they connect to us first, there may be reliable data
  66. arriving at our node that would get thrown out it we indicated it to
  67. the dplay layer, because dplay has not yet created the player. To avoid
  68. this problem we queue any incoming receives and wait until the player
  69. has been created locally before indicating that data to the dplay layer.
  70. We pend any incoming data on a PLAYERCONN structure that we put on the
  71. PendingConnList on the global data. The PLAYERCONN structure can be
  72. fully initialized except we won't know the playerid of the remote player,
  73. as a result of which we cannot put the PLAYERCONN into the PlayerHash
  74. hash table.
  75. Note there is an additional problem of not knowing which player a connect
  76. is from. This means we need to put the queueing in the dplay layer,
  77. not in the dpwsock layer.
  78. We connect to them:
  79. When we go to establish the connection with the remote, we must do it
  80. asynchronously so as not to block in case we are a server. During the
  81. connection process, we first look on the PendingConnList and see if
  82. the remote hasn't already connected to us. If it has, we pick up the
  83. socket from the conn list and immediately indicate any pending data.
  84. If we failed to find the connection in the Pending list, this doesn't
  85. mean they won't still beat us but we are going to try and connect to
  86. them first. We create our connect structure and put it in the hash
  87. table and mark it pending. We also put it on the pending connect list
  88. so any incoming connection could find it. We then issue an asynchronous
  89. connect on the socket.
  90. When the connect completes any pending sends are then sent by the
  91. send thread. If the connect fails because the other side connected
  92. to us first, then we wait for the thread accepting connections to find
  93. the connection structure and send out the pending sends.
  94. Since they may be connecting from an old client, there is no guarantee
  95. that their inbound connection and our outbound connection will use the
  96. same socket. Each player structure must therefore contain both an
  97. inbound and outbound socket.
  98. =============================================================================*/
  99. #ifdef DEBUG
  100. VOID DUMPCONN(PPLAYERCONN pConn, DWORD dwLevel)
  101. {
  102. DPF(8,"Conn %x dwRefCount %d sSocket %d sSocketIn %d dwFlags %x iEventHandle %d\n",
  103. pConn, pConn->dwRefCount, pConn->sSocket, pConn->sSocketIn, pConn->dwFlags, pConn->iEventHandle);
  104. if(dwLevel >= 1 ){
  105. if(pConn->dwFlags & PLYR_NEW_CLIENT){
  106. DEBUGPRINTADDR(8,"NEW CLIENT: Socket",&pConn->IOSock.sockaddr);
  107. }
  108. if(pConn->dwFlags & PLYR_OLD_CLIENT){
  109. DEBUGPRINTADDR(8,"OLD CLIENT: Socket Out",&pConn->IOSock.sockaddr);
  110. DEBUGPRINTADDR(8,"OLD CLIENT: Socket In",&pConn->IOnlySock.sockaddr);
  111. }
  112. }
  113. if(dwLevel >= 2){
  114. DPF(8,"Receive... pReceiveBuffer %x, cbReceiveBuffer %d, cbReceived %d, cbExpected %d\n",
  115. pConn->pReceiveBuffer, pConn->cbReceiveBuffer, pConn->cbReceived, pConn->cbExpected);
  116. }
  117. }
  118. #else
  119. #define DUMPCONN(pConn,Level)
  120. #endif
  121. int myclosesocket(LPGLOBALDATA pgd, SOCKET socket)
  122. {
  123. DWORD lNonBlock=1;
  124. int err;
  125. if(socket==INVALID_SOCKET){
  126. DPF(0,"Closing invalid socket... bad bad bad\n");
  127. DEBUG_BREAK();
  128. }
  129. if(socket==pgd->sSystemStreamSocket){
  130. DPF(0,"Closing listen socket... bad bad bad\n");
  131. DEBUG_BREAK();
  132. }
  133. err = ioctlsocket(socket,FIONBIO,&lNonBlock);
  134. if (SOCKET_ERROR == err)
  135. {
  136. err = WSAGetLastError();
  137. DPF(0,"myclosesocket: could not set non-blocking mode on socket err = %d!",err);
  138. }
  139. return closesocket(socket);
  140. }
  141. // TRUE -> same port and IP addr.
  142. BOOL _inline bSameAddr(SOCKADDR *psaddr, SOCKADDR *psaddr2)
  143. {
  144. SOCKADDR_IN *psaddr_in = (SOCKADDR_IN *)psaddr;
  145. SOCKADDR_IN *psaddr_in2 = (SOCKADDR_IN *)psaddr2;
  146. if( (psaddr_in->sin_port == psaddr_in2->sin_port) &&
  147. !memcmp(&psaddr_in->sin_addr,&psaddr_in2->sin_addr, 4 ))
  148. {
  149. return TRUE;
  150. } else {
  151. return FALSE;
  152. }
  153. }
  154. //
  155. // HashPlayer() - hash a dpid to a 0->PLAYER_HASH_SIZE index.
  156. //
  157. UINT _inline HashPlayer(DPID dpid){
  158. UINT Hash=0;
  159. Hash = ((dpid & 0xFF000000)>>24) ^ ((dpid & 0xFF0000)>>16) ^ ((dpid & 0xFF00)>>8) ^ (dpid & 0xFF);
  160. Hash = Hash % PLAYER_HASH_SIZE;
  161. DPF(8,"Player Hash %d\n",Hash);
  162. return Hash;
  163. }
  164. //
  165. // HashSocket() - hash a socket id, including port
  166. //
  167. UINT _inline HashSocket(SOCKADDR *psockaddr){
  168. unsigned char *pc = (char *)(&(*(SOCKADDR_IN *)(psockaddr)).sin_port);
  169. UINT Hash=0;
  170. Hash = *pc ^ *(pc+1) ^ *(pc+2) ^ *(pc+3) ^ *(pc+4) ^ *(pc+5);
  171. Hash = Hash % SOCKET_HASH_SIZE;
  172. DPF(8,"Socket Hash %d\n",Hash);
  173. return Hash;
  174. }
  175. /*=============================================================================
  176. FastSockInit - Initialize Fask socket processing
  177. Description:
  178. Parameters:
  179. pgd - Service Provider's global data blob for this instance
  180. Return Values:
  181. -----------------------------------------------------------------------------*/
  182. BOOL FastSockInit(LPGLOBALDATA pgd)
  183. {
  184. BOOL bReturn = TRUE;
  185. INT i;
  186. try {
  187. InitializeCriticalSection(&pgd->csFast);
  188. } except ( EXCEPTION_EXECUTE_HANDLER) {
  189. // Catch STATUS_NOMEMORY
  190. DPF(0,"FastSockInit: Couldn't allocate critical section, bailing\n");
  191. bReturn=FALSE;
  192. goto exit;
  193. }
  194. // Start at -1 so we get the Accept handle too.
  195. for(i=-1; i<NUM_EVENT_HANDLES; i++){
  196. pgd->EventHandles[i]=CreateEvent(NULL, FALSE, FALSE, NULL);
  197. if(!pgd->EventHandles[i]){
  198. DPF(0,"FastSockInit: Failed to allocate handles, bailing\n");
  199. for(;i>-1;--i){
  200. CloseHandle(pgd->EventHandles[i]);
  201. }
  202. bReturn = FALSE;
  203. goto err_exit1;
  204. }
  205. }
  206. // could initialize all the listenerlists to 0, but that would be pointless.
  207. pgd->BackStop=INVALID_HANDLE_VALUE;
  208. pgd->nEventSlotsAvail = NUM_EVENT_HANDLES * MAX_EVENTS_PER_HANDLE;
  209. InitBilink(&pgd->InboundPendingList);
  210. DPF(8,"FastSock Init: nEventSlots %d\n",pgd->nEventSlotsAvail);
  211. pgd->bFastSock=TRUE;
  212. exit:
  213. return bReturn;
  214. err_exit1:
  215. DeleteCriticalSection(&pgd->csFast);
  216. return bReturn;
  217. }
  218. /*=============================================================================
  219. FastSockCleanConnList - Release connections
  220. Description:
  221. Parameters:
  222. pgd - Service Provider's global data blob for this instance
  223. Return Values:
  224. -----------------------------------------------------------------------------*/
  225. VOID FastSockCleanConnList(LPGLOBALDATA pgd)
  226. {
  227. PPLAYERCONN pConn,pNextConn;
  228. BILINK *pBilink, *pBilinkWalker;
  229. INT i;
  230. DPF(8,"==>FastSockCleanConnList\n");
  231. DPF(8,"Cleaning up Player ID hash Table\n");
  232. EnterCriticalSection(&pgd->csFast);
  233. for(i=0;i<PLAYER_HASH_SIZE; i++){
  234. pConn=pgd->PlayerHash[i];
  235. pgd->PlayerHash[i]=NULL;
  236. while(pConn)
  237. {
  238. pNextConn=pConn->pNextP;
  239. DPF(8,"Destroying Connection for Playerid %x\n",pConn->dwPlayerID);
  240. DUMPCONN(pConn,3);
  241. CleanPlayerConn(pgd, pConn, TRUE);
  242. DecRefConnExist(pgd, pConn); // dump existence ref.
  243. DecRefConn(pgd,pConn); // dump playerid table ref.
  244. pConn=pNextConn;
  245. }
  246. }
  247. // Clean up socket hash table entries
  248. DPF(8,"Cleaning up Socket hash Table\n");
  249. for(i=0;i<SOCKET_HASH_SIZE; i++)
  250. {
  251. pConn=pgd->SocketHash[i];
  252. pgd->SocketHash[i]=NULL;
  253. while(pConn)
  254. {
  255. pNextConn=pConn->pNextP;
  256. DPF(8,"Destroying Connection for Playerid %x\n",pConn->dwPlayerID);
  257. DUMPCONN(pConn,3);
  258. CleanPlayerConn(pgd, pConn, TRUE);
  259. DecRefConnExist(pgd, pConn); // dump existence ref.
  260. DecRefConn(pgd,pConn); // dump socket table ref.
  261. pConn=pNextConn;
  262. }
  263. }
  264. // Clean up inbound list.
  265. DPF(8,"Cleaning up Inbound Pending List\n");
  266. pBilink=pgd->InboundPendingList.next;
  267. while(pBilink != &pgd->InboundPendingList)
  268. {
  269. pBilinkWalker=pBilink->next;
  270. pConn=CONTAINING_RECORD(pBilink, PLAYERCONN, InboundPendingList);
  271. DPF(8,"Destroying Connection for Playerid %x\n",pConn->dwPlayerID);
  272. DUMPCONN(pConn,3);
  273. CleanPlayerConn(pgd, pConn, TRUE);
  274. DecRefConnExist(pgd, pConn);
  275. //DecRefConn(pgd,pConn); // dump inbound list ref --no, gets handled in CleanPlayerConn for this case
  276. pBilink=pBilinkWalker;
  277. }
  278. InitBilink(&pgd->InboundPendingList);
  279. LeaveCriticalSection(&pgd->csFast);
  280. ASSERT(pgd->nEventSlotsAvail == NUM_EVENT_HANDLES * MAX_EVENTS_PER_HANDLE);
  281. DPF(8,"<==FastSockCleanConnList\n");
  282. }
  283. /*=============================================================================
  284. FastSockFini - Release resources for fast socket processing.
  285. Description:
  286. Parameters:
  287. pgd - Service Provider's global data blob for this instance
  288. Return Values:
  289. -----------------------------------------------------------------------------*/
  290. VOID FastSockFini(LPGLOBALDATA pgd)
  291. {
  292. BOOL bReturn = TRUE;
  293. INT i;
  294. DPF(8,"==>FastSockFini\n");
  295. for(i=-1;i<NUM_EVENT_HANDLES;i++){
  296. CloseHandle(pgd->EventHandles[i]);
  297. }
  298. // Clean up player hash table entries
  299. FastSockCleanConnList(pgd);
  300. DeleteCriticalSection(&pgd->csFast);
  301. pgd->bFastSock=FALSE;
  302. DPF(8,"<==FastSockFini\n");
  303. }
  304. /*=============================================================================
  305. GetEventHandle - Allocate an event handle for the connection
  306. Description:
  307. Parameters:
  308. pgd - Service Provider's global data blob for this instance
  309. pConn - connection to add processing for on the event.
  310. Return Values:
  311. -----------------------------------------------------------------------------*/
  312. BOOL GetEventHandle(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  313. {
  314. UINT i;
  315. int index;
  316. int iEvent=-1; // index of event
  317. int iConn; // index into connections on this event
  318. int bFoundSlot = FALSE;
  319. i=(pgd->iEventAlloc+(NUM_EVENT_HANDLES-1))%NUM_EVENT_HANDLES;
  320. while(pgd->iEventAlloc != i){
  321. if(pgd->EventList[pgd->iEventAlloc].nConn < MAX_EVENTS_PER_HANDLE){
  322. // Found a winner.
  323. iEvent = pgd->iEventAlloc;
  324. iConn=pgd->EventList[iEvent].nConn++;
  325. DPF(8,"GetEventHandle: For Conn %x, using Event index %d, Slot %d\n",pConn,iEvent,iConn);
  326. pgd->EventList[iEvent].pConn[iConn]=pConn;
  327. pConn->iEventHandle=iEvent;
  328. bFoundSlot=TRUE;
  329. pgd->nEventSlotsAvail--;
  330. DPF(8,"GetEventHandle: EventSlots Left %d\n",pgd->nEventSlotsAvail);
  331. if(!pgd->nEventSlotsAvail){
  332. DPF(0,"Out of Event slots, no new connections will be accepted\n");
  333. }
  334. break;
  335. }
  336. pgd->iEventAlloc = (pgd->iEventAlloc+1)%NUM_EVENT_HANDLES;
  337. }
  338. // advance the index so we distribute the load across the handles.
  339. pgd->iEventAlloc = (pgd->iEventAlloc+1)%NUM_EVENT_HANDLES;
  340. DPF(8,"iEventAlloc %d\n",pgd->iEventAlloc);
  341. ASSERT(iEvent != -1);
  342. return bFoundSlot;
  343. }
  344. /*=============================================================================
  345. FreeEventHandle - Remove the event handle for the connection
  346. Description:
  347. Parameters:
  348. pgd - Service Provider's global data blob for this instance
  349. pConn - connection to remove processing for on the event.
  350. Return Values:
  351. -----------------------------------------------------------------------------*/
  352. VOID FreeEventHandle(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  353. {
  354. int iEvent;
  355. int iLastConn;
  356. UINT iConn;
  357. iEvent = pConn->iEventHandle;
  358. if(iEvent == INVALID_EVENT_SLOT){
  359. DPF(1,"WARN: tried to free invalid event\n");
  360. return;
  361. }
  362. for(iConn=0;iConn<pgd->EventList[iEvent].nConn;iConn++){
  363. if(pgd->EventList[iEvent].pConn[iConn]==pConn){
  364. ASSERT(pgd->EventList[iEvent].nConn);
  365. iLastConn = pgd->EventList[iEvent].nConn-1;
  366. // copy the last entry over this entry (could be 0 over 0, but who cares?)
  367. pgd->EventList[iEvent].pConn[iConn]=pgd->EventList[iEvent].pConn[iLastConn];
  368. pgd->EventList[iEvent].nConn--;
  369. ASSERT((INT)(pgd->EventList[iEvent].nConn) >= 0);
  370. pgd->nEventSlotsAvail++;
  371. pConn->iEventHandle = INVALID_EVENT_SLOT;
  372. DPF(8,"FreeEventHandle index %d Slot %d nConn %d on slot Total Slots Left %d\n",iEvent,iConn,pgd->EventList[iEvent].nConn,pgd->nEventSlotsAvail);
  373. return;
  374. }
  375. }
  376. DPF(0,"UH OH, couldn't free event handle!\n");
  377. DEBUG_BREAK();
  378. }
  379. /*=============================================================================
  380. FindPlayerById - Find the connection structure for a player
  381. Description:
  382. Finds a player and returns the connection structure with a reference
  383. Parameters:
  384. pgd - Service Provider's global data blob for this instance
  385. dpid - player id of the player we are trying to find connection for.
  386. Return Values:
  387. PPLAYERCONN - player connection structure
  388. NULL - Didn't find the player connection.
  389. -----------------------------------------------------------------------------*/
  390. PPLAYERCONN FindPlayerById(LPGLOBALDATA pgd, DPID dpid)
  391. {
  392. PPLAYERCONN pConn;
  393. EnterCriticalSection(&pgd->csFast);
  394. pConn = pgd->PlayerHash[HashPlayer(dpid)];
  395. while(pConn && pConn->dwPlayerID != dpid){
  396. pConn = pConn->pNextP;
  397. }
  398. if(pConn){
  399. DPF(8,"FindPlayerById, found %x\n",pConn);
  400. DUMPCONN(pConn, 1);
  401. AddRefConn(pConn);
  402. }
  403. LeaveCriticalSection(&pgd->csFast);
  404. return pConn;
  405. }
  406. /*=============================================================================
  407. FindPlayerBySocket - Find the connection structure for a player
  408. Description:
  409. Finds a player and returns the connection structure with a reference
  410. Parameters:
  411. pgd - Service Provider's global data blob for this instance
  412. psockaddr - socketaddr of the player we are trying to find connection for.
  413. Return Values:
  414. PPLAYERCONN - player connection structure
  415. NULL - Didn't find the player connection.
  416. -----------------------------------------------------------------------------*/
  417. PPLAYERCONN FindPlayerBySocket(LPGLOBALDATA pgd, SOCKADDR *psockaddr)
  418. {
  419. PPLAYERCONN pConn;
  420. EnterCriticalSection(&pgd->csFast);
  421. DEBUGPRINTADDR(8,"FindPlyrBySock",psockaddr);
  422. pConn = pgd->SocketHash[HashSocket(psockaddr)];
  423. while(pConn && !bSameAddr(psockaddr, &pConn->IOSock.sockaddr))
  424. {
  425. DEBUGPRINTADDR(8,"FPBS: doesn't match",&pConn->IOSock.sockaddr);
  426. pConn = pConn->pNextS;
  427. }
  428. if(pConn){
  429. DPF(8,"FindPlayerBySocket, found %x\n",pConn);
  430. DUMPCONN(pConn,1);
  431. AddRefConn(pConn);
  432. }
  433. LeaveCriticalSection(&pgd->csFast);
  434. return pConn;
  435. }
  436. /*=============================================================================
  437. CreatePlayerConn - Create a player connection structure
  438. Description: Fast lock must be held!
  439. Parameters:
  440. pgd - Service Provider's global data blob for this instance
  441. dpid - dpid of the player (if known, else DPID_UNKNOWN)
  442. psockaddr - socket address (if known)
  443. Return Values:
  444. ptr to created player conn, or NULL if we couldn't create (out of mem).
  445. -----------------------------------------------------------------------------*/
  446. PPLAYERCONN CreatePlayerConn(LPGLOBALDATA pgd, DPID dpid, SOCKADDR *psockaddr)
  447. {
  448. PPLAYERCONN pConn;
  449. // Allocate and initialize a Player connection structure
  450. if(dpid != DPID_UNKNOWN && (pConn=FindPlayerById(pgd, dpid)))
  451. {
  452. return pConn; //Player already exists for this id.
  453. }
  454. if(!(pConn=SP_MemAlloc(sizeof(PLAYERCONN)+DEFAULT_RECEIVE_BUFFERSIZE)))
  455. {
  456. return pConn; //NULL
  457. }
  458. if(!GetEventHandle(pgd, pConn)){
  459. SP_MemFree(pConn);
  460. return NULL;
  461. }
  462. pConn->pDefaultReceiveBuffer = (PCHAR)(pConn+1);
  463. pConn->pReceiveBuffer = pConn->pDefaultReceiveBuffer;
  464. pConn->cbReceiveBuffer = DEFAULT_RECEIVE_BUFFERSIZE;
  465. pConn->cbReceived = 0;
  466. pConn->dwRefCount = 1;
  467. pConn->dwPlayerID = dpid;
  468. pConn->sSocket = INVALID_SOCKET;
  469. pConn->sSocketIn = INVALID_SOCKET;
  470. pConn->dwFlags = 0;
  471. pConn->bTrusted = FALSE;
  472. InitBilink(&pConn->PendingConnSendQ);
  473. InitBilink(&pConn->InboundPendingList);
  474. if(psockaddr){
  475. // Don't yet know if this guy can re-use sockets, bang only
  476. // socket we know about so far into both slots.
  477. memcpy(&pConn->IOSock.sockaddr, psockaddr, sizeof(SOCKADDR));
  478. memcpy(&pConn->IOnlySock.sockaddr, psockaddr, sizeof(SOCKADDR));
  479. }
  480. DPF(8,"CreatedPlayerConn %x\n",pConn);
  481. DUMPCONN(pConn,3);
  482. return pConn;
  483. }
  484. /*=============================================================================
  485. DestroyPlayerConn - Remove the connection from any lists, shut down any
  486. active sockets.
  487. Description:
  488. Parameters:
  489. pgd - Service Provider's global data blob for this instance
  490. pConn
  491. Return Values:
  492. Pulls the player Conn off of any hash tables and lists it lives on
  493. and gets rid of its existence count. No guarantee that this will
  494. actually free the object though, that happens when the last reference
  495. is released.
  496. -----------------------------------------------------------------------------*/
  497. PPLAYERCONN CleanPlayerConn(LPGLOBALDATA pgd, PPLAYERCONN pConn, BOOL bHard)
  498. {
  499. LINGER Linger;
  500. int err;
  501. LPREPLYLIST prd;
  502. #ifdef DEBUG
  503. DWORD dwTime;
  504. dwTime=timeGetTime();
  505. #endif
  506. EnterCriticalSection(&pgd->csFast);
  507. DPF(8,"==>CLEANPLAYERCONN %x time %d\n",pConn,dwTime);
  508. DUMPCONN(pConn,3);
  509. // Remove from listening.
  510. FastPlayerEventSelect(pgd, pConn, FALSE);
  511. // Dump event handle.
  512. FreeEventHandle(pgd, pConn);
  513. // Remove from lists.
  514. if(pConn->dwFlags & PLYR_PENDINGLIST)
  515. {
  516. RemoveConnFromPendingList(pgd, pConn);
  517. }
  518. if(pConn->dwFlags & PLYR_DPIDHASH)
  519. {
  520. RemoveConnFromPlayerHash(pgd,pConn);
  521. }
  522. if(pConn->dwFlags & PLYR_SOCKHASH)
  523. {
  524. RemoveConnFromSocketHash(pgd,pConn);
  525. }
  526. // Close all sockets.
  527. // When closing the sockets we want to avoid a bunch of nastiness where data sometimes isn't delivered
  528. // because we close the socket before the data is sent, but we don't want to linger the socket because
  529. // then it gets into a TIME_WAIT state where the same connection cannot be re-established for 4 minutes
  530. // which wrecks havoc with our tests and can cause connection problems since DirectPlay uses a limited
  531. // range (100 ports) between machines. So we set the socket to hard close (avoiding TIME_WAIT) but use
  532. // the "Reply" clean up code path to close the sockets down.
  533. if(pConn->sSocket != INVALID_SOCKET)
  534. {
  535. DPF(8,"Closing Socket %d\n",pConn->sSocket);
  536. Linger.l_onoff=TRUE; Linger.l_linger=0; // avoid TIME_WAIT
  537. if(SOCKET_ERROR == setsockopt( pConn->sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,sizeof(Linger)))
  538. {
  539. DPF(0,"DestroyPlayerConn:Couldn't set linger to short for hard close\n");
  540. }
  541. ENTER_DPSP();
  542. prd=SP_MemAlloc(sizeof(REPLYLIST));
  543. if(!prd){
  544. LEAVE_DPSP();
  545. DPF(8,"Closing Socket %d\n",pConn->sSocket);
  546. err=myclosesocket(pgd,pConn->sSocket);
  547. if(err == SOCKET_ERROR){
  548. err=WSAGetLastError();
  549. DPF(8,"Error Closing Socket %x, err=%d\n", pConn->sSocket,err);
  550. }
  551. } else {
  552. // very tricky, overloading the reply close list to close this socket with our own linger...
  553. prd->pNextReply=pgd->pReplyCloseList;
  554. pgd->pReplyCloseList=prd;
  555. prd->sSocket=pConn->sSocket;
  556. prd->tSent=timeGetTime();
  557. prd->lpMessage=NULL;
  558. LEAVE_DPSP();
  559. }
  560. pConn->sSocket=INVALID_SOCKET;
  561. if(pConn->sSocketIn==INVALID_SOCKET){
  562. pConn->dwFlags &= ~(PLYR_CONNECTED|PLYR_ACCEPTED);
  563. } else {
  564. pConn->dwFlags &= ~(PLYR_CONNECTED);
  565. }
  566. }
  567. if(pConn->sSocketIn != INVALID_SOCKET)
  568. {
  569. // may have to close another socket.
  570. DPF(8,"Closing SocketIn %d\n",pConn->sSocketIn);
  571. Linger.l_onoff=TRUE; Linger.l_linger=0; // avoid TIME_WAIT
  572. if(SOCKET_ERROR == setsockopt(pConn->sSocketIn,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,sizeof(Linger)))
  573. {
  574. DPF(0,"DestroyPlayerConn:Couldn't set linger to short for hard close\n");
  575. }
  576. ENTER_DPSP();
  577. prd=SP_MemAlloc(sizeof(REPLYLIST));
  578. if(!prd){
  579. LEAVE_DPSP();
  580. err=myclosesocket(pgd,pConn->sSocketIn);
  581. if(err == SOCKET_ERROR){
  582. err=WSAGetLastError();
  583. DPF(8,"Error Closing Socket %x, err=%d\n", pConn->sSocketIn,err);
  584. }
  585. } else {
  586. // very tricky, overloading the reply close list to close this socket with our own linger...
  587. prd->pNextReply=pgd->pReplyCloseList;
  588. pgd->pReplyCloseList=prd;
  589. prd->sSocket=pConn->sSocketIn;
  590. prd->tSent=timeGetTime();
  591. prd->lpMessage=NULL;
  592. LEAVE_DPSP();
  593. }
  594. pConn->sSocketIn=INVALID_SOCKET;
  595. pConn->dwFlags &= ~(PLYR_ACCEPTED);
  596. }
  597. // Free extra buffer.
  598. if(pConn->pReceiveBuffer != pConn->pDefaultReceiveBuffer){
  599. SP_MemFree(pConn->pReceiveBuffer);
  600. pConn->pReceiveBuffer = pConn->pDefaultReceiveBuffer;
  601. }
  602. // Dump Send Queue if present.
  603. while(!EMPTY_BILINK(&pConn->PendingConnSendQ)){
  604. PSENDINFO pSendInfo;
  605. pSendInfo=CONTAINING_RECORD(pConn->PendingConnSendQ.next, SENDINFO, PendingConnSendQ);
  606. Delete(&pSendInfo->PendingConnSendQ);
  607. pSendInfo->Status = DPERR_CONNECTIONLOST;
  608. EnterCriticalSection(&pgd->csSendEx);
  609. pSendInfo->RefCount = 1;
  610. LeaveCriticalSection(&pgd->csSendEx);
  611. wsaoDecRef(pSendInfo);
  612. }
  613. DUMPCONN(pConn,3);
  614. #ifdef DEBUG
  615. dwTime = timeGetTime()-dwTime;
  616. if(dwTime > 1000){
  617. DPF(0,"Took way too long in CleanPlayerConn, elapsed %d ms\n",dwTime);
  618. //DEBUG_BREAK(); // removed break due to stress hits
  619. }
  620. #endif
  621. DPF(8,"<==CleanPlayerConn total time %d ms\n",dwTime);
  622. LeaveCriticalSection(&pgd->csFast);
  623. return pConn;
  624. }
  625. /*=============================================================================
  626. DecRefConn - Decrement reference on PlayerConn, when it hits 0, free it.
  627. Description:
  628. Parameters:
  629. pConn - player connection.
  630. Return Values:
  631. decrements the reference on a player conn. If it hits 0, frees it.
  632. -----------------------------------------------------------------------------*/
  633. INT DecRefConn(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  634. {
  635. INT count;
  636. count=InterlockedDecrement(&pConn->dwRefCount);
  637. if(!count){
  638. CleanPlayerConn(pgd, pConn, FALSE);
  639. DPF(8,"Freeing Connection pConn %x\n",pConn);
  640. SP_MemFree(pConn);
  641. }
  642. #ifdef DEBUG
  643. if(count & 0x80000000){
  644. DPF(0,"DecRefConn: Conn refcount for conn %x has gone negative count %x\n",pConn,count);
  645. DUMPCONN(pConn,2);
  646. DEBUG_BREAK();
  647. }
  648. #endif
  649. return count;
  650. }
  651. /*=============================================================================
  652. DecRefConnExist - Dumps Existence ref if not already dumped.
  653. Description:
  654. Parameters:
  655. pConn - player connection.
  656. Return Values:
  657. -----------------------------------------------------------------------------*/
  658. INT DecRefConnExist(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  659. {
  660. INT count;
  661. EnterCriticalSection(&pgd->csFast);
  662. if(!(pConn->dwFlags & PLYR_DESTROYED)){
  663. pConn->dwFlags |= PLYR_DESTROYED;
  664. count=DecRefConn(pgd,pConn);
  665. } else {
  666. count=pConn->dwRefCount;
  667. }
  668. LeaveCriticalSection(&pgd->csFast);
  669. return count;
  670. }
  671. /*=============================================================================
  672. AddConnToPlayerHash - puts a connection in the player hash table.
  673. Description: The fast lock must be held!
  674. Parameters:
  675. pgd - Service Provider's global data blob for this instance
  676. pConn - connection to put in the hash table.
  677. Return Values:
  678. None.
  679. -----------------------------------------------------------------------------*/
  680. HRESULT AddConnToPlayerHash(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  681. {
  682. PPLAYERCONN pConn2;
  683. INT i;
  684. HRESULT hr=DP_OK;
  685. #ifdef DEBUG
  686. if(pConn->dwPlayerID == DPID_UNKNOWN){
  687. DEBUG_BREAK();
  688. }
  689. #endif
  690. ASSERT(!(pConn->dwFlags & PLYR_DPIDHASH));
  691. if(!(pConn->dwFlags & PLYR_DPIDHASH)){
  692. if(pConn2 = FindPlayerById(pgd, pConn->dwPlayerID)){
  693. DPF(0,"AddConnToPlayerHash: Player in %x id %d already exists, pConn=%x\n",pConn,pConn->dwPlayerID,pConn2);
  694. DecRefConn(pgd, pConn2);
  695. hr=DPERR_GENERIC;
  696. goto exit;
  697. }
  698. DPF(8,"Adding Conn %x to Player ID Hash\n",pConn);
  699. DUMPCONN(pConn,1);
  700. // add a reference for being in the player hash table.
  701. AddRefConn(pConn);
  702. i=HashPlayer(pConn->dwPlayerID);
  703. ASSERT(i<PLAYER_HASH_SIZE);
  704. pConn->pNextP = pgd->PlayerHash[i];
  705. pgd->PlayerHash[i] = pConn;
  706. pConn->dwFlags |= PLYR_DPIDHASH;
  707. } else {
  708. DPF(1,"WARNING:tried to add Conn %x to Player Hash again\n",pConn);
  709. }
  710. exit:
  711. return hr;
  712. }
  713. /*=============================================================================
  714. RemoveConnFromPlayerHash - pull a connection from the player hash table.
  715. Description:
  716. Parameters:
  717. pgd - Service Provider's global data blob for this instance
  718. pConn - connection to put in the hash table.
  719. Return Values:
  720. PPLAYERCONN - removed from hash, here it is.
  721. NULL - couldn't find it.
  722. -----------------------------------------------------------------------------*/
  723. PPLAYERCONN RemoveConnFromPlayerHash(LPGLOBALDATA pgd, PPLAYERCONN pConnIn)
  724. {
  725. PPLAYERCONN pConn=NULL,pConnPrev;
  726. INT i;
  727. if(pConnIn->dwFlags & PLYR_DPIDHASH){
  728. i=HashPlayer(pConnIn->dwPlayerID);
  729. EnterCriticalSection(&pgd->csFast);
  730. pConn = pgd->PlayerHash[i];
  731. pConnPrev = CONTAINING_RECORD(&pgd->PlayerHash[i], PLAYERCONN, pNextP); // sneaky
  732. while(pConn && pConn != pConnIn){
  733. pConnPrev = pConn;
  734. pConn = pConn->pNextP;
  735. }
  736. if(pConn){
  737. DPF(8,"Removing Conn %x from Player ID Hash\n",pConn);
  738. DUMPCONN(pConn,1);
  739. pConnPrev->pNextP = pConn->pNextP;
  740. pConn->dwFlags &= ~(PLYR_DPIDHASH);
  741. i=DecRefConn(pgd, pConn); // remove reference for player hash table
  742. ASSERT(i);
  743. }
  744. LeaveCriticalSection(&pgd->csFast);
  745. }
  746. return pConn;
  747. }
  748. /*=============================================================================
  749. AddConnToSocketHash - puts a connection in the socket hash table.
  750. Description:
  751. Parameters:
  752. pgd - Service Provider's global data blob for this instance
  753. pConn - connection to put in the hash table.
  754. Return Values:
  755. None.
  756. -----------------------------------------------------------------------------*/
  757. HRESULT AddConnToSocketHash(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  758. {
  759. PPLAYERCONN pConn2;
  760. INT i;
  761. HRESULT hr=DP_OK;
  762. EnterCriticalSection(&pgd->csFast);
  763. if(!(pConn->dwFlags & PLYR_SOCKHASH)){
  764. if(pConn2 = FindPlayerBySocket(pgd, &pConn->IOSock.sockaddr)){
  765. DecRefConn(pgd, pConn2);
  766. DPF(0,"AddConnToPlayerHash: Player in %x id %d already exists, pConn=%x\n",pConn,pConn->dwPlayerID,pConn2);
  767. hr=DPERR_GENERIC;
  768. goto exit;
  769. }
  770. DPF(8,"Adding Conn %x to Socket Hash\n",pConn);
  771. DUMPCONN(pConn,1);
  772. // add a reference for being in the socket hash.
  773. AddRefConn(pConn);
  774. i=HashSocket(&pConn->IOSock.sockaddr);
  775. ASSERT(i<SOCKET_HASH_SIZE);
  776. pConn->pNextS = pgd->SocketHash[i];
  777. pgd->SocketHash[i] = pConn;
  778. pConn->dwFlags |= PLYR_SOCKHASH;
  779. } else {
  780. DPF(0,"WARNING: tried to add pConn %x to socket hash again\n",pConn);
  781. DEBUG_BREAK();
  782. }
  783. exit:
  784. LeaveCriticalSection(&pgd->csFast);
  785. return hr;
  786. }
  787. /*=============================================================================
  788. RemoveConnFromSockHash - pull a connection from the socket hash table.
  789. Description:
  790. Parameters:
  791. pgd - Service Provider's global data blob for this instance
  792. pConn - connection to put in the hash table.
  793. Return Values:
  794. PPLAYERCONN - removed from hash, here it is.
  795. NULL - couldn't find it.
  796. -----------------------------------------------------------------------------*/
  797. PPLAYERCONN RemoveConnFromSocketHash(LPGLOBALDATA pgd, PPLAYERCONN pConnIn)
  798. {
  799. PPLAYERCONN pConn=NULL,pConnPrev;
  800. UINT i;
  801. if(pConnIn->dwFlags & PLYR_SOCKHASH){
  802. i=HashSocket(&pConnIn->IOSock.sockaddr);
  803. DPF(8,"Removing Player %x from Socket Hash\n",pConnIn);
  804. EnterCriticalSection(&pgd->csFast);
  805. pConn = pgd->SocketHash[i];
  806. pConnPrev = CONTAINING_RECORD(&pgd->SocketHash[i], PLAYERCONN, pNextS); // sneaky
  807. while(pConn && pConn!=pConnIn){
  808. pConnPrev = pConn;
  809. pConn = pConn->pNextS;
  810. }
  811. if(pConn){
  812. pConnPrev->pNextS = pConn->pNextS;
  813. pConn->dwFlags &= ~(PLYR_SOCKHASH);
  814. i=DecRefConn(pgd, pConn); // remove reference for socket hash table
  815. ASSERT(i);
  816. }
  817. LeaveCriticalSection(&pgd->csFast);
  818. }
  819. return pConn;
  820. }
  821. /*=============================================================================
  822. FindConnInPendingList - finds a connection from the pending list
  823. Description:
  824. Parameters:
  825. pgd - Service Provider's global data blob for this instance
  826. pConn - connection to put in the hash table.
  827. Return Values:
  828. PPLAYERCONN - pointer ot connection if found, and adds a reference.
  829. -----------------------------------------------------------------------------*/
  830. PPLAYERCONN FindConnInPendingList(LPGLOBALDATA pgd, SOCKADDR *psaddr)
  831. {
  832. PPLAYERCONN pConnWalker=NULL, pConn=NULL;
  833. BILINK *pBilink;
  834. EnterCriticalSection(&pgd->csFast);
  835. pBilink=pgd->InboundPendingList.next;
  836. while(pBilink != &pgd->InboundPendingList){
  837. pConnWalker=CONTAINING_RECORD(pBilink, PLAYERCONN, InboundPendingList);
  838. if(bSameAddr(psaddr, &pConnWalker->IOnlySock.sockaddr)){
  839. AddRefConn(pConnWalker);
  840. pConn=pConnWalker;
  841. break;
  842. }
  843. pBilink=pBilink->next;
  844. }
  845. if(pConn){
  846. DPF(8,"Found Conn %x in Pending List\n",pConn);
  847. DUMPCONN(pConn,3);
  848. AddRefConn(pConn);
  849. }
  850. LeaveCriticalSection(&pgd->csFast);
  851. return pConn;
  852. }
  853. /*=============================================================================
  854. AddConnToPendingList - puts a connection on the pending list
  855. Description:
  856. The Pending list keeps the list of connections that we have received
  857. from, but haven't received any information on yet. Until we receive
  858. from one of these connections, we don't have any way to know exactly
  859. who the connection is from. When we receive from one of these with
  860. a return address in the message, we can make an association with
  861. an outbound connection (if present) and can put this node in the
  862. socket hash table at that time.
  863. Parameters:
  864. pgd - Service Provider's global data blob for this instance
  865. pConn - connection to put in the hash table.
  866. Return Values:
  867. None.
  868. -----------------------------------------------------------------------------*/
  869. HRESULT AddConnToPendingList(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  870. {
  871. PPLAYERCONN pConn2;
  872. INT i;
  873. HRESULT hr=DP_OK;
  874. EnterCriticalSection(&pgd->csFast);
  875. if(pConn2 = FindConnInPendingList(pgd, &pConn->IOnlySock.sockaddr)){
  876. // OPTIMIZATION: should we remove the socket from the list here, it must be old.
  877. DPF(0,"AddConnToPendingList: Player in %x id %d already exists, pConn=%x\n",pConn,pConn->dwPlayerID,pConn2);
  878. DecRefConn(pgd, pConn2);
  879. hr=DPERR_GENERIC;
  880. goto exit;
  881. }
  882. InsertAfter(&pConn->InboundPendingList,&pgd->InboundPendingList);
  883. AddRefConn(pConn);
  884. pConn->dwFlags |= PLYR_PENDINGLIST;
  885. DPF(8,"Added Conn %x to PendingList\n",pConn);
  886. exit:
  887. LeaveCriticalSection(&pgd->csFast);
  888. return hr;
  889. }
  890. /*=============================================================================
  891. RemoveConnFromPendingList
  892. Description:
  893. Parameters:
  894. pgd - Service Provider's global data blob for this instance
  895. pConn - connection to put in the hash table.
  896. Return Values:
  897. None.
  898. -----------------------------------------------------------------------------*/
  899. VOID RemoveConnFromPendingList(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  900. {
  901. if(pConn->dwFlags & PLYR_PENDINGLIST)
  902. {
  903. ASSERT(!EMPTY_BILINK(&pConn->InboundPendingList));
  904. Delete(&pConn->InboundPendingList);
  905. pConn->dwFlags &= ~(PLYR_PENDINGLIST);
  906. DecRefConn(pgd, pConn);
  907. DPF(8,"Removed Conn %x From Pending List\n",pConn);
  908. }
  909. }
  910. /*=============================================================================
  911. GetPlayerConn - Finds or creates a player conn and starts connecting it.
  912. Description:
  913. Parameters:
  914. pgd - Service Provider's global data blob for this instance
  915. dpid - dpid of the player (if known)
  916. psockaddr - socket address (if known)
  917. Return Values:
  918. if found, creates a reference.
  919. -----------------------------------------------------------------------------*/
  920. PPLAYERCONN GetPlayerConn(LPGLOBALDATA pgd, DPID dpid, SOCKADDR *psockaddr)
  921. {
  922. PPLAYERCONN pConn=NULL;
  923. SOCKET sSocket;
  924. SOCKADDR_IN saddr;
  925. INT rc,err;
  926. DWORD dwSize;
  927. BOOL bTrue=TRUE;
  928. u_long lNonBlock = 1; // passed to ioctlsocket to make socket non-blocking
  929. u_long lBlock = 0; // passed to ioctlsocket to make socket blocking
  930. BOOL bCreated=FALSE;
  931. EnterCriticalSection(&pgd->csFast);
  932. // Do we already know this player by id?
  933. if(dpid != DPID_UNKNOWN) {
  934. if (pConn=FindPlayerById(pgd, dpid))
  935. {
  936. DPF(8,"GetPlayerConn: Found Con for dpid %x pConn %x\n",dpid,pConn);
  937. goto exit; //Player already exists for this id.
  938. }
  939. }
  940. if(pConn=FindPlayerBySocket(pgd, psockaddr)){
  941. if(pConn->dwFlags & (PLYR_CONNECTED|PLYR_CONN_PENDING))
  942. {
  943. DPF(8,"GetPlayerConn: Found Conn by socketaddr pConn %x\n",pConn);
  944. if(dpid != DPID_UNKNOWN){
  945. pConn->dwPlayerID=dpid;
  946. AddConnToPlayerHash(pgd, pConn);
  947. }
  948. DUMPCONN(pConn,1);
  949. goto exit;
  950. }
  951. } else {
  952. // do we already know this player by connection?
  953. if(psockaddr && (pConn=FindConnInPendingList(pgd, psockaddr)) )
  954. {
  955. //NOTE: I think we always catch this case in FastCombine
  956. // We may get it before the combine happens?
  957. if(!(pConn->dwFlags & PLYR_CONNECTED|PLYR_CONN_PENDING)){ //only once...
  958. // hey, this is a bi-directional socket, so make it so.
  959. ASSERT(pConn->dwPlayerID == DPID_UNKNOWN);
  960. if((dpid != DPID_UNKNOWN) && (pConn->dwPlayerID == DPID_UNKNOWN))
  961. {
  962. ASSERT(! (pConn->dwFlags & PLYR_DPIDHASH));
  963. pConn->dwPlayerID = dpid;
  964. AddConnToPlayerHash(pgd, pConn);
  965. }
  966. if(!(pConn->dwFlags & PLYR_SOCKHASH)){
  967. AddConnToSocketHash(pgd, pConn);
  968. }
  969. ASSERT(pConn->sSocketIn != INVALID_SOCKET);
  970. ASSERT(pConn->sSocket == INVALID_SOCKET);
  971. pConn->sSocket = pConn->sSocketIn;
  972. pConn->sSocketIn = INVALID_SOCKET;
  973. if(pConn->dwFlags & PLYR_ACCEPTED){
  974. pConn->dwFlags |= (PLYR_CONNECTED | PLYR_NEW_CLIENT);
  975. } else {
  976. ASSERT(pConn->dwFlags & PLYR_ACCEPT_PENDING);
  977. pConn->dwFlags |= (PLYR_CONN_PENDING | PLYR_NEW_CLIENT);
  978. }
  979. RemoveConnFromPendingList(pgd,pConn); // found a home, don't need on pending list anymore
  980. }
  981. DPF(8,"GetPlayerConn FoundConn in Pending List pConn %x\n",pConn);
  982. DUMPCONN(pConn,3);
  983. goto exit;
  984. }
  985. }
  986. // Have critical section...
  987. // Doesn't already exist, so create one.
  988. if(!pConn){
  989. DPF(8,"GetPlayerConn: No Conn Found, creating\n");
  990. pConn = CreatePlayerConn(pgd, dpid, psockaddr);
  991. if(!pConn){
  992. DPF(8, "CreatePlayerConn Failed\n");
  993. goto exit;
  994. }
  995. if(dpid != DPID_UNKNOWN)AddConnToPlayerHash(pgd, pConn);
  996. if(psockaddr)AddConnToSocketHash(pgd,pConn);
  997. bCreated=TRUE;
  998. AddRefConn(pConn); // need ref to return to caller.
  999. } else {
  1000. // already have ref to return to caller as result of find.
  1001. }
  1002. // have critical section and a pConn, maybe created (see bCreated), and a return ref.
  1003. ASSERT(pConn->sSocket == INVALID_SOCKET);
  1004. ASSERT(!(pConn->dwFlags & (PLYR_CONN_PENDING|PLYR_CONNECTED)));
  1005. //if(pgd->bSeparateIO && !(pgd->SystemStreamPortOut))
  1006. ASSERT(pgd->bSeparateIO);
  1007. {
  1008. // Workaround Win9x < Millennium sockets bug. Can't use same port for
  1009. // inbound/outbound traffic, because Win9x will not accept connections in
  1010. // some cases. So we create a socket for outbound traffic (and re-use
  1011. // that port for all outbound traffic).
  1012. rc=CreateSocket(pgd, &sSocket, SOCK_STREAM, 0, INADDR_ANY, &err, FALSE);
  1013. if(rc != DP_OK){
  1014. DPF(0,"Couldn't create Outbound socket on Win9x < Millennium platform, rc=%x , wserr=%d\n",rc, err);
  1015. goto err_exit;
  1016. }
  1017. dwSize = sizeof(saddr);
  1018. err=getsockname(sSocket, (SOCKADDR *)&saddr, &dwSize);
  1019. if(err){
  1020. DPF(0,"Couldn't get socket name?\n");
  1021. DEBUG_BREAK();
  1022. }
  1023. //pgd->SystemStreamPortOut = saddr.sin_port;
  1024. //DPF(2,"System stream out port is now %d.",ntohs(pgd->SystemStreamPortOut));
  1025. DPF(2,"Stream out socket %x port is now %d.",sSocket, ntohs(saddr.sin_port));
  1026. bTrue = SetSharedPortAccess(sSocket);
  1027. if (! bTrue)
  1028. {
  1029. DPF(0,"Failed to to set shared mode on socket - continue\n");
  1030. }
  1031. }
  1032. /*
  1033. else
  1034. {
  1035. // Normal execution path.
  1036. sSocket = socket(AF_INET, SOCK_STREAM, 0);
  1037. // Bind it to our system address (so we only use one address for a change)
  1038. memset(&saddr,0,sizeof(SOCKADDR_IN));
  1039. saddr.sin_family = AF_INET;
  1040. saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  1041. if(pgd->bSeparateIO && pgd->SystemStreamPortOut){
  1042. saddr.sin_port = pgd->SystemStreamPortOut; // part of Win9x Hack. (see above)
  1043. } else {
  1044. saddr.sin_port = pgd->SystemStreamPort;
  1045. }
  1046. ASSERT(pgd->SystemStreamPort);
  1047. DPF(7,"Using port %d.",ntohs(saddr.sin_port));
  1048. // Set socket for address re-use
  1049. bTrue = SetSharedPortAccess(sSocket);
  1050. if (! bTrue)
  1051. {
  1052. DPF(0,"Failed to to set shared mode on socket - continue\n");
  1053. }
  1054. rc = bind(sSocket, (SOCKADDR *)&saddr, sizeof(saddr));
  1055. if(rc){
  1056. err = WSAGetLastError();
  1057. DPF(0,"Failed to bind socket to port %d, error=%d.",ntohs(saddr.sin_port),err);
  1058. goto err_exit; // sends will fail until player killed.
  1059. }
  1060. }
  1061. */
  1062. // turn ON keepalive
  1063. if (SOCKET_ERROR == setsockopt(sSocket, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  1064. {
  1065. err = WSAGetLastError();
  1066. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  1067. }
  1068. ASSERT(bTrue);
  1069. // turn off nagling - always, avoids race on closing socket w/o linger, otherwise must linger socket.
  1070. DPF(5, "Turning nagling off on outbound socket");
  1071. if (SOCKET_ERROR == setsockopt(sSocket, IPPROTO_TCP, TCP_NODELAY, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  1072. {
  1073. err = WSAGetLastError();
  1074. DPF(0,"Failed to turn off naggling - continue : err = %d\n",err);
  1075. }
  1076. // update connection info.
  1077. pConn->dwFlags |= PLYR_CONN_PENDING;
  1078. pConn->sSocket = sSocket;
  1079. //
  1080. // Now Connect this puppy
  1081. //
  1082. // set socket to non-blocking
  1083. rc = ioctlsocket(sSocket,FIONBIO,&lNonBlock);
  1084. if (SOCKET_ERROR == rc)
  1085. {
  1086. err = WSAGetLastError();
  1087. DPF(0,"could not set non-blocking mode on socket err = %d!",err);
  1088. DPF(0,"will revert to synchronous behavior. bummer");
  1089. }
  1090. FastPlayerEventSelect(pgd,pConn, TRUE);
  1091. DEBUGPRINTADDR(4, "Fast connecting socket:", psockaddr);
  1092. rc = connect(sSocket,psockaddr,sizeof(SOCKADDR));
  1093. if(SOCKET_ERROR == rc)
  1094. {
  1095. err = WSAGetLastError();
  1096. if(err == WSAEISCONN || err == WSAEADDRINUSE || err == WSAEACCES){
  1097. // must be an accept about to happen
  1098. DPF(8,"Hey, we're already connected! got extended error %d on connect\n",err);
  1099. pConn->dwFlags |= PLYR_ACCEPT_PENDING;
  1100. } else if (err == WSAEWOULDBLOCK) {
  1101. // this is what we should normally get.
  1102. DPF(8,"Conn is pending connection %x\n",pConn);
  1103. } else if (err == WSAEHOSTUNREACH) {
  1104. DEBUGPRINTADDR(8,"Can't reach host, not connecting\n",psockaddr);
  1105. goto err_exit;
  1106. } else if (err == WSAENOBUFS) {
  1107. DEBUGPRINTADDR(8,"Winsock out of memory, not connecting\n",psockaddr);
  1108. goto err_exit;
  1109. } else {
  1110. DPF(0,"Trying to connect UH OH, very bad things, err=%d\n",err);
  1111. DEBUG_BREAK();
  1112. goto err_exit; // sends will fail until player deleted.
  1113. }
  1114. } else {
  1115. // Very unlikely, but WOO HOO, connected.
  1116. DPF(0,"Very surprising, connect didn't return pending on async call?");
  1117. pConn->dwFlags &= ~(PLYR_CONN_PENDING);
  1118. pConn->dwFlags |= PLYR_CONNECTED;
  1119. }
  1120. exit:
  1121. LeaveCriticalSection(&pgd->csFast);
  1122. DPF(8,"<===GetPlayerConn %x\n",pConn);
  1123. return pConn;
  1124. err_exit:
  1125. pConn->dwFlags &= ~(PLYR_CONN_PENDING);
  1126. if(bCreated){
  1127. // better blow it away.
  1128. DPF(0,"GetPlayerConn: Severe error connection Conn we made, so blowing it away.\n");
  1129. CleanPlayerConn(pgd,pConn,TRUE); // clean up
  1130. DecRefConnExist(pgd,pConn); // dump existence
  1131. DecRefConn(pgd,pConn); // bye bye...(ref we had for caller)
  1132. } else {
  1133. if(pConn) {
  1134. DecRefConn(pgd,pConn);
  1135. }
  1136. }
  1137. pConn=NULL; // Connection Lost.
  1138. goto exit;
  1139. }
  1140. /*=============================================================================
  1141. FastPlayerEventSelect - start listening for events for a player.
  1142. Description:
  1143. Starts the appropriate events waiting for a signal for a
  1144. PlayerConn structure.
  1145. Parameters:
  1146. pgd - Service Provider's global data blob for this instance
  1147. pConn - Player to start waiting for events on
  1148. Return Values:
  1149. -----------------------------------------------------------------------------*/
  1150. HRESULT FastPlayerEventSelect(LPGLOBALDATA pgd, PPLAYERCONN pConn, BOOL bSelect)
  1151. {
  1152. HRESULT hr=DP_OK;
  1153. DWORD lEvents;
  1154. INT rc;
  1155. UINT err;
  1156. DPF(8,"FastPlayerEventSelect pConn %x, bSelect %d\n",pConn, bSelect);
  1157. DUMPCONN(pConn,0);
  1158. if(pConn->sSocket != INVALID_SOCKET){
  1159. if(bSelect){
  1160. lEvents = FD_READ|FD_CLOSE;
  1161. if(pConn->dwFlags & PLYR_CONN_PENDING){
  1162. lEvents |= FD_CONNECT;
  1163. }
  1164. if(!EMPTY_BILINK(&pConn->PendingConnSendQ)){
  1165. lEvents |= FD_WRITE;
  1166. }
  1167. } else {
  1168. lEvents = 0;
  1169. }
  1170. DPF(8,"Selecting %x on IO Socket...\n",lEvents);
  1171. DEBUGPRINTADDR(8,"IO Socket",&pConn->IOSock.sockaddr);
  1172. rc=g_WSAEventSelect(pConn->sSocket, pgd->EventHandles[pConn->iEventHandle],lEvents);
  1173. if(rc == SOCKET_ERROR){
  1174. err = WSAGetLastError();
  1175. DPF(0,"FastPlayerEventSelect: failed to do select on 2-way socket extended error=%d\n",err);
  1176. hr=DPERR_GENERIC;
  1177. }
  1178. }
  1179. if(pConn->sSocketIn != INVALID_SOCKET){
  1180. if(bSelect){
  1181. lEvents = FD_READ|FD_CLOSE;
  1182. } else {
  1183. lEvents = 0;
  1184. }
  1185. DPF(8,"Selecting %x on IOnly Socket...\n",lEvents);
  1186. DEBUGPRINTADDR(8,"IOnly Socket",&pConn->IOnlySock.sockaddr);
  1187. rc=g_WSAEventSelect(pConn->sSocketIn, pgd->EventHandles[pConn->iEventHandle], lEvents);
  1188. if(rc == SOCKET_ERROR){
  1189. err = WSAGetLastError();
  1190. DPF(0,"FastPlayerEventSelect: failed to do select on receive-only socket extended error=%d\n",err);
  1191. hr=DPERR_GENERIC;
  1192. }
  1193. }
  1194. DPF(8,"<==FastPlayerEventSelect pConn %x\n",pConn);
  1195. return hr;
  1196. }
  1197. /*=============================================================================
  1198. FastStreamReceiveThreadProc - version of stream recevie thread proc
  1199. that uses Winsock 2.0 functions for
  1200. greater speed.
  1201. Description:
  1202. Parameters:
  1203. pgd - Service Provider's global data blob for this instance
  1204. pConn - connection to put in the hash table.
  1205. Return Values:
  1206. PPLAYERCONN - removed from hash, here it is.
  1207. NULL - couldn't find it.
  1208. -----------------------------------------------------------------------------*/
  1209. DWORD WINAPI FastStreamReceiveThreadProc(LPVOID pvCast)
  1210. {
  1211. IDirectPlaySP * pISP = (IDirectPlaySP *)pvCast;
  1212. HRESULT hr;
  1213. UINT i,j;
  1214. UINT err;
  1215. INT rc;
  1216. DWORD dwDataSize = sizeof(GLOBALDATA);
  1217. LPGLOBALDATA pgd;
  1218. WSANETWORKEVENTS NetEvents1, NetEvents2;
  1219. LPWSANETWORKEVENTS pNetEvents1, pNetEvents2;
  1220. DWORD Event;
  1221. PPLAYERCONN pConn;
  1222. DWORD nConn;
  1223. // get the global data
  1224. hr = pISP->lpVtbl->GetSPData(pISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  1225. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  1226. {
  1227. DPF_ERR("FastStreamReceiveThreadProc: couldn't get SP data from DirectPlay - failing");
  1228. ExitThread(0);
  1229. return 0;
  1230. }
  1231. pgd->pISP = pISP; // why not do this somewhere easier? -- because old dplay didn't.
  1232. listen(pgd->sSystemStreamSocket, 200);
  1233. err = g_WSAEventSelect(pgd->sSystemStreamSocket, pgd->hAccept, FD_ACCEPT);
  1234. if(err){
  1235. err = WSAGetLastError();
  1236. DPF(0,"FastStreamReceiveThreadProc: Event select for accept socket failed err=%d\n",err);
  1237. ExitThread(0);
  1238. return 0;
  1239. }
  1240. while (1)
  1241. {
  1242. if (pgd->bShutdown)
  1243. {
  1244. DPF(2,"FastStreamReceiveThreadProc: detected shutdown - bailing");
  1245. goto CLEANUP_EXIT;
  1246. }
  1247. Event=WaitForMultipleObjectsEx(NUM_EVENT_HANDLES+1, &pgd->hAccept, FALSE, 2500, TRUE);
  1248. if(Event != WAIT_TIMEOUT)
  1249. {
  1250. i = Event - WAIT_OBJECT_0;
  1251. if( i <= NUM_EVENT_HANDLES)
  1252. {
  1253. DPF(8,"GotSignal on iEvent %d Event %x\n", i, pgd->EventHandles[i]);
  1254. // Go to the signalled object and look for events on its sockets.
  1255. if(i != 0){
  1256. i--; // go from hAccept based index to table index.
  1257. EnterCriticalSection(&pgd->csFast);
  1258. // loop through the connections tied to this event and
  1259. // see if there is any work to do for this connection.
  1260. nConn=pgd->EventList[i].nConn;
  1261. for (j=0;j<nConn;j++){
  1262. pConn = pgd->EventList[i].pConn[j];
  1263. if(pConn){
  1264. AddRefConn(pConn); // lock it down.
  1265. pConn->bCombine=FALSE;
  1266. // Check for events on the connection.
  1267. NetEvents1.lNetworkEvents=0;
  1268. NetEvents2.lNetworkEvents=0;
  1269. pNetEvents1=NULL;
  1270. pNetEvents2=NULL;
  1271. if(pConn->sSocket != INVALID_SOCKET){
  1272. rc=g_WSAEnumNetworkEvents(pConn->sSocket, 0, &NetEvents1);
  1273. if(NetEvents1.lNetworkEvents){
  1274. pNetEvents1 = &NetEvents1;
  1275. }
  1276. }
  1277. if(pConn->sSocketIn != INVALID_SOCKET){
  1278. rc=g_WSAEnumNetworkEvents(pConn->sSocketIn, 0, &NetEvents2);
  1279. if(NetEvents2.lNetworkEvents){
  1280. pNetEvents2 = &NetEvents2;
  1281. }
  1282. }
  1283. if(pNetEvents1 || pNetEvents2){
  1284. DPF(8,"Found Events on Connection %x\n",pConn);
  1285. // There are events for this connection, deal with it!
  1286. hr=ProcessConnEvents(pgd, pConn, pNetEvents1, pNetEvents2); // can drop csFast
  1287. if(FAILED(hr)){
  1288. if(hr==DPERR_CONNECTIONLOST){
  1289. CleanPlayerConn(pgd, pConn, TRUE);
  1290. DecRefConnExist(pgd, pConn); // destory existence ref.
  1291. } else {
  1292. DPF(0,"Unexpected error processing connection events err=%x\n",hr);
  1293. }
  1294. }
  1295. }
  1296. if(pConn->bCombine || (nConn != pgd->EventList[i].nConn)){
  1297. // list changed, re-scan.
  1298. nConn = pgd->EventList[i].nConn;
  1299. j=0;
  1300. }
  1301. DecRefConn(pgd, pConn); // set it free
  1302. }
  1303. }
  1304. LeaveCriticalSection(&pgd->csFast);
  1305. } else {
  1306. // it's the accept socket, someone just connected to us. Yeah!
  1307. do{
  1308. rc = g_WSAEnumNetworkEvents(pgd->sSystemStreamSocket,0,&NetEvents1);
  1309. if(NetEvents1.lNetworkEvents & FD_ACCEPT)
  1310. {
  1311. EnterCriticalSection(&pgd->csFast);
  1312. FastAccept(pgd, &NetEvents1);
  1313. LeaveCriticalSection(&pgd->csFast);
  1314. }
  1315. }while(NetEvents1.lNetworkEvents & FD_ACCEPT);
  1316. }
  1317. }
  1318. }
  1319. }// while TRUE
  1320. CLEANUP_EXIT:
  1321. return 0;
  1322. } // StreamReceiveThreadProc
  1323. /*=============================================================================
  1324. FastHandleMessage - Indicate a message to the DirectPlay layer.
  1325. Description:
  1326. Parameters:
  1327. pgd - Service Provider's global data blob for this instance
  1328. pConn - connection to put in the hash table.
  1329. Return Values:
  1330. -----------------------------------------------------------------------------*/
  1331. HRESULT FastHandleMessage(LPGLOBALDATA pgd, PPLAYERCONN *ppConn)
  1332. {
  1333. PPLAYERCONN pConn = *ppConn;
  1334. if(SP_MESSAGE_TOKEN(pConn->pReceiveBuffer)==TOKEN && pConn->cbReceived != SPMESSAGEHEADERLEN)
  1335. {
  1336. ASSERT(pgd->AddressFamily == AF_INET);
  1337. if(pConn->dwFlags & PLYR_NEW_CLIENT){
  1338. IP_SetAddr((LPVOID)pConn->pReceiveBuffer, &pConn->IOSock.sockaddr_in);
  1339. } else {
  1340. IP_SetAddr((LPVOID)pConn->pReceiveBuffer, &pConn->IOnlySock.sockaddr_in);
  1341. }
  1342. if( !(pConn->dwFlags & PLYR_OLD_CLIENT) && // already combined
  1343. (pConn->sSocket == INVALID_SOCKET) && // just checking
  1344. !(pConn->lNetEventsSocketIn & FD_CLOSE) // don't bother if we're gonna blow it away
  1345. ){
  1346. LPMESSAGEHEADER phead = (LPMESSAGEHEADER)pConn->pReceiveBuffer;
  1347. pConn=*ppConn=FastCombine(pgd, pConn, &(phead->sockaddr));
  1348. }
  1349. LeaveCriticalSection(&pgd->csFast);
  1350. #if DUMPBYTES
  1351. {
  1352. PCHAR pBuf;
  1353. UINT buflen;
  1354. UINT i=0;
  1355. pBuf = pConn->pReceiveBuffer+sizeof(MESSAGEHEADER);
  1356. buflen = pConn->cbReceived-sizeof(MESSAGEHEADER);
  1357. while (((i + 16) < buflen) && (i < 4*16)){
  1358. DPF(9, "%08x %08x %08x %08x",*(PUINT)(&pBuf[i]),*(PUINT)(&pBuf[i+4]),*(PUINT)(&pBuf[i+8]),*(PUINT)(&pBuf[i+12]));
  1359. i += 16;
  1360. }
  1361. }
  1362. #endif
  1363. pgd->pISP->lpVtbl->HandleMessage(pgd->pISP,
  1364. pConn->pReceiveBuffer+sizeof(MESSAGEHEADER),
  1365. pConn->cbReceived-sizeof(MESSAGEHEADER),
  1366. pConn->pReceiveBuffer);
  1367. EnterCriticalSection(&pgd->csFast);
  1368. if(pConn->pReceiveBuffer != pConn->pDefaultReceiveBuffer){
  1369. DPF(8,"Releasing big receive buffer of size %d\n",pConn->cbReceiveBuffer);
  1370. SP_MemFree(pConn->pReceiveBuffer);
  1371. }
  1372. pConn->cbReceived=0;
  1373. pConn->cbExpected=0;
  1374. pConn->cbReceiveBuffer = DEFAULT_RECEIVE_BUFFERSIZE;
  1375. pConn->pReceiveBuffer=pConn->pDefaultReceiveBuffer;
  1376. if(pConn->pReceiveBuffer != (PCHAR)(pConn+1)){
  1377. DEBUG_BREAK();
  1378. }
  1379. }
  1380. return DP_OK;
  1381. }
  1382. /*=============================================================================
  1383. FastReceive - Receive data on a connection.
  1384. Description:
  1385. First receives a message header, then receives the message.
  1386. When a full message is received, it is indicated.
  1387. Parameters:
  1388. pgd - Service Provider's global data blob for this instance
  1389. pConn - connection to put in the hash table.
  1390. Return Values:
  1391. -----------------------------------------------------------------------------*/
  1392. HRESULT FastReceive(LPGLOBALDATA pgd, PPLAYERCONN *ppConn)
  1393. {
  1394. PPLAYERCONN pConn;
  1395. PCHAR pBuffer; // receive buffer pointer.
  1396. DWORD cbBuffer; // receive buffer size.
  1397. SOCKET sSocket; // socket to receive on
  1398. INT err; // sockets error.
  1399. DWORD cbReceived; // actual bytes received on this recv call.
  1400. DWORD cbMessageSize=0; // size of the message to receive
  1401. HRESULT hr;
  1402. pConn=*ppConn;
  1403. if(pConn->cbExpected == 0){
  1404. // all messages have a header, let get that first.
  1405. pConn->cbExpected = SPMESSAGEHEADERLEN;
  1406. }
  1407. // point to place in buffer we're going to receive latest data.
  1408. // don't get more than we expect, or we would have to be smart
  1409. // about setting up messages.
  1410. pBuffer = pConn->pReceiveBuffer+pConn->cbReceived;
  1411. cbBuffer = pConn->cbExpected-pConn->cbReceived;
  1412. if(cbBuffer > pConn->cbReceiveBuffer){
  1413. DPF(0,"Receive would overrun buffer\n");
  1414. DEBUG_BREAK();
  1415. }
  1416. if(pConn->dwFlags & PLYR_NEW_CLIENT){
  1417. // new client does bi-directional on socket.
  1418. sSocket = pConn->sSocket;
  1419. } else {
  1420. // old clients have separate receive socket.
  1421. sSocket = pConn->sSocketIn;
  1422. }
  1423. ASSERT(sSocket != INVALID_SOCKET);
  1424. DPF(8,"Attempting to receive %d bytes", cbBuffer);
  1425. DEBUGPRINTSOCK(8,">>> receiving data on socket - ",&sSocket);
  1426. cbReceived = recv(sSocket, pBuffer, cbBuffer, 0); // <----- Receive that data!
  1427. if(cbReceived == 0){
  1428. // remote side has shutdown connection gracefully
  1429. DEBUGPRINTSOCK(8,"<<< received notification on socket - ",&sSocket);
  1430. DEBUGPRINTSOCK(5,"Remote side has shutdown connection gracefully - ",&sSocket);
  1431. hr = DPERR_CONNECTIONLOST;
  1432. goto ERROR_EXIT;
  1433. } else if (cbReceived == SOCKET_ERROR){
  1434. err = WSAGetLastError();
  1435. if(err == WSAEWOULDBLOCK){
  1436. DPF(1,"WARN: Got WSAEWOULDBLOCK on non-blocking receive, round and round we go...\n");
  1437. goto exit;
  1438. }
  1439. DEBUGPRINTSOCK(8,"<<< received notification on socket - ",&sSocket);
  1440. DPF(0,"STREAMRECEIVEE: receive error - err = %d",err);
  1441. hr = DPERR_CONNECTIONLOST;
  1442. goto ERROR_EXIT;
  1443. }
  1444. DPF(5, "received %d bytes", cbReceived);
  1445. pConn->cbReceived += cbReceived;
  1446. if(pConn->cbReceived == SPMESSAGEHEADERLEN){
  1447. // got the header, set up for the body of the message.
  1448. if(VALID_DPWS_MESSAGE(pConn->pReceiveBuffer))
  1449. {
  1450. cbMessageSize = SP_MESSAGE_SIZE(pConn->pReceiveBuffer);
  1451. } else {
  1452. // Bad data. Shut this baby down!
  1453. DPF(2,"got invalid message - token = 0x%08x",SP_MESSAGE_TOKEN(pConn->pReceiveBuffer));
  1454. hr = DPERR_CONNECTIONLOST;
  1455. goto ERROR_EXIT;
  1456. }
  1457. }
  1458. if(cbMessageSize)
  1459. {
  1460. pConn->cbExpected = cbMessageSize;
  1461. if(cbMessageSize > DEFAULT_RECEIVE_BUFFERSIZE){
  1462. if(!pConn->bTrusted){
  1463. // until the connection is trusted, don't allow big messages to come in.
  1464. DPF(0,"Rejecting large receive size %d, on untrusted connection pConn %x, dropping link",cbMessageSize);
  1465. hr=DPERR_CONNECTIONLOST;
  1466. goto ERROR_EXIT;
  1467. }
  1468. pConn->pReceiveBuffer = SP_MemAlloc(cbMessageSize);
  1469. if(!pConn->pReceiveBuffer){
  1470. DPF(0,"Failed to allocate receive buffer for message - out of memory");
  1471. hr=DPERR_CONNECTIONLOST;
  1472. goto ERROR_EXIT;
  1473. }
  1474. pConn->cbReceiveBuffer = cbMessageSize;
  1475. // copy header into new message buffer
  1476. memcpy(pConn->pReceiveBuffer, pConn->pDefaultReceiveBuffer, SPMESSAGEHEADERLEN);
  1477. }
  1478. }
  1479. if(pConn->cbExpected == pConn->cbReceived)
  1480. {
  1481. // hey, got a whole message, send it up.
  1482. hr = FastHandleMessage(pgd, ppConn); // <---- INDICATE THE MESSAGE
  1483. #ifdef DEBUG
  1484. if(pConn != *ppConn){
  1485. DPF(8,"Connections pConn %x pNewConn %x combined\n",pConn, *ppConn);
  1486. }
  1487. #endif
  1488. pConn = *ppConn;
  1489. if(FAILED(hr)){
  1490. goto ERROR_EXIT;
  1491. }
  1492. }
  1493. exit:
  1494. return DP_OK;
  1495. ERROR_EXIT:
  1496. return hr;
  1497. }
  1498. /*=============================================================================
  1499. QueueSendOnConn - queue a send on a connection until we know it is ok to send.
  1500. Description:
  1501. Note: can only have 1 send outstanding to winsock per socket because of a winsock bug.
  1502. Parameters:
  1503. pgd - Service Provider's global data blob for this instance
  1504. pConn - connection to put in the hash table.
  1505. pSendInfo - send to queue.
  1506. Return Values:
  1507. PPLAYERCONN - removed from hash, here it is.
  1508. NULL - couldn't find it.
  1509. -----------------------------------------------------------------------------*/
  1510. VOID QueueSendOnConn(LPGLOBALDATA pgd, PPLAYERCONN pConn, PSENDINFO pSendInfo)
  1511. {
  1512. EnterCriticalSection(&pgd->csFast);
  1513. InsertBefore(&pSendInfo->PendingConnSendQ, &pConn->PendingConnSendQ);
  1514. LeaveCriticalSection(&pgd->csFast);
  1515. }
  1516. /*=============================================================================
  1517. QueueNextSend - Move a pending send into the real sendq.
  1518. Description:
  1519. Parameters:
  1520. pgd - Service Provider's global data blob for this instance
  1521. pConn - connection to put in the hash table.
  1522. pSendInfo - send to queue.
  1523. Return Values:
  1524. PPLAYERCONN - removed from hash, here it is.
  1525. NULL - couldn't find it.
  1526. -----------------------------------------------------------------------------*/
  1527. VOID QueueNextSend(LPGLOBALDATA pgd,PPLAYERCONN pConn)
  1528. {
  1529. BILINK *pBilink;
  1530. EnterCriticalSection(&pgd->csFast);
  1531. DPF(8,"==>QueueNextSend pConn %x",pConn);
  1532. while(!EMPTY_BILINK(&pConn->PendingConnSendQ) && !pConn->bSendOutstanding)
  1533. {
  1534. PSENDINFO pSendInfo;
  1535. pBilink=pConn->PendingConnSendQ.next;
  1536. pSendInfo=CONTAINING_RECORD(pBilink, SENDINFO, PendingConnSendQ);
  1537. Delete(pBilink);
  1538. DPF(8,"QueueNextSend: Queuing pConn %x pSendInfo %x\n",pConn,pSendInfo);
  1539. QueueForSend(pgd,pSendInfo);
  1540. }
  1541. DPF(8,"<==QueueNextSend pConn %x",pConn);
  1542. LeaveCriticalSection(&pgd->csFast);
  1543. }
  1544. /*=============================================================================
  1545. FastCombine - see if this socket should be made bidirectional
  1546. Description:
  1547. There are 3 cases where we want to combine connections.
  1548. 1. We have accepted the connection, we receive data and that
  1549. data tells us the back connection is an existing outbound
  1550. connection. In this case we combine the connections
  1551. a. The return address is the same as the from address,
  1552. in this case it is a NEW client, and we mark it so
  1553. and will use the same connection for outbound traffic
  1554. b. The return address is different thant the from address
  1555. in this case it is an OLD client, and we mark it so
  1556. and will need to establish the outbound connection
  1557. later.
  1558. 2. We receive data on a connection and there is no outbound
  1559. connection yet, but inbound and outbound connections are
  1560. different. We know that it is an "old" client and
  1561. eventually we will have to connect back. We mark the
  1562. connection as OLD and when the connection back is
  1563. made it will use this same Connection since it will match
  1564. up on the target address.
  1565. Parameters:
  1566. pgd - Service Provider's global data blob for this instance
  1567. pConn - connection to put in the hash table.
  1568. psockaddr - outbound socket address.
  1569. Return Values:
  1570. PPLAYERCONN pConn - if this isn't the same as the pConn on the way
  1571. in, then the connections have been combined.
  1572. - the old connection will disappear when decrefed.
  1573. - a reference is added for the returned connection
  1574. if it is not the original.
  1575. Note: csFast Held across this call. Nothing here is supposed to block...?
  1576. -----------------------------------------------------------------------------*/
  1577. PPLAYERCONN FastCombine(LPGLOBALDATA pgd, PPLAYERCONN pConn, SOCKADDR *psockaddr_in)
  1578. {
  1579. PPLAYERCONN pConnFind=NULL;
  1580. SOCKADDR sockaddr,*psockaddr;
  1581. // See if there is already a player with this target address...
  1582. DPF(8,"==>FastCombine pConn %x\n",pConn);
  1583. DEBUGPRINTADDR(8,"==>FastCombine saddr",psockaddr_in);
  1584. #if USE_RSIP
  1585. if(pgd->sRsip != INVALID_SOCKET){
  1586. HRESULT hr;
  1587. hr=rsipQueryLocalAddress(pgd, TRUE, psockaddr_in, &sockaddr);
  1588. if(hr==DP_OK){
  1589. psockaddr=&sockaddr;
  1590. } else {
  1591. psockaddr=psockaddr_in;
  1592. }
  1593. } else {
  1594. psockaddr=psockaddr_in;
  1595. }
  1596. #elif USE_NATHELP
  1597. if(pgd->pINatHelp){
  1598. HRESULT hr;
  1599. hr=IDirectPlayNATHelp_QueryAddress(
  1600. pgd->pINatHelp,
  1601. &pgd->INADDRANY,
  1602. psockaddr_in,
  1603. &sockaddr,
  1604. sizeof(SOCKADDR_IN),
  1605. DPNHQUERYADDRESS_TCP|DPNHQUERYADDRESS_CACHENOTFOUND
  1606. );
  1607. if(hr==DP_OK){
  1608. psockaddr=&sockaddr;
  1609. } else {
  1610. psockaddr=psockaddr_in;
  1611. }
  1612. } else {
  1613. psockaddr=psockaddr_in;
  1614. }
  1615. #else
  1616. psockaddr=psockaddr_in;
  1617. #endif
  1618. if(!pConn->bCombine) // don't combine more than once, we can't handle it.
  1619. {
  1620. pConnFind=FindPlayerBySocket(pgd, psockaddr);
  1621. if(pConnFind){
  1622. // We already have a connection to this guy. See if the back-connection
  1623. // is dead, if it is merge the two.
  1624. ASSERT(pConnFind != pConn);
  1625. if(!(pConnFind->dwFlags & (PLYR_ACCEPTED|PLYR_ACCEPT_PENDING))){
  1626. // In order to get here, the client must be an old style client.
  1627. // Otherwise, the connect for the outbound would have failed, since
  1628. // we would be re-using the address.
  1629. // Already correctly in the socket hash.
  1630. // Old conn gets pulled from pending list by CleanPlayerConn.
  1631. ASSERT(pConnFind->sSocketIn == INVALID_SOCKET);
  1632. DPF(8,"FastCombine: Merging Connections pConn %x, pConnFound %x\n",pConn,pConnFind);
  1633. DUMPCONN(pConn,3);
  1634. DUMPCONN(pConnFind,3);
  1635. //
  1636. // Merge the receive socket into the outbound player connection.
  1637. //
  1638. // copy socket information
  1639. pConnFind->sSocketIn = pConn->sSocketIn;
  1640. memcpy(&pConnFind->IOnlySock.sockaddr, &pConn->IOnlySock.sockaddr, sizeof(SOCKADDR));
  1641. // copy over receive data.
  1642. pConnFind->cbExpected = pConn->cbExpected;
  1643. pConnFind->cbReceived = pConn->cbReceived;
  1644. if(pConn->pReceiveBuffer != pConn->pDefaultReceiveBuffer){
  1645. pConnFind->pReceiveBuffer = pConn->pReceiveBuffer;
  1646. pConnFind->cbReceiveBuffer = pConn->cbReceiveBuffer;
  1647. pConn->pReceiveBuffer = pConn->pDefaultReceiveBuffer;
  1648. } else {
  1649. ASSERT(pConn->cbReceiveBuffer == DEFAULT_RECEIVE_BUFFERSIZE);
  1650. memcpy(pConnFind->pReceiveBuffer, pConn->pReceiveBuffer, pConn->cbReceived);
  1651. }
  1652. pConnFind->dwFlags |= (PLYR_ACCEPTED | PLYR_OLD_CLIENT);
  1653. // point events to the correct connection. Overrides old conn's select.
  1654. // Do this first so we don't drop any events.
  1655. pConnFind->lNetEventsSocketIn=pConn->lNetEventsSocketIn;
  1656. pConnFind->lNetEventsSocket=pConn->lNetEventsSocket;
  1657. FastPlayerEventSelect(pgd, pConnFind, TRUE);
  1658. // clean up old connection, but don't close the socket
  1659. pConn->dwFlags &= ~(PLYR_ACCEPTED);
  1660. pConn->sSocketIn = INVALID_SOCKET;
  1661. ASSERT(pConn->sSocket==INVALID_SOCKET);
  1662. CleanPlayerConn(pgd, pConn, FALSE);
  1663. pConn->bCombine=TRUE; // tell receive thread, to reload.
  1664. DecRefConnExist(pgd, pConn); // destroy existence ref
  1665. DPF(8,"MergedConn pConnFound%x\n",pConnFind);
  1666. DUMPCONN(pConnFind,3);
  1667. pConnFind->bCombine=TRUE; // to prevent re-combine.
  1668. if(pConn->bTrusted){
  1669. pConnFind->bTrusted=TRUE;
  1670. }
  1671. // leaves 1 reference for the caller.
  1672. return pConnFind;
  1673. }
  1674. DecRefConn(pgd, pConnFind); // found but can't combine... dump find ref.
  1675. }
  1676. } else {
  1677. DPF(0,"Called Fast Combine with already combined connection, may be bad\n");
  1678. }
  1679. // if we got here, we didn't combine.
  1680. if(bSameAddr(psockaddr,&pConn->IOnlySock.sockaddr)){
  1681. // If destination and source sockets match
  1682. // Promote this one to do both
  1683. pConn->sSocket = pConn->sSocketIn;
  1684. pConn->sSocketIn = INVALID_SOCKET;
  1685. pConn->dwFlags |= (PLYR_NEW_CLIENT | PLYR_CONNECTED);
  1686. if(!(pConn->dwFlags & PLYR_SOCKHASH)){// Hmmm, maybe always already in it.
  1687. AddConnToSocketHash(pgd, pConn);
  1688. }
  1689. RemoveConnFromPendingList(pgd, pConn);
  1690. DPF(8,"FastCombine: Promoted Connection to Bi-Directional %x\n",pConn);
  1691. DUMPCONN(pConn,3);
  1692. } else {
  1693. ASSERT(!(pConn->dwFlags & PLYR_NEW_CLIENT));
  1694. pConn->dwFlags |= PLYR_OLD_CLIENT;
  1695. // Remove from inbound hash, change to outbound hash.
  1696. memcpy(&pConn->IOSock.sockaddr, psockaddr, sizeof(SOCKADDR));
  1697. if(pConnFind && (pConnFind->dwFlags & (PLYR_CONNECTED|PLYR_CONN_PENDING))){
  1698. // already connecting...
  1699. } else {
  1700. // ok this is the back connection.
  1701. RemoveConnFromPendingList(pgd, pConn);
  1702. RemoveConnFromSocketHash(pgd, pConn);
  1703. AddConnToSocketHash(pgd, pConn);
  1704. }
  1705. DPF(8,"FastCombine: Connection is Old Client %x\n",pConn);
  1706. DUMPCONN(pConn,3);
  1707. }
  1708. FastPlayerEventSelect(pgd,pConn,TRUE); // make sure we're listening to all the right things.
  1709. DPF(8,"<==FastCombine\n");
  1710. return pConn;
  1711. }
  1712. /*=============================================================================
  1713. FastDropInbound - drop the inbound port for an old style client.
  1714. Description:
  1715. Parameters:
  1716. pgd - Service Provider's global data blob for this instance
  1717. pConn - connection to put in the hash table.
  1718. Return Values:
  1719. -----------------------------------------------------------------------------*/
  1720. VOID FastDropInbound(LPGLOBALDATA pgd, PPLAYERCONN pConn)
  1721. {
  1722. LINGER Linger;
  1723. int err;
  1724. LPREPLYLIST prd;
  1725. #ifdef DEBUG
  1726. DWORD dwTime;
  1727. dwTime=timeGetTime();
  1728. #endif
  1729. // See if there is already a player with this target address...
  1730. DPF(8, "==>FastDropInbound pConn %x",pConn);
  1731. pConn->dwFlags &= ~(PLYR_OLD_CLIENT|PLYR_ACCEPTED|PLYR_ACCEPT_PENDING);
  1732. if (pConn->sSocketIn != INVALID_SOCKET)
  1733. {
  1734. // Hard close inbound socket to avoid TIME_WAIT.
  1735. BOOL bNoLinger=TRUE;
  1736. if (SOCKET_ERROR == setsockopt( pConn->sSocketIn,SOL_SOCKET,SO_DONTLINGER,(char FAR *)&bNoLinger,sizeof(bNoLinger)))
  1737. {
  1738. DPF(0, "FastDropInbound:Couldn't set linger to \"don't linger\".");
  1739. }
  1740. }
  1741. RemoveConnFromPendingList(pgd, pConn);
  1742. if(pConn->sSocketIn != INVALID_SOCKET)
  1743. {
  1744. err=g_WSAEventSelect(pConn->sSocketIn, 0, 0);
  1745. if (err)
  1746. {
  1747. err=GetLastError();
  1748. DPF(8, "Error trying to deselect sSocketIn %d.",pConn->sSocketIn);
  1749. }
  1750. else
  1751. {
  1752. DPF(8, "Deselected socket %d.",pConn->sSocketIn);
  1753. }
  1754. ENTER_DPSP();
  1755. prd=SP_MemAlloc(sizeof(REPLYLIST));
  1756. if (!prd)
  1757. {
  1758. LEAVE_DPSP();
  1759. DPF(1, "Closing Socket %d immediately.", pConn->sSocketIn);
  1760. myclosesocket(pgd,pConn->sSocketIn);
  1761. }
  1762. else
  1763. {
  1764. DPF(4, "Beginning delayed socket %d close.", pConn->sSocketIn);
  1765. // very tricky, overloading the reply close list to close this socket with our own linger...
  1766. prd->pNextReply=pgd->pReplyCloseList;
  1767. pgd->pReplyCloseList=prd;
  1768. prd->sSocket=pConn->sSocketIn;
  1769. prd->tSent=timeGetTime();
  1770. prd->lpMessage=NULL;
  1771. LEAVE_DPSP();
  1772. }
  1773. pConn->sSocketIn = INVALID_SOCKET;
  1774. }
  1775. //memset(&pConn->IOnlySock,0,sizeof(pConn->IOnlySock));
  1776. //
  1777. // reset receive information.
  1778. //
  1779. // Free extra buffer.
  1780. if (pConn->pReceiveBuffer != pConn->pDefaultReceiveBuffer)
  1781. {
  1782. SP_MemFree(pConn->pReceiveBuffer);
  1783. }
  1784. pConn-> cbReceiveBuffer=DEFAULT_RECEIVE_BUFFERSIZE;
  1785. pConn->cbReceived=0;
  1786. pConn->cbExpected=0;
  1787. #ifdef DEBUG
  1788. dwTime = timeGetTime()-dwTime;
  1789. if(dwTime > 1000)
  1790. {
  1791. DPF(0, "Took way too long in FastDropInbound, elapsed %d ms.",dwTime);
  1792. //DEBUG_BREAK(); // removed break due to stress hits.
  1793. }
  1794. #endif
  1795. // Will shut down select for inbound.(done before close now.
  1796. //FastPlayerEventSelect(pgd,pConn,TRUE);
  1797. DPF(8, "<==FastDropInbound");
  1798. }
  1799. /*=============================================================================
  1800. ProcessConnEvents - handle the events on a connection.
  1801. Description:
  1802. Parameters:
  1803. pgd - Service Provider's global data blob for this instance
  1804. pConn - connection to put in the hash table.
  1805. pSockEvents - socket events on the bi-directional socket OR NULL
  1806. pSockInEvents - socket events for the inbound only socket OR NULL
  1807. Return Values:
  1808. PPLAYERCONN - removed from hash, here it is.
  1809. NULL - couldn't find it.
  1810. -----------------------------------------------------------------------------*/
  1811. HRESULT ProcessConnEvents(
  1812. LPGLOBALDATA pgd,
  1813. PPLAYERCONN pConn,
  1814. LPWSANETWORKEVENTS pSockEvents,
  1815. LPWSANETWORKEVENTS pSockInEvents
  1816. )
  1817. {
  1818. WSANETWORKEVENTS SockEvents;
  1819. HRESULT hr=DP_OK;
  1820. INT err;
  1821. PPLAYERCONN pConnIn; // connection passed by FastStreamReceiveThreadProc;
  1822. pConnIn=pConn;
  1823. DPF(8,"==>ProcessConnEvents pConn %x\n",pConn);
  1824. // store in the conn, so downstream routines know what we're processing.
  1825. if(pSockEvents){
  1826. pConn->lNetEventsSocket=pSockEvents->lNetworkEvents;
  1827. } else {
  1828. pConn->lNetEventsSocket=0;
  1829. }
  1830. if(pSockInEvents){
  1831. pConn->lNetEventsSocketIn=pSockInEvents->lNetworkEvents;
  1832. } else {
  1833. pConn->lNetEventsSocketIn=0;
  1834. }
  1835. if(pSockEvents){
  1836. DPF(8,"SockEvents %x pConn %x\n",pSockEvents->lNetworkEvents,pConn);
  1837. if(pSockEvents->lNetworkEvents & FD_READ){
  1838. // Keep reading until all the readings done.
  1839. ASSERT(!pSockInEvents);
  1840. ASSERT(!(pConn->dwFlags & PLYR_OLD_CLIENT));
  1841. pConn->dwFlags |= (PLYR_NEW_CLIENT|PLYR_ACCEPTED);
  1842. do {
  1843. // will indicate data if whole message received.
  1844. hr=FastReceive(pgd, &pConn); // can drop csFast
  1845. if(hr!=DP_OK){
  1846. goto exit;
  1847. }
  1848. err=g_WSAEnumNetworkEvents(pConn->sSocket, 0, &SockEvents);
  1849. if(err==SOCKET_ERROR){
  1850. err = WSAGetLastError();
  1851. DPF(8,"Error on EnumNetworkEvents, LastError = %d\n",err);
  1852. goto exit;
  1853. } else {
  1854. DPF(8,"ProcessConnEvents, Polling Sock NetEvents pConn %d Events %x\n",pConn, SockEvents.lNetworkEvents);
  1855. }
  1856. if(SockEvents.lNetworkEvents & FD_CLOSE && !(pSockEvents->lNetworkEvents & FD_CLOSE)){
  1857. pSockEvents->lNetworkEvents |= FD_CLOSE;
  1858. pSockEvents->iErrorCode[FD_CLOSE_BIT] = SockEvents.iErrorCode[FD_CLOSE_BIT];
  1859. }
  1860. } while (SockEvents.lNetworkEvents & FD_READ);
  1861. }
  1862. if(pSockEvents->lNetworkEvents & FD_WRITE){
  1863. // connection succeeded, send any pending sends now
  1864. QueueNextSend(pgd,pConn);
  1865. pConn->dwFlags |= PLYR_CONNECTED;
  1866. pConn->dwFlags &= ~(PLYR_CONN_PENDING);
  1867. g_WSAEventSelect(pConn->sSocket, pgd->EventHandles[pConn->iEventHandle], FD_READ|FD_CLOSE);
  1868. }
  1869. if(pSockEvents->lNetworkEvents & FD_CONNECT)
  1870. {
  1871. // Check the connect status.
  1872. if(pSockEvents->iErrorCode[FD_CONNECT_BIT]){
  1873. DPF(0,"Connect Error %d\n",pSockEvents->iErrorCode[FD_CONNECT_BIT]);
  1874. hr=DPERR_CONNECTIONLOST;
  1875. goto exit;
  1876. }
  1877. // don't want to know about connect any more...
  1878. pConn->dwFlags |= PLYR_CONNECTED;
  1879. pConn->dwFlags &= ~(PLYR_CONN_PENDING);
  1880. g_WSAEventSelect(pConn->sSocket, pgd->EventHandles[pConn->iEventHandle], FD_READ|FD_WRITE|FD_CLOSE);
  1881. }
  1882. if(pSockEvents->lNetworkEvents & FD_CLOSE)
  1883. {
  1884. DPF(8,"Outbound (Maybe I/O) Connection Closed\n");
  1885. hr=DPERR_CONNECTIONLOST;
  1886. goto exit;
  1887. }
  1888. }
  1889. if(pSockInEvents)
  1890. {
  1891. ASSERT(!(pConn->dwFlags & PLYR_NEW_CLIENT));
  1892. DPF(8,"SockEvents (IOnly) %x pConn %x\n",pSockInEvents->lNetworkEvents, pConn);
  1893. // Need to read first, don't want to drop the data on close
  1894. if(pSockInEvents->lNetworkEvents & FD_READ)
  1895. {
  1896. do{
  1897. // Careful here, we may combine connections changing pConn.
  1898. hr=FastReceive(pgd, &pConn); // can drop csFast
  1899. if(hr!=DP_OK)
  1900. {
  1901. FastDropInbound(pgd, pConn);
  1902. hr=DP_OK;
  1903. goto exit;
  1904. }
  1905. if(pConn->sSocketIn == INVALID_SOCKET){
  1906. // new pConn may be bi-directional.
  1907. if(pConn->sSocket == INVALID_SOCKET){
  1908. hr=DPERR_CONNECTIONLOST;
  1909. goto exit;
  1910. } else {
  1911. hr=DP_OK;
  1912. goto exit;
  1913. }
  1914. }
  1915. err=g_WSAEnumNetworkEvents(pConn->sSocketIn, 0, &SockEvents);
  1916. if(err==SOCKET_ERROR){
  1917. err = WSAGetLastError();
  1918. DPF(8,"Error on EnumNetworkEvents, LastError = %d\n",err);
  1919. goto exit;
  1920. } else {
  1921. DPF(8,"ProcessConnEvents, Polling SockIn NetEvents pConn %x Events %x\n",pConn,SockEvents.lNetworkEvents);
  1922. }
  1923. if((SockEvents.lNetworkEvents & FD_CLOSE) && !(pSockInEvents->lNetworkEvents & FD_CLOSE)){
  1924. pSockInEvents->lNetworkEvents |= FD_CLOSE;
  1925. pSockInEvents->iErrorCode[FD_CLOSE_BIT] = SockEvents.iErrorCode[FD_CLOSE_BIT];
  1926. }
  1927. } while (SockEvents.lNetworkEvents & FD_READ);
  1928. }
  1929. if(pSockInEvents->lNetworkEvents & FD_CLOSE)
  1930. {
  1931. if(pConn->sSocket == INVALID_SOCKET){
  1932. DPF(8,"ProcessConn Events, Got Close on Inbound Only, returning ConnectionLost\n");
  1933. ASSERT(!(pConn->dwFlags & (PLYR_CONN_PENDING|PLYR_CONNECTED)));
  1934. hr=DPERR_CONNECTIONLOST;
  1935. } else {
  1936. DPF(8,"ProcessConn Events, Got Close on I/O Connection dropping inbound only.\n");
  1937. FastDropInbound(pgd, pConn);
  1938. hr=DP_OK;
  1939. }
  1940. goto exit;
  1941. }
  1942. }
  1943. exit:
  1944. pConn->lNetEventsSocket=0;
  1945. pConn->lNetEventsSocketIn=0;
  1946. if(pConn != pConnIn){
  1947. // During a call to FastReceive, connections were combined and
  1948. // we were given a reference, now we drop that reference.
  1949. DecRefConn(pgd, pConn);
  1950. }
  1951. DPF(8,"<==ProcessConnEvents hr=0x%x\n",hr);
  1952. return hr;
  1953. }
  1954. /*=============================================================================
  1955. FastAccept - accept a connection
  1956. Description:
  1957. Parameters:
  1958. pgd - Service Provider's global data blob for this instance
  1959. pNetEvents - socket events on the accept socket
  1960. Return Values:
  1961. Note: csFast held across this call. Nothing here should block.
  1962. -----------------------------------------------------------------------------*/
  1963. VOID FastAccept(LPGLOBALDATA pgd, LPWSANETWORKEVENTS pNetEvents)
  1964. {
  1965. SOCKADDR sockaddr;
  1966. INT addrlen = sizeof(sockaddr);
  1967. SOCKET sSocket;
  1968. PPLAYERCONN pConn;
  1969. UINT err; // last error
  1970. DPF(8,"==>FastAccept\n");
  1971. sSocket = accept(pgd->sSystemStreamSocket,&sockaddr,&addrlen);
  1972. if (INVALID_SOCKET == sSocket)
  1973. {
  1974. err = WSAGetLastError();
  1975. DPF(2,"FastAccept: stream accept error - err = %d socket = %d",err,(DWORD)sSocket);
  1976. DEBUG_BREAK();
  1977. } else {
  1978. // All our sockets have KEEPALIVE...
  1979. BOOL bTrue = TRUE;
  1980. DEBUGPRINTADDR(5,"FastAccept - accepted connection from",&sockaddr);
  1981. // turn ON keepalive
  1982. if (SOCKET_ERROR == setsockopt(sSocket, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  1983. {
  1984. err = WSAGetLastError();
  1985. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  1986. }
  1987. // add the new socket to our receive q
  1988. // need to allocate a connection structure, lets see if someone is waiting on this accept
  1989. pConn=FindPlayerBySocket(pgd, &sockaddr);
  1990. if(pConn){
  1991. if(pConn->sSocket == INVALID_SOCKET){
  1992. // we found the connection because a connect is waiting for it.
  1993. ASSERT(pConn->dwFlags & PLYR_ACCEPT_PENDING);
  1994. ASSERT(pConn->dwFlags & PLYR_NEW_CLIENT);
  1995. ASSERT(bSameAddr(&sockaddr, &pConn->IOSock.sockaddr));
  1996. pConn->sSocket = sSocket;
  1997. pConn->dwFlags &= ~(PLYR_ACCEPT_PENDING);
  1998. pConn->dwFlags |= (PLYR_CONNECTED|PLYR_ACCEPTED);
  1999. FastPlayerEventSelect(pgd,pConn,TRUE);
  2000. DPF(8,"Found Pending Connection, now connected\n");
  2001. DUMPCONN(pConn,3);
  2002. } else {
  2003. if(TRUE /*pgd->bSeparateIO*/){
  2004. // more work for Win9x < Mill
  2005. // 8/30/00 ao - now we turn this on in all cases because we need to allow
  2006. // for a NATed client to have different inbound and outbound connections to
  2007. // workaround the NAT PAST bug where it picks a random from port for
  2008. // the outbound link when we haven't received before sending on an ASSIGNED port.
  2009. DPF(0,"New client connecting back to me, but I treat as old for compat\n");
  2010. pConn->sSocketIn=sSocket;
  2011. pConn->dwFlags |= PLYR_ACCEPTED|PLYR_OLD_CLIENT;
  2012. pConn->bCombine=TRUE;
  2013. FastPlayerEventSelect(pgd,pConn,TRUE);
  2014. } else {
  2015. DPF(0,"Nice race, already have a connection pConn %x, re-use\n", pConn);
  2016. closesocket(sSocket);
  2017. }
  2018. }
  2019. DecRefConn(pgd, pConn); // remove reference from FindPlayerBySocket().
  2020. } else {
  2021. if(pConn=FindConnInPendingList(pgd, &sockaddr)){
  2022. // This guy's in the pending list, blow old conn away.
  2023. DPF(8,"Found Accept for Player in Pending List, blow away old one\n");
  2024. CleanPlayerConn(pgd, pConn, TRUE);
  2025. DecRefConnExist(pgd, pConn); // dump existence ref.
  2026. DecRefConn(pgd, pConn); // dump our ref.
  2027. }
  2028. //
  2029. // No connection, we need to create one.
  2030. //
  2031. // make sure we have room.
  2032. if(pgd->nEventSlotsAvail && (pConn = CreatePlayerConn(pgd, DPID_UNKNOWN, &sockaddr))){
  2033. DPF(8,"Creating new Connection for Accept %x\n",pConn);
  2034. // put on pending list...
  2035. pConn->sSocketIn = sSocket;
  2036. AddConnToPendingList(pgd, pConn);
  2037. pConn->dwFlags |= PLYR_ACCEPTED;
  2038. FastPlayerEventSelect(pgd, pConn, TRUE);
  2039. } else {
  2040. // No room for more accept events ... blow this socket out!
  2041. LINGER Linger;
  2042. DPF(0,"FastAccept: VERY BAD, Out of Event Slots, can't accept any new connections, killing this one\n");
  2043. Linger.l_onoff=FALSE;
  2044. Linger.l_linger=0;
  2045. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger, sizeof(Linger) ) ){
  2046. err = WSAGetLastError();
  2047. DPF(0,"Couldn't set linger on socket, can't kill now, so it will be an orphan...bad.bad.bad\n");
  2048. } else {
  2049. // don't need to shutdown the socket, since we don't have any data on it.
  2050. myclosesocket(pgd,sSocket);
  2051. }
  2052. }
  2053. }
  2054. }
  2055. DPF(8,"<==FastAccept\n");
  2056. }
  2057. /*=============================================================================
  2058. FastInternalReliableSend - reliable send using fast socket code.
  2059. Description:
  2060. Parameters:
  2061. Return Values:
  2062. -----------------------------------------------------------------------------*/
  2063. HRESULT FastInternalReliableSend(LPGLOBALDATA pgd, LPDPSP_SENDDATA psd, SOCKADDR *lpSockAddr)
  2064. {
  2065. HRESULT hr=DP_OK;
  2066. SOCKET sSocket = INVALID_SOCKET;
  2067. UINT err;
  2068. PPLAYERCONN pConn=NULL;
  2069. LPSENDINFO pSendInfo=NULL;
  2070. PCHAR pBuffer=NULL;
  2071. DPID idPlayerTo;
  2072. DPF(6, "FastInternalReliableSend: Parameters: (0x%x, 0x%x, 0x%x)",
  2073. pgd, psd, lpSockAddr);
  2074. EnterCriticalSection(&pgd->csFast);
  2075. if(psd->idPlayerTo){
  2076. idPlayerTo=psd->idPlayerTo;
  2077. } else {
  2078. idPlayerTo=DPID_UNKNOWN;
  2079. }
  2080. pConn = GetPlayerConn(pgd, idPlayerTo, lpSockAddr); // adds a ref
  2081. if(!pConn){
  2082. hr=DPERR_CONNECTIONLOST;
  2083. goto exit;
  2084. }
  2085. // Always go async, since we are on a non-blocking mode socket.
  2086. {
  2087. // make this puppy asynchronous.... malloc ICK!
  2088. pSendInfo = pgd->pSendInfoPool->Get(pgd->pSendInfoPool);
  2089. pBuffer = SP_MemAlloc(psd->dwMessageSize);
  2090. if(!pSendInfo || !pBuffer){
  2091. hr=DPERR_OUTOFMEMORY;
  2092. goto CLEANUP_EXIT;
  2093. }
  2094. SetReturnAddress(psd->lpMessage,pgd->sSystemStreamSocket,SERVICE_SADDR_PUBLIC(pgd));
  2095. memcpy(pBuffer, psd->lpMessage, psd->dwMessageSize);
  2096. pSendInfo->SendArray[0].buf = pBuffer;
  2097. pSendInfo->SendArray[0].len = psd->dwMessageSize;
  2098. pSendInfo->iFirstBuf = 0;
  2099. pSendInfo->cBuffers = 1;
  2100. pSendInfo->sSocket = pConn->sSocket;
  2101. //CommonInitForSend
  2102. pSendInfo->pConn = pConn;
  2103. pSendInfo->dwMessageSize= psd->dwMessageSize;
  2104. pSendInfo->dwUserContext= 0;
  2105. pSendInfo->RefCount = 3; // one for completion, 1 for this routine, 1 for async completion of send.
  2106. pSendInfo->pgd = pgd;
  2107. pSendInfo->lpISP = pgd->pISP;
  2108. pSendInfo->Status = DP_OK;
  2109. pSendInfo->idTo = psd->idPlayerTo;
  2110. pSendInfo->idFrom = psd->idPlayerFrom;
  2111. pSendInfo->dwSendFlags = psd->dwFlags|DPSEND_ASYNC;
  2112. pSendInfo->dwFlags = SI_RELIABLE | SI_INTERNALBUFF;
  2113. EnterCriticalSection(&pgd->csSendEx);
  2114. InsertBefore(&pSendInfo->PendingSendQ,&pgd->PendingSendQ);
  2115. pgd->dwBytesPending += psd->dwMessageSize;
  2116. pgd->dwMessagesPending += 1;
  2117. LeaveCriticalSection(&pgd->csSendEx);
  2118. // End CommonInit for Send.
  2119. if((pConn->dwFlags & PLYR_CONNECTED) && EMPTY_BILINK(&pConn->PendingConnSendQ) && !pConn->bSendOutstanding){
  2120. QueueForSend(pgd, pSendInfo); // send it
  2121. } else {
  2122. QueueSendOnConn(pgd, pConn, pSendInfo);
  2123. }
  2124. wsaoDecRef(pSendInfo);
  2125. }
  2126. // success
  2127. hr = DP_OK;
  2128. exit:
  2129. if(pConn){
  2130. DecRefConn(pgd,pConn);
  2131. }
  2132. LeaveCriticalSection(&pgd->csFast);
  2133. DPF(6, "FastInternalReliableSend: Returning: [0x%lx] (exit)", hr);
  2134. return hr;
  2135. CLEANUP_EXIT:
  2136. if(pConn){
  2137. DecRefConn(pgd, pConn); // balance Get
  2138. }
  2139. LeaveCriticalSection(&pgd->csFast);
  2140. if(pBuffer){
  2141. SP_MemFree(pBuffer);
  2142. }
  2143. if(pSendInfo){
  2144. SP_MemFree(pSendInfo);
  2145. }
  2146. DPF(6, "FastInternalReliableSend: Returning: [0x%lx] (cleanup exit)", hr);
  2147. return hr;
  2148. }
  2149. /*=============================================================================
  2150. FastInternalReliableSendEx - reliable send using fast socket code.
  2151. Description:
  2152. Parameters:
  2153. Return Values:
  2154. -----------------------------------------------------------------------------*/
  2155. HRESULT FastInternalReliableSendEx(LPGLOBALDATA pgd, LPDPSP_SENDEXDATA psd, LPSENDINFO pSendInfo, SOCKADDR *lpSockAddr)
  2156. {
  2157. HRESULT hr=DP_OK;
  2158. SOCKET sSocket = INVALID_SOCKET;
  2159. UINT err;
  2160. PPLAYERCONN pConn=NULL;
  2161. PCHAR pBuffer=NULL;
  2162. DPID idPlayerTo;
  2163. UINT i;
  2164. DWORD dwOffset;
  2165. DPF(6, "FastInternalReliableSendEx: Parameters: (0x%x, 0x%x, 0x%x, 0x%x)",
  2166. pgd, psd, pSendInfo, lpSockAddr);
  2167. EnterCriticalSection(&pgd->csFast);
  2168. if(psd->idPlayerTo){
  2169. idPlayerTo=psd->idPlayerTo;
  2170. } else {
  2171. idPlayerTo=DPID_UNKNOWN;
  2172. }
  2173. pConn = GetPlayerConn(pgd, idPlayerTo, lpSockAddr); // adds a ref
  2174. if(!pConn){
  2175. hr=DPERR_CONNECTIONLOST;
  2176. goto exit;
  2177. }
  2178. // SECURITY: we will trust anyone we send data to.
  2179. pConn->bTrusted = TRUE;
  2180. // Always go async, since we are on a non-blocking mode socket.
  2181. {
  2182. // make this puppy asynchronous.... malloc ICK!
  2183. if(!(psd->dwFlags & DPSEND_ASYNC))
  2184. {
  2185. pBuffer = SP_MemAlloc(psd->dwMessageSize+sizeof(MESSAGEHEADER));
  2186. if(!pBuffer){
  2187. hr=DPERR_OUTOFMEMORY;
  2188. goto CLEANUP_EXIT;
  2189. }
  2190. }
  2191. pSendInfo->sSocket = pConn->sSocket;
  2192. //CommonInitForSend
  2193. pSendInfo->pConn = pConn;
  2194. pSendInfo->dwMessageSize = psd->dwMessageSize;
  2195. pSendInfo->dwUserContext = (DWORD_PTR)psd->lpDPContext;
  2196. pSendInfo->RefCount = 3; // one for completion, 1 for this routine, 1 for async completion of send.
  2197. pSendInfo->pgd = pgd;
  2198. pSendInfo->lpISP = pgd->pISP;
  2199. pSendInfo->Status = DP_OK;
  2200. pSendInfo->idTo = psd->idPlayerTo;
  2201. pSendInfo->idFrom = psd->idPlayerFrom;
  2202. pSendInfo->dwSendFlags = psd->dwFlags|DPSEND_ASYNC;
  2203. pSendInfo->iFirstBuf = 0;
  2204. if(psd->dwFlags & DPSEND_ASYNC) {
  2205. pSendInfo->dwFlags = SI_RELIABLE;
  2206. pSendInfo->cBuffers = psd->cBuffers+1;
  2207. } else {
  2208. // in sync case we need to copy the buffers since the upper layer
  2209. // is expecting ownership back immediately. Sync sends can't expect
  2210. // thrilling performance anyway so this should not show up in perf.
  2211. // copy message into one contiguous buffer.
  2212. dwOffset=0;
  2213. for( i = 0 ; i < psd->cBuffers+1 ; i++)
  2214. {
  2215. memcpy(pBuffer+dwOffset, pSendInfo->SendArray[i].buf, pSendInfo->SendArray[i].len);
  2216. dwOffset += pSendInfo->SendArray[i].len;
  2217. }
  2218. pSendInfo->dwFlags = SI_RELIABLE | SI_INTERNALBUFF;
  2219. pSendInfo->cBuffers = 1;
  2220. pSendInfo->SendArray[0].buf = pBuffer;
  2221. pSendInfo->SendArray[0].len = psd->dwMessageSize+sizeof(MESSAGEHEADER);
  2222. }
  2223. EnterCriticalSection(&pgd->csSendEx);
  2224. InsertBefore(&pSendInfo->PendingSendQ,&pgd->PendingSendQ);
  2225. pgd->dwBytesPending += psd->dwMessageSize;
  2226. pgd->dwMessagesPending += 1;
  2227. LeaveCriticalSection(&pgd->csSendEx);
  2228. // End CommonInit for Send.
  2229. if((pConn->dwFlags & PLYR_CONNECTED) && EMPTY_BILINK(&pConn->PendingConnSendQ) && !pConn->bSendOutstanding){
  2230. QueueForSend(pgd, pSendInfo); // send it
  2231. } else {
  2232. QueueSendOnConn(pgd, pConn, pSendInfo);
  2233. }
  2234. wsaoDecRef(pSendInfo);
  2235. }
  2236. // success
  2237. if(psd->dwFlags & DPSEND_ASYNC)
  2238. {
  2239. hr = DPERR_PENDING;
  2240. }else {
  2241. hr = DP_OK;
  2242. }
  2243. exit:
  2244. if(pConn){
  2245. DecRefConn(pgd,pConn);
  2246. }
  2247. LeaveCriticalSection(&pgd->csFast);
  2248. DPF(6, "FastInternalReliableSendEx: Returning: [0x%lx] (exit)", hr);
  2249. return hr;
  2250. CLEANUP_EXIT:
  2251. if(pConn){
  2252. DecRefConn(pgd, pConn); // balance Get
  2253. }
  2254. LeaveCriticalSection(&pgd->csFast);
  2255. if(pBuffer){
  2256. SP_MemFree(pBuffer);
  2257. }
  2258. DPF(6, "FastInternalReliableSendEx: Returning: [0x%lx] (cleanup exit)", hr);
  2259. return hr;
  2260. }
  2261. /*=============================================================================
  2262. FastReply - reliable reply using fast socket code.
  2263. Description:
  2264. Parameters:
  2265. Return Values:
  2266. -----------------------------------------------------------------------------*/
  2267. HRESULT FastReply(LPGLOBALDATA pgd, LPDPSP_REPLYDATA prd, DPID dwPlayerID)
  2268. {
  2269. HRESULT hr=DP_OK;
  2270. SOCKET sSocket = INVALID_SOCKET;
  2271. UINT err;
  2272. PPLAYERCONN pConn=NULL;
  2273. LPSENDINFO pSendInfo=NULL;
  2274. PCHAR pBuffer=NULL;
  2275. SOCKADDR *psaddr;
  2276. LPMESSAGEHEADER phead;
  2277. DPF(8,"==>FastReply\n");
  2278. phead=(LPMESSAGEHEADER)prd->lpSPMessageHeader;
  2279. psaddr=&phead->sockaddr;
  2280. if(dwPlayerID == 0){
  2281. dwPlayerID = DPID_UNKNOWN;
  2282. }
  2283. EnterCriticalSection(&pgd->csFast);
  2284. pConn = GetPlayerConn(pgd, dwPlayerID, psaddr); // adds a ref
  2285. if(!pConn){
  2286. hr = DPERR_CONNECTIONLOST;
  2287. goto exit;
  2288. }
  2289. // make this puppy asynchronous.... malloc ICK!
  2290. pSendInfo = pgd->pSendInfoPool->Get(pgd->pSendInfoPool);
  2291. pBuffer = SP_MemAlloc(prd->dwMessageSize);
  2292. if(!pSendInfo || !pBuffer){
  2293. hr=DPERR_OUTOFMEMORY;
  2294. goto CLEANUP_EXIT;
  2295. }
  2296. SetReturnAddress(prd->lpMessage,pgd->sSystemStreamSocket,SERVICE_SADDR_PUBLIC(pgd));
  2297. memcpy(pBuffer, prd->lpMessage, prd->dwMessageSize);
  2298. pSendInfo->SendArray[0].buf = pBuffer;
  2299. pSendInfo->SendArray[0].len = prd->dwMessageSize;
  2300. pSendInfo->iFirstBuf = 0;
  2301. pSendInfo->cBuffers = 1;
  2302. pSendInfo->sSocket = pConn->sSocket;
  2303. //CommonInitForSend
  2304. pSendInfo->pConn = pConn;
  2305. pSendInfo->dwMessageSize= prd->dwMessageSize;
  2306. pSendInfo->dwUserContext= 0;
  2307. pSendInfo->RefCount = 3; // one for send routine, one for completion, 1 for this routine
  2308. pSendInfo->pgd = pgd;
  2309. pSendInfo->lpISP = pgd->pISP;
  2310. pSendInfo->Status = DP_OK;
  2311. pSendInfo->idTo = dwPlayerID;
  2312. pSendInfo->idFrom = 0;
  2313. pSendInfo->dwSendFlags = DPSEND_GUARANTEE|DPSEND_ASYNC;
  2314. pSendInfo->Status = DP_OK;
  2315. pSendInfo->dwFlags = SI_RELIABLE | SI_INTERNALBUFF;
  2316. EnterCriticalSection(&pgd->csSendEx);
  2317. InsertBefore(&pSendInfo->PendingSendQ,&pgd->PendingSendQ);
  2318. pgd->dwBytesPending += prd->dwMessageSize;
  2319. pgd->dwMessagesPending += 1;
  2320. LeaveCriticalSection(&pgd->csSendEx);
  2321. DPF(9,"pConn->dwFlags & PLYR_CONNECTED = %x",pConn->dwFlags & PLYR_CONNECTED);
  2322. DPF(9,"EMPTY_BILINK PendingConnSendQ = %x",EMPTY_BILINK(&pConn->PendingConnSendQ));
  2323. DPF(9,"!pConn->bSendOutstanding = %x",!pConn->bSendOutstanding);
  2324. // End CommonInit for Send.
  2325. if((pConn->dwFlags & PLYR_CONNECTED) && EMPTY_BILINK(&pConn->PendingConnSendQ) && !pConn->bSendOutstanding){
  2326. DPF(9,"==>QueueForSend");
  2327. QueueForSend(pgd, pSendInfo); // send it
  2328. } else {
  2329. DPF(9,"==>QueueSendOnConn");
  2330. QueueSendOnConn(pgd, pConn, pSendInfo);
  2331. }
  2332. wsaoDecRef(pSendInfo);
  2333. // success
  2334. hr = DP_OK;
  2335. exit:
  2336. if(pConn){
  2337. DecRefConn(pgd, pConn);
  2338. }
  2339. LeaveCriticalSection(&pgd->csFast);
  2340. DPF(8,"<==Fast Reply\n");
  2341. return hr;
  2342. CLEANUP_EXIT:
  2343. if(pConn){
  2344. DecRefConn(pgd, pConn); // balance Get
  2345. }
  2346. LeaveCriticalSection(&pgd->csFast);
  2347. if(pBuffer){
  2348. SP_MemFree(pBuffer);
  2349. }
  2350. if(pSendInfo){
  2351. SP_MemFree(pSendInfo);
  2352. }
  2353. return hr;
  2354. }