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.

775 lines
23 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,const SOCKADDR_IN6 * psockaddr,
  67. SOCKERR * perr,BOOL bInRange)
  68. {
  69. SOCKET sNew;
  70. SOCKADDR_IN6 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. sNew = socket( pgd->AddressFamily, type, protocol);
  79. if (INVALID_SOCKET == sNew)
  80. {
  81. // no cleanup needed, just bail
  82. *perr = WSAGetLastError();
  83. return E_FAIL;
  84. }
  85. // try to bind an address to the socket.
  86. // set up the sockaddr
  87. memset(&sockAddr,0,sizeof(sockAddr));
  88. if ((SOCK_STREAM == type))
  89. {
  90. BOOL bTrue = TRUE;
  91. UINT err;
  92. // turn ON keepalive
  93. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_KEEPALIVE, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  94. {
  95. err = WSAGetLastError();
  96. DPF(0,"Failed to turn ON keepalive - continue : err = %d\n",err);
  97. }
  98. ASSERT(bTrue);
  99. // turn off nagling
  100. if(pgd->dwSessionFlags & DPSESSION_OPTIMIZELATENCY)
  101. {
  102. DPF(5, "Turning nagling off on socket");
  103. if (SOCKET_ERROR == setsockopt(sNew, IPPROTO_TCP, TCP_NODELAY, (CHAR FAR *)&bTrue, sizeof(bTrue)))
  104. {
  105. err = WSAGetLastError();
  106. DPF(0,"Failed to turn off naggling - continue : err = %d\n",err);
  107. }
  108. }
  109. }
  110. sockAddr = *psockaddr;
  111. sockAddr.sin6_port = htons(wApplicationPort);
  112. if (bInRange && !wApplicationPort)
  113. {
  114. USHORT rndoffset;
  115. DPF(5, "Application didn't specify a port - using dplay range");
  116. rndoffset=(USHORT)(GetTickCount()%DPSP_NUM_PORTS);
  117. wPort = DPSP_MIN_PORT+rndoffset;
  118. do
  119. {
  120. DPF(5, "Trying to bind to port %d",wPort);
  121. sockAddr.sin6_port = htons(wPort);
  122. // do the bind
  123. if( SOCKET_ERROR != bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr) ) )
  124. {
  125. bBound = TRUE;
  126. DPF(5, "Successfully bound to port %d", wPort);
  127. }
  128. else
  129. {
  130. if(++wPort > DPSP_MAX_PORT){
  131. wPort=DPSP_MIN_PORT;
  132. }
  133. }
  134. }
  135. while (!bBound && (wPort != DPSP_MIN_PORT+rndoffset));
  136. }
  137. // do the bind
  138. if( !bBound && (SOCKET_ERROR == bind( sNew, (LPSOCKADDR)&sockAddr, sizeof(sockAddr))) )
  139. {
  140. goto ERROR_EXIT;
  141. }
  142. // success!
  143. *psock = sNew;
  144. DEBUGPRINTSOCK(9,"created a new socket (bound) - ",psock);
  145. return DP_OK;
  146. ERROR_EXIT:
  147. // clean up and bail
  148. *perr = WSAGetLastError();
  149. DPF(0,"create socket failed- err = %d\n",*perr);
  150. closesocket(sNew);
  151. return E_FAIL;
  152. } // CreateSocket
  153. #undef DPF_MODNAME
  154. #define DPF_MODNAME "KillSocket"
  155. HRESULT KillSocket(SOCKET sSocket,BOOL fStream,BOOL fHard)
  156. {
  157. UINT err;
  158. if (INVALID_SOCKET == sSocket)
  159. {
  160. return E_FAIL;
  161. }
  162. if (!fStream)
  163. {
  164. if (SOCKET_ERROR == closesocket(sSocket))
  165. {
  166. err = WSAGetLastError();
  167. DPF(0,"killsocket - dgram close err = %d\n",err);
  168. return E_FAIL;
  169. }
  170. }
  171. else
  172. {
  173. LINGER Linger;
  174. if (fHard)
  175. {
  176. Linger.l_onoff=TRUE; // turn linger on
  177. Linger.l_linger=0; // nice small time out
  178. if( SOCKET_ERROR == setsockopt( sSocket,SOL_SOCKET,SO_LINGER,(char FAR *)&Linger,
  179. sizeof(Linger) ) )
  180. {
  181. err = WSAGetLastError();
  182. DPF(0,"killsocket - stream setopt err = %d\n",err);
  183. }
  184. }
  185. if (SOCKET_ERROR == shutdown(sSocket,2))
  186. {
  187. // this may well fail, if e.g. no one is using this socket right now...
  188. // the error would be wsaenotconn
  189. err = WSAGetLastError();
  190. DPF(5,"killsocket - stream shutdown err = %d\n",err);
  191. }
  192. if (SOCKET_ERROR == closesocket(sSocket))
  193. {
  194. err = WSAGetLastError();
  195. DPF(0,"killsocket - stream close err = %d\n",err);
  196. return E_FAIL;
  197. }
  198. }
  199. return DP_OK;
  200. }// KillSocket
  201. #undef DPF_MODNAME
  202. #define DPF_MODNAME "CreateAndInitStreamSocket"
  203. // set up a stream socket to receive connections
  204. // used w/ the gGlobalData.sStreamAcceptSocket
  205. HRESULT CreateAndInitStreamSocket(LPGLOBALDATA pgd)
  206. {
  207. HRESULT hr;
  208. UINT err;
  209. LINGER Linger;
  210. hr = CreateSocket(pgd,&(pgd->sSystemStreamSocket),SOCK_STREAM,pgd->wApplicationPort,&sockaddr_any,&err,TRUE);
  211. if (FAILED(hr))
  212. {
  213. DPF(0,"init listen socket failed - err = %d\n",err);
  214. return hr ;
  215. }
  216. // set up socket w/ max listening connections
  217. err = listen(pgd->sSystemStreamSocket,LISTEN_BACKLOG);
  218. if (SOCKET_ERROR == err)
  219. {
  220. err = WSAGetLastError();
  221. DPF(0,"init listen socket / listen error - err = %d\n",err);
  222. return E_FAIL ;
  223. }
  224. // set for hard disconnect
  225. Linger.l_onoff=1;
  226. Linger.l_linger=0;
  227. if( SOCKET_ERROR == setsockopt( pgd->sSystemStreamSocket,SOL_SOCKET,SO_LINGER,
  228. (char FAR *)&Linger,sizeof(Linger) ) )
  229. {
  230. err = WSAGetLastError();
  231. DPF(0,"Delete service socket - stream setopt err = %d\n",err);
  232. }
  233. DEBUGPRINTSOCK(1,"enum - listening on",&(pgd->sSystemStreamSocket));
  234. return DP_OK;
  235. } // CreateAndInitStreamSocket
  236. #undef DPF_MODNAME
  237. #define DPF_MODNAME "SPConnect"
  238. // connect socket to sockaddr
  239. HRESULT SPConnect(SOCKET* psSocket, LPSOCKADDR psockaddr,UINT addrlen, BOOL bOutBoundOnly)
  240. {
  241. UINT err;
  242. HRESULT hr = DP_OK;
  243. DWORD dwLastError;
  244. u_long lNonBlock = 1; // passed to ioctlsocket to make socket non-blocking
  245. u_long lBlock = 0; // passed to ioctlsocket to make socket blocking again
  246. fd_set fd_setConnect;
  247. fd_set fd_setExcept;
  248. TIMEVAL timevalConnect;
  249. err=ioctlsocket(*psSocket, FIONBIO, &lNonBlock); // make socket non-blocking
  250. if(SOCKET_ERROR == err){
  251. dwLastError=WSAGetLastError();
  252. DPF(0,"sp - failed to set socket %d to non-blocking mode err= %d\n", *psSocket, dwLastError);
  253. return DPERR_CONNECTIONLOST;
  254. }
  255. // Start the socket connecting.
  256. err = connect(*psSocket,psockaddr,addrlen);
  257. if(SOCKET_ERROR == err) {
  258. dwLastError=WSAGetLastError();
  259. if(dwLastError != WSAEWOULDBLOCK){
  260. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  261. return DPERR_CONNECTIONLOST;
  262. }
  263. // we are going to wait for either the connect to succeed (socket to be writeable)
  264. // or the connect to fail (except fdset bit to be set). So we init an FDSET with
  265. // the socket that is connecting and wait.
  266. FD_ZERO(&fd_setConnect);
  267. FD_SET(*psSocket, &fd_setConnect);
  268. FD_ZERO(&fd_setExcept);
  269. FD_SET(*psSocket, &fd_setExcept);
  270. timevalConnect.tv_sec=0;
  271. timevalConnect.tv_usec=CONNECT_WATCHER_TIMEOUT*1000; //msec -> usec
  272. err = select(0, NULL, &fd_setConnect, &fd_setExcept, &timevalConnect);
  273. // err is the number of sockets with activity or 0 for timeout
  274. // or SOCKET_ERROR for error
  275. if(SOCKET_ERROR == err) {
  276. dwLastError=WSAGetLastError();
  277. DPF(0,"sp - connect failed err= %d\n", dwLastError);
  278. return DPERR_CONNECTIONLOST;
  279. } else if (0==err){
  280. // timed out
  281. DPF(0,"Connect timed out on socket %d\n",*psSocket);
  282. return DPERR_CONNECTIONLOST;
  283. }
  284. // Now see if the connect succeeded or the connect got an exception
  285. if(!(FD_ISSET(*psSocket, &fd_setConnect))){
  286. DPF(0,"Connect did not succeed on socket %d\n",*psSocket);
  287. return DPERR_CONNECTIONLOST;
  288. }
  289. if(FD_ISSET(*psSocket,&fd_setExcept)){
  290. DPF(0,"Got exception on socket %d during connect\n",*psSocket);
  291. return DPERR_CONNECTIONLOST;
  292. }
  293. }
  294. err=ioctlsocket(*psSocket, FIONBIO, &lBlock); // make socket blocking again
  295. DEBUGPRINTSOCK(9,"successfully connected socket - ", psSocket);
  296. if (bOutBoundOnly)
  297. {
  298. DEBUGPRINTADDR(5, "Sending reuse connection message to - ",psockaddr);
  299. // tell receiver to reuse connection
  300. hr = SendReuseConnectionMessage(*psSocket);
  301. }
  302. return hr;
  303. } //SPConnect
  304. #undef DPF_MODNAME
  305. #define DPF_MODNAME "SetPlayerAddress"
  306. // we've created a socket for a player. store its address in the players
  307. // spplayerdata struct.
  308. HRESULT SetPlayerAddress(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,SOCKET sSocket,BOOL fStream)
  309. {
  310. SOCKADDR_IN6 sockaddr;
  311. UINT err;
  312. int iAddrLen = sizeof(sockaddr);
  313. err = getsockname(sSocket,(LPSOCKADDR)&sockaddr,&iAddrLen);
  314. if (SOCKET_ERROR == err)
  315. {
  316. err = WSAGetLastError();
  317. DPF(0,"setplayeraddress - getsockname - err = %d\n",err);
  318. closesocket(sSocket);
  319. return E_FAIL;
  320. }
  321. if (fStream)
  322. {
  323. ZeroMemory(STREAM_PSOCKADDR(ppd), sizeof(SOCKADDR_IN6));
  324. STREAM_PSOCKADDR(ppd)->sin6_family = AF_INET6;
  325. IP_STREAM_PORT(ppd) = sockaddr.sin6_port;
  326. // we don't know the address of the local player (multihomed!)
  327. } // stream
  328. else
  329. {
  330. ZeroMemory(DGRAM_PSOCKADDR(ppd), sizeof(SOCKADDR_IN6));
  331. DGRAM_PSOCKADDR(ppd)->sin6_family = AF_INET6;
  332. IP_DGRAM_PORT(ppd) = sockaddr.sin6_port;
  333. // we don't know the address of the local player (multihomed!)
  334. } // dgram
  335. return DP_OK;
  336. } // SetPlayerAddress
  337. #undef DPF_MODNAME
  338. #define DPF_MODNAME "CreatePlayerSocket"
  339. HRESULT CreatePlayerDgramSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  340. {
  341. HRESULT hr=DP_OK;
  342. UINT err;
  343. SOCKET sSocket;
  344. LPSOCKADDR_IN6 paddr;
  345. SOCKET_ADDRESS_LIST *pList;
  346. int i;
  347. if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  348. {
  349. if (INVALID_SOCKET == pgd->sSystemDGramSocket)
  350. {
  351. hr = CreateSocket(pgd,&sSocket,SOCK_DGRAM,pgd->wApplicationPort,&sockaddr_any,&err,TRUE);
  352. if (FAILED(hr))
  353. {
  354. DPF(0,"create sysplayer dgram socket failed - err = %d\n",err);
  355. return hr;
  356. }
  357. #ifdef DEBUG
  358. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  359. {
  360. DEBUGPRINTSOCK(2,"name server dgram socket - ",&sSocket);
  361. }
  362. #endif // DEBUG
  363. //
  364. // join link-local multicast group for enumeration on every link
  365. //
  366. // do a passive getaddrinfo
  367. pList = GetHostAddr();
  368. if (pList)
  369. {
  370. // for each linklocal address
  371. for (i=0; i<pList->iAddressCount; i++)
  372. {
  373. paddr = (LPSOCKADDR_IN6)pList->Address[i].lpSockaddr;
  374. // skip if not linklocal
  375. if (!IN6_IS_ADDR_LINKLOCAL(&paddr->sin6_addr))
  376. {
  377. continue;
  378. }
  379. // join the multicast group on that ifindex
  380. if (SOCKET_ERROR == JoinEnumGroup(sSocket, paddr->sin6_scope_id))
  381. {
  382. DPF(0,"join enum group failed - err = %d\n",WSAGetLastError());
  383. closesocket(sSocket);
  384. return hr;
  385. }
  386. }
  387. FreeHostAddr(pList);
  388. }
  389. pgd->sSystemDGramSocket = sSocket;
  390. }
  391. else
  392. {
  393. // store this for setting player address below
  394. sSocket = pgd->sSystemDGramSocket;
  395. }
  396. }
  397. else
  398. {
  399. ASSERT(INVALID_SOCKET != pgd->sSystemDGramSocket);
  400. sSocket = pgd->sSystemDGramSocket;
  401. }
  402. // store the ip + port w/ the player...
  403. hr = SetPlayerAddress(pgd,ppd,sSocket,FALSE);
  404. return hr;
  405. } // CreatePlayerDgramSocket
  406. HRESULT CreatePlayerStreamSocket(LPGLOBALDATA pgd,LPSPPLAYERDATA ppd,DWORD dwFlags)
  407. {
  408. SOCKET sSocket;
  409. HRESULT hr=DP_OK;
  410. UINT err;
  411. BOOL bListen = TRUE; // set if we created socket, + need to set it's listen
  412. if (dwFlags & DPLAYI_PLAYER_SYSPLAYER)
  413. {
  414. if (INVALID_SOCKET == pgd->sSystemStreamSocket)
  415. {
  416. hr = CreateSocket(pgd,&sSocket,SOCK_STREAM,pgd->wApplicationPort,&sockaddr_any,&err,TRUE);
  417. if (FAILED(hr))
  418. {
  419. DPF(0,"create player stream socket failed - err = %d\n",err);
  420. return hr;
  421. }
  422. #ifdef DEBUG
  423. if (dwFlags & DPLAYI_PLAYER_NAMESRVR)
  424. {
  425. DEBUGPRINTSOCK(2,"name server stream socket - ",&sSocket);
  426. }
  427. #endif // DEBUG
  428. pgd->sSystemStreamSocket = sSocket;
  429. }
  430. else
  431. {
  432. sSocket = pgd->sSystemStreamSocket;
  433. bListen = FALSE;
  434. }
  435. }
  436. else
  437. {
  438. ASSERT (INVALID_SOCKET != pgd->sSystemStreamSocket);
  439. sSocket = pgd->sSystemStreamSocket;
  440. bListen = FALSE;
  441. }
  442. if (bListen)
  443. {
  444. // set up socket to receive connections
  445. err = listen(sSocket,LISTEN_BACKLOG);
  446. if (SOCKET_ERROR == err)
  447. {
  448. err = WSAGetLastError();
  449. ASSERT(FALSE);
  450. DPF(0,"ACK! stream socket listen failed - err = %d\n",err);
  451. // keep trying
  452. }
  453. }
  454. hr = SetPlayerAddress(pgd,ppd,sSocket,TRUE);
  455. return hr;
  456. } // CreatePlayerStreamSocket
  457. #undef DPF_MODNAME
  458. #define DPF_MODNAME "PokeAddr"
  459. // poke an ip addr into a message blob
  460. void IP6_SetAddr(LPVOID pmsg,SOCKADDR_IN6 * paddrSrc)
  461. {
  462. LPSOCKADDR_IN6 paddrDest; // tempo variable, makes casting less ugly
  463. LPMESSAGEHEADER phead;
  464. phead = (LPMESSAGEHEADER)pmsg;
  465. // todo - validate header
  466. // leave the port intact, copy over the ip addr
  467. paddrDest = (SOCKADDR_IN6 *)&(phead->sockaddr);
  468. // poke the new ip addr into the message header
  469. paddrDest->sin6_addr = paddrSrc->sin6_addr;
  470. return;
  471. } // IP6_SetAddr
  472. // get an ip addr from a message blob
  473. void IP6_GetAddr(SOCKADDR_IN6 * paddrDest,SOCKADDR_IN6 * paddrSrc)
  474. {
  475. // leave the port intact, copy over the nodenum
  476. if (IN6_IS_ADDR_UNSPECIFIED(&paddrDest->sin6_addr))
  477. {
  478. DEBUGPRINTADDR(2,"remote player - setting address!! = %s\n",paddrSrc);
  479. paddrDest->sin6_addr = paddrSrc->sin6_addr;
  480. }
  481. return;
  482. } // IP_GetAddr
  483. // store the port of the socket w/ the message, so the receiving end
  484. // can reconstruct the address to reply to
  485. HRESULT SetReturnAddress(LPVOID pmsg,SOCKET sSocket)
  486. {
  487. SOCKADDR_IN6 sockaddr;
  488. INT addrlen=sizeof(sockaddr);
  489. LPMESSAGEHEADER phead;
  490. UINT err;
  491. // find out what port gGlobalData.sEnumSocket is on
  492. err = getsockname(sSocket,(LPSOCKADDR)&sockaddr,&addrlen);
  493. if (SOCKET_ERROR == err)
  494. {
  495. err = WSAGetLastError();
  496. DPF(0,"could not get socket name - err = %d\n",err);
  497. return DP_OK;
  498. }
  499. DEBUGPRINTADDR(9,"setting return address = ",&sockaddr);
  500. phead = (LPMESSAGEHEADER)pmsg;
  501. // todo - validate header
  502. phead->sockaddr = sockaddr;
  503. return DP_OK;
  504. } // SetReturnAddress
  505. // code below all called by GetServerAddress. For IP, prompts user for ip address
  506. // for name server.
  507. #undef DPF_MODNAME
  508. #define DPF_MODNAME "GetAddress"
  509. // get the ip address from the pBuffer passed in by a user
  510. // can either be a real ip, or a hostname
  511. // called after the user fills out our dialog box
  512. HRESULT GetAddress(SOCKADDR_IN6 * saAddress,char *pBuffer,int cch)
  513. {
  514. UINT err;
  515. struct addrinfo *ai, hints;
  516. if ( (0 == cch) || (!pBuffer) || (0 == strlen(pBuffer)) )
  517. {
  518. ZeroMemory(saAddress, sizeof(*saAddress));
  519. saAddress->sin6_family = AF_INET6;
  520. saAddress->sin6_addr = in6addr_multicast;
  521. return (DP_OK);
  522. }
  523. ZeroMemory(&hints, sizeof(hints));
  524. hints.ai_family = AF_INET6;
  525. err = Dplay_GetAddrInfo(pBuffer, NULL, &hints, &ai);
  526. if (0 != err) {
  527. DPF(0,"could not get host address - err = %d\n",err);
  528. return (DPERR_INVALIDPARAM);
  529. }
  530. DEBUGPRINTADDR(1, "name server address = %s \n",ai->ai_addr);
  531. CopyMemory(saAddress, ai->ai_addr, sizeof(SOCKADDR_IN6));
  532. Dplay_FreeAddrInfo(ai);
  533. return (DP_OK);
  534. } // GetAddress
  535. // put up a dialog asking for a network address
  536. // call get address to convert user specified address to network usable address
  537. // called by GetServerAddress
  538. INT_PTR CALLBACK DlgServer(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  539. {
  540. HWND hWndCtl;
  541. char pBuffer[ADDR_BUFFER_SIZE];
  542. UINT cch;
  543. SOCKADDR_IN6 *lpsaEnumAddress;
  544. HRESULT hr;
  545. switch (msg)
  546. {
  547. case WM_INITDIALOG:
  548. // set focus on edit box
  549. hWndCtl = GetDlgItem(hDlg, IDC_EDIT1);
  550. if (hWndCtl == NULL)
  551. {
  552. EndDialog(hDlg, FALSE);
  553. return(TRUE);
  554. }
  555. SetFocus(hWndCtl);
  556. SendMessage(hWndCtl, CB_SETCURSEL, 0, 0);
  557. // save pointer to enum address with the window
  558. SetWindowLongPtr(hDlg, DWLP_USER, (LONG) lParam);
  559. return(FALSE);
  560. case WM_COMMAND:
  561. switch(LOWORD(wParam))
  562. {
  563. case IDOK:
  564. // get text entered in control
  565. cch = GetDlgItemText(hDlg, IDC_EDIT1, pBuffer, ADDR_BUFFER_SIZE);
  566. // get pointer to return address in
  567. lpsaEnumAddress = (SOCKADDR_IN6 *)GetWindowLongPtr(hDlg, DWLP_USER);
  568. // convert string to enum address
  569. hr = GetAddress(lpsaEnumAddress,pBuffer,cch);
  570. if (FAILED(hr))
  571. EndDialog(hDlg, hr);
  572. else
  573. EndDialog(hDlg, TRUE);
  574. return(TRUE);
  575. case IDCANCEL:
  576. EndDialog(hDlg, FALSE);
  577. return(TRUE);
  578. }
  579. break;
  580. }
  581. return (FALSE);
  582. } // DlgServer
  583. /*
  584. ** GetServerAddress
  585. *
  586. * CALLED BY: EnumSessions
  587. *
  588. * DESCRIPTION: launches the select network address dialog
  589. *
  590. * RETURNS: ip address (sockaddr.sin_addr.s_addr)
  591. *
  592. */
  593. HRESULT ServerDialog(SOCKADDR_IN6 *lpsaEnumAddress)
  594. {
  595. HWND hwnd;
  596. INT_PTR iResult;
  597. HRESULT hr;
  598. // we have a valid enum address
  599. if (!IN6_IS_ADDR_UNSPECIFIED(&lpsaEnumAddress->sin6_addr))
  600. return (DP_OK);
  601. // use the fg window as our parent, since a ddraw app may be full screen
  602. // exclusive
  603. hwnd = GetForegroundWindow();
  604. iResult = DialogBoxParam(ghInstance, MAKEINTRESOURCE(IDD_SELECTSERVER), hwnd,
  605. DlgServer, (LPARAM) lpsaEnumAddress);
  606. if (iResult == -1)
  607. {
  608. DPF_ERR("GetServerAddress - dialog failed");
  609. hr = DPERR_GENERIC;
  610. }
  611. else if (iResult < 0)
  612. {
  613. DPF(0, "GetServerAddress - dialog failed: %08X", iResult);
  614. hr = (HRESULT) iResult;
  615. }
  616. else if (iResult == 0)
  617. {
  618. hr = DPERR_USERCANCEL;
  619. }
  620. else
  621. {
  622. hr = DP_OK;
  623. }
  624. return (hr);
  625. } //ServerDialog
  626. // called by enumsessions - find out where server is...
  627. HRESULT GetServerAddress(LPGLOBALDATA pgd,LPSOCKADDR_IN6 psockaddr)
  628. {
  629. HRESULT hr;
  630. if (pgd->bHaveServerAddress)
  631. {
  632. // use enum address passed to SPInit
  633. hr = GetAddress(&pgd->saddrEnumAddress,pgd->szServerAddress,strlen(pgd->szServerAddress));
  634. }
  635. else
  636. {
  637. // ask user for enum address
  638. hr = ServerDialog(&pgd->saddrEnumAddress);
  639. }
  640. if (SUCCEEDED(hr))
  641. {
  642. // setup winsock to enum this address
  643. *psockaddr = pgd->saddrEnumAddress;
  644. // see byte-order comment in dpsp.h for this constant
  645. psockaddr->sin6_port = SERVER_DGRAM_PORT;
  646. }
  647. else
  648. {
  649. DPF(0, "Invalid server address: 0x%08lx", hr);
  650. }
  651. return (hr);
  652. } // GetServerAddress