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.

947 lines
24 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. ***************************************************************************/
  41. #include "dpsp.h"
  42. // backlog for listen() api. no constant in winsock, so we ask for the moon
  43. #define LISTEN_BACKLOG 60
  44. // how long to wait, in ms, til we abort a blocking WinSock connect() call
  45. #define CONNECT_WATCHER_TIMEOUT 15000
  46. /*
  47. ** CreateSocket
  48. *
  49. * CALLED BY: all over
  50. *
  51. * PARAMETERS:
  52. * pgd - pointer to a global data
  53. * psock - new socket. return value.
  54. * type - stream or datagram
  55. * port - what port we bind to (host byte order)
  56. * address - what address to use (net byte order)
  57. * *perr - set to the last socket error if fn fails
  58. * bInRange - use reserved range of ports
  59. *
  60. * DESCRIPTION:
  61. * creates a new socket. binds to port specified, at the address specified
  62. *
  63. * RETURNS: DP_OK or E_FAIL. if E_FAIL, *perr is set with socket error code (see winsock.h)
  64. *
  65. */
  66. HRESULT FAR PASCAL CreateSocket(LPGLOBALDATA pgd,SOCKET * psock,INT type,WORD wApplicationPort,ULONG address,
  67. SOCKERR * perr,BOOL bInRange)
  68. {
  69. SOCKET sNew;
  70. SOCKADDR sockAddr;
  71. int bTrue = TRUE;
  72. int protocol = 0;
  73. BOOL bBroadcast = FALSE;
  74. WORD wPort;
  75. BOOL bBound = FALSE;
  76. *psock = INVALID_SOCKET; // in case we bail
  77. // Create the socket.
  78. if (AF_IPX == pgd->AddressFamily)
  79. {
  80. // set up protocol for ipx
  81. if (SOCK_STREAM == type)
  82. {
  83. protocol = NSPROTO_SPXII;
  84. }
  85. else protocol = NSPROTO_IPX;
  86. }
  87. sNew = socket( pgd->AddressFamily, type, protocol);
  88. if (INVALID_SOCKET == sNew)
  89. {
  90. // no cleanup needed, just bail
  91. *perr = WSAGetLastError();
  92. return E_FAIL;
  93. }
  94. // try to bind an address to the socket.
  95. // set up the sockaddr
  96. memset(&sockAddr,0,sizeof(sockAddr));
  97. switch (pgd->AddressFamily)
  98. {
  99. case AF_INET:
  100. {
  101. if ((SOCK_STREAM == type))
  102. {
  103. BOOL bTrue = TRUE;
  104. UINT err;
  105. // turn ON keepalive
  106. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  107. {
  108. err = WSAGetLastError();
  109. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  110. }
  111. ASSERT(bTrue);
  112. // turn off nagling
  113. if(pgd->dwSessionFlags & DPSESSION_OPTIMIZELATENCY)
  114. {
  115. DPF(5, "Turning nagling off on socket");
  116. if (SOCKET_ERROR == setsockopt(sNew, IPPROTO_TCP, TCP_NODELAY, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  117. {
  118. err = WSAGetLastError();
  119. DPF(0,"Failed to turn off naggling - continue : err = %d\n",err);
  120. }
  121. }
  122. }
  123. ((SOCKADDR_IN *)&sockAddr)->sin_family = PF_INET;
  124. ((SOCKADDR_IN *)&sockAddr)->sin_addr.s_addr = address;
  125. ((SOCKADDR_IN *)&sockAddr)->sin_port = htons(wApplicationPort);
  126. if (bInRange && !wApplicationPort)
  127. {
  128. USHORT rndoffset;
  129. DPF(5, "Application didn't specify a port - using dplay range");
  130. rndoffset=(USHORT)(GetTickCount()%DPSP_NUM_PORTS);
  131. wPort = DPSP_MIN_PORT+rndoffset;
  132. do
  133. {
  134. DPF(5, "Trying to bind to port %d",wPort);
  135. ((SOCKADDR_IN *)&sockAddr)->sin_port = htons(wPort);
  136. // do the bind
  137. if( SOCKET_ERROR != bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr) ) )
  138. {
  139. bBound = TRUE;
  140. DPF(5, "Successfully bound to port %d", wPort);
  141. }
  142. else
  143. {
  144. if(++wPort > DPSP_MAX_PORT){
  145. wPort=DPSP_MIN_PORT;
  146. }
  147. }
  148. }
  149. while (!bBound && (wPort != DPSP_MIN_PORT+rndoffset));
  150. }
  151. }
  152. break;
  153. case AF_IPX:
  154. {
  155. ((SOCKADDR_IPX *)&sockAddr)->sa_family = (SHORT)pgd->AddressFamily;
  156. ((SOCKADDR_IPX *)&sockAddr)->sa_socket = wApplicationPort;
  157. // nodenum?
  158. memset(&(((SOCKADDR_IPX *)&sockAddr)->sa_nodenum),0,6);
  159. }
  160. break;
  161. default:
  162. ASSERT(FALSE);
  163. break;
  164. } // switch
  165. // do the bind
  166. if( !bBound && (SOCKET_ERROR == bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr))) )
  167. {
  168. goto ERROR_EXIT;
  169. }
  170. // success!
  171. *psock = sNew;
  172. DEBUGPRINTSOCK(9,"created a new socket (bound) - ",psock);
  173. return DP_OK;
  174. ERROR_EXIT:
  175. // clean up and bail
  176. *perr = WSAGetLastError();
  177. DPF(0,"create socket failed- err = %d\n",*perr);
  178. closesocket(sNew);
  179. return E_FAIL;
  180. } // CreateSocket
  181. #undef DPF_MODNAME
  182. #define DPF_MODNAME "KillSocket"
  183. HRESULT KillSocket(SOCKET sSocket,BOOL fStream,BOOL fHard)
  184. {
  185. UINT err;
  186. if (INVALID_SOCKET == sSocket)
  187. {
  188. return E_FAIL;
  189. }
  190. if (!fStream)
  191. {
  192. if (SOCKET_ERROR == closesocket(sSocket))
  193. {
  194. err = WSAGetLastError();
  195. DPF(0,"killsocket - dgram close err = %d\n",err);
  196. return E_FAIL;
  197. }
  198. }
  199. else
  200. {
  201. LINGER Linger;
  202. if (fHard)
  203. {
  204. Linger.l_onoff=TRUE; // turn linger on
  205. Linger.l_linger=0; // nice small time out
  206. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,
  207. sizeof(Linger) ) )
  208. {
  209. err = WSAGetLastError();
  210. DPF(0,"killsocket - stream setopt err = %d\n",err);
  211. }
  212. }
  213. if (SOCKET_ERROR == shutdown(sSocket,2))
  214. {
  215. // this may well fail, if e.g. no one is using this socket right now...
  216. // the error would be wsaenotconn
  217. err = WSAGetLastError();
  218. DPF(5,"killsocket - stream shutdown err = %d\n",err);
  219. }
  220. if (SOCKET_ERROR == closesocket(sSocket))
  221. {
  222. err = WSAGetLastError();
  223. DPF(0,"killsocket - stream close err = %d\n",err);
  224. return E_FAIL;
  225. }
  226. }
  227. return DP_OK;
  228. }// KillSocket
  229. #undef DPF_MODNAME
  230. #define DPF_MODNAME "CreateAndInitStreamSocket"
  231. // set up a stream socket to receive connections
  232. // used w/ the gGlobalData.sStreamAcceptSocket
  233. HRESULT CreateAndInitStreamSocket(LPGLOBALDATA pgd)
  234. {
  235. HRESULT hr;
  236. UINT err;
  237. LINGER Linger;
  238. hr = CreateSocket(pgd,&(pgd->sSystemStreamSocket),SOCK_STREAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  239. if (FAILED(hr))
  240. {
  241. DPF(0,"init listen socket failed - err = %d\n",err);
  242. return hr ;
  243. }
  244. // set up socket w/ max listening connections
  245. err = listen(pgd->sSystemStreamSocket,LISTEN_BACKLOG);
  246. if (SOCKET_ERROR == err)
  247. {
  248. err = WSAGetLastError();
  249. DPF(0,"init listen socket / listen error - err = %d\n",err);
  250. return E_FAIL ;
  251. }
  252. // set for hard disconnect
  253. Linger.l_onoff=1;
  254. Linger.l_linger=0;
  255. if( SOCKET_ERROR == setsockopt( pgd->sSystemStreamSocket,SOL_SOCKET,SO_LINGER,
  256. (char FAR *)&Linger,sizeof(Linger) ) )
  257. {
  258. err = WSAGetLastError();
  259. DPF(0,"Delete service socket - stream setopt err = %d\n",err);
  260. }
  261. DEBUGPRINTSOCK(1,"enum - listening on",&(pgd->sSystemStreamSocket));
  262. return DP_OK;
  263. } // CreateAndInitStreamSocket
  264. #undef DPF_MODNAME
  265. #define DPF_MODNAME "SPConnect"
  266. // connect socket to sockaddr
  267. HRESULT SPConnect(SOCKET* psSocket, LPSOCKADDR psockaddr,UINT addrlen, BOOL bOutBoundOnly)
  268. {
  269. UINT err;
  270. HRESULT hr = DP_OK;
  271. DWORD dwLastError;
  272. u_long lNonBlock = 1; // passed to ioctlsocket to make socket non-blocking
  273. u_long lBlock = 0; // passed to ioctlsocket to make socket blocking again
  274. fd_set fd_setConnect;
  275. fd_set fd_setExcept;
  276. TIMEVAL timevalConnect;
  277. err=ioctlsocket(*psSocket, FIONBIO, &lNonBlock); // make socket non-blocking
  278. if(SOCKET_ERROR == err){
  279. dwLastError=WSAGetLastError();
  280. DPF(0,"sp - failed to set socket %d to non-blocking mode err= %d\n", *psSocket, dwLastError);
  281. return DPERR_CONNECTIONLOST;
  282. }
  283. // Start the socket connecting.
  284. err = connect(*psSocket,psockaddr,addrlen);
  285. if(SOCKET_ERROR == err) {
  286. dwLastError=WSAGetLastError();
  287. if(dwLastError != WSAEWOULDBLOCK){
  288. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  289. return DPERR_CONNECTIONLOST;
  290. }
  291. // we are going to wait for either the connect to succeed (socket to be writeable)
  292. // or the connect to fail (except fdset bit to be set). So we init an FDSET with
  293. // the socket that is connecting and wait.
  294. FD_ZERO(&fd_setConnect);
  295. FD_SET(*psSocket, &fd_setConnect);
  296. FD_ZERO(&fd_setExcept);
  297. FD_SET(*psSocket, &fd_setExcept);
  298. timevalConnect.tv_sec=0;
  299. timevalConnect.tv_usec=CONNECT_WATCHER_TIMEOUT*1000; //msec -> usec
  300. err = select(0, NULL, &fd_setConnect, &fd_setExcept, &timevalConnect);
  301. // err is the number of sockets with activity or 0 for timeout
  302. // or SOCKET_ERROR for error
  303. if(SOCKET_ERROR == err) {
  304. dwLastError=WSAGetLastError();
  305. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  306. return DPERR_CONNECTIONLOST;
  307. } else if (0==err){
  308. // timed out
  309. DPF(0,"Connect timed out on socket %d\n",*psSocket);
  310. return DPERR_CONNECTIONLOST;
  311. }
  312. // Now see if the connect succeeded or the connect got an exception
  313. if(!(FD_ISSET(*psSocket, &fd_setConnect))){
  314. DPF(0,"Connect did not succeed on socket %d\n",*psSocket);
  315. return DPERR_CONNECTIONLOST;
  316. }
  317. if(FD_ISSET(*psSocket,&fd_setExcept)){
  318. DPF(0,"Got exception on socket %d during connect\n",*psSocket);
  319. return DPERR_CONNECTIONLOST;
  320. }
  321. }
  322. err=ioctlsocket(*psSocket, FIONBIO, &lBlock); // make socket blocking again
  323. DEBUGPRINTSOCK(9,"successfully connected socket - ", psSocket);
  324. if (bOutBoundOnly)
  325. {
  326. DEBUGPRINTADDR(5, "Sending reuse connection message to - ",psockaddr);
  327. // tell receiver to reuse connection
  328. hr = SendReuseConnectionMessage(*psSocket);
  329. }
  330. return hr;
  331. } //SPConnect
  332. #undef DPF_MODNAME
  333. #define DPF_MODNAME "SetPlayerAddress"
  334. // we've created a socket for a player. store its address in the players
  335. // spplayerdata struct.
  336. HRESULT SetPlayerAddress(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,SOCKET sSocket,BOOL fStream)
  337. {
  338. SOCKADDR sockaddr;
  339. UINT err;
  340. int iAddrLen = sizeof(SOCKADDR);
  341. err = getsockname(sSocket,&sockaddr,&iAddrLen);
  342. if (SOCKET_ERROR == err)
  343. {
  344. err = WSAGetLastError();
  345. DPF(0,"setplayeraddress - getsockname - err = %d\n",err);
  346. closesocket(sSocket);
  347. return E_FAIL;
  348. }
  349. if (fStream)
  350. {
  351. switch (pgd->AddressFamily)
  352. {
  353. case AF_INET:
  354. STREAM_PSOCKADDR(ppd)->sa_family = AF_INET;
  355. IP_STREAM_PORT(ppd) = ((SOCKADDR_IN * )&sockaddr)->sin_port;
  356. // we don't know the address of the local player (multihomed!)
  357. IP_STREAM_ADDR(ppd) = 0;
  358. break;
  359. case AF_IPX:
  360. {
  361. SOCKADDR_IPX * pipx = (SOCKADDR_IPX * )STREAM_PSOCKADDR(ppd);
  362. pipx->sa_family = AF_IPX;
  363. pipx->sa_socket = ((SOCKADDR_IPX*)&sockaddr)->sa_socket;
  364. memset(pipx->sa_nodenum,0,6);
  365. break;
  366. }
  367. default:
  368. ASSERT(FALSE);
  369. }
  370. } // stream
  371. else
  372. {
  373. switch (pgd->AddressFamily)
  374. {
  375. case AF_INET:
  376. DGRAM_PSOCKADDR(ppd)->sa_family = AF_INET;
  377. IP_DGRAM_PORT(ppd) = ((SOCKADDR_IN *)&sockaddr)->sin_port;
  378. // we don't know the address of the local player (multihomed!)
  379. IP_DGRAM_ADDR(ppd) = 0;
  380. break;
  381. case AF_IPX:
  382. {
  383. SOCKADDR_IPX * pipx = (SOCKADDR_IPX * )DGRAM_PSOCKADDR(ppd);
  384. pipx->sa_family = AF_IPX;
  385. pipx->sa_socket = ((SOCKADDR_IPX*)&sockaddr)->sa_socket;
  386. memset(pipx->sa_nodenum,0,6);
  387. break;
  388. }
  389. default:
  390. ASSERT(FALSE);
  391. }
  392. } // dgram
  393. return DP_OK;
  394. } // SetPlayerAddress
  395. #undef DPF_MODNAME
  396. #define DPF_MODNAME "CreatePlayerSocket"
  397. // called by CreatePlayerDgramSocket
  398. // bind to our well known port for ipx
  399. HRESULT GetIPXNameServerSocket(LPGLOBALDATA pgd)
  400. {
  401. BOOL bTrue = TRUE;
  402. SOCKET sSocket;
  403. HRESULT hr;
  404. UINT err;
  405. // if there already was a receive thread, we need to kill
  406. // the socket, and remember the thread, so at shutdown we
  407. // can make sure it's gone. note - we can't wait for it to
  408. // leave now, since dplay hasn't dropped its locks, and
  409. // the thread may be blocked on dplay
  410. if (pgd->hDGramReceiveThread)
  411. {
  412. // it's ipx, and we're deleting the system player
  413. // we need to get rid of the system sockets, so that if we recreate as
  414. // nameserver we can bind to a specific port...
  415. // ipx only uses datagram, so we only stop those...kill the socket
  416. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  417. KillSocket(pgd->sSystemDGramSocket,FALSE,TRUE);
  418. pgd->sSystemDGramSocket = INVALID_SOCKET;
  419. // remember the old thread - we'll need to make sure it's gone when we
  420. // shut down
  421. pgd->hIPXSpareThread = pgd->hDGramReceiveThread;
  422. pgd->hDGramReceiveThread = NULL;
  423. }
  424. DPF(2,"ipx - creating name server dgram socket\n");
  425. // use name server port
  426. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,SERVER_DGRAM_PORT,INADDR_ANY,&err,FALSE);
  427. if (FAILED(hr))
  428. {
  429. DPF(0,"IPX - DPLAY SERVER SOCKET IS ALREADY IN USE. PLEASE SHUTDOWN ANY");
  430. DPF(0,"OTHER NETWORK APPLICATIONS AND TRY AGAIN");
  431. // boned!
  432. return DPERR_CANNOTCREATESERVER;
  433. }
  434. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_BROADCAST,(char FAR *)&bTrue,
  435. sizeof(bTrue) ) )
  436. {
  437. err = WSAGetLastError();
  438. DPF(0,"create - could not set broadcast err = %d\n",err);
  439. // keep trying
  440. }
  441. DEBUGPRINTSOCK(2,"name server dgram socket (bound) - ",&sSocket);
  442. pgd->sSystemDGramSocket = sSocket;
  443. return DP_OK;
  444. } // GetIPXNameServerSocket
  445. HRESULT CreatePlayerDgramSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  446. {
  447. HRESULT hr=DP_OK;
  448. UINT err;
  449. SOCKET sSocket;
  450. if ( (AF_IPX == pgd->AddressFamily) && (dwFlags & DPLAYI_PLAYER_NAMESRVR))
  451. {
  452. //
  453. // AF_INET uses ddhelp to bind the nameserver to a specific port
  454. // (SERVER_DGRAM_PORT). AF_IPX binds to that port here.
  455. hr = GetIPXNameServerSocket(pgd);
  456. if (FAILED(hr))
  457. {
  458. return hr;
  459. }
  460. // store this for setting player address below
  461. sSocket = pgd->sSystemDGramSocket;
  462. }
  463. else if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  464. {
  465. if (INVALID_SOCKET == pgd->sSystemDGramSocket)
  466. {
  467. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  468. if (FAILED(hr))
  469. {
  470. DPF(0,"create sysplayer dgram socket failed - err = %d\n",err);
  471. return hr;
  472. }
  473. #ifdef DEBUG
  474. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  475. {
  476. DEBUGPRINTSOCK(2,"name server dgram socket - ",&sSocket);
  477. }
  478. #endif // DEBUG
  479. pgd->sSystemDGramSocket = sSocket;
  480. }
  481. else
  482. {
  483. // store this for setting player address below
  484. sSocket = pgd->sSystemDGramSocket;
  485. }
  486. }
  487. else
  488. {
  489. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  490. sSocket = pgd->sSystemDGramSocket;
  491. }
  492. // store the ip + port w/ the player...
  493. hr = SetPlayerAddress(pgd,ppd,sSocket,FALSE);
  494. return hr;
  495. } // CreatePlayerDgramSocket
  496. HRESULT CreatePlayerStreamSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  497. {
  498. SOCKET sSocket;
  499. HRESULT hr=DP_OK;
  500. UINT err;
  501. BOOL bListen = TRUE; // set if we created socket, + need to set it's listen
  502. if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  503. {
  504. if (INVALID_SOCKET == pgd->sSystemStreamSocket)
  505. {
  506. hr = CreateSocket(pgd,&sSocket,SOCK_STREAM,pgd->wApplicationPort,INADDR_ANY,&err,TRUE);
  507. if (FAILED(hr))
  508. {
  509. DPF(0,"create player stream socket failed - err = %d\n",err);
  510. return hr;
  511. }
  512. #ifdef DEBUG
  513. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  514. {
  515. DEBUGPRINTSOCK(2,"name server stream socket - ",&sSocket);
  516. }
  517. #endif // DEBUG
  518. pgd->sSystemStreamSocket = sSocket;
  519. }
  520. else
  521. {
  522. sSocket = pgd->sSystemStreamSocket;
  523. bListen = FALSE;
  524. }
  525. }
  526. else
  527. {
  528. ASSERT (INVALID_SOCKET != pgd->sSystemStreamSocket);
  529. sSocket = pgd->sSystemStreamSocket;
  530. bListen = FALSE;
  531. }
  532. if (bListen)
  533. {
  534. // set up socket to receive connections
  535. err = listen(sSocket,LISTEN_BACKLOG);
  536. if (SOCKET_ERROR == err)
  537. {
  538. err = WSAGetLastError();
  539. ASSERT(FALSE);
  540. DPF(0,"ACK! stream socket listen failed - err = %d\n",err);
  541. // keep trying
  542. }
  543. }
  544. hr = SetPlayerAddress(pgd,ppd,sSocket,TRUE);
  545. return hr;
  546. } // CreatePlayerStreamSocket
  547. #undef DPF_MODNAME
  548. #define DPF_MODNAME "PokeAddr"
  549. // poke an ip addr into a message blob
  550. void IP_SetAddr(LPVOID pmsg,SOCKADDR_IN * paddrSrc)
  551. {
  552. LPSOCKADDR_IN paddrDest; // tempo variable, makes casting less ugly
  553. LPMESSAGEHEADER phead;
  554. phead = (LPMESSAGEHEADER)pmsg;
  555. // todo - validate header
  556. // leave the port intact, copy over the ip addr
  557. paddrDest = (SOCKADDR_IN *)&(phead->sockaddr);
  558. // poke the new ip addr into the message header
  559. paddrDest->sin_addr.s_addr = paddrSrc->sin_addr.s_addr;
  560. return;
  561. } // IP_SetAddr
  562. // get an ip addr from a message blob
  563. void IP_GetAddr(SOCKADDR_IN * paddrDest,SOCKADDR_IN * paddrSrc)
  564. {
  565. // leave the port intact, copy over the nodenum
  566. if (0 == paddrDest->sin_addr.s_addr)
  567. {
  568. DPF(2,"remote player - setting address!! = %s\n",inet_ntoa(paddrSrc->sin_addr));
  569. paddrDest->sin_addr.s_addr = paddrSrc->sin_addr.s_addr;
  570. }
  571. return;
  572. } // IP_GetAddr
  573. // poke the ipx nodenumber / a message
  574. void IPX_SetNodenum(LPVOID pmsg,SOCKADDR_IPX * paddrSrc)
  575. {
  576. LPSOCKADDR_IPX paddrDest; // tempo variable, makes casting less ugly
  577. LPMESSAGEHEADER phead;
  578. phead = (LPMESSAGEHEADER)pmsg;
  579. // todo - validate header
  580. // leave the port intact, copy over the nodenum
  581. paddrDest = (SOCKADDR_IPX *)&(phead->sockaddr);
  582. memcpy(paddrDest->sa_nodenum,paddrSrc->sa_nodenum,6);
  583. return;
  584. } // IPX_SetNodenum
  585. // reconstruct the nodenum from the msg
  586. void IPX_GetNodenum(SOCKADDR_IPX * paddrDest,SOCKADDR_IPX * paddrSrc)
  587. {
  588. char sa_nodenum_zero[6];
  589. memset(sa_nodenum_zero,0,6);
  590. // if the nodenum is zero, set it
  591. if (0 == memcmp(paddrDest->sa_nodenum,sa_nodenum_zero,6))
  592. {
  593. DEBUGPRINTADDR(4,"IPX - setting remote player nodenum",(SOCKADDR *)paddrSrc);
  594. // leave the port intact, copy over the nodenum
  595. memcpy(paddrDest->sa_nodenum,paddrSrc->sa_nodenum,6);
  596. }
  597. return;
  598. } // IPX_GetNodenum
  599. // store the port of the socket w/ the message, so the receiving end
  600. // can reconstruct the address to reply to
  601. HRESULT SetReturnAddress(LPVOID pmsg,SOCKET sSocket)
  602. {
  603. SOCKADDR sockaddr;
  604. INT addrlen=sizeof(SOCKADDR);
  605. LPMESSAGEHEADER phead;
  606. UINT err;
  607. // find out what port gGlobalData.sEnumSocket is on
  608. err = getsockname(sSocket,(LPSOCKADDR)&sockaddr,&addrlen);
  609. if (SOCKET_ERROR == err)
  610. {
  611. err = WSAGetLastError();
  612. DPF(0,"could not get socket name - err = %d\n",err);
  613. return DP_OK;
  614. }
  615. DEBUGPRINTADDR(9,"setting return address = ",&sockaddr);
  616. phead = (LPMESSAGEHEADER)pmsg;
  617. // todo - validate header
  618. phead->sockaddr = sockaddr;
  619. return DP_OK;
  620. } // SetReturnAddress
  621. // code below all called by GetServerAddress. For IP, prompts user for ip address
  622. // for name server.
  623. #undef DPF_MODNAME
  624. #define DPF_MODNAME "GetAddress"
  625. // get the ip address from the pBuffer passed in by a user
  626. // can either be a real ip, or a hostname
  627. // called after the user fills out our dialog box
  628. HRESULT GetAddress(ULONG * puAddress,char *pBuffer,int cch)
  629. {
  630. UINT uiAddr;
  631. UINT err;
  632. PHOSTENT phostent;
  633. IN_ADDR hostaddr;
  634. if ( (0 == cch) || (!pBuffer) || (0 == strlen(pBuffer)) )
  635. {
  636. *puAddress = INADDR_BROADCAST;
  637. return (DP_OK);
  638. }
  639. // try inet_addr first
  640. uiAddr = inet_addr(pBuffer);
  641. if(0 == uiAddr) // fix bug where "" buffer passed in.
  642. {
  643. *puAddress = INADDR_BROADCAST;
  644. return (DP_OK);
  645. }
  646. if (INADDR_NONE != uiAddr)
  647. {
  648. // found it
  649. *puAddress = uiAddr;
  650. return (DP_OK);
  651. }
  652. // try hostbyname
  653. phostent = gethostbyname(pBuffer);
  654. if (NULL == phostent )
  655. {
  656. err = WSAGetLastError();
  657. DPF(0,"could not get host address - err = %d\n",err);
  658. return (DPERR_INVALIDPARAM);
  659. }
  660. memcpy(&hostaddr,phostent->h_addr,sizeof(hostaddr));
  661. DPF(1,"name server address = %s \n",inet_ntoa(hostaddr));
  662. *puAddress = hostaddr.s_addr;
  663. return (DP_OK);
  664. } // GetAddress
  665. // put up a dialog asking for a network address
  666. // call get address to convert user specified address to network usable address
  667. // called by GetServerAddress
  668. INT_PTR CALLBACK DlgServer(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  669. {
  670. HWND hWndCtl;
  671. char pBuffer[ADDR_BUFFER_SIZE];
  672. UINT cch;
  673. ULONG *lpuEnumAddress;
  674. HRESULT hr;
  675. switch (msg)
  676. {
  677. case WM_INITDIALOG:
  678. // set focus on edit box
  679. hWndCtl = GetDlgItem(hDlg, IDC_EDIT1);
  680. if (hWndCtl == NULL)
  681. {
  682. EndDialog(hDlg, FALSE);
  683. return(TRUE);
  684. }
  685. SetFocus(hWndCtl);
  686. SendMessage(hWndCtl, CB_SETCURSEL, 0, 0);
  687. // save pointer to enum address with the window
  688. SetWindowLongPtr(hDlg, DWLP_USER, (LONG) lParam);
  689. return(FALSE);
  690. case WM_COMMAND:
  691. switch(LOWORD(wParam))
  692. {
  693. case IDOK:
  694. // get text entered in control
  695. cch = GetDlgItemText(hDlg, IDC_EDIT1, pBuffer, ADDR_BUFFER_SIZE);
  696. // get pointer to return address in
  697. lpuEnumAddress = (ULONG *) GetWindowLongPtr(hDlg, DWLP_USER);
  698. // convert string to enum address
  699. hr = GetAddress(lpuEnumAddress,pBuffer,cch);
  700. if (FAILED(hr))
  701. EndDialog(hDlg, hr);
  702. else
  703. EndDialog(hDlg, TRUE);
  704. return(TRUE);
  705. case IDCANCEL:
  706. EndDialog(hDlg, FALSE);
  707. return(TRUE);
  708. }
  709. break;
  710. }
  711. return (FALSE);
  712. } // DlgServer
  713. /*
  714. ** GetServerAddress
  715. *
  716. * CALLED BY: EnumSessions
  717. *
  718. * DESCRIPTION: launches the select network address dialog
  719. *
  720. * RETURNS: ip address (sockaddr.sin_addr.s_addr)
  721. *
  722. */
  723. HRESULT ServerDialog(ULONG *lpuEnumAddress)
  724. {
  725. HWND hwnd;
  726. INT_PTR iResult;
  727. HRESULT hr;
  728. // we have a valid enum address
  729. if (*lpuEnumAddress)
  730. return (DP_OK);
  731. // use the fg window as our parent, since a ddraw app may be full screen
  732. // exclusive
  733. hwnd = GetForegroundWindow();
  734. iResult = DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_SELECTSERVER), hwnd,
  735. DlgServer, (LPARAM) lpuEnumAddress);
  736. if (iResult == -1)
  737. {
  738. DPF_ERR("GetServerAddress - dialog failed");
  739. hr = DPERR_GENERIC;
  740. }
  741. else if (iResult < 0)
  742. {
  743. DPF(0, "GetServerAddress - dialog failed: %08X", iResult);
  744. hr = (HRESULT) iResult;
  745. }
  746. else if (iResult == 0)
  747. {
  748. hr = DPERR_USERCANCEL;
  749. }
  750. else
  751. {
  752. hr = DP_OK;
  753. }
  754. return (hr);
  755. } //ServerDialog
  756. // called by enumsessions - find out where server is...
  757. HRESULT GetServerAddress(LPGLOBALDATA pgd,LPSOCKADDR psockaddr)
  758. {
  759. HRESULT hr;
  760. if (AF_IPX == pgd->AddressFamily)
  761. {
  762. ((LPSOCKADDR_IPX)psockaddr)->sa_family = AF_IPX;
  763. ((LPSOCKADDR_IPX)psockaddr)->sa_socket = SERVER_DGRAM_PORT;
  764. memset(&(((LPSOCKADDR_IPX)psockaddr)->sa_nodenum),0xff,sizeof(((LPSOCKADDR_IPX)psockaddr)->sa_nodenum));
  765. hr = DP_OK;
  766. }
  767. else
  768. {
  769. if (pgd->bHaveServerAddress)
  770. {
  771. // use enum address passed to SPInit
  772. hr = GetAddress(&pgd->uEnumAddress,pgd->szServerAddress,strlen(pgd->szServerAddress));
  773. }
  774. else
  775. {
  776. // ask user for enum address
  777. hr = ServerDialog(&pgd->uEnumAddress);
  778. }
  779. if (SUCCEEDED(hr))
  780. {
  781. // setup winsock to enum this address
  782. ((LPSOCKADDR_IN)psockaddr)->sin_family = AF_INET;
  783. ((LPSOCKADDR_IN)psockaddr)->sin_addr.s_addr = pgd->uEnumAddress;
  784. // see byte-order comment in dpsp.h for this constant
  785. ((LPSOCKADDR_IN)psockaddr)->sin_port = SERVER_DGRAM_PORT;
  786. }
  787. else
  788. {
  789. DPF(0, "Invalid server address: 0x%08lx", hr);
  790. }
  791. }
  792. return (hr);
  793. } // GetServerAddress