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

1353 lines
37 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: winsock.c
  6. * Content: windows socket support for dpsp
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 3/15/96 andyco created it
  11. * 4/12/96 andyco got rid of dpmess.h! use DPlay_ instead of message macros
  12. * 4/18/96 andyco added multihomed support, started ipx
  13. * 4/25/96 andyco messages now have blobs (sockaddr's) instead of dwReserveds
  14. * 5/31/96 andyco all non-system players share a socket (gsStream and
  15. * gsDGramSocket).
  16. * 7/18/96 andyco added dphelp for server socket
  17. * 8/1/96 andyco no retry on connect failure
  18. * 8/15/96 andyco local + remote data - killthread
  19. * 8/30/96 andyco clean it up b4 you shut it down! added globaldata.
  20. * 9/4/96 andyco took out bye_bye message
  21. * 12/18/96 andyco de-threading - use a fixed # of prealloced threads.
  22. * cruised the enum socket / thread - use the system
  23. * socket / thread instead
  24. * 3/17/97 kipo rewrote server dialog code to not use global variable
  25. * to return the address and to return any errors getting
  26. * the address, especially DPERR_USERCANCEL
  27. * 5/12/97 kipo the server address string is now stored in the globals
  28. * at SPInit and resolved when you do EnumSessions so we
  29. * will return any errors at that time instead of popping
  30. * the dialog again. Fixes bug #5866
  31. * 11/19/97 myronth Changed LB_SETCURSEL to CB_SETCURSEL (#12711)
  32. * 01/27/98 sohaim added firewall support.
  33. * 02/13/98 aarono added async support.
  34. * 2/18/98 a-peterz Comment byte order for address and port params (CreateSocket)
  35. * 6/19/98 aarono turned on keepalive on reliable sockets. If we
  36. * don't do this we can hang if the send target crashes
  37. * while in a low buffer (i.e. no buffer) state.
  38. * 7/9/99 aarono Cleaning up GetLastError misuse, must call right away,
  39. * before calling anything else, including DPF.
  40. * 1/12/99 aarono added rsip support
  41. * 2/21/00 aarono fix socket leaks
  42. ***************************************************************************/
  43. #include "dpsp.h"
  44. #if USE_RSIP
  45. #include "rsip.h"
  46. #elif USE_NATHELP
  47. #include "nathelp.h"
  48. #endif
  49. // backlog for listen() api. no constant in winsock, so we ask for the moon
  50. #define LISTEN_BACKLOG 60
  51. // how long to wait, in ms, til we abort a blocking WinSock connect() call
  52. #define CONNECT_WATCHER_TIMEOUT 15000
  53. /*
  54. ** CreateSocket
  55. *
  56. * CALLED BY: all over
  57. *
  58. * PARAMETERS:
  59. * pgd - pointer to a global data
  60. * psock - new socket. return value.
  61. * type - stream or datagram
  62. * port - what port we bind to (host byte order)
  63. * address - what address to use (net byte order)
  64. * *perr - set to the last socket error if fn fails
  65. * bInRange - use reserved range of ports; we also use this to determine whether we need to try mapping it on the NAT or not
  66. *
  67. * DESCRIPTION:
  68. * creates a new socket. binds to port specified, at the address specified
  69. *
  70. * RETURNS: DP_OK or E_FAIL. if E_FAIL, *perr is set with socket error code (see winsock.h)
  71. *
  72. */
  73. HRESULT FAR PASCAL CreateSocket(LPGLOBALDATA pgd,SOCKET * psock,INT type,WORD wApplicationPort,ULONG address,
  74. SOCKERR * perr,BOOL bInRange)
  75. {
  76. WORD wRebindPort = 0;
  77. SOCKET sNew;
  78. SOCKADDR sockAddr;
  79. int bTrue = TRUE;
  80. int protocol = 0;
  81. BOOL bBroadcast = FALSE;
  82. WORD wPort;
  83. BOOL bBound = FALSE;
  84. UINT err;
  85. #if USE_NATHELP
  86. BOOL bPortMapped=FALSE;
  87. BOOL ftcp_udp;
  88. #endif
  89. *psock = INVALID_SOCKET; // in case we bail
  90. // Create the socket.
  91. if (AF_IPX == pgd->AddressFamily)
  92. {
  93. // set up protocol for ipx
  94. if (SOCK_STREAM == type)
  95. {
  96. protocol = NSPROTO_SPXII;
  97. }
  98. else protocol = NSPROTO_IPX;
  99. }
  100. Rebind:
  101. sNew = socket( pgd->AddressFamily, type, protocol);
  102. if (INVALID_SOCKET == sNew)
  103. {
  104. // no cleanup needed, just bail
  105. *perr = WSAGetLastError();
  106. return E_FAIL;
  107. }
  108. if (wRebindPort == 0)
  109. {
  110. DPF(8,"Creating new socket %d (app port = %u, bInRange = %i)",sNew,wApplicationPort,bInRange);
  111. }
  112. else
  113. {
  114. DPF(8,"Rebinding to port %u, new socket %d",wRebindPort,sNew);
  115. }
  116. // try to bind an address to the socket.
  117. // set up the sockaddr
  118. memset(&sockAddr,0,sizeof(sockAddr));
  119. switch (pgd->AddressFamily)
  120. {
  121. case AF_INET:
  122. {
  123. if ((SOCK_STREAM == type))
  124. {
  125. // turn ON keepalive
  126. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  127. {
  128. err = WSAGetLastError();
  129. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  130. }
  131. ASSERT(bTrue);
  132. // turn off nagling
  133. if(pgd->dwSessionFlags & DPSESSION_OPTIMIZELATENCY)
  134. {
  135. DPF(5, "Turning nagling off on socket");
  136. if (SOCKET_ERROR == setsockopt(sNew, IPPROTO_TCP, TCP_NODELAY, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  137. {
  138. err = WSAGetLastError();
  139. DPF(0,"Failed to turn off nagling - continue : err = %d\n",err);
  140. }
  141. }
  142. // Start out preventing others from using this port (and keeping us
  143. // from sharing a port with another copy of DPlay). This may fail
  144. // if we're not on NT, or we're not admin. The default settings
  145. // will still work (and are pretty much as secure with the .NET
  146. // Server behavior changes).
  147. // The next time through we need to allow sharing in order for
  148. // the fastsock code to work properly.
  149. if (wRebindPort == 0)
  150. {
  151. SetExclusivePortAccess(sNew);
  152. }
  153. else
  154. {
  155. SetSharedPortAccess(sNew);
  156. }
  157. }
  158. ((SOCKADDR_IN *)&sockAddr)->sin_family = PF_INET;
  159. ((SOCKADDR_IN *)&sockAddr)->sin_addr.s_addr = address;
  160. ((SOCKADDR_IN *)&sockAddr)->sin_port = (wRebindPort == 0) ? htons(wApplicationPort) : htons(wRebindPort);
  161. if (bInRange && !wApplicationPort && !wRebindPort)
  162. {
  163. #ifdef RANDOM_PORTS
  164. USHORT rndoffset;
  165. #else // ! RANDOM_PORTS
  166. USHORT wInitialPort;
  167. #endif // ! RANDOM_PORTS
  168. DPF(5, "Application didn't specify a port - using dplay range");
  169. #ifdef RANDOM_PORTS
  170. rndoffset=(USHORT)(GetTickCount()%DPSP_NUM_PORTS); //(USHORT)(0);// make predictable!
  171. if (type != SOCK_STREAM)
  172. {
  173. // workaround bug in winsock using the same socket.
  174. rndoffset = ((rndoffset + DPSP_NUM_PORTS/2) % DPSP_NUM_PORTS);
  175. }
  176. wPort = DPSP_MIN_PORT+rndoffset;
  177. #else // ! RANDOM_PORTS
  178. wInitialPort = DPSP_MIN_PORT;
  179. if (type != SOCK_STREAM)
  180. {
  181. // workaround bug in winsock using the same socket.
  182. wInitialPort = wInitialPort + (DPSP_NUM_PORTS / 2);
  183. }
  184. // minimize problem with ICS machine stealing client's NAT connection entries by
  185. // picking a different starting point on the ICS machine
  186. if (natIsICSMachine(pgd))
  187. {
  188. wInitialPort += (DPSP_NUM_PORTS / 4);
  189. }
  190. wPort = wInitialPort;
  191. #endif // ! RANDOM_PORTS
  192. do
  193. {
  194. #if USE_NATHELP
  195. HRESULT hr;
  196. if (pgd->pINatHelp)
  197. {
  198. if (type == SOCK_STREAM)
  199. {
  200. if (pgd->hNatHelpTCP)
  201. {
  202. DPF(1, "Already have registered TCP port 0x%x.", pgd->hNatHelpTCP);
  203. goto pass_nat;
  204. }
  205. ftcp_udp=TRUE;
  206. }
  207. else
  208. {
  209. if (pgd->hNatHelpUDP)
  210. {
  211. DPF(1, "Already have registered UDP port 0x%x.", pgd->hNatHelpUDP);
  212. goto pass_nat;
  213. }
  214. ftcp_udp=FALSE;
  215. }
  216. hr = natRegisterPort(pgd, ftcp_udp, wPort);
  217. if (hr == DPNHERR_PORTUNAVAILABLE)
  218. {
  219. DPF(1,"CreateSocket: NatHelp said port %u was already in use, trying another.",
  220. wPort);
  221. goto try_next_port;
  222. }
  223. if (hr != DP_OK)
  224. {
  225. DPF(1,"CreateSocket: NatHelp returned error 0x%x, port %u will not have mapping.",
  226. hr, wPort);
  227. }
  228. else
  229. {
  230. bPortMapped=TRUE;
  231. DPF(1,"CreateSocket: NatHelp successfully mapped port %u.", wPort);
  232. }
  233. }
  234. pass_nat:
  235. #endif
  236. DPF(5, "Trying to bind to port %d",wPort);
  237. ((SOCKADDR_IN *)&sockAddr)->sin_port = htons(wPort);
  238. // do the bind
  239. if( SOCKET_ERROR != bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr) ) )
  240. {
  241. bBound = TRUE;
  242. DPF(5, "Successfully bound to port %d", wPort);
  243. }
  244. else
  245. {
  246. err = WSAGetLastError();
  247. DPF(1, "Bind to specific port failed (err %u), continuing.", err);
  248. try_next_port:
  249. #if USE_NATHELP
  250. if (bPortMapped)
  251. {
  252. natDeregisterPort(pgd,ftcp_udp);
  253. bPortMapped=FALSE;
  254. }
  255. #endif
  256. if(++wPort > DPSP_MAX_PORT){
  257. wPort=DPSP_MIN_PORT;
  258. }
  259. }
  260. }
  261. #ifdef RANDOM_PORTS
  262. while (!bBound && (wPort != DPSP_MIN_PORT+rndoffset));
  263. #else // ! RANDOM_PORTS
  264. while (!bBound && (wPort != wInitialPort));
  265. #endif // ! RANDOM_PORTS
  266. }
  267. else
  268. {
  269. DPF(5, "Application specified a port (%u), it doesn't need to be in dplay range (%i), or rebinding (port %u).",
  270. wApplicationPort, bInRange, wRebindPort);
  271. }
  272. }
  273. break;
  274. case AF_IPX:
  275. {
  276. ((SOCKADDR_IPX *)&sockAddr)->sa_family = (SHORT)pgd->AddressFamily;
  277. ((SOCKADDR_IPX *)&sockAddr)->sa_socket = wApplicationPort;
  278. // nodenum?
  279. memset(&(((SOCKADDR_IPX *)&sockAddr)->sa_nodenum),0,6);
  280. }
  281. break;
  282. default:
  283. ASSERT(FALSE);
  284. break;
  285. } // switch
  286. // do the bind
  287. if( !bBound && (SOCKET_ERROR == bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr))) )
  288. {
  289. // Winsock sometimes complains if you attempt to rebind too quickly. Wait a bit, then
  290. // try again a few times.
  291. if (wRebindPort != 0)
  292. {
  293. DWORD dwSleepTime;
  294. dwSleepTime = 50;
  295. do
  296. {
  297. dwSleepTime *= 2; // 100, 200, 400, 800
  298. if (dwSleepTime >= 1000)
  299. {
  300. goto ERROR_EXIT;
  301. }
  302. err = WSAGetLastError();
  303. DPF(1, "Port %u reused too quickly, waiting %u ms then trying again (err = %u).",
  304. wRebindPort, dwSleepTime, err);
  305. Sleep(dwSleepTime);
  306. }
  307. while (bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR);
  308. }
  309. else
  310. {
  311. goto ERROR_EXIT;
  312. }
  313. }
  314. // if this is the first time through the loop for a AF_INET stream socket, we need to shutdown
  315. // and rebind using shared access.
  316. if ((wRebindPort == 0) && (pgd->AddressFamily == AF_INET) && (type==SOCK_STREAM))
  317. {
  318. wRebindPort = ntohs(((SOCKADDR_IN *)&sockAddr)->sin_port);
  319. // Make sure we know the port to rebind.
  320. if (wRebindPort == 0)
  321. {
  322. int iAddrLen;
  323. iAddrLen = sizeof(sockAddr);
  324. if (getsockname(sNew, &sockAddr, &iAddrLen) == SOCKET_ERROR)
  325. {
  326. goto ERROR_EXIT;
  327. }
  328. wRebindPort = ntohs(((SOCKADDR_IN *)&sockAddr)->sin_port);
  329. ASSERT(wRebindPort != 0);
  330. }
  331. DPF(8, "Closing socket 0x%p (port %u).", sNew, wRebindPort);
  332. closesocket(sNew);
  333. sNew = INVALID_SOCKET;
  334. bBound = FALSE;
  335. goto Rebind;
  336. }
  337. // success!
  338. *psock = sNew;
  339. if(type==SOCK_STREAM){
  340. DEBUGPRINTSOCK(8,"created a new stream socket (bound) - ",psock);
  341. } else {
  342. DEBUGPRINTSOCK(8,"created a new datagram socket (bound) - ",psock);
  343. }
  344. return DP_OK;
  345. ERROR_EXIT:
  346. // clean up and bail
  347. *perr = WSAGetLastError();
  348. DPF(0,"create socket failed- err = %d\n",*perr);
  349. closesocket(sNew);
  350. #if USE_NATHELP
  351. if (bPortMapped)
  352. {
  353. natDeregisterPort(pgd,ftcp_udp);
  354. bPortMapped=FALSE;
  355. }
  356. #endif
  357. return E_FAIL;
  358. } // CreateSocket
  359. #undef DPF_MODNAME
  360. #define DPF_MODNAME "KillSocket"
  361. HRESULT KillSocket(SOCKET sSocket,BOOL fStream,BOOL fHard)
  362. {
  363. UINT err;
  364. if (INVALID_SOCKET == sSocket)
  365. {
  366. return E_FAIL;
  367. }
  368. if (!fStream)
  369. {
  370. DPF(8,"killsocket - closing datagram socket %d\n",
  371. sSocket);
  372. if (SOCKET_ERROR == closesocket(sSocket))
  373. {
  374. err = WSAGetLastError();
  375. DPF(0,"killsocket - dgram close err = %d\n",err);
  376. return E_FAIL;
  377. }
  378. }
  379. else
  380. {
  381. LINGER Linger;
  382. if (fHard)
  383. {
  384. // LINGER T/O=0 => Shutdown hard.
  385. Linger.l_onoff=TRUE; // turn linger on
  386. Linger.l_linger=0; // nice small time out
  387. }
  388. else
  389. {
  390. // NOLINGER => shutdown clean, but not hard.
  391. Linger.l_onoff=FALSE; // turn linger off -- SO_NOLINGER
  392. Linger.l_linger=0; // nice small time out
  393. }
  394. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,
  395. sizeof(Linger) ) )
  396. {
  397. err = WSAGetLastError();
  398. DPF(0,"killsocket - stream setopt err = %d\n",err);
  399. }
  400. #if 0
  401. DWORD lNonBlock=0;
  402. err = ioctlsocket(sSocket,FIONBIO,&lNonBlock);
  403. if (SOCKET_ERROR == err)
  404. {
  405. err = WSAGetLastError();
  406. DPF(0,"could not set blocking mode on socket err = %d!",err);
  407. }
  408. #endif
  409. #if 0
  410. if (SOCKET_ERROR == shutdown(sSocket,2))
  411. {
  412. // this may well fail, if e.g. no one is using this socket right now...
  413. // the error would be wsaenotconn
  414. err = WSAGetLastError();
  415. DPF(5,"killsocket - stream shutdown err = %d\n",err);
  416. }
  417. #endif
  418. DPF(8,"killsocket - %s closing stream socket %d:",
  419. ((fHard) ? "hard" : "soft"), sSocket);
  420. DEBUGPRINTSOCK(8,"Addr :",&sSocket);
  421. if (SOCKET_ERROR == closesocket(sSocket))
  422. {
  423. err = WSAGetLastError();
  424. DPF(0,"killsocket - stream close err = %d\n",err);
  425. return E_FAIL;
  426. }
  427. else
  428. {
  429. DPF(8,"killsocket - closed socket %d\n",sSocket);
  430. }
  431. }
  432. return DP_OK;
  433. }// KillSocket
  434. #undef DPF_MODNAME
  435. #define DPF_MODNAME "CreateAndInitStreamSocket"
  436. // set up a stream socket to receive connections
  437. // used w/ the gGlobalData.sStreamAcceptSocket
  438. HRESULT CreateAndInitStreamSocket(LPGLOBALDATA pgd)
  439. {
  440. HRESULT hr;
  441. UINT err;
  442. LINGER Linger;
  443. BOOL bTrue=TRUE;
  444. SOCKADDR_IN saddr;
  445. INT dwSize;
  446. hr = CreateSocket(pgd,&(pgd->sSystemStreamSocket),SOCK_STREAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  447. if (FAILED(hr))
  448. {
  449. DPF(0,"init listen socket failed - err = %d\n",err);
  450. return hr ;
  451. }
  452. bTrue = SetSharedPortAccess(pgd->sSystemStreamSocket);
  453. if (! bTrue)
  454. {
  455. DPF(0,"Failed to to set shared mode on socket - continue\n");
  456. }
  457. // get the socket address, and keep it around for future reference.
  458. dwSize = sizeof(saddr);
  459. err=getsockname(pgd->sSystemStreamSocket, (SOCKADDR *)&saddr, &dwSize);
  460. if(err){
  461. DPF(0,"Couldn't get socket name?\n");
  462. DEBUG_BREAK();
  463. }
  464. pgd->SystemStreamPort = saddr.sin_port;
  465. // set up socket w/ max listening connections
  466. err = listen(pgd->sSystemStreamSocket,LISTEN_BACKLOG);
  467. if (SOCKET_ERROR == err)
  468. {
  469. err = WSAGetLastError();
  470. DPF(0,"init listen socket / listen error - err = %d\n",err);
  471. return E_FAIL ;
  472. }
  473. // set for hard disconnect
  474. Linger.l_onoff=1;
  475. Linger.l_linger=0;
  476. if( SOCKET_ERROR == setsockopt( pgd->sSystemStreamSocket,SOL_SOCKET,SO_LINGER,
  477. (char FAR *)&Linger,sizeof(Linger) ) )
  478. {
  479. err = WSAGetLastError();
  480. DPF(0,"Delete service socket - stream setopt err = %d\n",err);
  481. }
  482. DEBUGPRINTSOCK(1,"enum - listening on",&(pgd->sSystemStreamSocket));
  483. return DP_OK;
  484. } // CreateAndInitStreamSocket
  485. #undef DPF_MODNAME
  486. #define DPF_MODNAME "SPConnect"
  487. // connect socket to sockaddr
  488. HRESULT SPConnect(SOCKET* psSocket, LPSOCKADDR psockaddr,UINT addrlen, BOOL bOutBoundOnly)
  489. {
  490. UINT err;
  491. HRESULT hr = DP_OK;
  492. DWORD dwLastError;
  493. u_long lNonBlock = 1; // passed to ioctlsocket to make socket non-blocking
  494. u_long lBlock = 0; // passed to ioctlsocket to make socket blocking again
  495. fd_set fd_setConnect;
  496. fd_set fd_setExcept;
  497. TIMEVAL timevalConnect;
  498. DPF(6, "SPConnect: Parameters (0x%x, 0x%x, %u, %i)", psSocket, psockaddr, addrlen, bOutBoundOnly);
  499. err=ioctlsocket(*psSocket, FIONBIO, &lNonBlock); // make socket non-blocking
  500. if(SOCKET_ERROR == err){
  501. dwLastError=WSAGetLastError();
  502. DPF(0,"sp - failed to set socket %d to non-blocking mode err= %d\n", *psSocket, dwLastError);
  503. return DPERR_CONNECTIONLOST;
  504. }
  505. DEBUGPRINTADDR(4, "Connecting socket:", psockaddr);
  506. // Start the socket connecting.
  507. err = connect(*psSocket,psockaddr,addrlen);
  508. if(SOCKET_ERROR == err) {
  509. dwLastError=WSAGetLastError();
  510. if(dwLastError != WSAEWOULDBLOCK){
  511. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  512. hr = DPERR_CONNECTIONLOST;
  513. goto err_exit;
  514. }
  515. // we are going to wait for either the connect to succeed (socket to be writeable)
  516. // or the connect to fail (except fdset bit to be set). So we init an FDSET with
  517. // the socket that is connecting and wait.
  518. FD_ZERO(&fd_setConnect);
  519. FD_SET(*psSocket, &fd_setConnect);
  520. FD_ZERO(&fd_setExcept);
  521. FD_SET(*psSocket, &fd_setExcept);
  522. timevalConnect.tv_sec=0;
  523. timevalConnect.tv_usec=CONNECT_WATCHER_TIMEOUT*1000; //msec -> usec
  524. err = select(0, NULL, &fd_setConnect, &fd_setExcept, &timevalConnect);
  525. // err is the number of sockets with activity or 0 for timeout
  526. // or SOCKET_ERROR for error
  527. if(SOCKET_ERROR == err) {
  528. dwLastError=WSAGetLastError();
  529. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  530. hr = DPERR_CONNECTIONLOST;
  531. goto err_exit;
  532. } else if (0==err){
  533. // timed out
  534. DPF(0,"Connect timed out on socket %d\n",*psSocket);
  535. hr = DPERR_CONNECTIONLOST;
  536. goto err_exit;
  537. }
  538. // Now see if the connect succeeded or the connect got an exception
  539. if(!(FD_ISSET(*psSocket, &fd_setConnect))){
  540. #ifdef DEBUG
  541. DWORD optval=0;
  542. DWORD optlen=sizeof(optval);
  543. DPF(0,"Connect did not succeed on socket %d\n",*psSocket);
  544. if(FD_ISSET(*psSocket,&fd_setExcept)){
  545. DPF(0,"FD Except Set IS Set (expected)\n");
  546. } else {
  547. DPF(0,"FD Except Set IS NOT SET (unexpected)\n");
  548. }
  549. err=getsockopt(*psSocket, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen);
  550. DPF(0,"Socket error %x\n",optval);
  551. #endif
  552. return DPERR_CONNECTIONLOST;
  553. }
  554. if(FD_ISSET(*psSocket,&fd_setExcept)){
  555. DPF(0,"Got exception on socket %d during connect\n",*psSocket);
  556. hr = DPERR_CONNECTIONLOST;
  557. goto err_exit;
  558. }
  559. }
  560. err=ioctlsocket(*psSocket, FIONBIO, &lBlock); // make socket blocking again
  561. DEBUGPRINTSOCK(8,"successfully connected socket - ", psSocket);
  562. if (bOutBoundOnly)
  563. {
  564. DEBUGPRINTADDR(5, "Sending reuse connection message to - ",psockaddr);
  565. // tell receiver to reuse connection
  566. hr = SendReuseConnectionMessage(*psSocket);
  567. }
  568. DPF(6, "SPConnect: Return: [0x%lx]", hr);
  569. return hr;
  570. err_exit:
  571. err=ioctlsocket(*psSocket, FIONBIO, &lBlock); // make socket blocking again
  572. DPF(6, "SPConnect: Return (err exit): [0x%lx]", hr);
  573. return hr;
  574. } //SPConnect
  575. #undef DPF_MODNAME
  576. #define DPF_MODNAME "SetPlayerAddress"
  577. // we've created a socket for a player. store its address in the players
  578. // spplayerdata struct.
  579. HRESULT SetPlayerAddress(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,SOCKET sSocket,BOOL fStream)
  580. {
  581. SOCKADDR sockaddr;
  582. UINT err;
  583. int iAddrLen = sizeof(SOCKADDR);
  584. err = getsockname(sSocket,&sockaddr,&iAddrLen);
  585. if (SOCKET_ERROR == err)
  586. {
  587. err = WSAGetLastError();
  588. DPF(0,"setplayeraddress - getsockname - err = %d\n",err);
  589. DPF(0,"closing socket %d\n",sSocket);
  590. closesocket(sSocket);
  591. return E_FAIL;
  592. }
  593. if (fStream)
  594. {
  595. switch (pgd->AddressFamily)
  596. {
  597. case AF_INET:
  598. DEBUGPRINTADDR(7, "Setting player AF_INET stream socket address:", &sockaddr);
  599. STREAM_PSOCKADDR(ppd)->sa_family = AF_INET;
  600. IP_STREAM_PORT(ppd) = ((SOCKADDR_IN * )&sockaddr)->sin_port;
  601. // we don't know the address of the local player (multihomed!)
  602. IP_STREAM_ADDR(ppd) = 0;
  603. break;
  604. case AF_IPX:
  605. {
  606. SOCKADDR_IPX * pipx = (SOCKADDR_IPX * )STREAM_PSOCKADDR(ppd);
  607. pipx->sa_family = AF_IPX;
  608. pipx->sa_socket = ((SOCKADDR_IPX*)&sockaddr)->sa_socket;
  609. memset(pipx->sa_nodenum,0,6);
  610. break;
  611. }
  612. default:
  613. ASSERT(FALSE);
  614. }
  615. } // stream
  616. else
  617. {
  618. switch (pgd->AddressFamily)
  619. {
  620. case AF_INET:
  621. DEBUGPRINTADDR(7, "Setting player AF_INET datagram socket address:", &sockaddr);
  622. DGRAM_PSOCKADDR(ppd)->sa_family = AF_INET;
  623. IP_DGRAM_PORT(ppd) = ((SOCKADDR_IN *)&sockaddr)->sin_port;
  624. // we don't know the address of the local player (multihomed!)
  625. IP_DGRAM_ADDR(ppd) = 0;
  626. break;
  627. case AF_IPX:
  628. {
  629. SOCKADDR_IPX * pipx = (SOCKADDR_IPX * )DGRAM_PSOCKADDR(ppd);
  630. pipx->sa_family = AF_IPX;
  631. pipx->sa_socket = ((SOCKADDR_IPX*)&sockaddr)->sa_socket;
  632. memset(pipx->sa_nodenum,0,6);
  633. break;
  634. }
  635. default:
  636. ASSERT(FALSE);
  637. }
  638. } // dgram
  639. return DP_OK;
  640. } // SetPlayerAddress
  641. #undef DPF_MODNAME
  642. #define DPF_MODNAME "GetIPXNameServerSocket"
  643. // called by CreatePlayerDgramSocket
  644. // bind to our well known port for ipx
  645. HRESULT GetIPXNameServerSocket(LPGLOBALDATA pgd)
  646. {
  647. BOOL bTrue = TRUE;
  648. SOCKET sSocket;
  649. HRESULT hr;
  650. UINT err;
  651. // if there already was a receive thread, we need to kill
  652. // the socket, and remember the thread, so at shutdown we
  653. // can make sure it's gone. note - we can't wait for it to
  654. // leave now, since dplay hasn't dropped its locks, and
  655. // the thread may be blocked on dplay
  656. if (pgd->hDGramReceiveThread)
  657. {
  658. // it's ipx, and we're deleting the system player
  659. // we need to get rid of the system sockets, so that if we recreate as
  660. // nameserver we can bind to a specific port...
  661. // ipx only uses datagram, so we only stop those...kill the socket
  662. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  663. KillSocket(pgd->sSystemDGramSocket,FALSE,TRUE);
  664. pgd->sSystemDGramSocket = INVALID_SOCKET;
  665. // remember the old thread - we'll need to make sure it's gone when we
  666. // shut down
  667. pgd->hIPXSpareThread = pgd->hDGramReceiveThread;
  668. pgd->hDGramReceiveThread = NULL;
  669. }
  670. DPF(2,"ipx - creating name server dgram socket\n");
  671. // use name server port
  672. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,SERVER_DGRAM_PORT,INADDR_ANY,&err,FALSE);
  673. if (FAILED(hr))
  674. {
  675. DPF(0,"IPX - DPLAY SERVER SOCKET IS ALREADY IN USE. PLEASE SHUTDOWN ANY");
  676. DPF(0,"OTHER NETWORK APPLICATIONS AND TRY AGAIN");
  677. // boned!
  678. return DPERR_CANNOTCREATESERVER;
  679. }
  680. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_BROADCAST,(char FAR *)&bTrue,
  681. sizeof(bTrue) ) )
  682. {
  683. err = WSAGetLastError();
  684. DPF(0,"create - could not set broadcast err = %d\n",err);
  685. // keep trying
  686. }
  687. DEBUGPRINTSOCK(2,"name server dgram socket (bound) - ",&sSocket);
  688. pgd->sSystemDGramSocket = sSocket;
  689. return DP_OK;
  690. } // GetIPXNameServerSocket
  691. HRESULT CreatePlayerDgramSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  692. {
  693. HRESULT hr=DP_OK;
  694. UINT err;
  695. SOCKET sSocket;
  696. if ( (AF_IPX == pgd->AddressFamily) && (dwFlags & DPLAYI_PLAYER_NAMESRVR))
  697. {
  698. //
  699. // AF_INET uses ddhelp to bind the nameserver to a specific port
  700. // (SERVER_DGRAM_PORT). AF_IPX binds to that port here.
  701. hr = GetIPXNameServerSocket(pgd);
  702. if (FAILED(hr))
  703. {
  704. return hr;
  705. }
  706. // store this for setting player address below
  707. sSocket = pgd->sSystemDGramSocket;
  708. }
  709. else if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  710. {
  711. if (INVALID_SOCKET == pgd->sSystemDGramSocket)
  712. {
  713. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  714. if (FAILED(hr))
  715. {
  716. DPF(0,"create sysplayer dgram socket failed - err = %d\n",err);
  717. return hr;
  718. }
  719. #ifdef DEBUG
  720. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  721. {
  722. DEBUGPRINTSOCK(2,"name server dgram socket - ",&sSocket);
  723. }
  724. #endif // DEBUG
  725. pgd->sSystemDGramSocket = sSocket;
  726. }
  727. else
  728. {
  729. // store this for setting player address below
  730. sSocket = pgd->sSystemDGramSocket;
  731. }
  732. }
  733. else
  734. {
  735. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  736. sSocket = pgd->sSystemDGramSocket;
  737. }
  738. // store the ip + port w/ the player...
  739. hr = SetPlayerAddress(pgd,ppd,sSocket,FALSE);
  740. return hr;
  741. } // CreatePlayerDgramSocket
  742. HRESULT CreatePlayerStreamSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  743. {
  744. SOCKET sSocket;
  745. HRESULT hr=DP_OK;
  746. UINT err;
  747. BOOL bListen = TRUE; // set if we created socket, + need to set it's listen
  748. BOOL bTrue = TRUE;
  749. DWORD dwSize;
  750. SOCKADDR_IN saddr;
  751. if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  752. {
  753. if (INVALID_SOCKET == pgd->sSystemStreamSocket)
  754. {
  755. hr = CreateSocket(pgd,&sSocket,SOCK_STREAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  756. if (FAILED(hr))
  757. {
  758. DPF(0,"create player stream socket failed - err = %d\n",err);
  759. return hr;
  760. }
  761. #ifdef DEBUG
  762. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  763. {
  764. DEBUGPRINTSOCK(2,"name server stream socket - ",&sSocket);
  765. }
  766. #endif // DEBUG
  767. bTrue = SetSharedPortAccess(sSocket);
  768. if (! bTrue)
  769. {
  770. DPF(0,"Failed to to set shared mode on socket - continue\n");
  771. }
  772. pgd->sSystemStreamSocket = sSocket;
  773. // get the socket address, and keep it around for future reference.
  774. dwSize = sizeof(saddr);
  775. err=getsockname(pgd->sSystemStreamSocket, (SOCKADDR *)&saddr, &dwSize);
  776. if(err){
  777. DPF(0,"Couldn't get socket name?\n");
  778. DEBUG_BREAK();
  779. }
  780. pgd->SystemStreamPort = saddr.sin_port;
  781. }
  782. else
  783. {
  784. sSocket = pgd->sSystemStreamSocket;
  785. bListen = FALSE;
  786. }
  787. }
  788. else
  789. {
  790. ASSERT (INVALID_SOCKET != pgd->sSystemStreamSocket);
  791. sSocket = pgd->sSystemStreamSocket;
  792. bListen = FALSE;
  793. }
  794. if (bListen)
  795. {
  796. // set up socket to receive connections
  797. err = listen(sSocket,LISTEN_BACKLOG);
  798. if (SOCKET_ERROR == err)
  799. {
  800. err = WSAGetLastError();
  801. ASSERT(FALSE);
  802. DPF(0,"ACK! stream socket listen failed - err = %d\n",err);
  803. // keep trying
  804. }
  805. }
  806. hr = SetPlayerAddress(pgd,ppd,sSocket,TRUE);
  807. return hr;
  808. } // CreatePlayerStreamSocket
  809. #undef DPF_MODNAME
  810. #define DPF_MODNAME "PokeAddr"
  811. // poke an ip addr into a message blob
  812. void IP_SetAddr(LPVOID pmsg,SOCKADDR_IN * paddrSrc)
  813. {
  814. LPSOCKADDR_IN paddrDest; // tempo variable, makes casting less ugly
  815. LPMESSAGEHEADER phead;
  816. phead = (LPMESSAGEHEADER)pmsg;
  817. // todo - validate header
  818. // leave the port intact, copy over the ip addr
  819. paddrDest = (SOCKADDR_IN *)&(phead->sockaddr);
  820. // poke the new ip addr into the message header
  821. // only rehome addresses that aren't already homed.
  822. if(paddrDest->sin_addr.s_addr == 0){
  823. paddrDest->sin_addr.s_addr = paddrSrc->sin_addr.s_addr;
  824. }
  825. return;
  826. } // IP_SetAddr
  827. // get an ip addr from a message blob
  828. void IP_GetAddr(SOCKADDR_IN * paddrDest,SOCKADDR_IN * paddrSrc)
  829. {
  830. // leave the port intact, copy over the nodenum
  831. if (0 == paddrDest->sin_addr.s_addr)
  832. {
  833. DPF(2,"remote player - setting address!! = %s\n",inet_ntoa(paddrSrc->sin_addr));
  834. paddrDest->sin_addr.s_addr = paddrSrc->sin_addr.s_addr;
  835. }
  836. return;
  837. } // IP_GetAddr
  838. // poke the ipx nodenumber / a message
  839. void IPX_SetNodenum(LPVOID pmsg,SOCKADDR_IPX * paddrSrc)
  840. {
  841. LPSOCKADDR_IPX paddrDest; // tempo variable, makes casting less ugly
  842. LPMESSAGEHEADER phead;
  843. phead = (LPMESSAGEHEADER)pmsg;
  844. // todo - validate header
  845. // leave the port intact, copy over the nodenum
  846. paddrDest = (SOCKADDR_IPX *)&(phead->sockaddr);
  847. memcpy(paddrDest->sa_nodenum,paddrSrc->sa_nodenum,6);
  848. memcpy(paddrDest->sa_netnum,paddrSrc->sa_netnum,4);
  849. return;
  850. } // IPX_SetNodenum
  851. // reconstruct the nodenum from the msg
  852. void IPX_GetNodenum(SOCKADDR_IPX * paddrDest,SOCKADDR_IPX * paddrSrc)
  853. {
  854. char sa_nodenum_zero[6];
  855. memset(sa_nodenum_zero,0,6);
  856. // if the nodenum is zero, set it
  857. if (0 == memcmp(paddrDest->sa_nodenum,sa_nodenum_zero,6))
  858. {
  859. DEBUGPRINTADDR(4,"IPX - setting remote player address",(SOCKADDR *)paddrSrc);
  860. // leave the port intact, copy over the nodenum
  861. memcpy(paddrDest->sa_nodenum,paddrSrc->sa_nodenum,6);
  862. memcpy(paddrDest->sa_netnum,paddrSrc->sa_netnum,4);
  863. }
  864. return;
  865. } // IPX_GetNodenum
  866. // store the port of the socket w/ the message, so the receiving end
  867. // can reconstruct the address to reply to
  868. // psaddr will override the address if present
  869. HRESULT SetReturnAddress(LPVOID pmsg,SOCKET sSocket, LPSOCKADDR psaddrPublic)
  870. {
  871. #define psaddr_inPublic ((LPSOCKADDR_IN)psaddrPublic)
  872. SOCKADDR sockaddr;
  873. INT addrlen=sizeof(SOCKADDR);
  874. LPMESSAGEHEADER phead;
  875. UINT err;
  876. // Note: extra test for 0 IP address may be extraneous (but certainly won't hurt).
  877. if(psaddrPublic && psaddr_inPublic->sin_addr.s_addr ){
  878. // We are behind an RSIP gateway, so put the public address in the header
  879. phead = (LPMESSAGEHEADER)pmsg;
  880. phead->sockaddr = *psaddrPublic;
  881. DEBUGPRINTADDR(8,"setting return address (using rsip public address) = ",&phead->sockaddr);
  882. } else {
  883. // find out what port gGlobalData.sEnumSocket is on
  884. DPF(8,"==>GetSockName\n");
  885. err = getsockname(sSocket,(LPSOCKADDR)&sockaddr,&addrlen);
  886. DPF(8,"<==GetSockName\n");
  887. if (SOCKET_ERROR == err)
  888. {
  889. err = WSAGetLastError();
  890. DPF(0,"could not get socket name - err = %d\n",err);
  891. return DP_OK;
  892. }
  893. DEBUGPRINTADDR(8,"setting return address = ",&sockaddr);
  894. phead = (LPMESSAGEHEADER)pmsg;
  895. // todo - validate header
  896. phead->sockaddr = sockaddr;
  897. }
  898. return DP_OK;
  899. #undef psaddr_inPublic
  900. } // SetReturnAddress
  901. // code below all called by GetServerAddress. For IP, prompts user for ip address
  902. // for name server.
  903. #undef DPF_MODNAME
  904. #define DPF_MODNAME "GetAddress"
  905. // get the ip address from the pBuffer passed in by a user
  906. // can either be a real ip, or a hostname
  907. // called after the user fills out our dialog box
  908. HRESULT GetAddress(ULONG * puAddress,char *pBuffer,int cch)
  909. {
  910. UINT uiAddr;
  911. UINT err;
  912. PHOSTENT phostent;
  913. IN_ADDR hostaddr;
  914. if ( (0 == cch) || (!pBuffer) || (0 == strlen(pBuffer)) )
  915. {
  916. *puAddress = INADDR_BROADCAST;
  917. return (DP_OK);
  918. }
  919. // try inet_addr first
  920. uiAddr = inet_addr(pBuffer);
  921. if(0 == uiAddr) // fix bug where "" buffer passed in.
  922. {
  923. *puAddress = INADDR_BROADCAST;
  924. return (DP_OK);
  925. }
  926. if (INADDR_NONE != uiAddr)
  927. {
  928. // found it
  929. *puAddress = uiAddr;
  930. return (DP_OK);
  931. }
  932. // try hostbyname
  933. phostent = gethostbyname(pBuffer);
  934. if (NULL == phostent )
  935. {
  936. err = WSAGetLastError();
  937. DPF(0,"could not get host address - err = %d\n",err);
  938. return (DPERR_INVALIDPARAM);
  939. }
  940. memcpy(&hostaddr,phostent->h_addr,sizeof(hostaddr));
  941. DPF(1,"name server address = %s \n",inet_ntoa(hostaddr));
  942. *puAddress = hostaddr.s_addr;
  943. return (DP_OK);
  944. } // GetAddress
  945. // put up a dialog asking for a network address
  946. // call get address to convert user specified address to network usable address
  947. // called by GetServerAddress
  948. INT_PTR CALLBACK DlgServer(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  949. {
  950. HWND hWndCtl;
  951. char pBuffer[ADDR_BUFFER_SIZE];
  952. UINT cch;
  953. ULONG *lpuEnumAddress;
  954. HRESULT hr;
  955. switch (msg)
  956. {
  957. case WM_INITDIALOG:
  958. // set focus on edit box
  959. hWndCtl = GetDlgItem(hDlg, IDC_EDIT1);
  960. if (hWndCtl == NULL)
  961. {
  962. EndDialog(hDlg, FALSE);
  963. return(TRUE);
  964. }
  965. SetFocus(hWndCtl);
  966. SendMessage(hWndCtl, CB_SETCURSEL, 0, 0);
  967. // save pointer to enum address with the window
  968. SetWindowLongPtr(hDlg, DWLP_USER, (LONG) lParam);
  969. return(FALSE);
  970. case WM_COMMAND:
  971. switch(LOWORD(wParam))
  972. {
  973. case IDOK:
  974. // get text entered in control
  975. cch = GetDlgItemText(hDlg, IDC_EDIT1, pBuffer, ADDR_BUFFER_SIZE);
  976. // get pointer to return address in
  977. lpuEnumAddress = (ULONG *) GetWindowLongPtr(hDlg, DWLP_USER);
  978. // convert string to enum address
  979. hr = GetAddress(lpuEnumAddress,pBuffer,cch);
  980. if (FAILED(hr))
  981. EndDialog(hDlg, hr);
  982. else
  983. EndDialog(hDlg, TRUE);
  984. return(TRUE);
  985. case IDCANCEL:
  986. EndDialog(hDlg, FALSE);
  987. return(TRUE);
  988. }
  989. break;
  990. }
  991. return (FALSE);
  992. } // DlgServer
  993. /*
  994. ** GetServerAddress
  995. *
  996. * CALLED BY: EnumSessions
  997. *
  998. * DESCRIPTION: launches the select network address dialog
  999. *
  1000. * RETURNS: ip address (sockaddr.sin_addr.s_addr)
  1001. *
  1002. */
  1003. HRESULT ServerDialog(ULONG *lpuEnumAddress)
  1004. {
  1005. HWND hwnd;
  1006. INT_PTR iResult;
  1007. HRESULT hr;
  1008. // we have a valid enum address
  1009. if (*lpuEnumAddress)
  1010. return (DP_OK);
  1011. // use the fg window as our parent, since a ddraw app may be full screen
  1012. // exclusive
  1013. hwnd = GetForegroundWindow();
  1014. iResult = DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_SELECTSERVER), hwnd,
  1015. DlgServer, (LPARAM) lpuEnumAddress);
  1016. if (iResult == -1)
  1017. {
  1018. DPF_ERR("GetServerAddress - dialog failed");
  1019. hr = DPERR_GENERIC;
  1020. }
  1021. else if (iResult < 0)
  1022. {
  1023. DPF(0, "GetServerAddress - dialog failed: %08X", iResult);
  1024. hr = (HRESULT) iResult;
  1025. }
  1026. else if (iResult == 0)
  1027. {
  1028. hr = DPERR_USERCANCEL;
  1029. }
  1030. else
  1031. {
  1032. hr = DP_OK;
  1033. }
  1034. return (hr);
  1035. } //ServerDialog
  1036. // called by enumsessions - find out where server is...
  1037. HRESULT GetServerAddress(LPGLOBALDATA pgd,LPSOCKADDR psockaddr)
  1038. {
  1039. HRESULT hr;
  1040. if (AF_IPX == pgd->AddressFamily)
  1041. {
  1042. ((LPSOCKADDR_IPX)psockaddr)->sa_family = AF_IPX;
  1043. ((LPSOCKADDR_IPX)psockaddr)->sa_socket = SERVER_DGRAM_PORT;
  1044. memset(&(((LPSOCKADDR_IPX)psockaddr)->sa_nodenum),0xff,sizeof(((LPSOCKADDR_IPX)psockaddr)->sa_nodenum));
  1045. hr = DP_OK;
  1046. }
  1047. else
  1048. {
  1049. if (pgd->bHaveServerAddress)
  1050. {
  1051. // use enum address passed to SPInit
  1052. hr = GetAddress(&pgd->uEnumAddress,pgd->szServerAddress,strlen(pgd->szServerAddress));
  1053. }
  1054. else
  1055. {
  1056. // ask user for enum address
  1057. hr = ServerDialog(&pgd->uEnumAddress);
  1058. }
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. // setup winsock to enum this address
  1062. ((LPSOCKADDR_IN)psockaddr)->sin_family = AF_INET;
  1063. ((LPSOCKADDR_IN)psockaddr)->sin_addr.s_addr = pgd->uEnumAddress;
  1064. // see byte-order comment in dpsp.h for this constant
  1065. ((LPSOCKADDR_IN)psockaddr)->sin_port = SERVER_DGRAM_PORT;
  1066. #if USE_RSIP
  1067. #define IP_SOCKADDR(a) (((SOCKADDR_IN *)(&a))->sin_addr.s_addr)
  1068. // Make sure the address we are enumming doesn't have a local alias.
  1069. // If it does, use the local alias instead of the public address.
  1070. if(pgd->sRsip!=INVALID_SOCKET &&
  1071. pgd->uEnumAddress != INADDR_BROADCAST &&
  1072. pgd->uEnumAddress != INADDR_LOOPBACK){
  1073. SOCKADDR saddr;
  1074. hr=rsipQueryLocalAddress(pgd, FALSE, psockaddr, &saddr);
  1075. if(hr==DP_OK){
  1076. // If there is an alias, go broadcast. This works just as well
  1077. // and avoids problems where more than 1 mapped shared
  1078. // UDP port is allocated.
  1079. DEBUGPRINTADDR(7, "Enum Socket is ",psockaddr);
  1080. DEBUGPRINTADDR(7, "Got Local Alias for Enum socket ",&saddr);
  1081. IP_SOCKADDR(*psockaddr)=0xFFFFFFFF;
  1082. #if 0
  1083. if(IP_SOCKADDR(saddr)==IP_SOCKADDR(*psockaddr))
  1084. {
  1085. DPF(7, "Alias had same IP as queried, assuming local ICS, so using broadcast enum\n");
  1086. IP_SOCKADDR(*psockaddr)=0xFFFFFFFF;
  1087. } else {
  1088. memcpy(psockaddr, &saddr, sizeof(SOCKADDR));
  1089. }
  1090. #endif
  1091. }else{
  1092. DEBUGPRINTADDR(7,"No local alias for Enum socket ",psockaddr);
  1093. hr = DP_OK;
  1094. }
  1095. }
  1096. #undef IP_SOCKADDR
  1097. #elif USE_NATHELP
  1098. #define IP_SOCKADDR(a) (((SOCKADDR_IN *)(&a))->sin_addr.s_addr)
  1099. // Make sure the address we are enumming doesn't have a local alias.
  1100. // If it does, use the local alias instead of the public address.
  1101. if(pgd->pINatHelp &&
  1102. pgd->uEnumAddress != INADDR_BROADCAST &&
  1103. pgd->uEnumAddress != INADDR_LOOPBACK){
  1104. SOCKADDR saddr;
  1105. hr=IDirectPlayNATHelp_QueryAddress(
  1106. pgd->pINatHelp,
  1107. &pgd->INADDRANY,
  1108. psockaddr,
  1109. &saddr,
  1110. sizeof(SOCKADDR_IN),
  1111. DPNHQUERYADDRESS_CACHENOTFOUND
  1112. );
  1113. if(hr==DP_OK){
  1114. // If there is an alias, go broadcast. This works just as well
  1115. // and avoids problems where more than 1 mapped shared
  1116. // UDP port is allocated.
  1117. DEBUGPRINTADDR(7, "Enum Socket is ",psockaddr);
  1118. DEBUGPRINTADDR(7, "Got Local Alias for Enum socket ",&saddr);
  1119. IP_SOCKADDR(*psockaddr)=0xFFFFFFFF;
  1120. }else{
  1121. DEBUGPRINTADDR(7,"No local alias for Enum socket ",psockaddr);
  1122. hr = DP_OK;
  1123. }
  1124. }
  1125. #undef IP_SOCKADDR
  1126. #endif
  1127. }
  1128. else
  1129. {
  1130. DPF(0, "Invalid server address: 0x%08lx", hr);
  1131. }
  1132. }
  1133. return (hr);
  1134. } // GetServerAddress