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

4053 lines
118 KiB

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