Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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