Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4268 lines
107 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 - 1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpsp.c
  6. * Content: sample direct play service provider, based on winsock
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 1/96 andyco created it
  11. * 2/8/96 andyco steam + dgram model, including name server support
  12. * 2/15/96 andyco added reliable receive. added send (udp + stream).
  13. * added macros for dwReserved to clean up, (and provide
  14. * means for reducing # dwords reserved per player)
  15. * 3/13/96 andyco relaible send + receive for all players. MW2
  16. * 3/16/96 andyco shutdown method - code cleanup - shared stream receive, etc.
  17. * 3/19/96 andyco new message macros (IS_VALID, GET_MESSAGE_SIZE). see dpmess.h
  18. * 4/3/96 andyco moved start up / shut down winsock code here from dllmain
  19. * 4/10/96 andyco added spplayerdata
  20. * 4/12/96 andyco got rid of dpmess.h! use DPlay_ instead of message macros
  21. * 4/18/96 andyco added multihomed support, started ipx
  22. * 4/23/96 andyco ipx support. ipx only - no spx. spx doesn't support
  23. * graceful disconnect (winsock bug?) so we don't know
  24. * when it's safe to closesocket.
  25. * 4/25/96 andyco messages now have blobs (sockaddr's) instead of dwReserveds
  26. * 5/31/96 andyco all non-system players share a socket (gsStream and
  27. * gsDGramSocket).
  28. * 6/9/96 andyco ouch. dplayi_player + group are gone!
  29. * 6/19/96 andyco sp sets own header!
  30. * 6/22/96 andyco no more stashing goodies in sessiondesc. tossed cookies.
  31. * 6/23/96 kipo updated for latest service provider interfaces.
  32. * 6/25/96 kipo added WINAPI prototypes and updated for DPADDRESS;
  33. * added version.
  34. * 7/11/96 andyco reset gsEnumSocket to INVALID_SOCKET if spInit fails
  35. * #2348. added sp_getaddress.
  36. * 7/18/96 andyco added dphelp for server socket
  37. * 7/16/96 kipo changed address types to be GUIDs instead of 4CC
  38. * 8/1/96 andyco fixed up caps. dplay allocs sp data, not us.
  39. * 8/9/96 andyco throw DPCAPS_GUARANTEEDOPTIMIZED for AF_INET
  40. * 8/12/96 andyco changed failure check on inithelper
  41. * 8/15/96 andyco added sp local data + clean up on thread terminate
  42. * 8/30/96 andyco clean it up b4 you shut it down! added globaldata.
  43. * 9/1/96 andyco right said thread! if you spin it, they won't block.
  44. * bagosockets.
  45. * 9/4/96 andyco kill threads at shutdown only. add all threads to
  46. * threadlist. don't add thread to list if it's already
  47. * done.
  48. * 11/11/96 andyco check for NULL header or data when creating
  49. * non-local players (support game server). Memset our
  50. * sockaddr to 0 before calling getserveraddress.
  51. * 12/18/96 andyco de-threading - use a fixed # of prealloced threads.
  52. * cruised the enum socket / thread - use the system
  53. * socket / thread instead
  54. * 1/15/97 andyco return actual hr on open failure (bug 5197) instead of
  55. * just DP_OK. also, allow system messages to go in the
  56. * socket cache.
  57. * 1/17/97 andyco workaround for nt bug 68093 - recvfrom returns buffer size
  58. * instead of WSAEMSGSIZE
  59. * 1/23/97 kipo return an error code from StartDPHelp() so Open() returns
  60. * an error if you cannot host a session.
  61. * 1/24/97 andyco handle incoming message when receive thread isn't running yet
  62. * 2/7/97 andyco store globals w/ IDirectPlaySP, so we can have > 1 SP per DLL.
  63. * 2/10/97 andyco remove sockets from receive list if we get an error when receiving
  64. * on them. this keeps us from going into a spin on select(...).
  65. * 2/15/97 andyco wait on accept thread b4 receive thread. pass port to
  66. * helperdeletedplayserver.
  67. * 3/04/97 kipo external definition of gdwDPlaySPRefCount now in dplaysp.h
  68. * 3/18/97 andyco create socket at spinit to verify support for requested
  69. * address family
  70. * 3/18/97 kipo GetServerAddress() now returns an error so that we can
  71. * return DPERR_USERCANCEL from the EnumSessions dialog
  72. * 3/25/97 andyco tweaked shutdown code to send message to streamreceivethreadproc
  73. * to exit, rather than nuking the control socket which
  74. * would sometimes hang.
  75. * 4/11/97 andyco make sure it's really the control socket @ init
  76. * 5/12/97 kipo return DPERR_UNAVAILABLE if SP could not be opened (i.e. if
  77. * IPX not installed) to be compatible with the modem SP; added
  78. * support for Unicode IP address strings.
  79. * 5/18/97 andyco close threads + sockets at close. this way, we don't hold
  80. * sockets across sessions.
  81. * 6/11/97 andyco changed reply thread proc to flush q when waking up
  82. * 6/18/97 andyco check for bogus reply headers, just to be safe
  83. * 6/19/97 myronth Fixed handle leak (#10059)
  84. * 6/20/97 andyco check for bogus IPX install by looking for sa_nodenum
  85. * of all 0's at SPInit. raid 9625.
  86. * 7/11/97 andyco added async reply thread and ws2 support
  87. * 7/30/97 andyco call wsastartup w/ version 1.1 if app has already
  88. * called it.
  89. * 8/4/97 andyco added support for DPSEND_ASYNC (no return status) so
  90. * we can make addforward async
  91. * 8/25/97 sohailm updated stream receive logic to avoid congestion (bug #10952)
  92. * 9/05/97 kipo Fixed memphis bug #43655 to deal with getsockopt failing
  93. * 12/5/97 andyco voice support
  94. * 01/5/98 sohailm fd set now grows dynamically - allows for any number of clients (#15244).
  95. * 01/14/98 sohailm don't look for Winsock2.0 on non-nt platforms for IPX (#15253)
  96. * 1/20/98 myronth #ifdef'd out voice support
  97. * 1/21/98 a-PeterZ Fix #15242 SP_GetAddress supports local players
  98. * 1/27/98 sohailm added Firewall support.
  99. * 1/30/98 sohailm bug fix for 17731
  100. * 2/09/98 a-PeterZ Fix #17737 ReceiveList Memory Leak
  101. * 2/13/98 aarono added async support
  102. * 2/13/98 aarono made IPX return proper header size
  103. * 2/16/98 a-PeterZ Fix #15342 Detect no local connection in SP_EnumSessions and SP_Open
  104. * 2/18/98 a-peterz Comment byte order mess-up with SERVER_xxx_PORT constants
  105. * 2/24/98 aarono Bug#18646 fix startup/close race crashing stress.
  106. * 3/3/98 aarono Bug#19188 remove accept thread
  107. * 3/30/98 aarono changed KillSocket on StreamAccept socket to closesocket
  108. * 4/6/98 aarono mapped WSAECONNRESET to DPERR_CONNECTIONLOST
  109. * 4/23/98 aarono workaround Winsock shutdown bug.
  110. * The workaround for DPLAY would be to close all accepted sockets first
  111. * and only then listening socket. (VadimE)
  112. * 6/19/98 aarono map WSAENETRESET and WSAENOTCONN to DPERR_CONNECTIONLOST too.
  113. * required since we now turn on keepalives on reliable
  114. * connections.
  115. * 12/15/98 aarono Fix Async Enum.
  116. * 7/9/99 aarono Cleaning up GetLastError misuse, must call right away,
  117. * before calling anything else, including DPF.
  118. *
  119. ***************************************************************************/
  120. /***************************************************************************
  121. * summary -
  122. * + SPInit is the entry point called by dplay. SP fills in callbacks,
  123. * does any other init stuff there.
  124. * + All dplay callbacks start with SP_
  125. *
  126. *****************************************************************************/
  127. // todo - need a meaningful mapping from socket errors to hresults
  128. // todo - figure out when to pop a message box to the user for tragic errors
  129. #define INITGUID
  130. #ifdef BIGMESSAGEDEFENSE
  131. #include <dplobby.h>
  132. // a-josbor: this terrible, terrible hack is brought to you by the elmer build system
  133. #ifndef MAXMSGSIZEGUIDDEFINED
  134. // {F5D09980-F0C4-11d1-8326-006097B01411}
  135. DEFINE_GUID(DPAID_MaxMessageSize,
  136. 0xf5d09980, 0xf0c4, 0x11d1, 0x83, 0x26, 0x0, 0x60, 0x97, 0xb0, 0x14, 0x11);
  137. #endif
  138. #endif /* BIGMESSAGEDEFENSE */
  139. #include "dpsp.h"
  140. #include "fpm.h"
  141. #include <initguid.h>
  142. #include "helpcli.h"
  143. /* */
  144. /* globals */
  145. /* */
  146. WSADATA gwsaData; // from wsastartup
  147. HINSTANCE hWS2; // dynaload the ws2_32.dll, so if it's not installed (e.g. win 95 gold)
  148. // we still load
  149. // stuff for ddhelp
  150. DWORD dwHelperPid; // for ddhelp
  151. HANDLE hModule; // for ddhelp
  152. CRITICAL_SECTION gcsDPSPCritSection;
  153. #ifdef DEBUG
  154. int gCSCount;
  155. #endif
  156. #ifdef DPLAY_VOICE_SUPPORT
  157. BOOL gbVoiceInit = FALSE; // set to TRUE if we have nm voice init'ed
  158. BOOL gbVoiceOpen = FALSE; // set to TRUE if we have a call open
  159. #endif // DPLAY_VOICE_SUPPORT
  160. #undef DPF_MODNAME
  161. #define DPF_MODNAME "DEBUGPRINTSOCKADDR"
  162. #ifdef DEBUG
  163. void DebugPrintAddr(UINT nLevel,LPSTR pStr,SOCKADDR * psockaddr)
  164. {
  165. switch (psockaddr->sa_family)
  166. {
  167. case AF_INET:
  168. {
  169. SOCKADDR_IN * pin;
  170. pin = (SOCKADDR_IN *)psockaddr;
  171. DPF(nLevel,"%s af = AF_INET : address = %s : port = %d\n",pStr,
  172. inet_ntoa(pin->sin_addr),ntohs(pin->sin_port));
  173. break;
  174. }
  175. case AF_IPX:
  176. {
  177. SOCKADDR_IPX * pipx;
  178. pipx = (SOCKADDR_IPX *)psockaddr;
  179. DPF(nLevel,"%s AF = AF_IPX : sa_socket = %d : sa_nodenum = %d,%d,%d,%d,%d,%d",
  180. pStr,pipx->sa_socket,pipx->sa_nodenum[0],pipx->sa_nodenum[1],
  181. pipx->sa_nodenum[2],pipx->sa_nodenum[3],pipx->sa_nodenum[4],
  182. pipx->sa_nodenum[5]);
  183. break;
  184. }
  185. default:
  186. ASSERT(FALSE);
  187. break;
  188. }
  189. } // DebugPrintAddr
  190. void DebugPrintSocket(UINT level,LPSTR pStr,SOCKET * pSock)
  191. {
  192. SOCKADDR sockaddr;
  193. int addrlen=sizeof(sockaddr);
  194. getsockname(*pSock,&sockaddr,&addrlen);
  195. DEBUGPRINTADDR(level,pStr,&sockaddr);
  196. }
  197. #endif // debug
  198. #undef DPF_MODNAME
  199. #define DPF_MODNAME "GetHostAddr"
  200. // Helper function to retrieve host IP Address(es).
  201. // System owns structure returned.
  202. PHOSTENT GetHostAddr(void)
  203. {
  204. char pHostName[HOST_NAME_LENGTH];
  205. PHOSTENT phostent;
  206. UINT err;
  207. if (0 != gethostname(pHostName, HOST_NAME_LENGTH))
  208. {
  209. err = WSAGetLastError();
  210. DPF(0,"could not get host name - err = %d\n",err);
  211. return NULL;
  212. }
  213. phostent = gethostbyname(pHostName);
  214. if (NULL == phostent)
  215. {
  216. err = WSAGetLastError();
  217. DPF(0,"could not get address for '%s' - err = %d\n", pHostName, err);
  218. return NULL;
  219. }
  220. return phostent;
  221. } // GetHostAddr
  222. #undef DPF_MODNAME
  223. #define DPF_MODNAME "DatagramListenThread"
  224. void SetMessageHeader(LPDWORD pdwMsg,DWORD dwSize, DWORD dwToken)
  225. {
  226. if (dwSize > SPMAXMESSAGELEN)
  227. {
  228. ASSERT(FALSE);
  229. }
  230. *pdwMsg = dwSize | dwToken;
  231. return ;
  232. }// SetMessageHeader
  233. #undef DPF_MODNAME
  234. #define DPF_MODNAME "DatagramReceiveThread"
  235. // our initial guess at the size of the dgram receive buffer.
  236. // any messages bigger than this will be truncated BUT when we
  237. // receive a too big message, we double the buffer size (winsock
  238. // won't tell us exactly how big the message was, so we guess).
  239. // a-josbor: I thought 1024 was really stingy, so I bumped this up to 16K
  240. #define BUF_SIZE 0x4000
  241. DWORD WINAPI DgramListenThreadProc(LPVOID pvCast)
  242. {
  243. UINT err;
  244. LPBYTE pBuffer;
  245. INT addrlen=sizeof(SOCKADDR);
  246. SOCKADDR sockaddr; // the from address
  247. DWORD dwBufSize = BUF_SIZE;
  248. IDirectPlaySP * pISP = (IDirectPlaySP *)pvCast;
  249. LPGLOBALDATA pgd;
  250. DWORD dwDataSize = sizeof(GLOBALDATA);
  251. SOCKET sSocket;
  252. HRESULT hr;
  253. DPF(2,"starting udp listen thread ");
  254. // get the global data
  255. hr =pISP->lpVtbl->GetSPData(pISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  256. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  257. {
  258. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  259. ExitThread(0);
  260. return 0;
  261. }
  262. // use the dgram socket
  263. sSocket = pgd->sSystemDGramSocket;
  264. ENTER_DPSP();
  265. pBuffer = MemAlloc(BUF_SIZE);
  266. LEAVE_DPSP();
  267. if (!pBuffer)
  268. {
  269. DPF_ERR("could not alloc dgram receive buffer");
  270. ExitThread(0);
  271. return 0;
  272. }
  273. while (1)
  274. {
  275. err = recvfrom(sSocket,pBuffer,dwBufSize,0,&sockaddr,&addrlen);
  276. if ( (SOCKET_ERROR == err) || (dwBufSize == err))
  277. {
  278. if (dwBufSize == err)
  279. {
  280. // this works around NT bug 68093
  281. err = WSAEMSGSIZE;
  282. }
  283. else
  284. {
  285. err = WSAGetLastError();
  286. }
  287. DPF(2,"\n udp recv error - err = %d socket = %d",err,(DWORD)sSocket);
  288. if (WSAEMSGSIZE == err)
  289. {
  290. // buffer too small!
  291. dwBufSize *= 2;
  292. ENTER_DPSP();
  293. pBuffer = MemReAlloc(pBuffer,dwBufSize);
  294. LEAVE_DPSP();
  295. if (!pBuffer)
  296. {
  297. DPF_ERR("could not realloc dgram receive buffer");
  298. ExitThread(0);
  299. return 0;
  300. }
  301. // we don't pass dplay this message, since it was truncated...
  302. }
  303. else
  304. {
  305. // bail on other errors
  306. goto ERROR_EXIT;
  307. }
  308. }
  309. else if ( (err >= sizeof(DWORD)) && (VALID_DPWS_MESSAGE(pBuffer)) )
  310. {
  311. DEBUGPRINTADDR(9,"received udp message from : ",&sockaddr);
  312. if (VALID_SP_MESSAGE(pBuffer))
  313. {
  314. // it came from another dplay (not from our dplay helper)
  315. // if it came from our helper, we've already poked the ip addr
  316. // into the message body
  317. switch (pgd->AddressFamily)
  318. {
  319. case AF_IPX:
  320. IPX_SetNodenum((LPVOID)pBuffer,(SOCKADDR_IPX *)&sockaddr);
  321. break;
  322. case AF_INET:
  323. IP_SetAddr((LPVOID)pBuffer,(SOCKADDR_IN *)&sockaddr);
  324. break;
  325. default:
  326. ASSERT(FALSE);
  327. break;
  328. }
  329. }
  330. // pass message to dplays handler
  331. pISP->lpVtbl->HandleMessage(pISP,pBuffer + sizeof(MESSAGEHEADER),
  332. err - sizeof(MESSAGEHEADER), pBuffer);
  333. }
  334. else
  335. {
  336. DEBUGPRINTADDR(9,"received udp message from : ",&sockaddr);
  337. // it must be just a raw send...
  338. pISP->lpVtbl->HandleMessage(pISP,pBuffer,err,NULL);
  339. }
  340. }
  341. ERROR_EXIT:
  342. DPF(2,"UDP Listen thread exiting");
  343. ENTER_DPSP();
  344. if (pBuffer) MemFree(pBuffer);
  345. LEAVE_DPSP();
  346. // all done
  347. ExitThread(0);
  348. return 0;
  349. } // UDPListenThreadProc
  350. #undef DPF_MODNAME
  351. #define DPF_MODNAME "StreamListenThread"
  352. // make sure the buffer is big enough to fit the message size
  353. HRESULT MakeBufferSpace(LPBYTE * ppBuffer,LPDWORD pdwBufferSize,DWORD dwMessageSize)
  354. {
  355. HRESULT hr = DP_OK;
  356. ASSERT(ppBuffer);
  357. ASSERT(pdwBufferSize);
  358. ENTER_DPSP();
  359. if (!*ppBuffer)
  360. {
  361. DPF(9, "Allocating space for message of size %d", dwMessageSize);
  362. // need to alloc receive buffer?
  363. *ppBuffer = MemAlloc(dwMessageSize);
  364. if (!*ppBuffer)
  365. {
  366. DPF_ERR("could not alloc stream receive buffer - out of memory");
  367. hr = E_OUTOFMEMORY;
  368. goto CLEANUP_EXIT;
  369. }
  370. *pdwBufferSize = dwMessageSize;
  371. }
  372. // make sure receive buffer can hold data
  373. else if (dwMessageSize > *pdwBufferSize)
  374. {
  375. LPVOID pvTemp;
  376. DPF(9, "ReAllocating space for message of size %d", dwMessageSize);
  377. // realloc buffer to hold data
  378. pvTemp = MemReAlloc(*ppBuffer,dwMessageSize);
  379. if (!pvTemp)
  380. {
  381. DPF_ERR("could not realloc stream receive buffer - out of memory");
  382. hr = E_OUTOFMEMORY;
  383. goto CLEANUP_EXIT;
  384. }
  385. *ppBuffer = pvTemp;
  386. *pdwBufferSize = dwMessageSize;
  387. }
  388. // fall through
  389. CLEANUP_EXIT:
  390. LEAVE_DPSP();
  391. return hr;
  392. } // MakeBufferSpace
  393. // is this sockaddr local to this machine?
  394. BOOL IsLocalIP(SOCKADDR_IN sockaddr)
  395. {
  396. PHOSTENT phostent;
  397. IN_ADDR hostaddr;
  398. HRESULT hr = DP_OK;
  399. int i;
  400. phostent = GetHostAddr();
  401. if (NULL == phostent)
  402. {
  403. return FALSE;
  404. }
  405. i=0;
  406. while (phostent->h_addr_list[i])
  407. {
  408. memcpy(&hostaddr,phostent->h_addr_list[i],sizeof(hostaddr));
  409. if (hostaddr.s_addr == sockaddr.sin_addr.s_addr )
  410. {
  411. return TRUE;
  412. }
  413. i++;
  414. }
  415. return FALSE;
  416. } // IsLocalIP
  417. // adds socket to our send list
  418. HRESULT AddSocketToBag(LPGLOBALDATA pgd, SOCKET socket, DPID dpid, SOCKADDR *psockaddr, DWORD dwFlags)
  419. {
  420. UINT i=0;
  421. BOOL bFound = FALSE;
  422. BOOL bTrue = TRUE;
  423. HRESULT hr=DP_OK;
  424. ASSERT(psockaddr);
  425. ENTER_DPSP();
  426. // see if we can find an empty slot
  427. i=0;
  428. while (( i < pgd->nSocketsInBag) && !bFound)
  429. {
  430. if (INVALID_SOCKET == pgd->BagOSockets[i].sSocket) bFound = TRUE;
  431. else i++;
  432. }
  433. if (!bFound)
  434. {
  435. // no space. bummer
  436. DPF(5,"no space in bag o' sockets. slowness ensues");
  437. hr = E_FAIL;
  438. goto CLEANUP_EXIT;
  439. }
  440. DPF(5,"adding new socket to bag for id = %d, slot = %d",dpid,i);
  441. DEBUGPRINTSOCK(7, "Adding socket to bag - ",&socket);
  442. pgd->BagOSockets[i].dwPlayerID = dpid;
  443. pgd->BagOSockets[i].sSocket = socket;
  444. pgd->BagOSockets[i].sockaddr = *psockaddr;
  445. pgd->BagOSockets[i].dwFlags = dwFlags;
  446. // fall through
  447. CLEANUP_EXIT:
  448. LEAVE_DPSP();
  449. return hr;
  450. }
  451. void FreeConnection(LPCONNECTION pConnection)
  452. {
  453. if (pConnection->pBuffer && (pConnection->pBuffer != pConnection->pDefaultBuffer))
  454. {
  455. MemFree(pConnection->pBuffer);
  456. pConnection->pBuffer = NULL;
  457. }
  458. if (pConnection->pDefaultBuffer)
  459. {
  460. MemFree(pConnection->pDefaultBuffer);
  461. pConnection->pDefaultBuffer = NULL;
  462. }
  463. // initialize connection
  464. pConnection->socket = INVALID_SOCKET; // this tells us if connection is valid
  465. pConnection->dwCurMessageSize = 0;
  466. pConnection->dwTotalMessageSize = 0;
  467. pConnection->dwFlags = 0;
  468. }
  469. HRESULT AddSocketToReceiveList(LPGLOBALDATA pgd,SOCKET sSocket,DWORD dwFlags)
  470. {
  471. UINT i = 0;
  472. UINT err, iNewSlot;
  473. BOOL bFoundSlot = FALSE;
  474. HRESULT hr = DP_OK;
  475. INT addrlen=sizeof(SOCKADDR);
  476. LPCONNECTION pNewConnection=NULL;
  477. DWORD dwCurrentSize,dwNewSize;
  478. ENTER_DPSP();
  479. // look for an empty slot
  480. while ( (i < pgd->ReceiveList.nConnections) && !bFoundSlot)
  481. {
  482. if (INVALID_SOCKET == pgd->ReceiveList.pConnection[i].socket)
  483. {
  484. bFoundSlot = TRUE;
  485. iNewSlot = i;
  486. }
  487. else
  488. {
  489. i++;
  490. }
  491. }
  492. if (!bFoundSlot)
  493. {
  494. // allocate space for list of connections
  495. dwCurrentSize = pgd->ReceiveList.nConnections * sizeof(CONNECTION);
  496. dwNewSize = dwCurrentSize + INITIAL_RECEIVELIST_SIZE * sizeof(CONNECTION);
  497. hr = MakeBufferSpace((LPBYTE *)&(pgd->ReceiveList.pConnection),&dwCurrentSize,dwNewSize);
  498. if (FAILED(hr))
  499. {
  500. ASSERT(FALSE);
  501. goto ERROR_EXIT;
  502. }
  503. ASSERT(dwCurrentSize == dwNewSize);
  504. // set all the new entries to INVALID
  505. for (i = pgd->ReceiveList.nConnections + 1;
  506. i < pgd->ReceiveList.nConnections + INITIAL_RECEIVELIST_SIZE; i++ )
  507. {
  508. pgd->ReceiveList.pConnection[i].socket = INVALID_SOCKET;
  509. }
  510. // store the new socket in the 1st new spot
  511. iNewSlot = pgd->ReceiveList.nConnections;
  512. // allocate space for an fd set (fd_count + fd_array)
  513. if (pgd->ReceiveList.nConnections)
  514. {
  515. dwCurrentSize = sizeof(u_int) + pgd->ReceiveList.nConnections * sizeof(SOCKET);
  516. dwNewSize = dwCurrentSize + INITIAL_RECEIVELIST_SIZE * sizeof(SOCKET);
  517. }
  518. else
  519. {
  520. dwCurrentSize = 0;
  521. dwNewSize = sizeof(u_int) + INITIAL_RECEIVELIST_SIZE * sizeof(SOCKET);
  522. }
  523. hr = MakeBufferSpace((LPBYTE *)&(pgd->readfds.pfdbigset),&dwCurrentSize,dwNewSize);
  524. if (FAILED(hr))
  525. {
  526. ASSERT(FALSE);
  527. goto ERROR_EXIT;
  528. }
  529. ASSERT(dwCurrentSize == dwNewSize);
  530. // update the # of connections
  531. pgd->ReceiveList.nConnections += INITIAL_RECEIVELIST_SIZE;
  532. // update the fd_array buffer size
  533. pgd->readfds.dwArraySize = pgd->ReceiveList.nConnections;
  534. } // !bFoundSlot
  535. // we have a space holder for a connection when we get here
  536. // Initialize new connection
  537. pNewConnection = &(pgd->ReceiveList.pConnection[iNewSlot]);
  538. pNewConnection->socket = sSocket;
  539. pNewConnection->dwFlags = dwFlags;
  540. if(dwFlags != SP_STREAM_ACCEPT){
  541. // allocate a default receive buffer if don't have one already
  542. if (!pNewConnection->pDefaultBuffer)
  543. {
  544. pNewConnection->pDefaultBuffer = MemAlloc(DEFAULT_RECEIVE_BUFFERSIZE);
  545. if (!pNewConnection->pDefaultBuffer)
  546. {
  547. hr = DPERR_OUTOFMEMORY;
  548. DPF_ERR("could not alloc default receive buffer - out of memory");
  549. goto ERROR_EXIT;
  550. }
  551. }
  552. // receive buffer initially points to our default buffer
  553. pNewConnection->pBuffer = pNewConnection->pDefaultBuffer;
  554. // remember the address we are connected to
  555. err = getpeername(pNewConnection->socket, &(pNewConnection->sockAddr), &addrlen);
  556. if (SOCKET_ERROR == err)
  557. {
  558. err = WSAGetLastError();
  559. DPF(1,"could not getpeername err = %d\n",err);
  560. }
  561. DEBUGPRINTADDR(9, "Socket is connected to address - ",&(pNewConnection->sockAddr));
  562. }
  563. LEAVE_DPSP();
  564. DPF(5, "Added new socket at index %d", iNewSlot);
  565. // success
  566. return DP_OK;
  567. // not a fall through
  568. ERROR_EXIT:
  569. if (pNewConnection)
  570. {
  571. KillSocket(pNewConnection->socket,TRUE,FALSE);
  572. FreeConnection(pNewConnection);
  573. }
  574. LEAVE_DPSP();
  575. return hr;
  576. } // AddSocketToReceiveList
  577. // updates the player associated with a socket in the send list
  578. void UpdateSocketPlayerID(LPGLOBALDATA pgd, SOCKADDR *pSockAddr, DPID dpidPlayer)
  579. {
  580. UINT i=0;
  581. IN_ADDR *pIPCurrent, *pIPFind;
  582. BOOL bFound = FALSE;
  583. ASSERT(pSockAddr);
  584. DEBUGPRINTADDR(9, "Updating player id for socket connected to - ",pSockAddr);
  585. ENTER_DPSP();
  586. while (!bFound && (i < pgd->nSocketsInBag))
  587. {
  588. pIPCurrent = &(((SOCKADDR_IN *)&pgd->BagOSockets[i].sockaddr)->sin_addr);
  589. pIPFind = &(((SOCKADDR_IN *)pSockAddr)->sin_addr);
  590. // todo - we are only comparing the IP here, need to look at the complete socket address
  591. if ((INVALID_SOCKET != pgd->BagOSockets[i].sSocket) &&
  592. !memcmp(pIPCurrent, pIPFind, sizeof(IN_ADDR)))
  593. {
  594. bFound = TRUE;
  595. // update the player id
  596. pgd->BagOSockets[i].dwPlayerID = dpidPlayer;
  597. }
  598. i++;
  599. }
  600. LEAVE_DPSP();
  601. return;
  602. }
  603. BOOL FindSocketInReceiveList(LPGLOBALDATA pgd, SOCKADDR *pSockAddr, SOCKET * psSocket)
  604. {
  605. UINT i=0;
  606. IN_ADDR *pIPCurrent, *pIPFind;
  607. BOOL bFound = FALSE;
  608. ASSERT(psSocket);
  609. ENTER_DPSP();
  610. while (!bFound && (i < pgd->ReceiveList.nConnections))
  611. {
  612. pIPCurrent = &(((SOCKADDR_IN *)&pgd->ReceiveList.pConnection[i].sockAddr)->sin_addr);
  613. pIPFind = &(((SOCKADDR_IN *)pSockAddr)->sin_addr);
  614. // todo - we are only comparing the IP here, need to look at the complete socket address
  615. if ((INVALID_SOCKET != pgd->ReceiveList.pConnection[i].socket) &&
  616. !memcmp(pIPCurrent, pIPFind, sizeof(IN_ADDR)))
  617. {
  618. *psSocket = pgd->ReceiveList.pConnection[i].socket;
  619. bFound = TRUE;
  620. }
  621. i++;
  622. }
  623. LEAVE_DPSP();
  624. return bFound;
  625. }
  626. BOOL FindSocketInBag(LPGLOBALDATA pgd, SOCKADDR *pSockAddr, SOCKET * psSocket, LPDPID lpdpidPlayer)
  627. {
  628. UINT i=0;
  629. IN_ADDR *pIPCurrent, *pIPFind;
  630. BOOL bFound = FALSE;
  631. ASSERT(psSocket);
  632. ASSERT(lpdpidPlayer);
  633. ENTER_DPSP();
  634. while (!bFound && (i < pgd->nSocketsInBag))
  635. {
  636. pIPCurrent = &(((SOCKADDR_IN *)&pgd->BagOSockets[i].sockaddr)->sin_addr);
  637. pIPFind = &(((SOCKADDR_IN *)pSockAddr)->sin_addr);
  638. if ((INVALID_SOCKET != pgd->BagOSockets[i].sSocket) &&
  639. !memcmp(pIPCurrent, pIPFind, sizeof(IN_ADDR)))
  640. {
  641. *psSocket = pgd->BagOSockets[i].sSocket;
  642. *lpdpidPlayer = pgd->BagOSockets[i].dwPlayerID;
  643. DPF(9, "Found socket in send list for id %d", *lpdpidPlayer);
  644. bFound = TRUE;
  645. }
  646. i++;
  647. }
  648. LEAVE_DPSP();
  649. return bFound;
  650. }
  651. void RemoveSocketFromBag(LPGLOBALDATA pgd, SOCKET socket)
  652. {
  653. BOOL bFound = FALSE;
  654. UINT i=0;
  655. ENTER_DPSP();
  656. // look for the socket
  657. while (!bFound && (i < pgd->nSocketsInBag))
  658. {
  659. if (socket == pgd->BagOSockets[i].sSocket)
  660. {
  661. pgd->BagOSockets[i].sSocket = INVALID_SOCKET;
  662. bFound = TRUE;
  663. }
  664. else
  665. {
  666. i++;
  667. }
  668. } // while
  669. LEAVE_DPSP();
  670. }
  671. void RemoveSocketFromReceiveList(LPGLOBALDATA pgd, SOCKET socket)
  672. {
  673. UINT i = 0;
  674. BOOL bFound = FALSE;
  675. SOCKET sSocket=INVALID_SOCKET;
  676. DWORD dwSocketFlags=0;
  677. ENTER_DPSP();
  678. // look for the corresponding connection
  679. while ( !bFound && (i < pgd->ReceiveList.nConnections))
  680. {
  681. if (socket == pgd->ReceiveList.pConnection[i].socket)
  682. {
  683. DEBUGPRINTSOCK(9, "Removing socket from receive list - ", &socket);
  684. socket = pgd->ReceiveList.pConnection[i].socket;
  685. dwSocketFlags = pgd->ReceiveList.pConnection[i].dwFlags;
  686. FreeConnection(&pgd->ReceiveList.pConnection[i]);
  687. bFound = TRUE;
  688. }
  689. else
  690. {
  691. i++;
  692. }
  693. } // while
  694. LEAVE_DPSP();
  695. if (bFound)
  696. {
  697. KillSocket(socket, TRUE, FALSE);
  698. if (dwSocketFlags & SP_CONNECTION_FULLDUPLEX)
  699. RemoveSocketFromBag(pgd,sSocket);
  700. }
  701. return ;
  702. } //RemoveSocketFromReceiveList
  703. HRESULT HandleSPMessage(IDirectPlaySP *pISP, LPGLOBALDATA pgd, LPCONNECTION pConnection)
  704. {
  705. HRESULT hr;
  706. switch (SP_MESSAGE_TOKEN(pConnection->pBuffer))
  707. {
  708. // VALID_SP_MESSAGE
  709. case TOKEN:
  710. {
  711. if (SPMESSAGEHEADERLEN == pConnection->dwTotalMessageSize)
  712. {
  713. // if we get a message w/ 0 size, it means we've accepted a connection
  714. // and need to add the new socket to our recv list...
  715. // basically, it's a no-op for the receive loop
  716. return DP_OK;
  717. }
  718. // now, we've read all the bits
  719. // store the address we received from w/ the message
  720. // todo - don't store address if it's a player - player message
  721. switch (pgd->AddressFamily)
  722. {
  723. case AF_INET:
  724. if (pgd->dwFlags & DPSP_OUTBOUNDONLY)
  725. {
  726. ((LPMESSAGEHEADER)pConnection->pBuffer)->sockaddr = pConnection->sockAddr;
  727. }
  728. else
  729. {
  730. IP_SetAddr((LPVOID)pConnection->pBuffer,(SOCKADDR_IN *)&pConnection->sockAddr);
  731. }
  732. break;
  733. case AF_IPX:
  734. IPX_SetNodenum((LPVOID)pConnection->pBuffer,(SOCKADDR_IPX *)&pConnection->sockAddr);
  735. break;
  736. default:
  737. ASSERT(FALSE);
  738. break;
  739. }
  740. // pass message to dplays handler
  741. // need to drop the lock here...
  742. ASSERT( 1 == gCSCount);
  743. DPF(9, "received a complete message - handing it off to dplay");
  744. LEAVE_DPSP();
  745. // received a complete message - hand it off to dplay
  746. pISP->lpVtbl->HandleMessage(pISP, pConnection->pBuffer + sizeof(MESSAGEHEADER),
  747. pConnection->dwTotalMessageSize - sizeof(MESSAGEHEADER),pConnection->pBuffer);
  748. ENTER_DPSP();
  749. }
  750. break;
  751. // VALID_SERVER_MESSAGE
  752. case SERVER_TOKEN:
  753. {
  754. HandleServerMessage(pgd, pConnection->socket, pConnection->pBuffer + sizeof(MESSAGEHEADER),
  755. pConnection->dwTotalMessageSize - sizeof(MESSAGEHEADER));
  756. }
  757. break;
  758. // if we get this token, the sender wants us to reuse the connection
  759. // so put it in the send list
  760. case REUSE_TOKEN:
  761. {
  762. DEBUGPRINTSOCK(9, "Received reuse message on - ", &pConnection->socket);
  763. // we only allow reusing connections in client/server mode at this time.
  764. // peer-peer can't work without making inbound connections
  765. if (pgd->dwSessionFlags & DPSESSION_CLIENTSERVER)
  766. {
  767. DEBUGPRINTSOCK(9, "Reusing connection - ", &pConnection->socket);
  768. hr = AddSocketToBag(pgd, pConnection->socket, 0, &pConnection->sockAddr,
  769. SP_CONNECTION_FULLDUPLEX);
  770. if (FAILED(hr))
  771. {
  772. DEBUGPRINTSOCK(0, "Failed to reuse connection - ",&pConnection->socket);
  773. return hr;
  774. }
  775. }
  776. else
  777. {
  778. DPF(2, "Not accepting reuse request in peer-peer");
  779. return E_FAIL;
  780. }
  781. }
  782. break;
  783. default:
  784. {
  785. DPF(0, "Received a message with invalid token - 0x%08x",SP_MESSAGE_TOKEN(pConnection->pBuffer));
  786. }
  787. break;
  788. } // switch
  789. return DP_OK;
  790. } // HandleSPMessage
  791. /*
  792. ** StreamReceive
  793. *
  794. * CALLED BY: StreamReceiveThreadProc
  795. *
  796. * PARAMETERS:
  797. * sSocket - socket to receive on
  798. * ppBuffer - buffer to receive into - alloc'ed / realloc'ed as necessary
  799. * pdwBuffersize - size of pBuffer
  800. *
  801. * DESCRIPTION:
  802. * take the bytes out of sSocket until no more bytes
  803. *
  804. * RETURNS: E_FAIL on sockerr, or DP_OK.
  805. *
  806. */
  807. HRESULT StreamReceive(IDirectPlaySP * pISP,LPGLOBALDATA pgd, LPCONNECTION pConnection)
  808. {
  809. HRESULT hr = DP_OK;
  810. UINT err;
  811. DWORD dwBytesReceived=0;
  812. DWORD dwMessageSize = 0;
  813. LPBYTE pReceiveBuffer=NULL;
  814. DWORD dwReceiveBufferSize;
  815. // is it a new message ?
  816. if (pConnection->dwCurMessageSize == 0)
  817. {
  818. // make sure we have a buffer to recive data in
  819. if (!pConnection->pDefaultBuffer)
  820. {
  821. DEBUGPRINTADDR(0, "No buffer to receive data - removing connection to - ",&pConnection->sockAddr);
  822. goto CLEANUP_EXIT;
  823. }
  824. // receive the header first
  825. pConnection->dwTotalMessageSize = SPMESSAGEHEADERLEN;
  826. }
  827. // continue receiving message
  828. pReceiveBuffer = pConnection->pBuffer + pConnection->dwCurMessageSize;
  829. dwReceiveBufferSize = pConnection->dwTotalMessageSize - pConnection->dwCurMessageSize;
  830. DPF(9,"Attempting to receive %d bytes", dwReceiveBufferSize);
  831. DEBUGPRINTSOCK(9,">>> receiving data on socket - ",&pConnection->socket);
  832. // receive data from socket
  833. // note - make exactly one call to recv after select otherwise we'll hang
  834. dwBytesReceived = recv(pConnection->socket, (LPBYTE)pReceiveBuffer, dwReceiveBufferSize, 0);
  835. if (0 == dwBytesReceived)
  836. {
  837. // remote side has shutdown connection gracefully
  838. DEBUGPRINTSOCK(9,"<<< received data on socket - ",&pConnection->socket);
  839. hr = DP_OK;
  840. DEBUGPRINTSOCK(5,"Remote side has shutdown connection gracefully - ",&pConnection->socket);
  841. goto CLEANUP_EXIT;
  842. }
  843. else if (SOCKET_ERROR == dwBytesReceived)
  844. {
  845. err = WSAGetLastError();
  846. DEBUGPRINTSOCK(9,"<<< received data on socket - ",&pConnection->socket);
  847. DPF(0,"STREAMRECEIVEE: receive error - err = %d",err);
  848. hr = E_UNEXPECTED;
  849. goto CLEANUP_EXIT;
  850. }
  851. DPF(5, "received %d bytes", dwBytesReceived);
  852. // we have received this much message so far
  853. pConnection->dwCurMessageSize += dwBytesReceived;
  854. // did we receive the header
  855. if (pConnection->dwCurMessageSize == SPMESSAGEHEADERLEN)
  856. {
  857. // we just completed receiving message header
  858. // make sure its valid
  859. if (VALID_DPWS_MESSAGE(pConnection->pDefaultBuffer))
  860. {
  861. dwMessageSize = SP_MESSAGE_SIZE(pConnection->pDefaultBuffer); // total message size
  862. #ifdef BIGMESSAGEDEFENSE
  863. // make sure it is not greater that the max message len
  864. if (dwMessageSize > pgd->dwMaxMessageSize)
  865. {
  866. DPF(0, "Got message (%d bytes) that's bigger than max allowed len (%d)! Disconnecting sender.\n",
  867. dwMessageSize - sizeof(MESSAGEHEADER), pgd->dwMaxMessageSize - sizeof(MESSAGEHEADER));
  868. ASSERT(dwMessageSize <= pgd->dwMaxMessageSize);
  869. // we want to receive another 12 bytes so that DPLAY can have
  870. // something to look at to decide whether or not to continue
  871. // receiving this message. So instead of setting dwMessageSize
  872. // to its real size, we fake it out.
  873. dwMessageSize = SPMESSAGEHEADERLEN + 12;
  874. }
  875. #endif
  876. }
  877. else
  878. {
  879. DPF(2,"got invalid message - token = 0x%08x",SP_MESSAGE_TOKEN(pConnection->pDefaultBuffer));
  880. ASSERT(FALSE);
  881. hr = E_UNEXPECTED;
  882. goto CLEANUP_EXIT;
  883. }
  884. // prepare to receive rest of the message (after the token)
  885. if (dwMessageSize)
  886. {
  887. pConnection->dwTotalMessageSize = dwMessageSize;
  888. // which buffer to receive message in ?
  889. if (dwMessageSize > DEFAULT_RECEIVE_BUFFERSIZE)
  890. {
  891. ASSERT(pConnection->pBuffer == pConnection->pDefaultBuffer);
  892. // get a new buffer to fit the message
  893. pConnection->pBuffer = MemAlloc(dwMessageSize);
  894. if (!pConnection->pBuffer)
  895. {
  896. DPF(0,"Failed to allocate receive buffer for message - out of memory");
  897. goto CLEANUP_EXIT;
  898. }
  899. // copy header into new message buffer
  900. memcpy(pConnection->pBuffer, pConnection->pDefaultBuffer, SPMESSAGEHEADERLEN);
  901. }
  902. }
  903. }
  904. #ifdef BIGMESSAGEDEFENSE
  905. // this MIGHT be because the message is really huge, and we're just getting
  906. // enough to hand to DPLAY
  907. else if (pConnection->dwCurMessageSize == SPMESSAGEHEADERLEN + 12)
  908. {
  909. dwMessageSize = SP_MESSAGE_SIZE(pConnection->pBuffer);
  910. if (dwMessageSize > pgd->dwMaxMessageSize)
  911. {
  912. DPSP_MSGTOOBIG msgTooBigErr;
  913. // okay. This is message is too big, and we now have enough data
  914. // to hand to DPLAY. Find out if it wants us to continue receiving,
  915. // or bail on this connection
  916. // call into DPLAY to let it do its thing
  917. msgTooBigErr.dwType = DPSPWARN_MESSAGETOOBIG;
  918. msgTooBigErr.pReceiveBuffer = pConnection->pBuffer + sizeof(MESSAGEHEADER);
  919. msgTooBigErr.dwBytesReceived = pConnection->dwCurMessageSize;
  920. msgTooBigErr.dwMessageSize = dwMessageSize - sizeof(MESSAGEHEADER);
  921. LEAVE_DPSP();
  922. pISP->lpVtbl->HandleSPWarning(pISP, &msgTooBigErr, sizeof(DPSP_MSGTOOBIG), pConnection->pBuffer);
  923. ENTER_DPSP();
  924. // now, kill the connection
  925. hr = E_UNEXPECTED;
  926. goto CLEANUP_EXIT;
  927. }
  928. }
  929. #endif
  930. // did we receive a complete message ?
  931. if (pConnection->dwCurMessageSize == pConnection->dwTotalMessageSize)
  932. {
  933. // process message
  934. hr = HandleSPMessage(pISP, pgd, pConnection);
  935. // cleanup up new receive buffer if any
  936. if (pConnection->dwTotalMessageSize > DEFAULT_RECEIVE_BUFFERSIZE)
  937. {
  938. DPF(9, "Releasing receive buffer of size %d", pConnection->dwTotalMessageSize);
  939. if (pConnection->pBuffer) MemFree(pConnection->pBuffer);
  940. }
  941. // initialize message information
  942. pConnection->dwCurMessageSize = 0;
  943. pConnection->dwTotalMessageSize = 0;
  944. pConnection->pBuffer = pConnection->pDefaultBuffer;
  945. if (FAILED(hr))
  946. {
  947. goto CLEANUP_EXIT;
  948. }
  949. }
  950. // all done
  951. return DP_OK;
  952. CLEANUP_EXIT:
  953. RemoveSocketFromReceiveList(pgd,pConnection->socket);
  954. return hr;
  955. } // StreamReceive
  956. void EmptyConnectionList(LPGLOBALDATA pgd)
  957. {
  958. UINT i;
  959. ENTER_DPSP();
  960. for (i=0;i<pgd->ReceiveList.nConnections ;i++ )
  961. {
  962. if (INVALID_SOCKET != pgd->ReceiveList.pConnection[i].socket)
  963. {
  964. KillSocket(pgd->ReceiveList.pConnection[i].socket,TRUE,FALSE);
  965. FreeConnection(&(pgd->ReceiveList.pConnection[i]));
  966. }
  967. }
  968. LEAVE_DPSP();
  969. return ;
  970. } // EmptyConnectionList
  971. // when we get a control event, we need to send a message to the control
  972. // socket (to wake up the receive thread proc).
  973. // this finds the ip addr of this machine to send to.
  974. HRESULT GetDefaultHostAddr(SOCKADDR * psockaddr)
  975. {
  976. PHOSTENT phostent;
  977. IN_ADDR hostaddr;
  978. ((LPSOCKADDR_IN)psockaddr)->sin_addr.s_addr = 0;
  979. // find an ip address for this machine
  980. // we use the default, since all our sends are to local
  981. // name servers (no homing issues)
  982. phostent = GetHostAddr();
  983. if (NULL == phostent)
  984. {
  985. return E_FAIL;
  986. }
  987. DPF(5,"found host name %s \n",phostent->h_name);
  988. memcpy(&hostaddr,phostent->h_addr_list[0],sizeof(hostaddr));
  989. DPF(5,"GetDefaultHostAddr :: found host addr = %s \n",inet_ntoa(hostaddr));
  990. // store the default sockaddr for this system
  991. ((LPSOCKADDR_IN)psockaddr)->sin_addr.s_addr = hostaddr.s_addr;
  992. return DP_OK;
  993. } // GetDefaultHostAddr
  994. // watch our list of sockets, waiting for one to have data to be received, or to be closed
  995. DWORD WINAPI StreamReceiveThreadProc(LPVOID pvCast)
  996. {
  997. HRESULT hr;
  998. int rval;
  999. UINT i = 0;
  1000. UINT err;
  1001. DWORD dwBufferSize = 0;
  1002. UINT nSelected;
  1003. IDirectPlaySP * pISP = (IDirectPlaySP *)pvCast;
  1004. DWORD dwDataSize = sizeof(GLOBALDATA);
  1005. LPGLOBALDATA pgd;
  1006. TIMEVAL tv={0,250000}; // 250000 us = 1/4 sec.
  1007. DWORD dwPrevSelectLastError=0;
  1008. // get the global data
  1009. hr =pISP->lpVtbl->GetSPData(pISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  1010. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  1011. {
  1012. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  1013. ExitThread(0);
  1014. return 0;
  1015. }
  1016. AddSocketToReceiveList(pgd,pgd->sSystemStreamSocket,SP_STREAM_ACCEPT);
  1017. while (1)
  1018. {
  1019. ENTER_DPSP();
  1020. ASSERT(pgd->readfds.pfdbigset);
  1021. // add all sockets in our recv list to readfds
  1022. FD_ZERO(pgd->readfds.pfdbigset);
  1023. nSelected = 0;
  1024. for (i=0;i < pgd->ReceiveList.nConnections ; i++)
  1025. {
  1026. if (INVALID_SOCKET != pgd->ReceiveList.pConnection[i].socket)
  1027. {
  1028. FD_BIG_SET(pgd->ReceiveList.pConnection[i].socket,&pgd->readfds);
  1029. nSelected++;
  1030. }
  1031. }
  1032. LEAVE_DPSP();
  1033. if (0 == nSelected)
  1034. {
  1035. if (pgd->bShutdown)
  1036. {
  1037. DPF(2,"stream receive thread proc detected shutdown - bailing");
  1038. goto CLEANUP_EXIT;
  1039. }
  1040. // we should have at least one?
  1041. DPF_ERR("No sockets in receive list - missing control socket? bailing!");
  1042. ASSERT(FALSE);
  1043. goto CLEANUP_EXIT;
  1044. }
  1045. // now, we wait for something to happen w/ our socket set
  1046. rval = select(0,(fd_set *)(pgd->readfds.pfdbigset),NULL,NULL,&tv);
  1047. if (SOCKET_ERROR == rval)
  1048. {
  1049. err = WSAGetLastError();
  1050. if(dwPrevSelectLastError==err){
  1051. DPF(0,"Got two bogus last errors of(%x) from select, bailing",err);
  1052. goto CLEANUP_EXIT;
  1053. }
  1054. // WSAEINTR is returned when a socket is shutdown behind us - this can happen
  1055. // when a socket is removed from the receivelist
  1056. if (WSAEINTR != err)
  1057. {
  1058. dwPrevSelectLastError=err;
  1059. DPF(2,"StreamReceiveThreadProc failing w/ sockerr = %d\n - trying again",err);
  1060. ASSERT(FALSE);
  1061. rval = 0; // try again...
  1062. } else {
  1063. dwPrevSelectLastError=0;
  1064. }
  1065. } else {
  1066. dwPrevSelectLastError=0;
  1067. }
  1068. // shut 'em down?
  1069. if (pgd->bShutdown)
  1070. {
  1071. DPF(2,"receive thread proc detected bShutdown - bailing");
  1072. goto CLEANUP_EXIT;
  1073. }
  1074. // a-josbor: why are we waking up with 0 events?
  1075. // in any case, a workaround is to just go back to sleep if we have
  1076. // no real events
  1077. if ( rval == 0)
  1078. {
  1079. continue;
  1080. }
  1081. DPF(5,"receive thread proc - events on %d sockets",rval);
  1082. i = 0;
  1083. ENTER_DPSP();
  1084. while (rval>0)
  1085. {
  1086. // walk the receive list, dealing w/ all new sockets
  1087. if (i >= pgd->ReceiveList.nConnections)
  1088. {
  1089. DPF(0, "nConnections = %d, selected = %d", pgd->ReceiveList.nConnections, i);
  1090. ASSERT(FALSE); // should never happen
  1091. rval = 0; // just to be safe, reset
  1092. }
  1093. if (pgd->ReceiveList.pConnection[i].socket != INVALID_SOCKET)
  1094. {
  1095. // see if it's in the set
  1096. if (FD_ISSET(pgd->ReceiveList.pConnection[i].socket,pgd->readfds.pfdbigset))
  1097. {
  1098. DPF(9, "Receiving on socket %d from ReceiveList", i);
  1099. if(pgd->ReceiveList.pConnection[i].dwFlags != SP_STREAM_ACCEPT){
  1100. // got one! this socket has something going on...
  1101. hr = StreamReceive(pISP, pgd, &(pgd->ReceiveList.pConnection[i]));
  1102. if (FAILED(hr))
  1103. {
  1104. DPF(1,"Stream Receive failed - hr = 0x%08lx\n",hr);
  1105. }
  1106. } else {
  1107. // accept any incoming connection
  1108. SOCKADDR sockaddr;
  1109. INT addrlen=sizeof(sockaddr);
  1110. SOCKET sSocket;
  1111. sSocket = accept(pgd->sSystemStreamSocket,&sockaddr,&addrlen);
  1112. if (INVALID_SOCKET == sSocket)
  1113. {
  1114. err = WSAGetLastError();
  1115. DPF(2,"\n stream accept error - err = %d socket = %d",err,(DWORD)sSocket);
  1116. } else {
  1117. DEBUGPRINTADDR(5,"stream - accepted connection from",&sockaddr);
  1118. // add the new socket to our receive q
  1119. hr = AddSocketToReceiveList(pgd,sSocket,0);
  1120. if (FAILED(hr))
  1121. {
  1122. ASSERT(FALSE);
  1123. }
  1124. }
  1125. }
  1126. rval--; // one less to hunt for
  1127. } // IS_SET
  1128. } // != INVALID_SOCKET
  1129. i++;
  1130. } // while rval
  1131. LEAVE_DPSP();
  1132. } // while 1
  1133. CLEANUP_EXIT:
  1134. EmptyConnectionList(pgd);
  1135. return 0;
  1136. } // ReceiveThreadProc
  1137. // send a message of 0 length telling receiver to reuse connection
  1138. HRESULT SendReuseConnectionMessage(SOCKET sSocket)
  1139. {
  1140. DWORD dwMessage;
  1141. HRESULT hr=DP_OK;
  1142. UINT err;
  1143. // send a 0 sized message (w/ our header) to the stream socket, to tell
  1144. // receive thread proc to reuse this socket for replies to us
  1145. SetMessageHeader(&dwMessage,0,REUSE_TOKEN);
  1146. err = send(sSocket,(LPBYTE)&dwMessage,sizeof(DWORD),0);
  1147. if (SOCKET_ERROR == err)
  1148. {
  1149. err = WSAGetLastError();
  1150. // if we're shutdown, don't print a scary
  1151. DPF(0,"SendReuseControlMessage failed with error - err = %d\n",err);
  1152. hr = E_FAIL;
  1153. }
  1154. return hr;
  1155. }
  1156. #undef DPF_MODNAME
  1157. #define DPF_MODNAME "CreateAndConnectSocket"
  1158. // called by reliable send and DoTCPEnumSessions
  1159. HRESULT CreateAndConnectSocket(LPGLOBALDATA pgd,SOCKET * psSocket,DWORD dwType,LPSOCKADDR psockaddr, BOOL bOutBoundOnly)
  1160. {
  1161. UINT err;
  1162. HRESULT hr;
  1163. int iAddrLen = sizeof(SOCKADDR);
  1164. ASSERT(psSocket);
  1165. hr = CreateSocket(pgd,psSocket,dwType,0,INADDR_ANY,&err,FALSE);
  1166. if (FAILED(hr))
  1167. {
  1168. DPF(0,"createandconnect :: create socket failed - err = %d\n",err);
  1169. return hr;
  1170. }
  1171. // try to connect
  1172. hr = SPConnect(psSocket,(LPSOCKADDR)psockaddr,iAddrLen, bOutBoundOnly);
  1173. if (FAILED(hr))
  1174. {
  1175. DPF(0,"createandconnect - connect socket failed\n");
  1176. goto ERROR_EXIT;
  1177. }
  1178. if (bOutBoundOnly)
  1179. {
  1180. // so we receive the reply (server will reuse the connection)
  1181. hr = AddSocketToReceiveList(pgd, *psSocket,SP_CONNECTION_FULLDUPLEX);
  1182. if (FAILED(hr))
  1183. {
  1184. DPF(0, "failed to add socket to receive list");
  1185. goto ERROR_EXIT;
  1186. }
  1187. }
  1188. return DP_OK;
  1189. // not a fall through
  1190. ERROR_EXIT:
  1191. if (INVALID_SOCKET != *psSocket)
  1192. {
  1193. err = closesocket(*psSocket);
  1194. if (SOCKET_ERROR == err)
  1195. {
  1196. err = WSAGetLastError();
  1197. DPF(0,"send closesocket error - err = %d\n",err);
  1198. return E_UNEXPECTED;
  1199. }
  1200. *psSocket = INVALID_SOCKET;
  1201. }
  1202. return hr;
  1203. } // CreateAndConnectSocket
  1204. #undef DPF_MODNAME
  1205. #define DPF_MODNAME "EnumSessions"
  1206. // starts the streamacceptthread (TCP) or the dgramlistenthreadproc (IPX) so we can
  1207. // get replies from the nameserver for our requests
  1208. HRESULT StartupEnumThread(IDirectPlaySP * pISP,LPGLOBALDATA pgd)
  1209. {
  1210. HRESULT hr;
  1211. UINT err;
  1212. DWORD dwThreadID;
  1213. // set up socket
  1214. if (AF_IPX == pgd->AddressFamily) // ipx gets dgram socket
  1215. {
  1216. if (pgd->hDGramReceiveThread)
  1217. {
  1218. return DP_OK; // already running
  1219. }
  1220. ASSERT(INVALID_SOCKET == pgd->sSystemDGramSocket);
  1221. hr = CreateSocket(pgd,&(pgd->sSystemDGramSocket),SOCK_DGRAM,0,INADDR_ANY,&err,TRUE);
  1222. if (FAILED(hr))
  1223. {
  1224. DPF(0,"could not create enum socket - err = %d\n",err);
  1225. return hr;
  1226. }
  1227. pgd->hDGramReceiveThread = CreateThread(NULL,0,DgramListenThreadProc,
  1228. (LPVOID)pISP,0,&dwThreadID);
  1229. if (!pgd->hDGramReceiveThread)
  1230. {
  1231. ASSERT(FALSE);
  1232. } else SetThreadPriority(pgd->hDGramReceiveThread, THREAD_PRIORITY_ABOVE_NORMAL);
  1233. }
  1234. else // everything else uses reliable
  1235. {
  1236. if (pgd->hStreamReceiveThread)
  1237. {
  1238. return DP_OK; // already running
  1239. }
  1240. // create system stream socket so we can start listening for connections
  1241. ASSERT(INVALID_SOCKET == pgd->sSystemStreamSocket);
  1242. hr = CreateAndInitStreamSocket(pgd);
  1243. if (FAILED(hr))
  1244. {
  1245. ASSERT(FALSE);
  1246. return hr;
  1247. }
  1248. // start the enum accept thread (listen for new connections)
  1249. pgd->hStreamReceiveThread = CreateThread(NULL,0,StreamReceiveThreadProc,
  1250. (LPVOID)pISP,0,&dwThreadID);
  1251. if (!pgd->hStreamReceiveThread)
  1252. {
  1253. DPF(0, "Failed to start stream receive thread");
  1254. ASSERT(FALSE);
  1255. } else SetThreadPriority(pgd->hDGramReceiveThread, THREAD_PRIORITY_ABOVE_NORMAL);
  1256. }
  1257. return DP_OK;
  1258. } // StartupEnumThread
  1259. /*
  1260. * Creates a dgram socket, sends enum sessions request, and closes socket.
  1261. *
  1262. * reply is received in streamlistenthreadproc and passed into dplay.
  1263. */
  1264. HRESULT DoUDPEnumSessions(LPGLOBALDATA pgd, SOCKADDR *lpSockAddr, DWORD dwAddrSize,
  1265. LPDPSP_ENUMSESSIONSDATA ped)
  1266. {
  1267. SOCKET sSocket;
  1268. HRESULT hr;
  1269. BOOL bTrue=TRUE;
  1270. UINT err;
  1271. DEBUGPRINTADDR(5,"enum unreliable - sending to ",lpSockAddr);
  1272. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,0,INADDR_ANY,&err,FALSE);
  1273. if (FAILED(hr))
  1274. {
  1275. DPF(0,"!!! enum - could not create socket error = %d\n",err);
  1276. return E_FAIL;
  1277. }
  1278. // enable broadcast on our socket
  1279. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_BROADCAST,(char FAR *)&bTrue,
  1280. sizeof(bTrue) ) )
  1281. {
  1282. err = WSAGetLastError();
  1283. DPF(0,"enum - could not set broadcast err = %d\n",err);
  1284. goto CLEANUP_EXIT;
  1285. }
  1286. // send out the enum message
  1287. err = sendto(sSocket,ped->lpMessage,ped->dwMessageSize,0,lpSockAddr,dwAddrSize);
  1288. if (SOCKET_ERROR == err)
  1289. {
  1290. err = WSAGetLastError();
  1291. DPF(0,"send error - err = %d\n",err);
  1292. hr = E_UNEXPECTED;
  1293. }
  1294. // fall through
  1295. CLEANUP_EXIT:
  1296. KillSocket(sSocket,TRUE,FALSE);
  1297. return hr;
  1298. } // DoUDPEnumSessions
  1299. // A very short lived thread -- may hang in connect with invalid id to connect to.
  1300. DWORD WINAPI TCPEnumSessionsAsyncThread(LPVOID lpv)
  1301. {
  1302. LPGLOBALDATA pgd=(LPGLOBALDATA) lpv;
  1303. HRESULT hr;
  1304. UINT err;
  1305. DPF(9,"==> Entering TCPEnumSessionsAsyncThread(0x%08x)\n", lpv);
  1306. pgd->sEnum = INVALID_SOCKET;
  1307. DEBUGPRINTADDR(5,"enum reliable - sending to ",&pgd->saEnum);
  1308. // get us a new connection
  1309. hr = CreateAndConnectSocket(pgd,&pgd->sEnum,SOCK_STREAM,&pgd->saEnum,pgd->bOutBoundOnly);
  1310. if (FAILED(hr))
  1311. {
  1312. DPF(0, "Failed to get socket for enum sessions - hr: 0x%08x",hr);
  1313. goto EXIT;
  1314. }
  1315. // send the request
  1316. err = send(pgd->sEnum,pgd->lpEnumMessage,pgd->dwEnumMessageSize,0);
  1317. if (SOCKET_ERROR == err)
  1318. {
  1319. err = WSAGetLastError();
  1320. DPF(0,"send error - err = %d\n",err);
  1321. DEBUGPRINTADDR(0,"reliable send - FAILED - sending to ",&pgd->saEnum);
  1322. hr = E_FAIL;
  1323. goto ERROR_EXIT;
  1324. // fall through
  1325. }
  1326. if (!pgd->bOutBoundOnly)
  1327. {
  1328. DEBUGPRINTSOCK(5,"Closing enum sessions connection - ", &pgd->sEnum);
  1329. // close the connection
  1330. KillSocket(pgd->sEnum,TRUE,FALSE);
  1331. pgd->sEnum=INVALID_SOCKET;
  1332. }
  1333. goto EXIT;
  1334. // not a fall through
  1335. ERROR_EXIT:
  1336. if (INVALID_SOCKET != pgd->sEnum) {
  1337. KillSocket(pgd->sEnum,TRUE,FALSE);
  1338. pgd->sEnum=INVALID_SOCKET;
  1339. }
  1340. EXIT:
  1341. ENTER_DPSP();
  1342. if(pgd->hTCPEnumAsyncThread){
  1343. CloseHandle(pgd->hTCPEnumAsyncThread);
  1344. pgd->hTCPEnumAsyncThread=0;
  1345. }
  1346. if(pgd->lpEnumMessage){
  1347. MemFree(pgd->lpEnumMessage);
  1348. pgd->lpEnumMessage=0;
  1349. }
  1350. LEAVE_DPSP();
  1351. DPF(5,"<== Leaving TCPEnumSessionsAsyncThread\n");
  1352. return 0;
  1353. } // TCPEnumSessionsAsyncThread
  1354. /*
  1355. * Creates a stream socket, sends enum sessions request, and closes socket
  1356. * depending on bHostWillReuseConnection. If bHostWillReuseConnection is TRUE, server will
  1357. * close the connection after sending reply.
  1358. *
  1359. * reply is received in streamlistenthreadproc and passed into dplay.
  1360. */
  1361. HRESULT DoTCPEnumSessionsAsync(LPGLOBALDATA pgd, SOCKADDR *lpSockAddr, DWORD dwAddrSize,
  1362. LPDPSP_ENUMSESSIONSDATA ped,BOOL bOutBoundOnly)
  1363. {
  1364. DWORD dwJunk;
  1365. HRESULT hr=DP_OK;
  1366. // First see if we have a thread running already, if we do cancel it.
  1367. KillTCPEnumAsyncThread(pgd);
  1368. // package the request up and hand it to the thread.
  1369. ENTER_DPSP();
  1370. pgd->lpEnumMessage=MemAlloc(ped->dwMessageSize);
  1371. if(pgd->lpEnumMessage){
  1372. memcpy(pgd->lpEnumMessage, ped->lpMessage, ped->dwMessageSize);
  1373. pgd->dwEnumMessageSize=ped->dwMessageSize;
  1374. } else {
  1375. hr=DPERR_OUTOFMEMORY;
  1376. goto EXIT;
  1377. }
  1378. memcpy(&pgd->saEnum,lpSockAddr,dwAddrSize);
  1379. pgd->dwEnumAddrSize=dwAddrSize;
  1380. pgd->bOutBoundOnly=bOutBoundOnly;
  1381. pgd->sEnum=INVALID_SOCKET;
  1382. if(!(pgd->hTCPEnumAsyncThread=CreateThread(NULL,0,TCPEnumSessionsAsyncThread,pgd,0,&dwJunk))){
  1383. MemFree(pgd->lpEnumMessage);
  1384. pgd->lpEnumMessage=NULL;
  1385. hr=DPERR_OUTOFMEMORY;
  1386. }
  1387. EXIT:
  1388. LEAVE_DPSP();
  1389. return hr;
  1390. }
  1391. /*
  1392. ** EnumSessions
  1393. *
  1394. * CALLED BY: DPLAY
  1395. *
  1396. * PARAMETERS: ped - see dplayi.h
  1397. *
  1398. * DESCRIPTION:
  1399. *
  1400. * creates a stream socket. sends a message to the address specified by the user.
  1401. * fills in return address so server can reply.
  1402. *
  1403. * reply is received in streamlistenthreadproc and passed into dplay.
  1404. *
  1405. * RETURNS:
  1406. * DP_OK always.
  1407. *
  1408. */
  1409. HRESULT WINAPI SP_EnumSessions(LPDPSP_ENUMSESSIONSDATA ped)
  1410. {
  1411. #ifdef DEBUG
  1412. SOCKET sSocket; // bcast socket
  1413. #endif // DEBUG
  1414. SOCKADDR sockaddr;
  1415. INT addrlen=sizeof(SOCKADDR);
  1416. HRESULT hr;
  1417. DWORD dwErr=0;
  1418. BOOL bTrue = TRUE;
  1419. DWORD dwDataSize = sizeof(GLOBALDATA);
  1420. LPGLOBALDATA pgd;
  1421. BOOL bOutBoundOnly = FALSE;
  1422. DPF(5,"SP_EnumSessions");
  1423. // get the global data
  1424. hr =ped->lpISP->lpVtbl->GetSPData(ped->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  1425. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  1426. {
  1427. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  1428. return E_FAIL;
  1429. }
  1430. // Do we have an active IP address? If not and DUN is enabled, a DUN
  1431. // dialog will pop for enum to a specific machine.
  1432. // bReturnStatus means no extra dialogs are wanted so we will abort
  1433. // if there are no local connections.
  1434. if (ped->bReturnStatus && AF_INET == pgd->AddressFamily)
  1435. {
  1436. PHOSTENT phostent = GetHostAddr();
  1437. if (!phostent || phostent->h_addr_list[0] == 0)
  1438. {
  1439. DPF(0, "No Dial-up network or netcard present");
  1440. return DPERR_NOCONNECTION; // no local IP address = no network
  1441. }
  1442. }
  1443. memset(&sockaddr,0,sizeof(sockaddr));
  1444. // find out where we should send request to
  1445. hr = GetServerAddress(pgd,&sockaddr);
  1446. if (FAILED(hr))
  1447. {
  1448. DPF_ERR("failed to get enumeration address");
  1449. return hr;
  1450. }
  1451. hr = StartupEnumThread(ped->lpISP,pgd);
  1452. if (FAILED(hr))
  1453. {
  1454. DPF(0," could not start enum handler - hr = 0x%08lx\n",hr);
  1455. return hr;
  1456. }
  1457. // set message header
  1458. SetMessageHeader(ped->lpMessage,ped->dwMessageSize,TOKEN);
  1459. SetReturnAddress(ped->lpMessage,SERVICE_SOCKET(pgd));
  1460. #ifdef DEBUG
  1461. sSocket = SERVICE_SOCKET(pgd); // we'll borrow this var for our debug spew
  1462. DEBUGPRINTSOCK(5,"enum - return address = ",&sSocket);
  1463. #endif // DEBUG
  1464. hr = DoUDPEnumSessions(pgd, &sockaddr, addrlen, ped);
  1465. if (FAILED(hr))
  1466. {
  1467. return hr;
  1468. }
  1469. // send a reliable enum sessions as well, duplicates will be filtered by dplay
  1470. if ((pgd->AddressFamily == AF_INET) && (INADDR_BROADCAST != ((LPSOCKADDR_IN)&sockaddr)->sin_addr.s_addr))
  1471. {
  1472. // poke the correct server port
  1473. if (pgd->wApplicationPort)
  1474. {
  1475. // if app specified a port, let's use the mode specified
  1476. // because we'll be enuming the app directly
  1477. ((LPSOCKADDR_IN)&sockaddr)->sin_port = htons(pgd->wApplicationPort);
  1478. bOutBoundOnly = (pgd->dwFlags & DPSP_OUTBOUNDONLY);
  1479. }
  1480. else
  1481. {
  1482. // otherwise send enum to dplaysvr
  1483. // see byte-order comment in dpsp.h for this constant
  1484. ((LPSOCKADDR_IN)&sockaddr)->sin_port = SERVER_STREAM_PORT;
  1485. bOutBoundOnly = FALSE;
  1486. }
  1487. hr = DoTCPEnumSessionsAsync(pgd, &sockaddr, addrlen, ped, bOutBoundOnly);
  1488. }
  1489. // fall through
  1490. DPF(5,"enum exiting");
  1491. return DP_OK;
  1492. }// EnumSessions
  1493. #undef DPFSessions
  1494. #undef DPF_MODNAME
  1495. #define DPF_MODNAME "SP_GetAddress"
  1496. // helper to handle local player address(es)
  1497. HRESULT WINAPI SP_GetAddressLocal(LPDPSP_GETADDRESSDATA pad)
  1498. {
  1499. int i, j, count;
  1500. HRESULT hr = DP_OK;
  1501. PHOSTENT phostent;
  1502. char *pszIPAddr, *pszBuf = NULL;
  1503. WCHAR *pszIPAddrW, *pszBufW = NULL;
  1504. LPDPCOMPOUNDADDRESSELEMENT paDPAddrEl = NULL;
  1505. phostent = GetHostAddr();
  1506. if (!phostent || !phostent->h_addr_list[0])
  1507. {
  1508. return DPERR_GENERIC;
  1509. }
  1510. // how many IP addresses do we have?
  1511. for (count=0; phostent->h_addr_list[count]; count++) {}
  1512. // allocate our DPAddress assembly buffers
  1513. // ANSI and UNICODE elements for each IP address plus one SP guid
  1514. // max size of IP address dot notation = 15 + terminator = 16
  1515. ENTER_DPSP();
  1516. // addressElement array
  1517. paDPAddrEl = MemAlloc(sizeof(DPCOMPOUNDADDRESSELEMENT)*(2*count + 1));
  1518. // one big buffer each for ANSI and UNICODE strings
  1519. pszIPAddr = pszBuf = MemAlloc(16*count);
  1520. pszIPAddrW = pszBufW = MemAlloc(sizeof(WCHAR)*(16*count));
  1521. if (!paDPAddrEl || !pszBuf || !pszBufW)
  1522. {
  1523. ASSERT(FALSE);
  1524. MemFree(paDPAddrEl);
  1525. MemFree(pszBuf);
  1526. MemFree(pszBufW);
  1527. LEAVE_DPSP();
  1528. return DPERR_NOMEMORY;
  1529. }
  1530. LEAVE_DPSP();
  1531. // service provider chunk
  1532. paDPAddrEl[0].guidDataType = DPAID_ServiceProvider;
  1533. paDPAddrEl[0].dwDataSize = sizeof(GUID);
  1534. paDPAddrEl[0].lpData = (LPVOID) &GUID_TCP;
  1535. // make an ANSI and UNICODE string of each IP address
  1536. for (i=0, j=1; i < count; i++)
  1537. {
  1538. DWORD dwStrLen; // includes terminator
  1539. IN_ADDR hostaddr;
  1540. memcpy(&hostaddr, phostent->h_addr_list[i], sizeof(hostaddr));
  1541. strcpy(pszIPAddr, inet_ntoa(hostaddr));
  1542. dwStrLen = (DWORD)AnsiToWide(pszIPAddrW, pszIPAddr, 16);
  1543. if (dwStrLen == 0 || dwStrLen > 16)
  1544. {
  1545. ASSERT(FALSE);
  1546. hr = DPERR_GENERIC;
  1547. goto cleanup;
  1548. }
  1549. paDPAddrEl[j].guidDataType = DPAID_INet;
  1550. paDPAddrEl[j].dwDataSize = dwStrLen;
  1551. paDPAddrEl[j++].lpData = pszIPAddr;
  1552. paDPAddrEl[j].guidDataType = DPAID_INetW;
  1553. paDPAddrEl[j].dwDataSize = dwStrLen * sizeof(WCHAR);
  1554. paDPAddrEl[j++].lpData = pszIPAddrW;
  1555. pszIPAddr += 16; // bump buffer ptrs by max str size
  1556. pszIPAddrW += 16;
  1557. }
  1558. // create the address
  1559. hr = pad->lpISP->lpVtbl->CreateCompoundAddress(pad->lpISP,
  1560. paDPAddrEl, 2*count+1, pad->lpAddress, pad->lpdwAddressSize);
  1561. cleanup:
  1562. ENTER_DPSP();
  1563. MemFree(paDPAddrEl);
  1564. MemFree(pszBuf);
  1565. MemFree(pszBufW);
  1566. LEAVE_DPSP();
  1567. return hr;
  1568. } // SP_GetAddressLocal
  1569. // get the ip address of the player from its playerdata
  1570. // ask winsock to convert that to a hostname
  1571. HRESULT WINAPI SP_GetAddress(LPDPSP_GETADDRESSDATA pad)
  1572. {
  1573. HRESULT hr = DP_OK;
  1574. LPSPPLAYERDATA ppd;
  1575. DWORD dwSize = sizeof(SPPLAYERDATA);
  1576. LPSTR pszNetName;
  1577. UINT nStrLen;
  1578. LPSOCKADDR_IN psockaddr;
  1579. DWORD dwDataSize = sizeof(GLOBALDATA);
  1580. LPGLOBALDATA pgd;
  1581. DPCOMPOUNDADDRESSELEMENT addressElements[3];
  1582. WCHAR szNetNameW[HOST_NAME_LENGTH];
  1583. // get the global data
  1584. hr = pad->lpISP->lpVtbl->GetSPData(pad->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  1585. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  1586. {
  1587. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  1588. return E_FAIL;
  1589. }
  1590. if (AF_IPX == pgd->AddressFamily)
  1591. {
  1592. // not gonna happen
  1593. return E_NOTIMPL;
  1594. }
  1595. hr = pad->lpISP->lpVtbl->GetSPPlayerData(pad->lpISP,pad->idPlayer,&ppd,&dwSize,DPGET_REMOTE);
  1596. if (FAILED(hr))
  1597. {
  1598. ASSERT(FALSE);
  1599. return hr;
  1600. }
  1601. if (pad->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL)
  1602. {
  1603. // We use a different approach for local players
  1604. return SP_GetAddressLocal(pad);
  1605. }
  1606. else
  1607. {
  1608. psockaddr = (LPSOCKADDR_IN)DGRAM_PSOCKADDR(ppd);
  1609. pszNetName = inet_ntoa(psockaddr->sin_addr);
  1610. }
  1611. if (!pszNetName)
  1612. {
  1613. // rut ro
  1614. DPF_ERR("got no string back from getaddress");
  1615. return E_FAIL;
  1616. }
  1617. nStrLen = strlen(pszNetName)+1;
  1618. DPF(2,"get address found address for player id %d = %s\n",pad->idPlayer,pszNetName);
  1619. // get UNICODE version of address
  1620. if (!AnsiToWide(szNetNameW, pszNetName, HOST_NAME_LENGTH))
  1621. return (DPERR_GENERIC);
  1622. // service provider chunk
  1623. addressElements[0].guidDataType = DPAID_ServiceProvider;
  1624. addressElements[0].dwDataSize = sizeof(GUID);
  1625. addressElements[0].lpData = (LPVOID) &GUID_TCP;
  1626. // ANSI name
  1627. addressElements[1].guidDataType = DPAID_INet;
  1628. addressElements[1].dwDataSize = nStrLen;
  1629. addressElements[1].lpData = pszNetName;
  1630. // UNICODE name
  1631. addressElements[2].guidDataType = DPAID_INetW;
  1632. addressElements[2].dwDataSize = nStrLen * sizeof(WCHAR);
  1633. addressElements[2].lpData = szNetNameW;
  1634. // create the address
  1635. hr = pad->lpISP->lpVtbl->CreateCompoundAddress(pad->lpISP,
  1636. addressElements, 3,
  1637. pad->lpAddress, pad->lpdwAddressSize);
  1638. return hr;
  1639. } // SP_GetAddress
  1640. #undef DPF_MODNAME
  1641. #define DPF_MODNAME "Reply"
  1642. // called by ReplyThreadProc to send the reply out on the wire
  1643. HRESULT SendReply(LPGLOBALDATA pgd,LPREPLYLIST prd)
  1644. {
  1645. HRESULT hr;
  1646. SOCKET sSocket;
  1647. UINT addrlen = sizeof(SOCKADDR);
  1648. UINT err;
  1649. BOOL bConnectionExists = FALSE;
  1650. // now, send out prd
  1651. switch (pgd->AddressFamily)
  1652. {
  1653. case AF_INET:
  1654. {
  1655. DPID dpidPlayer=0;
  1656. #ifdef FULLDUPLEX_SUPPORT
  1657. // if client wants us to reuse a connection, it would have indicated so and the connection
  1658. // would have been added to our send list by now. See if it exists.
  1659. // todo - we don't want to search the receive list everytime - find a better way
  1660. bConnectionExists = FindSocketInBag(pgd, &prd->sockaddr, &prd->sSocket,&dpidPlayer);
  1661. #endif // FULLDUPLEX_SUPPORT
  1662. if (!bConnectionExists)
  1663. {
  1664. // socket didn't exist in our send list, let's send it on a new temporary connection
  1665. DEBUGPRINTADDR(9,"Sending reply on a new connection to - ", &(prd->sockaddr));
  1666. hr = CreateSocket(pgd,&sSocket,SOCK_STREAM,0,INADDR_ANY,&err,FALSE);
  1667. if (FAILED(hr))
  1668. {
  1669. DPF(0,"create reply socket failed - err = %d\n",err);
  1670. return hr;
  1671. }
  1672. SetReturnAddress(prd->lpMessage,pgd->sSystemStreamSocket);
  1673. hr = SPConnect(&sSocket,(LPSOCKADDR)&(prd->sockaddr),addrlen,FALSE);
  1674. if (FAILED(hr))
  1675. {
  1676. DEBUGPRINTADDR(0,"reply - connect failed - addr = ",(LPSOCKADDR)&(prd->sockaddr));
  1677. }
  1678. else
  1679. {
  1680. DEBUGPRINTADDR(9,"Sending reply to - ", &(prd->sockaddr));
  1681. err = send(sSocket,prd->lpMessage,prd->dwMessageSize,0);
  1682. if (SOCKET_ERROR == err)
  1683. {
  1684. err = WSAGetLastError();
  1685. DPF(0,"reply - send error - err = %d\n",err);
  1686. hr = E_FAIL;
  1687. }
  1688. }
  1689. // nuke the socket
  1690. KillSocket(sSocket,TRUE,FALSE);
  1691. }
  1692. else
  1693. {
  1694. DEBUGPRINTADDR(9,"Sending reply on an existing connection to - ", &(prd->sockaddr));
  1695. err = send(prd->sSocket,prd->lpMessage,prd->dwMessageSize,0);
  1696. if (SOCKET_ERROR == err)
  1697. {
  1698. err = WSAGetLastError();
  1699. DPF(0,"reply - send error - err = %d\n",err);
  1700. hr = E_FAIL;
  1701. }
  1702. // close the connection if it's a temporary one (no player id yet).
  1703. if (0 == dpidPlayer)
  1704. {
  1705. RemoveSocketFromReceiveList(pgd,prd->sSocket);
  1706. RemoveSocketFromBag(pgd,prd->sSocket);
  1707. }
  1708. }
  1709. break;
  1710. }
  1711. case AF_IPX:
  1712. {
  1713. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,0,INADDR_ANY,&err,FALSE);
  1714. if (FAILED(hr))
  1715. {
  1716. DPF(0,"create reply socket failed - err = %d\n",err);
  1717. return hr;
  1718. }
  1719. SetReturnAddress(prd->lpMessage,pgd->sSystemDGramSocket);
  1720. err = sendto(sSocket,prd->lpMessage,prd->dwMessageSize,0,
  1721. (LPSOCKADDR)&(prd->sockaddr),addrlen);
  1722. if (SOCKET_ERROR == err)
  1723. {
  1724. err = WSAGetLastError();
  1725. DPF(0,"reply - send error - err = %d\n",err);
  1726. hr = E_FAIL;
  1727. }
  1728. // nuke the socket
  1729. KillSocket(sSocket,FALSE,FALSE);
  1730. break;
  1731. }
  1732. default:
  1733. hr = E_FAIL;
  1734. ASSERT(FALSE);
  1735. break;
  1736. }
  1737. return hr;
  1738. } // SendReply
  1739. DWORD WINAPI ReplyThreadProc(LPVOID pvCast)
  1740. {
  1741. LPREPLYLIST prd,prdNext;
  1742. HRESULT hr=DP_OK;
  1743. DWORD dwRet;
  1744. LPGLOBALDATA pgd = (LPGLOBALDATA) pvCast;
  1745. while (1)
  1746. {
  1747. // wait on our event. when it's set, we either split, or empty the reply list
  1748. dwRet = WaitForSingleObject(pgd->hReplyEvent,INFINITE);
  1749. if (WAIT_OBJECT_0 != dwRet)
  1750. {
  1751. ASSERT(FALSE);
  1752. goto CLEANUP_EXIT;
  1753. }
  1754. // shutdown?
  1755. if (pgd->bShutdown)
  1756. {
  1757. goto CLEANUP_EXIT;
  1758. }
  1759. Top:
  1760. // find our reply node
  1761. ENTER_DPSP();
  1762. // take the first one off the list
  1763. prd = pgd->pReplyList;
  1764. if (pgd->pReplyList) pgd->pReplyList = pgd->pReplyList->pNextReply;
  1765. LEAVE_DPSP();
  1766. while (prd)
  1767. {
  1768. hr = SendReply(pgd,prd);
  1769. if (FAILED(hr))
  1770. {
  1771. DPF_ERR("SendReply failed hr = 0x%08lx\n");
  1772. // we can't reach the guy, clean out other async sends.
  1773. RemovePendingAsyncSends(pgd, prd->dwPlayerTo);
  1774. goto Top;
  1775. }
  1776. // free up the reply node
  1777. ENTER_DPSP();
  1778. if (prd->lpMessage) MemFree(prd->lpMessage);
  1779. MemFree(prd);
  1780. // take the next one off the list
  1781. prd = pgd->pReplyList;
  1782. if (pgd->pReplyList) pgd->pReplyList = pgd->pReplyList->pNextReply;
  1783. LEAVE_DPSP();
  1784. }
  1785. } // 1
  1786. CLEANUP_EXIT:
  1787. ENTER_DPSP();
  1788. // cleanout reply list
  1789. prd = pgd->pReplyList;
  1790. while (prd)
  1791. {
  1792. prdNext = prd->pNextReply;
  1793. if (prd->lpMessage) MemFree(prd->lpMessage);
  1794. MemFree(prd);
  1795. prd = prdNext;
  1796. }
  1797. pgd->pReplyList = NULL;
  1798. CloseHandle(pgd->hReplyEvent);
  1799. pgd->hReplyEvent = 0;
  1800. LEAVE_DPSP();
  1801. DPF(6,"replythreadproc exit");
  1802. return 0;
  1803. } // ReplyThreadProc
  1804. HRESULT StartReplyThread(LPGLOBALDATA pgd)
  1805. {
  1806. HANDLE hThread;
  1807. DWORD dwThreadID;
  1808. // 1st, create the event
  1809. pgd->hReplyEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
  1810. if (!pgd->hReplyEvent)
  1811. {
  1812. ASSERT(FALSE);
  1813. return E_FAIL;
  1814. }
  1815. // now, spin the thread
  1816. if (hWS2 && (AF_IPX != pgd->AddressFamily))
  1817. {
  1818. hThread = CreateThread(NULL,0,AsyncSendThreadProc,pgd,0,&dwThreadID);
  1819. }
  1820. else
  1821. {
  1822. hThread = CreateThread(NULL,0,ReplyThreadProc,pgd,0,&dwThreadID);
  1823. }
  1824. if (!hThread)
  1825. {
  1826. ASSERT(FALSE);
  1827. return E_FAIL;
  1828. }
  1829. pgd->hReplyThread = hThread;
  1830. return DP_OK;
  1831. } // StartReplyThread
  1832. HRESULT WINAPI InternalSP_Reply(LPDPSP_REPLYDATA prd, DPID dwPlayerID)
  1833. {
  1834. LPSOCKADDR psockaddr;
  1835. HRESULT hr=DP_OK;
  1836. LPMESSAGEHEADER phead;
  1837. LPBYTE pSendBufferCopy;
  1838. LPREPLYLIST prl,prlList;
  1839. DWORD dwDataSize = sizeof(GLOBALDATA);
  1840. LPGLOBALDATA pgd;
  1841. // get the global data
  1842. hr =prd->lpISP->lpVtbl->GetSPData(prd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  1843. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  1844. {
  1845. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  1846. return E_FAIL;
  1847. }
  1848. if (prd->dwMessageSize > SPMAXMESSAGELEN)
  1849. {
  1850. ASSERT(FALSE);
  1851. return DPERR_SENDTOOBIG;
  1852. }
  1853. // check the header
  1854. if (!prd->lpSPMessageHeader || !VALID_DPWS_MESSAGE(prd->lpSPMessageHeader))
  1855. {
  1856. DPF_ERR(" YIKES! Got invalid SP header - can't reply ");
  1857. ASSERT(FALSE);
  1858. return E_FAIL;
  1859. }
  1860. // get the address to reply to
  1861. phead = (LPMESSAGEHEADER)prd->lpSPMessageHeader;
  1862. psockaddr = &(phead->sockaddr);
  1863. DEBUGPRINTADDR(5,"reply - sending to ",psockaddr);
  1864. DPF(7,"reply - q'ing %d bytes hEvent = 0x%08lx\n",prd->dwMessageSize,pgd->hReplyEvent);
  1865. // stick the message size in the message
  1866. SetMessageHeader(prd->lpMessage,prd->dwMessageSize,TOKEN);
  1867. // build a copy of everything for our receive thread
  1868. ENTER_DPSP();
  1869. prl = MemAlloc(sizeof(REPLYLIST));
  1870. if (!prl)
  1871. {
  1872. LEAVE_DPSP();
  1873. DPF_ERR("could not send reply - out of memory");
  1874. return E_OUTOFMEMORY;
  1875. }
  1876. pSendBufferCopy = MemAlloc(prd->dwMessageSize);
  1877. if (!pSendBufferCopy)
  1878. {
  1879. MemFree(prl);
  1880. LEAVE_DPSP();
  1881. DPF_ERR("could not send reply - out of memory");
  1882. return E_OUTOFMEMORY;
  1883. }
  1884. memcpy(pSendBufferCopy,prd->lpMessage,prd->dwMessageSize);
  1885. prl->lpMessage = pSendBufferCopy;
  1886. prl->dwMessageSize = prd->dwMessageSize;
  1887. prl->sockaddr = *psockaddr;
  1888. prl->sSocket = INVALID_SOCKET;
  1889. // since are replies could be sent async, we need to keep track
  1890. // of how many bytes have gone out
  1891. prl->pbSend = pSendBufferCopy;
  1892. prl->dwBytesLeft = prd->dwMessageSize;
  1893. prl->dwPlayerTo=dwPlayerID;
  1894. // put prl on the end of the reply list
  1895. prlList = pgd->pReplyList;
  1896. if (!prlList)
  1897. {
  1898. pgd->pReplyList = prl;
  1899. }
  1900. else
  1901. {
  1902. // find the end
  1903. while (prlList->pNextReply) prlList = prlList->pNextReply;
  1904. ASSERT(!prlList->pNextReply);
  1905. prlList->pNextReply = prl;
  1906. }
  1907. // do we need to start the reply event?
  1908. if (!pgd->hReplyThread)
  1909. {
  1910. hr = StartReplyThread(pgd);
  1911. if (FAILED(hr))
  1912. {
  1913. ASSERT(FALSE);
  1914. }
  1915. }
  1916. LEAVE_DPSP();
  1917. // tell the reply event to do its thing
  1918. SetEvent(pgd->hReplyEvent);
  1919. return DP_OK;
  1920. } // reply
  1921. /*
  1922. ** Reply
  1923. *
  1924. * CALLED BY: DPLAY
  1925. *
  1926. * PARAMETERS: prd - see dplayi.h
  1927. *
  1928. * DESCRIPTION:
  1929. * when one of the receive loops calls into dplay, dplay may call reply.
  1930. * the receive loop extracts the return address out of the message, and passes
  1931. * it to dplay . dplay passes this to reply (via prd), which figures out how to send the
  1932. * return message.
  1933. *
  1934. *
  1935. * RETURNS: E_FAIL on a socket error or DP_OK.
  1936. *
  1937. */
  1938. HRESULT WINAPI SP_Reply(LPDPSP_REPLYDATA prd)
  1939. {
  1940. return InternalSP_Reply(prd, 0);
  1941. }
  1942. #undef DPF_MODNAME
  1943. #define DPF_MODNAME "CreatePlayer"
  1944. //
  1945. // if we're starting up a nameserver, register it w/ dphelp.exe
  1946. // see %MANROOT%\misc\w95help.c and %MANROOT%\ddhelp\dphelp.c
  1947. HRESULT StartDPHelp(LPGLOBALDATA pgd, USHORT port)
  1948. {
  1949. DWORD hpid = 0, dwFlags=0;
  1950. HRESULT hr;
  1951. CreateHelperProcess( &hpid );
  1952. if (!hpid)
  1953. {
  1954. // could't start one...
  1955. return DPERR_UNAVAILABLE;
  1956. }
  1957. if (!WaitForHelperStartup())
  1958. {
  1959. return DPERR_UNAVAILABLE;
  1960. }
  1961. hr = HelperAddDPlayServer(port);
  1962. return hr;
  1963. } // StartDPHelp
  1964. //
  1965. // we've just created a player of type dwFlags.
  1966. // if it's a system player, see if we need to start up our receive thread procs
  1967. //
  1968. HRESULT StartPlayerListenThreads(IDirectPlaySP * pISP,LPGLOBALDATA pgd,DWORD dwFlags)
  1969. {
  1970. DWORD dwThreadID;
  1971. HANDLE hThread;
  1972. if ( !(dwFlags & DPLAYI_PLAYER_SYSPLAYER) ) return DP_OK;
  1973. if (!pgd->hDGramReceiveThread)
  1974. {
  1975. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  1976. hThread = CreateThread(NULL,0,DgramListenThreadProc,
  1977. (LPVOID)pISP,0,&dwThreadID);
  1978. ASSERT(hThread);
  1979. if(pgd->hDGramReceiveThread = hThread){ // check for non-zero hThread
  1980. SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  1981. }
  1982. }
  1983. if ( (AF_IPX != pgd->AddressFamily) && !(pgd->hStreamReceiveThread) )
  1984. {
  1985. ASSERT(INVALID_SOCKET != pgd->sSystemStreamSocket);
  1986. hThread = CreateThread(NULL,0,StreamReceiveThreadProc,
  1987. (LPVOID)pISP,0,&dwThreadID);
  1988. ASSERT(hThread);
  1989. if(pgd->hStreamReceiveThread = hThread){ // check for non-zero hThread
  1990. SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  1991. }
  1992. }
  1993. return DP_OK;
  1994. } // StartPlayerListenThreads
  1995. // create a player. get a stream and dgram socket for it, and start their listen threads.
  1996. HRESULT WINAPI SP_CreatePlayer(LPDPSP_CREATEPLAYERDATA pcpd)
  1997. {
  1998. HRESULT hr=DP_OK;
  1999. LPSPPLAYERDATA ppd;
  2000. DWORD dwSize = sizeof(SPPLAYERDATA);
  2001. DWORD dwDataSize = sizeof(GLOBALDATA);
  2002. LPGLOBALDATA pgd;
  2003. // get the global data
  2004. hr =pcpd->lpISP->lpVtbl->GetSPData(pcpd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2005. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2006. {
  2007. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2008. return E_FAIL;
  2009. }
  2010. if (!(pcpd->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  2011. {
  2012. DWORD dwSize = sizeof(SPPLAYERDATA);
  2013. LPMESSAGEHEADER pmsg;
  2014. hr = pcpd->lpISP->lpVtbl->GetSPPlayerData(pcpd->lpISP,pcpd->idPlayer,&ppd,&dwSize,DPGET_REMOTE);
  2015. if (FAILED(hr))
  2016. {
  2017. ASSERT(FALSE);
  2018. return hr;
  2019. }
  2020. if (sizeof(SPPLAYERDATA) != dwSize)
  2021. {
  2022. // this can happen if it's a game server supplied player
  2023. return DP_OK;
  2024. }
  2025. pmsg = (LPMESSAGEHEADER)pcpd->lpSPMessageHeader;
  2026. if (!pmsg)
  2027. {
  2028. // this can happen if it's a game server supplied player
  2029. return DP_OK;
  2030. }
  2031. // make it multihomed. we passed the received address w/ the createplayer message.
  2032. // set the receive address on the player here.
  2033. // if the ip addr wasn't set, this player hasn't been "homed" yet.
  2034. // we set it here.
  2035. if (AF_INET == pgd->AddressFamily)
  2036. {
  2037. IP_GetAddr((SOCKADDR_IN *)DGRAM_PSOCKADDR(ppd),(SOCKADDR_IN *)&(pmsg->sockaddr));
  2038. IP_GetAddr((SOCKADDR_IN *)STREAM_PSOCKADDR(ppd),(SOCKADDR_IN *)&(pmsg->sockaddr));
  2039. #ifdef FULLDUPLEX_SUPPORT
  2040. // if client want's us to reuse a connection, the socket would have been added to the
  2041. // send bag already, but the id would be 0. Update the player id.
  2042. UpdateSocketPlayerID(pgd,&pmsg->sockaddr,pcpd->idPlayer);
  2043. #endif // FULLDUPLEX_SUPPORT
  2044. }
  2045. else if (AF_IPX == pgd->AddressFamily)
  2046. {
  2047. IPX_GetNodenum((SOCKADDR_IPX *)DGRAM_PSOCKADDR(ppd),(SOCKADDR_IPX *)&(pmsg->sockaddr));
  2048. IPX_GetNodenum((SOCKADDR_IPX *)STREAM_PSOCKADDR(ppd),(SOCKADDR_IPX *)&(pmsg->sockaddr));
  2049. }
  2050. return DP_OK;
  2051. } // !Local
  2052. // it's local, so get it some sockets + threads if we need to
  2053. // alloc the sp player data for this player
  2054. ENTER_DPSP();
  2055. ppd = MemAlloc(sizeof(SPPLAYERDATA));
  2056. LEAVE_DPSP();
  2057. if (!ppd)
  2058. {
  2059. DPF_ERR("could not alloc player data struct");
  2060. return E_OUTOFMEMORY;
  2061. }
  2062. hr = CreatePlayerDgramSocket(pgd,ppd,pcpd->dwFlags);
  2063. if (FAILED(hr))
  2064. {
  2065. DPF_ERR("could not create dgram socket");
  2066. goto CLEANUP_EXIT;
  2067. }
  2068. if (AF_IPX != pgd->AddressFamily)
  2069. {
  2070. hr = CreatePlayerStreamSocket(pgd,ppd,pcpd->dwFlags);
  2071. if (FAILED(hr))
  2072. {
  2073. DPF_ERR("could not create stream socket");
  2074. goto CLEANUP_EXIT;
  2075. }
  2076. }
  2077. // store the ppd
  2078. hr = pcpd->lpISP->lpVtbl->SetSPPlayerData(pcpd->lpISP,pcpd->idPlayer,ppd,dwSize,DPSET_REMOTE);
  2079. if (FAILED(hr))
  2080. {
  2081. ASSERT(FALSE);
  2082. goto CLEANUP_EXIT;
  2083. }
  2084. // see if we need to start listen thread for this player type.
  2085. hr = StartPlayerListenThreads(pcpd->lpISP,pgd,pcpd->dwFlags);
  2086. // if we need ddhelp, start it up
  2087. if ((AF_IPX != pgd->AddressFamily) && (pcpd->dwFlags & DPLAYI_PLAYER_NAMESRVR))
  2088. {
  2089. // it's ok to pass dgram port to dplaysvr always - we use the same number for stream
  2090. // socket as well
  2091. hr = StartDPHelp(pgd,IP_DGRAM_PORT(ppd));
  2092. if (FAILED(hr))
  2093. {
  2094. // ddhelp.exe barfed
  2095. DPF_ERR(" CREATE SERVER - COULD NOT START ENUM LISTEN APPLICATION");
  2096. DPF_ERR(" GAME WILL PLAY - BUT WILL NOT RECEIVE ENUMSESSIONS REQUESTS");
  2097. goto CLEANUP_EXIT;
  2098. }
  2099. }
  2100. // fall through to clean up
  2101. CLEANUP_EXIT:
  2102. ENTER_DPSP();
  2103. if (ppd) MemFree(ppd);
  2104. LEAVE_DPSP();
  2105. return hr;
  2106. } // CreatePlayer
  2107. #undef DPF_MODNAME
  2108. #define DPF_MODNAME "DeletePlayer"
  2109. void RemovePlayerFromSocketBag(LPGLOBALDATA pgd,DWORD dwID)
  2110. {
  2111. UINT i=0;
  2112. BOOL bFound = FALSE;
  2113. SOCKET sSocket=INVALID_SOCKET;
  2114. DWORD dwSocketFlags;
  2115. if (0 == dwID)
  2116. {
  2117. return;
  2118. }
  2119. ENTER_DPSP();
  2120. // see if we've got one
  2121. while (!bFound && (i<pgd->nSocketsInBag))
  2122. {
  2123. if (pgd->BagOSockets[i].dwPlayerID == dwID)
  2124. {
  2125. bFound = TRUE;
  2126. sSocket = pgd->BagOSockets[i].sSocket;
  2127. dwSocketFlags = pgd->BagOSockets[i].dwFlags;
  2128. DPF(5,"removing socket from bago id = %d, slot = %d",dwID,i);
  2129. pgd->BagOSockets[i].sSocket = INVALID_SOCKET;
  2130. pgd->BagOSockets[i].dwPlayerID = 0;
  2131. }
  2132. else i++;
  2133. }
  2134. LEAVE_DPSP();
  2135. if (bFound)
  2136. {
  2137. if (INVALID_SOCKET == sSocket) return ;
  2138. // if socket is fullduplex, remove it from the receive list as well
  2139. if (dwSocketFlags & DPSP_OUTBOUNDONLY)
  2140. {
  2141. // this function will kill the socket as well
  2142. RemoveSocketFromReceiveList(pgd,sSocket);
  2143. }
  2144. else
  2145. {
  2146. KillSocket(sSocket,TRUE,FALSE);
  2147. }
  2148. }
  2149. return ;
  2150. } // RemovePlayerFromSocketBag
  2151. HRESULT WINAPI SP_DeletePlayer(LPDPSP_DELETEPLAYERDATA pdpd)
  2152. {
  2153. DWORD dwDataSize = sizeof(GLOBALDATA);
  2154. LPGLOBALDATA pgd;
  2155. HRESULT hr;
  2156. DWORD sleepcount=0;
  2157. DPF(9, "Entering SP_DeletePlayer, player %d, flags 0x%x, lpISP 0x%08x\n",
  2158. pdpd->idPlayer, pdpd->dwFlags, pdpd->lpISP);
  2159. // get the global data
  2160. hr =pdpd->lpISP->lpVtbl->GetSPData(pdpd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2161. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2162. {
  2163. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2164. return E_FAIL;
  2165. }
  2166. // give the reply list 5 seconds to clear out
  2167. while(bAsyncSendsPending(pgd, pdpd->idPlayer)){
  2168. Sleep(100);
  2169. if(sleepcount++ == 50){
  2170. break;
  2171. }
  2172. }
  2173. RemovePendingAsyncSends(pgd, pdpd->idPlayer);
  2174. // if it's not local, we don't care
  2175. if (!(pdpd->dwFlags & DPLAYI_PLAYER_PLAYERLOCAL))
  2176. {
  2177. RemovePlayerFromSocketBag(pgd,pdpd->idPlayer);
  2178. return DP_OK;
  2179. }
  2180. // if it's not a sysplayer - we're done
  2181. // if its a sysplayer, we kill 'em, cause we may need to rebind to a new port
  2182. if (!(pdpd->dwFlags & DPLAYI_PLAYER_SYSPLAYER))
  2183. {
  2184. return DP_OK;
  2185. }
  2186. if ( (pdpd->dwFlags & DPLAYI_PLAYER_NAMESRVR) && (AF_IPX != pgd->AddressFamily) )
  2187. {
  2188. USHORT port;
  2189. LPSPPLAYERDATA ppd;
  2190. DWORD dwSize = sizeof(SPPLAYERDATA);
  2191. // we need to get the port to to delete the server
  2192. hr = pdpd->lpISP->lpVtbl->GetSPPlayerData(pdpd->lpISP,pdpd->idPlayer,&ppd,&dwSize,DPGET_REMOTE);
  2193. if ( FAILED(hr) || (sizeof(SPPLAYERDATA) != dwSize) )
  2194. {
  2195. ASSERT(FALSE);
  2196. }
  2197. else
  2198. {
  2199. // tell dplaysvr to delete this server
  2200. port = IP_DGRAM_PORT(ppd);
  2201. if ( !HelperDeleteDPlayServer(port) )
  2202. {
  2203. // ddhelp.exe barfed
  2204. DPF_ERR(" could not unregister w/ dphelp");
  2205. // keep going...
  2206. }
  2207. }
  2208. }
  2209. return DP_OK;
  2210. } // DeletePlayer
  2211. #undef DPF_MODNAME
  2212. #define DPF_MODNAME "UnreliableSend"
  2213. HRESULT UnreliableSend(LPDPSP_SENDDATA psd)
  2214. {
  2215. SOCKADDR sockaddr;
  2216. INT iAddrLen = sizeof(sockaddr);
  2217. HRESULT hr=DP_OK;
  2218. UINT err;
  2219. DWORD dwSize = sizeof(SPPLAYERDATA);
  2220. LPSPPLAYERDATA ppdTo;
  2221. DWORD dwDataSize = sizeof(GLOBALDATA);
  2222. LPGLOBALDATA pgd;
  2223. // get the global data
  2224. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2225. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2226. {
  2227. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2228. return E_FAIL;
  2229. }
  2230. if (pgd->iMaxUdpDg && (psd->dwMessageSize >= pgd->iMaxUdpDg))
  2231. {
  2232. return DPERR_SENDTOOBIG;
  2233. }
  2234. if (INVALID_SOCKET == pgd->sUnreliableSocket)
  2235. {
  2236. hr = CreateSocket(pgd,&(pgd->sUnreliableSocket),SOCK_DGRAM,0,INADDR_ANY,&err,FALSE);
  2237. if (FAILED(hr))
  2238. {
  2239. DPF(0,"create unreliable send socket failed - err = %d\n",err);
  2240. return hr;
  2241. }
  2242. }
  2243. // get to address
  2244. if (0 == psd->idPlayerTo)
  2245. {
  2246. sockaddr = pgd->saddrNS;
  2247. }
  2248. else
  2249. {
  2250. hr = psd->lpISP->lpVtbl->GetSPPlayerData(psd->lpISP,psd->idPlayerTo,&ppdTo,&dwSize,DPGET_REMOTE);
  2251. if (FAILED(hr))
  2252. {
  2253. ASSERT(FALSE);
  2254. return hr;
  2255. }
  2256. sockaddr = *(DGRAM_PSOCKADDR(ppdTo));
  2257. }
  2258. // put the token + size on front of the mesage
  2259. SetMessageHeader(psd->lpMessage,psd->dwMessageSize,TOKEN);
  2260. if (psd->bSystemMessage)
  2261. {
  2262. SetReturnAddress(psd->lpMessage,SERVICE_SOCKET(pgd));
  2263. } // reply
  2264. else
  2265. {
  2266. // see if we can send this message w/ no header
  2267. // if the message is smaller than a dword, or, if it's a valid sp header (fooling us
  2268. // on the other end, don't send any header
  2269. if ( !((psd->dwMessageSize >= sizeof(DWORD)) && !(VALID_SP_MESSAGE(psd->lpMessage))) )
  2270. {
  2271. psd->lpMessage = (LPBYTE)psd->lpMessage +sizeof(MESSAGEHEADER);
  2272. psd->dwMessageSize -= sizeof(MESSAGEHEADER);
  2273. }
  2274. }
  2275. DEBUGPRINTADDR(5,"unreliable send - sending to ",&sockaddr);
  2276. err = sendto(pgd->sUnreliableSocket,psd->lpMessage,psd->dwMessageSize,0,
  2277. (LPSOCKADDR)&sockaddr,iAddrLen);
  2278. if (SOCKET_ERROR == err)
  2279. {
  2280. err = WSAGetLastError();
  2281. DPF(0,"send error - err = %d\n",err);
  2282. hr = E_UNEXPECTED;
  2283. }
  2284. // fall through...
  2285. return hr;
  2286. } // UnreliableSend
  2287. #undef DPF_MODNAME
  2288. #define DPF_MODNAME "ReliableSend"
  2289. // see if we can find or create a connected socket in our
  2290. // bag o' sockets for player dwID
  2291. HRESULT GetSocketFromBag(LPGLOBALDATA pgd,SOCKET * psSocket, DWORD dwID,
  2292. LPSOCKADDR psockaddr)
  2293. {
  2294. HRESULT hr;
  2295. UINT i=0;
  2296. BOOL bFound = FALSE;
  2297. BOOL bTrue = TRUE;
  2298. UINT err;
  2299. SOCKET sSocket;
  2300. DPF(9, "GetSocketFromBag for id %d",dwID);
  2301. if (0 == dwID)
  2302. {
  2303. // need a real id
  2304. return E_FAIL;
  2305. }
  2306. ENTER_DPSP();
  2307. // see if we've got one already hooked up
  2308. while ((i < pgd->nSocketsInBag) && !bFound)
  2309. {
  2310. // if it's a valid socket and the id's match, use it
  2311. if ( (INVALID_SOCKET != pgd->BagOSockets[i].sSocket) &&
  2312. (pgd->BagOSockets[i].dwPlayerID == dwID) )
  2313. {
  2314. bFound = TRUE;
  2315. }
  2316. else i++;
  2317. }
  2318. LEAVE_DPSP();
  2319. if (bFound)
  2320. {
  2321. // bingo! got one
  2322. DPF(7, "Found socket in bag for player %d",dwID);
  2323. *psSocket = pgd->BagOSockets[i].sSocket;
  2324. return DP_OK;
  2325. }
  2326. // we don't have a socket for this player, let's get a new one
  2327. DPF(5,"adding new socket to bag for id = %d, slot = %d",dwID,i);
  2328. // create and connect socket
  2329. hr = CreateAndConnectSocket(pgd,&sSocket,SOCK_STREAM,psockaddr, (pgd->dwFlags & DPSP_OUTBOUNDONLY));
  2330. if (FAILED(hr))
  2331. {
  2332. return hr;
  2333. }
  2334. // enable keepalives
  2335. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_KEEPALIVE,
  2336. (char FAR *)&bTrue,sizeof(bTrue) ) )
  2337. {
  2338. err = WSAGetLastError();
  2339. DPF(2,"create - could not turn on keepalive err = %d\n",err);
  2340. // keep trying
  2341. }
  2342. hr = AddSocketToBag(pgd, sSocket, dwID, psockaddr,0);
  2343. if (FAILED(hr))
  2344. {
  2345. DPF(0,"Failed to add socket to bag: hr = 0x%08x", hr);
  2346. return hr;
  2347. }
  2348. DPF(7,"Created a new socket for player %d",dwID);
  2349. *psSocket = sSocket ;
  2350. return hr;
  2351. } // GetSocketFromBag
  2352. HRESULT ReliableSend(LPDPSP_SENDDATA psd)
  2353. {
  2354. SOCKET sSocket = INVALID_SOCKET;
  2355. SOCKADDR sockaddr;
  2356. INT iAddrLen = sizeof(sockaddr);
  2357. HRESULT hr;
  2358. DWORD dwSize = sizeof(SPPLAYERDATA);
  2359. LPSPPLAYERDATA ppdTo;
  2360. BOOL fKillSocket = FALSE; // don't kill this socket, it's from the bago
  2361. DWORD dwDataSize = sizeof(GLOBALDATA);
  2362. LPGLOBALDATA pgd;
  2363. // get the global data
  2364. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2365. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2366. {
  2367. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2368. return E_FAIL;
  2369. }
  2370. // get player to
  2371. if (0 == psd->idPlayerTo)
  2372. {
  2373. sockaddr = pgd->saddrNS;
  2374. }
  2375. else
  2376. {
  2377. hr = psd->lpISP->lpVtbl->GetSPPlayerData(psd->lpISP,psd->idPlayerTo,&ppdTo,&dwSize,DPGET_REMOTE);
  2378. if (FAILED(hr))
  2379. {
  2380. DPF(1, "GetSPPlayerData for player %d returned err %d", psd->idPlayerTo, hr);
  2381. if (hr != DPERR_INVALIDPLAYER) // this can happen because of race conditions
  2382. ASSERT(FALSE);
  2383. return hr;
  2384. }
  2385. sockaddr = *(STREAM_PSOCKADDR(ppdTo));
  2386. }
  2387. if (psd->bSystemMessage)
  2388. {
  2389. SetReturnAddress(psd->lpMessage,SERVICE_SOCKET(pgd));
  2390. }
  2391. // put the token + size on front of the mesage
  2392. SetMessageHeader(psd->lpMessage,psd->dwMessageSize,TOKEN);
  2393. DEBUGPRINTADDR(5,"reliable send - sending to ",&sockaddr);
  2394. hr = InternalReliableSend(pgd,psd->idPlayerTo,&sockaddr, psd->lpMessage, psd->dwMessageSize);
  2395. return hr;
  2396. } // InternalReliableSend
  2397. // puts together a replynode, and calls sp_reply to do
  2398. // an async send
  2399. HRESULT AsyncSend(LPDPSP_SENDDATA psd)
  2400. {
  2401. SOCKADDR sockaddr;
  2402. INT iAddrLen = sizeof(sockaddr);
  2403. HRESULT hr;
  2404. DWORD dwSize = sizeof(SPPLAYERDATA);
  2405. LPSPPLAYERDATA ppdTo;
  2406. DWORD dwDataSize = sizeof(GLOBALDATA);
  2407. LPGLOBALDATA pgd;
  2408. MESSAGEHEADER head;
  2409. DPSP_REPLYDATA rd;
  2410. // get the global data
  2411. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2412. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2413. {
  2414. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2415. return E_FAIL;
  2416. }
  2417. // get player to
  2418. if (0 == psd->idPlayerTo)
  2419. {
  2420. sockaddr = pgd->saddrNS;
  2421. }
  2422. else
  2423. {
  2424. hr = psd->lpISP->lpVtbl->GetSPPlayerData(psd->lpISP,psd->idPlayerTo,&ppdTo,&dwSize,DPGET_REMOTE);
  2425. if (FAILED(hr))
  2426. {
  2427. ASSERT(FALSE);
  2428. return hr;
  2429. }
  2430. sockaddr = *(STREAM_PSOCKADDR(ppdTo));
  2431. }
  2432. // write the return address into the on the wire message
  2433. SetReturnAddress(psd->lpMessage,SERVICE_SOCKET(pgd));
  2434. // put the token + size on front of the mesage
  2435. SetMessageHeader(psd->lpMessage,psd->dwMessageSize,TOKEN);
  2436. // set up a header. this will be passed to reply, and will tell the reply thread
  2437. // whre to send teh message
  2438. head.sockaddr = sockaddr;
  2439. // put our token on the front so the reply thread knows its a valid reply
  2440. SetMessageHeader((LPDWORD)(&head),0,TOKEN);
  2441. // use SP_Reply to send this for us...
  2442. memset(&rd,0,sizeof(rd));
  2443. rd.lpSPMessageHeader = &head;
  2444. rd.lpMessage = psd->lpMessage;
  2445. rd.dwMessageSize = psd->dwMessageSize;
  2446. rd.lpISP = psd->lpISP;
  2447. hr = InternalSP_Reply(&rd,psd->idPlayerTo);
  2448. return hr;
  2449. } // AsyncSend
  2450. #ifdef SENDEX
  2451. HRESULT WINAPI SP_GetMessageQueue(LPDPSP_GETMESSAGEQUEUEDATA pgqd)
  2452. {
  2453. LPGLOBALDATA pgd;
  2454. DWORD dwDataSize;
  2455. BILINK *pBilinkWalker;
  2456. DWORD dwNumMsgs = 0;
  2457. DWORD dwNumBytes = 0;
  2458. LPSENDINFO lpSendInfo;
  2459. HRESULT hr;
  2460. hr = pgqd->lpISP->lpVtbl->GetSPData(pgqd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2461. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2462. {
  2463. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2464. return E_FAIL;
  2465. }
  2466. EnterCriticalSection(&pgd->csSendEx);
  2467. if(!pgqd->idFrom && !pgqd->idTo){
  2468. // just wants totals, I already know that!
  2469. dwNumMsgs = pgd->dwMessagesPending;
  2470. dwNumBytes = pgd->dwBytesPending;
  2471. } else {
  2472. // gotta walk the list.
  2473. pBilinkWalker=pgd->PendingSendQ.next;
  2474. while(pBilinkWalker != &pgd->PendingSendQ)
  2475. {
  2476. lpSendInfo=CONTAINING_RECORD(pBilinkWalker, SENDINFO, PendingSendQ);
  2477. pBilinkWalker=pBilinkWalker->next;
  2478. if(pgqd->idTo && pgqd->idFrom) {
  2479. if(lpSendInfo->idTo==pgqd->idTo && lpSendInfo->idFrom==pgqd->idFrom){
  2480. dwNumMsgs++;
  2481. dwNumBytes+=lpSendInfo->dwMessageSize;
  2482. }
  2483. } else if (pgqd->idTo){
  2484. if(lpSendInfo->idTo==pgqd->idTo){
  2485. dwNumMsgs++;
  2486. dwNumBytes+=lpSendInfo->dwMessageSize;
  2487. }
  2488. } else if (pgqd->idFrom) {
  2489. if(lpSendInfo->idFrom==pgqd->idFrom){
  2490. dwNumMsgs++;
  2491. dwNumBytes+=lpSendInfo->dwMessageSize;
  2492. }
  2493. } else {
  2494. ASSERT(0);
  2495. }
  2496. }
  2497. }
  2498. LeaveCriticalSection(&pgd->csSendEx);
  2499. if(pgqd->lpdwNumMsgs){
  2500. *pgqd->lpdwNumMsgs = dwNumMsgs;
  2501. }
  2502. if(pgqd->lpdwNumBytes){
  2503. *pgqd->lpdwNumBytes = dwNumBytes;
  2504. }
  2505. return DP_OK;
  2506. }
  2507. HRESULT WINAPI SP_SendEx(LPDPSP_SENDEXDATA psd)
  2508. {
  2509. HRESULT hr=DP_OK;
  2510. DWORD dwDataSize = sizeof(GLOBALDATA);
  2511. LPGLOBALDATA pgd;
  2512. LPSENDINFO lpSendInfo;
  2513. // get the global data
  2514. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2515. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2516. {
  2517. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2518. return E_FAIL;
  2519. }
  2520. if (psd->dwMessageSize >= SPMAXMESSAGELEN)
  2521. {
  2522. return DPERR_SENDTOOBIG;
  2523. }
  2524. // overlapped and SPheader buffer are allocated together.
  2525. lpSendInfo = pgd->pSendInfoPool->Get(pgd->pSendInfoPool);
  2526. if(!lpSendInfo){
  2527. hr=DPERR_OUTOFMEMORY;
  2528. DPF(0,"WSOCK: sendex couldn't allocate overlapped, out of memory!\n");
  2529. goto EXIT;
  2530. }
  2531. lpSendInfo->SendArray[0].buf = (CHAR *)(lpSendInfo+1);
  2532. lpSendInfo->SendArray[0].len = sizeof(MESSAGEHEADER);
  2533. ASSERT(psd->cBuffers < MAX_SG-1); //BUGBUG: coalesce please!
  2534. memcpy(&lpSendInfo->SendArray[1], psd->lpSendBuffers, psd->cBuffers*sizeof(SGBUFFER));
  2535. if ((psd->dwFlags & DPSEND_GUARANTEE) && (AF_IPX != pgd->AddressFamily))
  2536. {
  2537. hr = ReliableSendEx(psd,lpSendInfo);
  2538. if (hr!=DPERR_PENDING && FAILED(hr)) {
  2539. pgd->pSendInfoPool->Release(pgd->pSendInfoPool, lpSendInfo);
  2540. DPF(0,"reliable sendex failed - error - hr = 0x%08lx\n",hr);
  2541. }
  2542. }
  2543. else
  2544. {
  2545. hr = UnreliableSendEx(psd,lpSendInfo);
  2546. if (hr!=DPERR_PENDING && FAILED(hr)) {
  2547. pgd->pSendInfoPool->Release(pgd->pSendInfoPool, lpSendInfo);
  2548. DPF(0,"unreliable sendex failed - error - hr = 0x%08lx\n",hr);
  2549. }
  2550. }
  2551. EXIT:
  2552. return hr;
  2553. } // send
  2554. HRESULT ReliableSendEx(LPDPSP_SENDEXDATA psd, LPSENDINFO pSendInfo)
  2555. {
  2556. SOCKET sSocket = INVALID_SOCKET;
  2557. SOCKADDR sockaddr;
  2558. INT iAddrLen = sizeof(sockaddr);
  2559. HRESULT hr;
  2560. DWORD dwSize = sizeof(SPPLAYERDATA);
  2561. LPSPPLAYERDATA ppdTo;
  2562. BOOL fKillSocket = FALSE; // don't kill this socket, it's from the bago
  2563. DWORD dwDataSize = sizeof(GLOBALDATA);
  2564. LPGLOBALDATA pgd;
  2565. // get the global data
  2566. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2567. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2568. {
  2569. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2570. return E_FAIL;
  2571. }
  2572. // get player to
  2573. if (0 == psd->idPlayerTo)
  2574. {
  2575. sockaddr = pgd->saddrNS;
  2576. }
  2577. else
  2578. {
  2579. hr = psd->lpISP->lpVtbl->GetSPPlayerData(psd->lpISP,psd->idPlayerTo,&ppdTo,&dwSize,DPGET_REMOTE);
  2580. if (FAILED(hr))
  2581. {
  2582. DPF(1, "GetSPPlayerData for player %d returned err %d", psd->idPlayerTo, hr);
  2583. if (hr != DPERR_INVALIDPLAYER) // this can happen because of race conditions
  2584. ASSERT(FALSE);
  2585. return hr;
  2586. }
  2587. sockaddr = *(STREAM_PSOCKADDR(ppdTo));
  2588. }
  2589. if (psd->bSystemMessage)
  2590. {
  2591. SetReturnAddress((pSendInfo->SendArray)[0].buf,SERVICE_SOCKET(pgd));
  2592. }
  2593. // put the token + size on front of the mesage
  2594. SetMessageHeader((LPVOID)(pSendInfo->SendArray)[0].buf,psd->dwMessageSize+sizeof(MESSAGEHEADER),TOKEN);
  2595. DEBUGPRINTADDR(5,"reliable send - sending to ",&sockaddr);
  2596. hr = InternalReliableSendEx(pgd,psd,pSendInfo,&sockaddr);
  2597. return hr;
  2598. } // ReliableSendEx
  2599. #endif //SENDEX
  2600. HRESULT InternalReliableSend(LPGLOBALDATA pgd, DPID idPlayerTo, SOCKADDR *
  2601. lpSockAddr, LPBYTE lpMessage, DWORD dwMessageSize)
  2602. {
  2603. HRESULT hr;
  2604. SOCKET sSocket = INVALID_SOCKET;
  2605. UINT err;
  2606. // see if we have a connection already
  2607. hr = GetSocketFromBag(pgd,&sSocket,idPlayerTo,lpSockAddr);
  2608. if (SUCCEEDED(hr))
  2609. {
  2610. // we do, send the message
  2611. err = send(sSocket,lpMessage,dwMessageSize,0);
  2612. if (SOCKET_ERROR == err)
  2613. {
  2614. err = WSAGetLastError();
  2615. // we got a socket from the bag. send failed,
  2616. // so we're cruising it from the bag
  2617. DPF(0,"send error - err = %d\n",err);
  2618. DPF(4,"send failed - removing socket from bag");
  2619. RemovePlayerFromSocketBag(pgd,idPlayerTo);
  2620. if(err==WSAECONNRESET || err==WSAENETRESET || err==WSAENOTCONN){
  2621. hr=DPERR_CONNECTIONLOST;
  2622. } else {
  2623. hr = E_FAIL;
  2624. }
  2625. }
  2626. return hr;
  2627. }
  2628. // if we reach here, we don't have a connection so get a new one
  2629. hr = CreateAndConnectSocket(pgd,&sSocket,SOCK_STREAM,lpSockAddr, (pgd->dwFlags & DPSP_OUTBOUNDONLY));
  2630. if (FAILED(hr))
  2631. {
  2632. goto CLEANUP_EXIT;
  2633. }
  2634. // send the message
  2635. err = send(sSocket,lpMessage,dwMessageSize,0);
  2636. if (SOCKET_ERROR == err)
  2637. {
  2638. err = WSAGetLastError();
  2639. DPF(0,"send error - err = %d\n",err);
  2640. if(err == WSAECONNRESET || err==WSAENETRESET || err==WSAENOTCONN){
  2641. hr = DPERR_CONNECTIONLOST;
  2642. } else {
  2643. hr = E_FAIL;
  2644. }
  2645. goto CLEANUP_EXIT;
  2646. }
  2647. // success
  2648. hr = DP_OK;
  2649. // fall through
  2650. CLEANUP_EXIT:
  2651. // if we are in outbound only mode, receiver will close the connection, so don't bother
  2652. if ((INVALID_SOCKET != sSocket) && !(pgd->dwFlags & DPSP_OUTBOUNDONLY))
  2653. {
  2654. KillSocket(sSocket, TRUE, FALSE);
  2655. }
  2656. return hr;
  2657. }
  2658. // called when a to player can't be reached or is deleted.
  2659. VOID RemovePendingAsyncSends(LPGLOBALDATA pgd, DPID dwPlayerTo)
  2660. {
  2661. LPREPLYLIST prl, prlPrev;
  2662. #ifdef DEBUG
  2663. DWORD dwBlowAwayCount=0;
  2664. #endif
  2665. if(!dwPlayerTo){
  2666. return;
  2667. }
  2668. ENTER_DPSP();
  2669. prlPrev = (LPREPLYLIST)(&pgd->pReplyList); // HACKHACK, treat struct as dummy node.
  2670. prl = pgd->pReplyList;
  2671. while(prl){
  2672. if(prl->dwPlayerTo == dwPlayerTo){
  2673. prlPrev->pNextReply=prl->pNextReply;
  2674. if(prl->lpMessage) {
  2675. MemFree(prl->lpMessage);
  2676. }
  2677. MemFree(prl);
  2678. #ifdef DEBUG
  2679. dwBlowAwayCount++;
  2680. #endif
  2681. } else {
  2682. prlPrev=prl;
  2683. }
  2684. prl=prlPrev->pNextReply;
  2685. }
  2686. DPF(4,"RemovePendingAsyncSends for player %x, blew away %d pending sends\n",dwPlayerTo,dwBlowAwayCount);
  2687. LEAVE_DPSP();
  2688. }
  2689. // In order to ensure send ordering even if we are doing async sends, we
  2690. // check and wait for any pending async sends to complete. If they don't complete
  2691. // in 5 seconds then we make the send async.
  2692. BOOL bAsyncSendsPending(LPGLOBALDATA pgd, DPID dwPlayerTo)
  2693. {
  2694. LPREPLYLIST prlList;
  2695. if(!dwPlayerTo){
  2696. return FALSE;
  2697. }
  2698. ENTER_DPSP();
  2699. prlList = pgd->pReplyList;
  2700. while(prlList){
  2701. if(prlList->dwPlayerTo == dwPlayerTo){
  2702. LEAVE_DPSP();
  2703. return TRUE;
  2704. }
  2705. prlList=prlList->pNextReply;
  2706. }
  2707. LEAVE_DPSP()
  2708. return FALSE;
  2709. }
  2710. HRESULT WINAPI SP_Send(LPDPSP_SENDDATA psd)
  2711. {
  2712. HRESULT hr=DP_OK;
  2713. DWORD dwDataSize = sizeof(GLOBALDATA);
  2714. LPGLOBALDATA pgd;
  2715. // get the global data
  2716. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2717. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2718. {
  2719. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2720. return E_FAIL;
  2721. }
  2722. if (psd->dwMessageSize >= SPMAXMESSAGELEN)
  2723. {
  2724. return DPERR_SENDTOOBIG;
  2725. }
  2726. if ((psd->dwFlags & DPSEND_GUARANTEE) && (AF_IPX != pgd->AddressFamily))
  2727. {
  2728. if (psd->dwFlags & DPSEND_ASYNC) hr = AsyncSend(psd);
  2729. else {
  2730. if(bAsyncSendsPending(pgd, psd->idPlayerTo)){
  2731. hr = AsyncSend(psd);
  2732. } else {
  2733. hr = ReliableSend(psd);
  2734. }
  2735. }
  2736. if (FAILED(hr)) DPF(0,"reliable send failed - error - hr = 0x%08lx\n",hr);
  2737. }
  2738. else
  2739. {
  2740. hr = UnreliableSend(psd);
  2741. if (FAILED(hr)) DPF(0,"unreliable send failed - error - hr = 0x%08lx\n",hr);
  2742. }
  2743. return hr;
  2744. } // send
  2745. #ifdef SENDEX
  2746. HRESULT InitGlobalsInPlace(LPGLOBALDATA pgd)
  2747. {
  2748. InitBilink(&pgd->PendingSendQ);
  2749. InitBilink(&pgd->ReadyToSendQ);
  2750. //pgd->dwBytesPending=0; //by memset below.
  2751. //pgd->dwMessagesPending=0; //by memset below.
  2752. // Initialize the pool for send headers and overlapped stucts
  2753. pgd->pSendInfoPool=FPM_Init(sizeof(SENDINFO)+sizeof(MESSAGEHEADER),NULL,NULL,NULL);
  2754. if(!pgd->pSendInfoPool){
  2755. goto ERROR_EXIT;
  2756. }
  2757. InitializeCriticalSection(&pgd->csSendEx);
  2758. return DP_OK;
  2759. ERROR_EXIT:
  2760. return DPERR_NOMEMORY;
  2761. }
  2762. #endif
  2763. void KillTCPEnumAsyncThread(LPGLOBALDATA pgd)
  2764. {
  2765. HANDLE hTCPEnumAsyncThread;
  2766. DWORD SleepCount=0;
  2767. ENTER_DPSP();
  2768. if(pgd->hTCPEnumAsyncThread){
  2769. DPF(9,"Killing Running Async TCP enum thread\n");
  2770. //hTCPEnumAsyncThread is 0, thread knows we are
  2771. //waiting for thread to finish, so we own closing
  2772. // the handle.
  2773. hTCPEnumAsyncThread=pgd->hTCPEnumAsyncThread;
  2774. pgd->hTCPEnumAsyncThread=0;
  2775. // We need to close the socket out from under the
  2776. // TCPEnum thread in order to have it continue and
  2777. // exit. So make sure the socket has been allocated
  2778. // first, but don't wait if the thread has exited
  2779. // already (which is why we check lpEnumMessage.)
  2780. while(pgd->sEnum==INVALID_SOCKET && pgd->lpEnumMessage){
  2781. LEAVE_DPSP();
  2782. Sleep(500);
  2783. ENTER_DPSP();
  2784. if(SleepCount++ > 10 )break; // don't wait more than 5 seconds.
  2785. }
  2786. if(pgd->sEnum!=INVALID_SOCKET){
  2787. if(pgd->bOutBoundOnly){
  2788. RemoveSocketFromReceiveList(pgd,pgd->sEnum);
  2789. } else {
  2790. closesocket(pgd->sEnum);
  2791. }
  2792. }
  2793. LEAVE_DPSP();
  2794. WaitForSingleObject(hTCPEnumAsyncThread,150*1000);
  2795. CloseHandle(hTCPEnumAsyncThread);
  2796. DPF(9,"Async enum thread is dead.\n");
  2797. } else {
  2798. LEAVE_DPSP();
  2799. }
  2800. }
  2801. void InitGlobals(LPGLOBALDATA pgd)
  2802. {
  2803. if(pgd->hTCPEnumAsyncThread){
  2804. KillTCPEnumAsyncThread(pgd);
  2805. }
  2806. ENTER_DPSP();
  2807. if (pgd->BagOSockets)
  2808. {
  2809. MemFree(pgd->BagOSockets);
  2810. }
  2811. if (pgd->ReceiveList.pConnection)
  2812. {
  2813. MemFree(pgd->ReceiveList.pConnection);
  2814. }
  2815. if (pgd->readfds.pfdbigset)
  2816. {
  2817. MemFree(pgd->readfds.pfdbigset);
  2818. }
  2819. #ifdef SENDEX
  2820. if(pgd->bSendThreadRunning){
  2821. pgd->bStopSendThread=TRUE;
  2822. SetEvent(pgd->hSendWait);
  2823. }
  2824. while(pgd->bSendThreadRunning){
  2825. Sleep(0);
  2826. }
  2827. if(pgd->hSendWait){
  2828. CloseHandle(pgd->hSendWait);
  2829. pgd->hSendWait=NULL;
  2830. }
  2831. if(pgd->pSendInfoPool){
  2832. pgd->pSendInfoPool->Fini(pgd->pSendInfoPool,0);
  2833. DeleteCriticalSection(&pgd->csSendEx);
  2834. //pgd->pSendInfoPool=NULL; //by memset below.
  2835. }
  2836. #endif
  2837. // set global data to 0
  2838. memset(pgd,0,sizeof(GLOBALDATA));
  2839. // uses INVALID_SOCKET, not 0, to indicate bogus socket
  2840. pgd->sSystemDGramSocket= INVALID_SOCKET;
  2841. pgd->sSystemStreamSocket= INVALID_SOCKET;
  2842. pgd->sUnreliableSocket = INVALID_SOCKET;
  2843. #ifdef BIGMESSAGEDEFENSE
  2844. pgd->dwMaxMessageSize = SPMAXMESSAGELEN;
  2845. #endif
  2846. pgd->uEnumAddress = 0;
  2847. LEAVE_DPSP();
  2848. } // InitGlobals
  2849. HRESULT WaitForThread(HANDLE hThread)
  2850. {
  2851. DWORD dwRet;
  2852. if (!hThread) return DP_OK;
  2853. // we assume the thread has been told to go away
  2854. // we wait for it to do so
  2855. dwRet = WaitForSingleObject(hThread,INFINITE);
  2856. if (WAIT_OBJECT_0 != dwRet)
  2857. {
  2858. ASSERT(FALSE);
  2859. return E_FAIL;
  2860. }
  2861. CloseHandle(hThread);
  2862. return DP_OK;
  2863. } // WaitForThread
  2864. HRESULT WINAPI SP_Shutdown(LPDPSP_SHUTDOWNDATA psd)
  2865. {
  2866. UINT err;
  2867. DWORD dwDataSize = sizeof(GLOBALDATA);
  2868. LPGLOBALDATA pgd;
  2869. HRESULT hr;
  2870. DPSP_CLOSEDATA cd;
  2871. BOOL bFree;
  2872. DPF(2," dpwsock - got shutdown!!\n");
  2873. // get the global data
  2874. hr = psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2875. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2876. {
  2877. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2878. return E_FAIL;
  2879. }
  2880. // call close
  2881. cd.lpISP = psd->lpISP;
  2882. hr = SP_Close(&cd);
  2883. if (FAILED(hr))
  2884. {
  2885. DPF(0," shutdown - could not close SP hr = 0x%08lx\n",hr);
  2886. ASSERT(FALSE);
  2887. // rut roh! - keep trying
  2888. }
  2889. #ifdef DPLAY_VOICE_SUPPORT
  2890. // turn off voice, if it exists...
  2891. if (gbVoiceInit)
  2892. {
  2893. ASSERT(!gbVoiceOpen); // dplay should have shut it down!
  2894. FiniVoice();
  2895. gbVoiceInit = FALSE;
  2896. }
  2897. #endif // DPLAY_VOICE_SUPPORT
  2898. DPF(2,"shutdown, calling WSACleanup");
  2899. // it's ok to call this for each idirectplaysp that goes away, since
  2900. // we called WSAStartup once for each one at SPInit
  2901. if ( SOCKET_ERROR == WSACleanup())
  2902. {
  2903. err = WSAGetLastError();
  2904. DPF(0,"could not stop winsock err = %d\n",err);
  2905. // keep trying...
  2906. }
  2907. // if we have a winsock2, free it
  2908. if (hWS2)
  2909. {
  2910. bFree = FreeLibrary(hWS2);
  2911. if (!bFree)
  2912. {
  2913. DWORD dwError = GetLastError();
  2914. DPF(0,"SP_Shutdown - could not free ws2 library - error = %d\n",dwError);
  2915. // keep trying
  2916. }
  2917. hWS2 = NULL;
  2918. }
  2919. // reset everything...
  2920. InitGlobals(pgd);
  2921. gdwDPlaySPRefCount--;
  2922. DPF(2,"shutdown leaving");
  2923. return DP_OK;
  2924. } //Shutdown
  2925. // sp only sets fields it cares about
  2926. HRESULT WINAPI SP_GetCaps(LPDPSP_GETCAPSDATA pcd)
  2927. {
  2928. DWORD dwDataSize = sizeof(GLOBALDATA);
  2929. LPGLOBALDATA pgd;
  2930. HRESULT hr;
  2931. // get the global data
  2932. hr =pcd->lpISP->lpVtbl->GetSPData(pcd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  2933. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  2934. {
  2935. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  2936. return E_FAIL;
  2937. }
  2938. if (AF_IPX == pgd->AddressFamily)
  2939. {
  2940. // IPX
  2941. pcd->lpCaps->dwHeaderLength = sizeof(MESSAGEHEADER);
  2942. pcd->lpCaps->dwMaxBufferSize = IPX_MAX_DGRAM;
  2943. }
  2944. // else, they want AF_INET
  2945. else
  2946. {
  2947. // AF_INET optimizes guaranteed
  2948. pcd->lpCaps->dwFlags |= DPCAPS_GUARANTEEDOPTIMIZED;
  2949. if (pcd->dwFlags & DPGETCAPS_GUARANTEED)
  2950. {
  2951. // TCP
  2952. pcd->lpCaps->dwHeaderLength = sizeof(MESSAGEHEADER);
  2953. pcd->lpCaps->dwMaxBufferSize = SPMAXMESSAGELEN -sizeof(MESSAGEHEADER);
  2954. pcd->lpCaps->dwMaxPlayers = pgd->nSocketsInBag;
  2955. }
  2956. else
  2957. {
  2958. // UDP
  2959. pcd->lpCaps->dwHeaderLength = sizeof(MESSAGEHEADER);
  2960. pcd->lpCaps->dwMaxBufferSize = pgd->iMaxUdpDg-sizeof(MESSAGEHEADER);
  2961. }
  2962. }
  2963. // set async caps flags
  2964. if(pgd->bSendThreadRunning){
  2965. // we are supporting async.
  2966. pcd->lpCaps->dwFlags |= (DPCAPS_ASYNCSUPPORTED);
  2967. }
  2968. // set the timeout
  2969. pcd->lpCaps->dwLatency = pgd->dwLatency;
  2970. pcd->lpCaps->dwTimeout = SPTIMEOUT(pcd->lpCaps->dwLatency);
  2971. #ifdef DPLAY_VOICE_SUPPORT
  2972. // check the voice
  2973. if (gbVoiceInit || CheckVoice()) pcd->lpCaps->dwFlags |= DPCAPS_VOICE;
  2974. #endif // DPLAY_VOICE_SUPPORT
  2975. return DP_OK;
  2976. } // SP_GetCaps
  2977. HRESULT WINAPI SP_Open(LPDPSP_OPENDATA pod)
  2978. {
  2979. LPMESSAGEHEADER phead;
  2980. DWORD dwDataSize = sizeof(GLOBALDATA);
  2981. LPGLOBALDATA pgd;
  2982. HRESULT hr;
  2983. DPF(5,"SP_Open");
  2984. #ifdef DPLAY_VOICE_SUPPORT
  2985. if (pod->dwOpenFlags & DPOPEN_VOICE)
  2986. {
  2987. if (gbVoiceOpen)
  2988. {
  2989. DPF_ERR("voice channel already open - only one per process");
  2990. return DPERR_ALREADYINITIALIZED;
  2991. }
  2992. if (!gbVoiceInit)
  2993. {
  2994. DPF(0,"DPWSOCK - listen up!!! - init'ing voice!");
  2995. hr = InitVoice();
  2996. if (FAILED(hr))
  2997. {
  2998. DPF(0,"init voice failed hr = 0x%08lx\n");
  2999. return hr;
  3000. }
  3001. gbVoiceInit = TRUE;
  3002. }
  3003. }
  3004. #endif // DPLAY_VOICE_SUPPORT
  3005. // get the global data
  3006. hr =pod->lpISP->lpVtbl->GetSPData(pod->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  3007. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  3008. {
  3009. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  3010. return E_FAIL;
  3011. }
  3012. // do we have a TCP connection?
  3013. if (AF_INET == pgd->AddressFamily)
  3014. {
  3015. PHOSTENT phostent = GetHostAddr();
  3016. if (!phostent || phostent->h_addr_list[0] == 0)
  3017. {
  3018. DPF(0, "No Dial-up network or netcard present");
  3019. return DPERR_NOCONNECTION; // no local IP address = no network
  3020. }
  3021. }
  3022. // remember session information so we know if we need to turn off nagling
  3023. pgd->dwSessionFlags = pod->dwSessionFlags;
  3024. if (pod->dwOpenFlags & DPOPEN_CREATE)
  3025. {
  3026. // host should never go into this mode
  3027. pgd->dwFlags &= ~(DPSP_OUTBOUNDONLY);
  3028. }
  3029. if (pod->bCreate)
  3030. return DP_OK; // all done
  3031. phead = (LPMESSAGEHEADER)pod->lpSPMessageHeader;
  3032. // get name server address out of phead, stores it in pgd->saddrNS
  3033. pgd->saddrNS = phead->sockaddr;
  3034. // make sure we have a thread running to get the nametable
  3035. hr = StartupEnumThread(pod->lpISP,pgd);
  3036. if (FAILED(hr))
  3037. {
  3038. DPF(0," could not start open threads - hr = 0x%08lx\n",hr);
  3039. return hr;
  3040. }
  3041. return DP_OK;
  3042. } // SP_Open
  3043. #ifdef DEBUG
  3044. // make sure there are no connected sockets left in the bug
  3045. void VerifySocketBagIsEmpty(LPGLOBALDATA pgd)
  3046. {
  3047. UINT i=0;
  3048. while (i < pgd->nSocketsInBag)
  3049. {
  3050. if (INVALID_SOCKET != pgd->BagOSockets[i].sSocket)
  3051. {
  3052. DPF_ERR("socket bag not empty at close!");
  3053. ASSERT(FALSE);
  3054. }
  3055. i++;
  3056. }
  3057. } // VerifySocketBagIsEmpty
  3058. #endif // DEBUG
  3059. HRESULT WINAPI SP_Close(LPDPSP_CLOSEDATA pcd)
  3060. {
  3061. DWORD dwDataSize = sizeof(GLOBALDATA);
  3062. LPGLOBALDATA pgd;
  3063. HRESULT hr;
  3064. DWORD sleepcount=0;
  3065. DPF(2," dpwsock - got close");
  3066. // get the global data
  3067. hr =pcd->lpISP->lpVtbl->GetSPData(pcd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  3068. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  3069. {
  3070. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  3071. return E_FAIL;
  3072. }
  3073. // Stop asynchronous TCP enumeration thread if it's running
  3074. KillTCPEnumAsyncThread(pgd);
  3075. // give the reply list 5 seconds to clear out
  3076. while(pgd->pReplyList){
  3077. Sleep(100);
  3078. if(sleepcount++ == 50){
  3079. break;
  3080. }
  3081. }
  3082. // reset the nameserver address
  3083. memset(&(pgd->saddrNS),0,sizeof(SOCKADDR));
  3084. pgd->bShutdown = TRUE;
  3085. DPF(2,"close, datagram sockets");
  3086. KillSocket(pgd->sSystemDGramSocket,FALSE,TRUE);
  3087. pgd->sSystemDGramSocket = INVALID_SOCKET;
  3088. DPF(2,"Waiting for stream receive thread");
  3089. WaitForThread(pgd->hStreamReceiveThread);
  3090. pgd->hStreamReceiveThread = NULL;
  3091. DPF(2,"close stream socket");
  3092. closesocket(pgd->sSystemStreamSocket);
  3093. pgd->sSystemStreamSocket = INVALID_SOCKET;
  3094. DPF(2,"close unreliable socket");
  3095. KillSocket(pgd->sUnreliableSocket,FALSE,TRUE);
  3096. pgd->sUnreliableSocket = INVALID_SOCKET;
  3097. DPF(2,"close, waiting on threads");
  3098. // signal the reply thread
  3099. if (pgd->hReplyEvent)
  3100. {
  3101. SetEvent(pgd->hReplyEvent);
  3102. }
  3103. WaitForThread(pgd->hDGramReceiveThread);
  3104. pgd->hDGramReceiveThread = NULL;
  3105. WaitForThread(pgd->hReplyThread);
  3106. pgd->hReplyThread = NULL;
  3107. // if it was ipx, and the nameserver has migrated to us, we may have a spare thread
  3108. // we need to make sure is gone
  3109. if (AF_IPX == pgd->AddressFamily)
  3110. {
  3111. WaitForThread(pgd->hIPXSpareThread);
  3112. pgd->hIPXSpareThread = NULL;
  3113. }
  3114. pgd->bShutdown = FALSE;
  3115. #ifdef DEBUG
  3116. // verify that the bag o' sockets is really empty
  3117. VerifySocketBagIsEmpty(pgd);
  3118. #endif
  3119. while(pgd->dwMessagesPending){
  3120. DPF(0,"Waiting for pending messages to complete\n");
  3121. Sleep(55);
  3122. }
  3123. return DP_OK;
  3124. } // SP_Close
  3125. #ifdef FIND_IP
  3126. //
  3127. // we get the ip addr of our host. this is for debug purposes only.
  3128. // we never use the ip addr of our host, since it may be multihomed.
  3129. // the receiving system assigns our players their ip addresses
  3130. HRESULT DebugFindIPAddresses(void)
  3131. {
  3132. PHOSTENT phostent;
  3133. IN_ADDR hostaddr;
  3134. int i;
  3135. phostent = GetHostAddr();
  3136. if (NULL == phostent)
  3137. {
  3138. return E_FAIL;
  3139. }
  3140. DPF(0,"dpwsock - running on host name %s\n",phostent->h_name);
  3141. i=0;
  3142. while (phostent->h_addr_list[i])
  3143. {
  3144. memcpy(&hostaddr,phostent->h_addr_list[i],sizeof(hostaddr));
  3145. DPF(0,"sp - found host addr = %s \n",inet_ntoa(hostaddr));
  3146. i++;
  3147. }
  3148. return DP_OK;
  3149. } // DebugFindIPAddresses
  3150. #endif // FIND_IP
  3151. /*
  3152. * EnumConnectionData
  3153. *
  3154. * Search for valid connection data
  3155. */
  3156. BOOL FAR PASCAL EnumConnectionData(REFGUID lpguidDataType, DWORD dwDataSize,
  3157. LPCVOID lpData, LPVOID lpContext)
  3158. {
  3159. LPGLOBALDATA pgd = (LPGLOBALDATA) lpContext;
  3160. // this is an ANSI internet address
  3161. if (IsEqualGUID(lpguidDataType, &DPAID_INet))
  3162. {
  3163. // make sure there is room (for terminating null too)
  3164. if (dwDataSize > ADDR_BUFFER_SIZE)
  3165. dwDataSize = (ADDR_BUFFER_SIZE - 1);
  3166. // copy string for use later
  3167. memcpy(pgd->szServerAddress, lpData, dwDataSize);
  3168. pgd->bHaveServerAddress = TRUE; // we have a server address
  3169. }
  3170. // this is a UNICODE internet address
  3171. else if (IsEqualGUID(lpguidDataType, &DPAID_INetW))
  3172. {
  3173. if (WideToAnsi(pgd->szServerAddress, (LPWSTR) lpData, ADDR_BUFFER_SIZE))
  3174. pgd->bHaveServerAddress = TRUE; // we have a server address
  3175. }
  3176. else if (IsEqualGUID(lpguidDataType, &DPAID_INetPort))
  3177. {
  3178. pgd->wApplicationPort = *(LPWORD)lpData;
  3179. DPF(5, "Application port specified in dp address: %d",pgd->wApplicationPort);
  3180. }
  3181. #ifdef BIGMESSAGEDEFENSE
  3182. else if (IsEqualGUID(lpguidDataType, &DPAID_MaxMessageSize))
  3183. {
  3184. pgd->dwMaxMessageSize = *(LPDWORD)lpData;
  3185. ASSERT(pgd->dwMaxMessageSize > 11); // set an arbitrary minimum
  3186. if (pgd->dwMaxMessageSize < 12)
  3187. pgd->dwMaxMessageSize = 12;
  3188. DPF(5, "Max message size specified in dp address: %d",pgd->dwMaxMessageSize);
  3189. pgd->dwMaxMessageSize += sizeof(MESSAGEHEADER); // add a little extra for the shop
  3190. }
  3191. #endif
  3192. return TRUE;
  3193. } // EnumConnectionData
  3194. // nSockets was passed into spinit as dwReserved2
  3195. HRESULT InitBagOSockets(LPGLOBALDATA pgd,DWORD nSockets)
  3196. {
  3197. UINT i;
  3198. ENTER_DPSP();
  3199. if (0 == nSockets)
  3200. {
  3201. pgd->nSocketsInBag = MAX_CONNECTED_SOCKETS;
  3202. }
  3203. else
  3204. {
  3205. pgd->nSocketsInBag = nSockets;
  3206. }
  3207. pgd->BagOSockets = MemAlloc(pgd->nSocketsInBag * sizeof(PLAYERSOCK));
  3208. LEAVE_DPSP();
  3209. if (!pgd->BagOSockets)
  3210. {
  3211. pgd->nSocketsInBag = 0;
  3212. DPF_ERR("could not alloc space for socket cache - out of memory");
  3213. return E_OUTOFMEMORY;
  3214. }
  3215. for (i=0;i<pgd->nSocketsInBag;i++ )
  3216. {
  3217. pgd->BagOSockets[i].sSocket = INVALID_SOCKET;
  3218. }
  3219. return DP_OK ;
  3220. } // InitBagOSockets
  3221. // CheckIPXInstall
  3222. // on win 95 gold
  3223. // go to control panel / network
  3224. // select your net card / properties
  3225. // select bindings tab. unbind ipx.
  3226. // socket(...) call succeeds, but sendto(...) hangs.
  3227. // we check here that the sa_nodenum is not 0,0,0,0,0,0
  3228. // if it is, we will hang later, so we fail. andyco.
  3229. //
  3230. HRESULT CheckIPXInstall(SOCKET sSocket)
  3231. {
  3232. int cbOpt;
  3233. UINT err;
  3234. IPX_ADDRESS_DATA IpxData;
  3235. char pSixZeros[6];
  3236. if (INVALID_SOCKET == sSocket)
  3237. {
  3238. return E_FAIL;
  3239. }
  3240. // go ask the driver for our ipx address
  3241. memset( &IpxData, 0, sizeof(IpxData));
  3242. cbOpt = sizeof( IpxData );
  3243. err = getsockopt( sSocket, NSPROTO_IPX, IPX_ADDRESS,
  3244. (char*) &IpxData, &cbOpt );
  3245. if (SOCKET_ERROR == err)
  3246. {
  3247. err = WSAGetLastError();
  3248. DPF(0," could not test ipx getopt - err = %d\n",err);
  3249. return E_FAIL;
  3250. }
  3251. // see if it's 0
  3252. memset(pSixZeros,0,6*sizeof(char));
  3253. if (0 == memcmp(pSixZeros,&(IpxData.nodenum),6))
  3254. {
  3255. DPF_ERR("found invalid IPX install!");
  3256. DPF_ERR("IPX has been improperly un-installed by unbinding from net adaptor");
  3257. return E_FAIL;
  3258. }
  3259. return DP_OK;
  3260. } // CheckIPXInstall
  3261. // main entry point for service provider
  3262. // sp should fill in callbacks (pSD->lpCB) and do init stuff here
  3263. HRESULT WINAPI SPInit(LPSPINITDATA pSD)
  3264. {
  3265. HRESULT hr;
  3266. UINT err;
  3267. GLOBALDATA gd,*pgd;
  3268. UINT dwSize;
  3269. SOCKET sVerifySocket; // used to verify support for the requested address family
  3270. // so, if they ask for ipx, and it's not installed, we fail here
  3271. WORD wVersion;
  3272. OSVERSIONINFO osInfo;
  3273. HANDLE hAlertThread;
  3274. // initialize global data
  3275. memset(&gd,0,sizeof(gd));
  3276. InitGlobals(&gd);
  3277. ASSERT(pSD->lpGuid);
  3278. if (IsEqualIID(pSD->lpGuid,&GUID_IPX))
  3279. {
  3280. DPF(0,"---------------- DPWSOCK -- RUNNING IPX -------------");
  3281. gd.AddressFamily = AF_IPX;
  3282. }
  3283. else
  3284. {
  3285. if (IsEqualIID(pSD->lpGuid,&GUID_LOCAL_TCP))
  3286. {
  3287. gd.uEnumAddress = INADDR_BROADCAST;
  3288. DPF(0," ** DPWSOCK -- RUNNING LOCAL TCP / IP ** ");
  3289. }
  3290. else
  3291. {
  3292. DPF(0," ** DPWSOCK -- RUNNING INTERNET TCP / IP ** ");
  3293. }
  3294. gd.AddressFamily = AF_INET;
  3295. }
  3296. // find out what os we are running on
  3297. memset(&osInfo,0,sizeof(osInfo));
  3298. osInfo.dwOSVersionInfoSize = sizeof(osInfo);
  3299. if (!GetVersionEx(&osInfo))
  3300. {
  3301. err = GetLastError();
  3302. DPF(0,"Failed to get OS information - err = %d\n", err);
  3303. return DPERR_GENERIC;
  3304. }
  3305. // start up sockets
  3306. if (gwsaData.wVersion)
  3307. {
  3308. // note - there is a bug in winsock 1.1. if you've called WSAStartup 1x in a process,
  3309. // then if any subsequent call asks for a version # > then that returned to the first
  3310. // call, we get WSAEVERNOTSUPPORTED. So, if we've already got a version in the wsadata,
  3311. // we make sure to use that
  3312. wVersion = gwsaData.wVersion;
  3313. }
  3314. // otherwise, ask for winsock 2.0
  3315. else
  3316. {
  3317. // if we are trying to initialize IPX on a non-NT platform, don't look for Winsock 2.0
  3318. // Only look for Winsock 1.1 as Winsock 2.0 functionality is not supported for IPX on
  3319. // Memphis and Win'95.
  3320. if ((AF_IPX == gd.AddressFamily) && (VER_PLATFORM_WIN32_NT != osInfo.dwPlatformId))
  3321. wVersion = MAKEWORD(1,1);
  3322. else
  3323. wVersion = MAKEWORD(2,0);
  3324. }
  3325. err = WSAStartup(wVersion, &gwsaData);
  3326. if (WSAVERNOTSUPPORTED == err)
  3327. {
  3328. // they (the app) must have already called WSAStartup. see note above
  3329. // about winsock 1.1 bug.
  3330. wVersion = MAKEWORD(1,1);
  3331. err = WSAStartup(wVersion, &gwsaData);
  3332. }
  3333. if (err)
  3334. {
  3335. DPF(0,"could not start winsock err = %d\n",err);
  3336. return E_FAIL;
  3337. }
  3338. DPF(1,"spinit - name = %ls,dwReserved1 = %d,dwReserved2 = %d\n",pSD->lpszName,
  3339. pSD->dwReserved1,pSD->dwReserved2);
  3340. gd.iMaxUdpDg = gwsaData.iMaxUdpDg;
  3341. DPF(0,"detected winsock version %d.%d\n",LOBYTE(gwsaData.wVersion),HIBYTE(gwsaData.wVersion));
  3342. if (LOBYTE(gwsaData.wVersion) >= 2)
  3343. {
  3344. hr = InitWinsock2();
  3345. if (FAILED(hr))
  3346. {
  3347. DPF_ERR("detected winsock 2, but could not init it! yikes!");
  3348. ASSERT(FALSE);
  3349. }
  3350. }
  3351. DPF(1,"\nspinit - setting latency to %d\n\n", pSD->dwReserved1);
  3352. gd.dwLatency = pSD->dwReserved1;
  3353. hr = InitBagOSockets(&gd,pSD->dwReserved2);
  3354. if (FAILED(hr))
  3355. {
  3356. DPF_ERR("could not init socket cache. bailing");
  3357. goto ERROR_EXIT;
  3358. }
  3359. // make sure support exists for address family
  3360. hr = CreateSocket(&gd,&sVerifySocket,SOCK_DGRAM,0,INADDR_ANY,&err,FALSE);
  3361. if (FAILED(hr))
  3362. {
  3363. DPF(0," COULD NOT CREATE SOCKET IN REQUESTED ADDRESS FAMILY af = %d, err = %d\n",gd.AddressFamily,err);
  3364. DPF(0," SERVICE PROVIDER INITIALIZATION FAILED");
  3365. // return the same error as the modem service provider
  3366. hr = DPERR_UNAVAILABLE;
  3367. goto ERROR_EXIT;
  3368. }
  3369. if (LOBYTE(gwsaData.wVersion) >= 2)
  3370. {
  3371. // get max udp buffer size through getsockopt because
  3372. // WSAStartup doesn't return this info from winsock 2.0 onwards.
  3373. hr = GetMaxUdpBufferSize(sVerifySocket, &gd.iMaxUdpDg);
  3374. if (FAILED(hr))
  3375. {
  3376. DPF(0,"Failed to get max udp buffer size");
  3377. // since memphis still returns this value in WSAStartup
  3378. // use it. This is just a workaround for memphis bug #43655
  3379. if (gwsaData.iMaxUdpDg)
  3380. {
  3381. DPF(0, "Using iMaxUdpDg value from WSAStartup: %d", gwsaData.iMaxUdpDg);
  3382. gd.iMaxUdpDg = gwsaData.iMaxUdpDg;
  3383. }
  3384. else
  3385. {
  3386. DPF_ERR("No max UDP buffer size could be found!");
  3387. // all done w/ verify socket
  3388. KillSocket(sVerifySocket,FALSE,TRUE);
  3389. goto ERROR_EXIT;
  3390. }
  3391. }
  3392. }
  3393. // check that the IPX stack won't hose us
  3394. if (AF_IPX == gd.AddressFamily)
  3395. {
  3396. hr = CheckIPXInstall(sVerifySocket);
  3397. if (FAILED(hr))
  3398. {
  3399. DPF_ERR("SPInit Failing - corrupt IPX install");
  3400. hr = DPERR_UNAVAILABLE;
  3401. // all done w/ verify socket
  3402. KillSocket(sVerifySocket,FALSE,TRUE);
  3403. goto ERROR_EXIT;
  3404. }
  3405. }
  3406. // all done w/ verify socket
  3407. KillSocket(sVerifySocket,FALSE,TRUE);
  3408. #ifdef FIND_IP
  3409. // print out the ip address(es) of this host
  3410. DebugFindIPAddresses();
  3411. #endif
  3412. // set up callbacks
  3413. pSD->lpCB->CreatePlayer = SP_CreatePlayer;
  3414. pSD->lpCB->DeletePlayer = SP_DeletePlayer;
  3415. pSD->lpCB->Send = SP_Send;
  3416. pSD->lpCB->EnumSessions = SP_EnumSessions;
  3417. pSD->lpCB->Reply = SP_Reply;
  3418. pSD->lpCB->ShutdownEx = SP_Shutdown;
  3419. pSD->lpCB->GetCaps = SP_GetCaps;
  3420. pSD->lpCB->Open = SP_Open;
  3421. pSD->lpCB->CloseEx = SP_Close;
  3422. pSD->lpCB->GetAddress = SP_GetAddress;
  3423. #ifdef DPLAY_VOICE_SUPPORT
  3424. pSD->lpCB->OpenVoice = SP_OpenVoice;
  3425. pSD->lpCB->CloseVoice = SP_CloseVoice;
  3426. #endif // DPLAY_VOICE_SUPPORT
  3427. #ifdef SENDEX
  3428. if(LOBYTE(gwsaData.wVersion) >= 2)
  3429. {
  3430. DPF(1,"SENDEX being provided by SP\n");
  3431. // Only do new functions when Winsock 2 functions avail.
  3432. // NOTE: not supported on IPX with win9x at present, but reports 1.1 in this case.
  3433. //pSD->lpCB->SendToGroupEx = SP_SendToGroupEx; // optional - not impl
  3434. //pSD->lpCB->Cancel = SP_Cancel; // optional - not impl
  3435. pSD->lpCB->SendEx = SP_SendEx; // required for async
  3436. pSD->lpCB->GetMessageQueue = SP_GetMessageQueue;
  3437. } else {
  3438. DPF(1,"SENDEX not being provided by SP on winsock ver < 2\n");
  3439. }
  3440. #endif
  3441. // we put (at most) 1 sockaddr and one dword (size) in each message
  3442. pSD->dwSPHeaderSize = sizeof(MESSAGEHEADER);
  3443. // return version number so DirectPlay will treat us with respect
  3444. pSD->dwSPVersion = VERSIONNUMBER;
  3445. // look at connnection data
  3446. if (pSD->dwAddressSize)
  3447. {
  3448. // ask dplay to enum the chunks for us. if one of them is
  3449. // af_inet, we'll use it as our name servers address
  3450. pSD->lpISP->lpVtbl->EnumAddress(pSD->lpISP, EnumConnectionData,
  3451. pSD->lpAddress, pSD->dwAddressSize,
  3452. &gd);
  3453. }
  3454. #ifdef FULLDUPLEX_SUPPORT
  3455. // get the flags from registry
  3456. hr = GetFlagsFromRegistry(pSD->lpGuid, &gd.dwFlags);
  3457. if (FAILED(hr))
  3458. {
  3459. DPF(2, "Failed to get sp flags from the registry");
  3460. }
  3461. #endif // FULLDUPLEX_SUPPORT
  3462. // store the globaldata
  3463. hr = pSD->lpISP->lpVtbl->SetSPData(pSD->lpISP,&gd,sizeof(GLOBALDATA),DPSET_LOCAL);
  3464. if (FAILED(hr))
  3465. {
  3466. ASSERT(FALSE);
  3467. goto ERROR_EXIT;
  3468. }
  3469. hr = pSD->lpISP->lpVtbl->GetSPData(pSD->lpISP,&pgd,&dwSize,DPGET_LOCAL);
  3470. if (FAILED(hr))
  3471. {
  3472. ASSERT(FALSE);
  3473. goto ERROR_EXIT;
  3474. }
  3475. #ifdef SENDEX
  3476. if(LOBYTE(gwsaData.wVersion) >= 2) {
  3477. // some globals are self referential, can't set until here.
  3478. hr=InitGlobalsInPlace(pgd);
  3479. if(FAILED(hr))
  3480. {
  3481. ASSERT(FALSE);
  3482. goto ERROR_EXIT;
  3483. }
  3484. // added alertable thread.
  3485. pgd->hSendWait=CreateEvent(NULL, FALSE, FALSE, NULL); // autoreset.
  3486. if(!pgd->hSendWait){
  3487. ASSERT(FALSE);
  3488. goto ERROR_EXIT;
  3489. }
  3490. pgd->bSendThreadRunning=TRUE;
  3491. hAlertThread=CreateThread(NULL, 4000, SPSendThread, pgd, 0, (ULONG *)&hAlertThread);
  3492. if(!hAlertThread){
  3493. pgd->bSendThreadRunning=FALSE;
  3494. ASSERT(FALSE);
  3495. goto ERROR_EXIT;
  3496. } else {
  3497. SetThreadPriority(hAlertThread, THREAD_PRIORITY_ABOVE_NORMAL);
  3498. }
  3499. CloseHandle(hAlertThread);// don't need a handle.
  3500. }
  3501. #endif
  3502. gdwDPlaySPRefCount++;
  3503. // success!
  3504. return DP_OK;
  3505. ERROR_EXIT:
  3506. DPF_ERR("SPInit - abnormal exit");
  3507. // call this again to clean up anything we alloc'ed
  3508. InitGlobals(&gd);
  3509. DPF(2,"SPInit - calling WSACleanup");
  3510. if ( SOCKET_ERROR == WSACleanup())
  3511. {
  3512. err = WSAGetLastError();
  3513. DPF(0,"could not stop winsock err = %d\n",err);
  3514. }
  3515. return hr;
  3516. } // SPInit