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.

801 lines
23 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dphelp.c
  6. * Content: allows the dplay winsock sp's to all share a single
  7. * server socket
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 18-jul-96 andyco initial implementation
  12. * 25-jul-96 andyco ddhelp now watches dplay procs so it can remove
  13. * them from our list when they go away
  14. * 3-sep-96 andyco don't get stale ip's - pick up a default ip whenever
  15. * we add a servernode. bug 3716.
  16. * 2-oct-96 andyco propagated from \orange\ddhelp.2 to \mustard\ddhelp
  17. * 3-oct-96 andyco made the winmain crit section "cs" a global so we can take
  18. * it in dphelps receive thread before forwarding requests
  19. * 21-jan-97 kipo use LoadLibrary on "wsock32.dll" instead of statically
  20. * linking to it so DDHELP will still run even when Winsock
  21. * is not around. This lets DDRAW and DSOUND work. Fixes
  22. * bug #68596.
  23. * 15-feb-97 andyco moved from ddhelp to the project formerly known as
  24. * ddhelp (playhelp? dplayhlp? dplay.exe? dphost?) Allowed
  25. * one process to host mulitple sessions
  26. * 29-jan-98 sohailm added support for stream enum sessions
  27. *
  28. ***************************************************************************/
  29. /*============================================================================
  30. *
  31. * Why this file exists :
  32. *
  33. * when you want to find a dplay game, you send a message to a well
  34. * known port (an enumrequest).
  35. *
  36. * if a game is being hosted on that system, it will listen on that
  37. * port, and respond to the message.
  38. *
  39. * BUT, only one process can listen on a given socket.
  40. *
  41. * So, we let ddhelp.exe listen on that socket, and forward enumrequests
  42. * to all games registered as being hosted on this system.
  43. *
  44. * see also : \%MANROOT%\dplay\wsock\dpsp.h
  45. *
  46. *****************************************************************************/
  47. // todo - should we return error codes on AddServer xproc to our caller?
  48. #include "dphelp.h"
  49. #undef DPF_MODNAME
  50. #define DPF_MODNAME "DPHELP"
  51. /*
  52. * GLOBALS
  53. */
  54. const IN6_ADDR in6addr_multicast = IN6ADDR_MULTICAST_INIT;
  55. SOCKET gsDatagramListener = INVALID_SOCKET; // we listen for datagrams on this socket
  56. SOCKET gsForwardSocket = INVALID_SOCKET;
  57. SOCKET gsStreamListener; // we listen for tcp connections on this socket
  58. LPSPNODE gNodeList;
  59. BOOL gbInit;
  60. HANDLE ghDatagramReceiveThread,ghStreamReceiveThread;
  61. BOOL gbReceiveShutdown; // receive thread will exit when TRUE
  62. // pointers to Winsock routines returned from GetProcAddress
  63. cb_accept g_accept;
  64. cb_bind g_bind;
  65. cb_closesocket g_closesocket;
  66. cb_gethostbyname g_gethostbyname;
  67. cb_gethostname g_gethostname;
  68. cb_getpeername g_getpeername;
  69. cb_getsockname g_getsockname;
  70. cb_recvfrom g_recvfrom;
  71. cb_recv g_recv;
  72. cb_select g_select;
  73. cb_send g_send;
  74. cb_sendto g_sendto;
  75. cb_setsockopt g_setsockopt;
  76. cb_shutdown g_shutdown;
  77. cb_socket g_socket;
  78. cb_WSAFDIsSet g_WSAFDIsSet;
  79. cb_WSAGetLastError g_WSAGetLastError;
  80. cb_WSAStartup g_WSAStartup;
  81. cb_listen g_listen;
  82. cb_htons g_htons;
  83. #ifdef DEBUG
  84. #undef DPF_MODNAME
  85. #define DPF_MODNAME "DebugPrintAddr"
  86. // helper function called from DEBUGPRINTADDR macro
  87. void DebugPrintAddr(UINT nLevel,LPSTR pStr,SOCKADDR * psockaddr)
  88. {
  89. char buff[INET6_ADDRSTRLEN];
  90. int ret;
  91. LPSOCKADDR_IN6 pin6 = (LPSOCKADDR_IN6)psockaddr;
  92. ULONG ulLength = INET6_ADDRSTRLEN;
  93. ret = WSAAddressToString(psockaddr, sizeof(SOCKADDR_IN6), NULL,
  94. buff, &ulLength);
  95. if (!ret)
  96. DPF(nLevel,"%s af = AF_INET6 : address = %s\n",pStr,buff);
  97. } // DebugPrintAddr
  98. #undef DPF_MODNAME
  99. #define DPF_MODNAME "DebugPrintSocket"
  100. void DebugPrintSocket(UINT level,LPSTR pStr,SOCKET * pSock)
  101. {
  102. SOCKADDR_IN6 sockaddr;
  103. int addrlen=sizeof(sockaddr);
  104. g_getsockname(*pSock,(LPSOCKADDR)&sockaddr,&addrlen);
  105. DEBUGPRINTADDR(level,pStr,&sockaddr);
  106. }
  107. #endif // debug
  108. // this is called every time we add a new server node to our list...
  109. HRESULT GetDefaultHostAddr(SOCKADDR_IN6 * psockaddr)
  110. {
  111. // a-josbor: we used to get the first interface and use that, but WebTV taught
  112. // us that that can be dangerous. So we just use the loopback address.
  113. // It's guaranteed to be there. Or so they say...
  114. ZeroMemory(psockaddr, sizeof(SOCKADDR_IN6));
  115. psockaddr->sin6_family = AF_INET6;
  116. psockaddr->sin6_addr = in6addr_loopback;
  117. return DP_OK;
  118. } // GetDefaultHostAddr
  119. // the functions DPlayHelp_xxx are called from dphelp.c
  120. //
  121. // add a new node to our list of servers which want to have enum
  122. // requests forwarded to them...
  123. HRESULT DPlayHelp_AddServer(LPDPHELPDATA phd)
  124. {
  125. LPSPNODE pNode;
  126. BOOL bFoundIt=FALSE;
  127. HRESULT hr;
  128. if (!gbInit)
  129. {
  130. hr = DPlayHelp_Init();
  131. if (FAILED(hr))
  132. {
  133. DPF_ERR("dphelp : could not init wsock ! not adding server");
  134. return (hr);
  135. }
  136. }
  137. // see if we're already watching this process
  138. // if we are, we won't start a watcher thread (below)
  139. pNode = gNodeList;
  140. // search the list
  141. while (pNode && !bFoundIt)
  142. {
  143. if (pNode->pid == phd->pid) bFoundIt = TRUE;
  144. pNode = pNode->pNextNode;
  145. }
  146. //
  147. // now, build a new server node
  148. pNode = MemAlloc(sizeof(SPNODE));
  149. if (!pNode)
  150. {
  151. DPF_ERR("could not add new server node OUT OF MEMORY");
  152. return (DPERR_OUTOFMEMORY);
  153. }
  154. pNode->pid = phd->pid;
  155. // build the sockaddr
  156. // dwReserved1 of the phd is the port that the server is listening on
  157. pNode->sockaddr.sin6_family = AF_INET6;
  158. // find the default ip to use w/ this host
  159. hr = GetDefaultHostAddr(&(pNode->sockaddr));
  160. if (FAILED(hr))
  161. {
  162. DPF_ERR("could not get host IP address");
  163. MemFree(pNode);
  164. return (DPERR_UNAVAILABLE);
  165. }
  166. pNode->sockaddr.sin6_port = phd->port;
  167. DPF(5,"dphelp :: adding new server node : pid = %d, port = %d\n",phd->pid,g_htons(phd->port));
  168. // link our new node onto the beginning of the list
  169. pNode->pNextNode = gNodeList;
  170. gNodeList = pNode;
  171. // see if we need to start our watcher thread
  172. if (!bFoundIt)
  173. {
  174. //
  175. // set up a thread to keep on eye on this process.
  176. // we'll let the thread notify us when the process goes away
  177. WatchNewPid(phd);
  178. }
  179. return (DP_OK);
  180. } // DPlayHelp_AddServer
  181. //
  182. // delete the server node from proc pid from our list
  183. // called by "ThreadProc" from DPHELP.c when the process that
  184. // goes away, or from the client side when a session goes away.
  185. //
  186. // if bFreeAll is TRUE, we delete all server nodes for process
  187. // phd->pid. otherwise, we just delete the first server node whose
  188. // port matches phd->port
  189. //
  190. BOOL FAR PASCAL DPlayHelp_DeleteServer(LPDPHELPDATA phd,BOOL bFreeAll)
  191. {
  192. BOOL bFoundIt = FALSE;
  193. LPSPNODE pNode,pNodePrev,pNodeNext;
  194. pNode = gNodeList;
  195. pNodePrev = NULL;
  196. pNodeNext = NULL;
  197. // search the whole list
  198. while (pNode && !bFoundIt)
  199. {
  200. // if we have the right pid, and it's either FreeAll or the right port - cruise it!
  201. if ((pNode->pid == phd->pid) && (bFreeAll || (pNode->sockaddr.sin6_port == phd->port)) )
  202. {
  203. // remove it from the list
  204. if (pNodePrev) pNodePrev->pNextNode = pNode->pNextNode;
  205. else gNodeList = pNode->pNextNode;
  206. if (bFreeAll)
  207. {
  208. // pick up the next one b4 we free pNode
  209. pNodeNext = pNode->pNextNode;
  210. }
  211. else
  212. {
  213. // mark us as done
  214. bFoundIt = TRUE;
  215. pNodeNext = NULL;
  216. }
  217. DPF(5,"dphelp :: deleting server node : pid = %d\n",pNode->pid);
  218. // free up the node
  219. MemFree(pNode);
  220. pNode = pNodeNext;
  221. // pNodePrev doesn't change here...
  222. }
  223. else
  224. {
  225. // just get the next one
  226. pNodePrev = pNode;
  227. pNode = pNode->pNextNode;
  228. }
  229. }
  230. return FALSE;
  231. } // DPlayHelp_DeleteServer
  232. //
  233. // poke an ip addr into a message blob
  234. // code stolen from \orange\dplay\wsock\winsock.c
  235. void IP6_SetAddr(LPVOID pmsg,SOCKADDR_IN6 * paddrSrc)
  236. {
  237. LPSOCKADDR_IN6 paddrDest; // tempo variable, makes casting less ugly
  238. LPMESSAGEHEADER phead;
  239. phead = (LPMESSAGEHEADER)pmsg;
  240. paddrDest = (SOCKADDR_IN6 *)&(phead->sockaddr);
  241. // poke the new ip addr into the message header
  242. paddrDest->sin6_addr = paddrSrc->sin6_addr;
  243. return;
  244. } // IP6_SetAddr
  245. //
  246. // we get a message. presumably its an enumrequest. forward it to all registered clients.
  247. // we "home" the message (store the received ip addr w/ it) here, 'cause otherwise the clients
  248. // would all think it came from us. we change the token to srvr_token so the clients know it
  249. // came from us (so they don't home it again)
  250. void HandleIncomingMessage(LPBYTE pBuffer,DWORD dwBufferSize,SOCKADDR_IN6 * psockaddr)
  251. {
  252. LPSPNODE pNode = gNodeList;
  253. UINT addrlen = sizeof(SOCKADDR_IN6);
  254. UINT err;
  255. ASSERT(VALID_SP_MESSAGE(pBuffer));
  256. // reset the old token
  257. *( (DWORD *)pBuffer) &= ~TOKEN_MASK;
  258. // set the new token
  259. *( (DWORD *)pBuffer) |= HELPER_TOKEN;
  260. // home it
  261. IP6_SetAddr((LPVOID)pBuffer,psockaddr);
  262. // now, forward the message to all registered servers
  263. while (pNode)
  264. {
  265. DEBUGPRINTADDR(7,"dplay helper :: forwarding enum request to",(SOCKADDR *)&(pNode->sockaddr));
  266. // send out the enum message
  267. err = g_sendto(gsForwardSocket,pBuffer,dwBufferSize,0,(LPSOCKADDR)&(pNode->sockaddr),
  268. addrlen);
  269. if (SOCKET_ERROR == err)
  270. {
  271. err = g_WSAGetLastError();
  272. DPF(0,"dphelp : send failed err = %d\n",err);
  273. }
  274. pNode = pNode->pNextNode;
  275. }
  276. return ;
  277. } // HandleIncomingMessage
  278. #if 1
  279. void JoinEnumGroups(SOCKET s)
  280. {
  281. SOCKET_ADDRESS_LIST *pList;
  282. int i;
  283. LPSOCKADDR_IN6 paddr;
  284. HRESULT hr;
  285. //
  286. // join link-local multicast group for enumeration on every link
  287. //
  288. // do a passive getaddrinfo
  289. pList = GetHostAddr();
  290. if (pList)
  291. {
  292. // for each linklocal address
  293. for (i=0; i<pList->iAddressCount; i++)
  294. {
  295. paddr = (LPSOCKADDR_IN6)pList->Address[i].lpSockaddr;
  296. // skip if not linklocal
  297. if (!IN6_IS_ADDR_LINKLOCAL(&paddr->sin6_addr))
  298. {
  299. continue;
  300. }
  301. // join the multicast group on that ifindex
  302. if (SOCKET_ERROR == JoinEnumGroup(s, paddr->sin6_scope_id))
  303. {
  304. DPF(0,"join enum group failed - err = %d\n",WSAGetLastError());
  305. closesocket(s);
  306. }
  307. }
  308. FreeHostAddr(pList);
  309. }
  310. }
  311. #endif
  312. //
  313. // BUF_SIZE is our initial guess at a receive buffer size
  314. // if we get an enum request bigger than this, we'll realloc our
  315. // buffer, and receive successfully if they send again
  316. // (the only way this could happen is if they have password > ~ 1000
  317. // bytes).
  318. #define BUF_SIZE 1024
  319. //
  320. // listen on our socket for enum requests
  321. DWORD WINAPI ListenThreadProc(LPVOID pvUnused)
  322. {
  323. UINT err;
  324. LPBYTE pBuffer=NULL;
  325. SOCKADDR_IN6 sockaddr; // the from address
  326. INT addrlen=sizeof(sockaddr);
  327. DWORD dwBufSize = BUF_SIZE;
  328. DPF(2,"dphelp :: starting udp listen thread ");
  329. pBuffer = MemAlloc(BUF_SIZE);
  330. if (!pBuffer)
  331. {
  332. DPF_ERR("could not alloc dgram receive buffer");
  333. ExitThread(0);
  334. return 0;
  335. }
  336. JoinEnumGroups(gsDatagramListener);
  337. while (1)
  338. {
  339. err = g_recvfrom(gsDatagramListener,pBuffer,dwBufSize,0,(LPSOCKADDR)&sockaddr,&addrlen);
  340. if (SOCKET_ERROR == err)
  341. {
  342. err = g_WSAGetLastError();
  343. if (WSAEMSGSIZE == err)
  344. {
  345. LPBYTE pNewBuffer;
  346. // buffer too small!
  347. dwBufSize *= 2;
  348. DPF(9,"\n udp recv thread - resizing buffer newsize = %d\n",dwBufSize);
  349. pNewBuffer = MemReAlloc(pBuffer,dwBufSize);
  350. if (!pNewBuffer)
  351. {
  352. DPF_ERR("could not realloc dgram receive buffer");
  353. goto ERROR_EXIT;
  354. }
  355. pBuffer = pNewBuffer;
  356. // we can't do anything with this message, since it was truncated...
  357. } // WSAEMSGSIZE
  358. else
  359. {
  360. #ifdef DEBUG
  361. if (WSAEINTR != err)
  362. {
  363. // WSAEINTR is what winsock uses to break a blocking socket out of
  364. // its wait. it means someone killed this socket.
  365. // if it's not that, then it's a real error.
  366. DPF(0,"\n udp recv error - err = %d socket = %d",err,(DWORD)gsDatagramListener);
  367. }
  368. else
  369. {
  370. DPF(9,"\n udp recv error - err = %d socket = %d",err,(DWORD)gsDatagramListener);
  371. }
  372. #endif // DEBUG
  373. // we bail on errors other than WSAEMSGSIZE
  374. goto ERROR_EXIT;
  375. }
  376. } // SOCKET_ERROR
  377. else if ((err >= sizeof(DWORD)) && VALID_SP_MESSAGE(pBuffer))
  378. {
  379. // now, if we succeeded, err is the # of bytes read
  380. DEBUGPRINTADDR(9,"dplay helper :: received enum request from ",(SOCKADDR *)&sockaddr);
  381. // take the dplay lock so no one messes w/ our list of registered serves while we're
  382. // trying to send to them...
  383. ENTER_DPLAYSVR();
  384. HandleIncomingMessage(pBuffer,err,(SOCKADDR_IN6 *)&sockaddr);
  385. // give up the lock
  386. LEAVE_DPLAYSVR();
  387. }
  388. else
  389. {
  390. ASSERT(FALSE);
  391. // ?
  392. }
  393. } // 1
  394. ERROR_EXIT:
  395. DPF(2,"UDP Listen thread exiting");
  396. if (pBuffer) MemFree(pBuffer);
  397. // all done
  398. ExitThread(0);
  399. return 0;
  400. } // UDPListenThreadProc
  401. // startup winsock and find the default ip addr for this machine
  402. HRESULT StartupIP()
  403. {
  404. UINT err;
  405. WSADATA wsaData;
  406. HINSTANCE hWinsock;
  407. // load winsock library
  408. hWinsock = LoadLibrary("wsock32.dll");
  409. if (!hWinsock)
  410. {
  411. DPF(0,"Could not load wsock32.dll\n");
  412. goto LOADLIBRARYFAILED;
  413. }
  414. // get pointers to the entry points we need
  415. g_accept = (cb_accept) GetProcAddress(hWinsock, "accept");
  416. if (!g_accept)
  417. goto GETPROCADDRESSFAILED;
  418. g_bind = (cb_bind) GetProcAddress(hWinsock, "bind");
  419. if (!g_bind)
  420. goto GETPROCADDRESSFAILED;
  421. g_closesocket = (cb_closesocket) GetProcAddress(hWinsock, "closesocket");
  422. if (!g_closesocket)
  423. goto GETPROCADDRESSFAILED;
  424. g_gethostbyname = (cb_gethostbyname) GetProcAddress(hWinsock, "gethostbyname");
  425. if (!g_gethostbyname)
  426. goto GETPROCADDRESSFAILED;
  427. g_gethostname = (cb_gethostname) GetProcAddress(hWinsock, "gethostname");
  428. if (!g_gethostname)
  429. goto GETPROCADDRESSFAILED;
  430. g_getpeername = (cb_getpeername) GetProcAddress(hWinsock, "getpeername");
  431. if (!g_getpeername)
  432. goto GETPROCADDRESSFAILED;
  433. g_getsockname = (cb_getsockname) GetProcAddress(hWinsock, "getsockname");
  434. if (!g_getsockname)
  435. goto GETPROCADDRESSFAILED;
  436. g_htons = (cb_htons) GetProcAddress(hWinsock, "htons");
  437. if (!g_htons)
  438. goto GETPROCADDRESSFAILED;
  439. g_listen = (cb_listen) GetProcAddress(hWinsock, "listen");
  440. if (!g_listen)
  441. goto GETPROCADDRESSFAILED;
  442. g_recv = (cb_recv) GetProcAddress(hWinsock, "recv");
  443. if (!g_recv)
  444. goto GETPROCADDRESSFAILED;
  445. g_recvfrom = (cb_recvfrom) GetProcAddress(hWinsock, "recvfrom");
  446. if (!g_recvfrom)
  447. goto GETPROCADDRESSFAILED;
  448. g_select = (cb_select) GetProcAddress(hWinsock, "select");
  449. if (!g_select)
  450. goto GETPROCADDRESSFAILED;
  451. g_send = (cb_send) GetProcAddress(hWinsock, "send");
  452. if (!g_send)
  453. goto GETPROCADDRESSFAILED;
  454. g_sendto = (cb_sendto) GetProcAddress(hWinsock, "sendto");
  455. if (!g_sendto)
  456. goto GETPROCADDRESSFAILED;
  457. g_setsockopt = (cb_setsockopt) GetProcAddress(hWinsock, "setsockopt");
  458. if (!g_setsockopt)
  459. goto GETPROCADDRESSFAILED;
  460. g_shutdown = (cb_shutdown) GetProcAddress(hWinsock, "shutdown");
  461. if (!g_shutdown)
  462. goto GETPROCADDRESSFAILED;
  463. g_socket = (cb_socket) GetProcAddress(hWinsock, "socket");
  464. if (!g_socket)
  465. goto GETPROCADDRESSFAILED;
  466. g_WSAFDIsSet = (cb_WSAFDIsSet) GetProcAddress(hWinsock, "__WSAFDIsSet");
  467. if (!g_WSAFDIsSet)
  468. goto GETPROCADDRESSFAILED;
  469. g_WSAGetLastError = (cb_WSAGetLastError) GetProcAddress(hWinsock, "WSAGetLastError");
  470. if (!g_WSAGetLastError)
  471. goto GETPROCADDRESSFAILED;
  472. g_WSAStartup = (cb_WSAStartup) GetProcAddress(hWinsock, "WSAStartup");
  473. if (!g_WSAStartup)
  474. goto GETPROCADDRESSFAILED;
  475. // start up sockets, asking for version 1.1
  476. err = g_WSAStartup(MAKEWORD(1,1), &wsaData);
  477. if (err)
  478. {
  479. DPF(0,"dphelp :: could not start winsock err = %d\n",err);
  480. goto WSASTARTUPFAILED;
  481. }
  482. DPF(3,"dphelp :: started up winsock succesfully");
  483. return DP_OK;
  484. GETPROCADDRESSFAILED:
  485. DPF(0,"Could not find required Winsock entry point");
  486. WSASTARTUPFAILED:
  487. FreeLibrary(hWinsock);
  488. LOADLIBRARYFAILED:
  489. return DPERR_UNAVAILABLE;
  490. } // StartupIP
  491. // helper function to create the socket we listen on
  492. HRESULT GetSocket(SOCKET * psock,DWORD type,PORT port,BOOL bBroadcast,BOOL bListen)
  493. {
  494. SOCKADDR_IN6 sockaddr;
  495. UINT err;
  496. SOCKET sNew;
  497. sNew = g_socket( AF_INET6, type, 0);
  498. if (INVALID_SOCKET == sNew)
  499. {
  500. goto ERROR_EXIT;
  501. }
  502. // set up the sockaddr to bind to
  503. ZeroMemory(&sockaddr, sizeof(sockaddr));
  504. sockaddr.sin6_family = PF_INET6;
  505. sockaddr.sin6_port = port;
  506. // do the bind
  507. if( SOCKET_ERROR == g_bind( sNew, (LPSOCKADDR)&sockaddr, sizeof(sockaddr) ) )
  508. {
  509. goto ERROR_EXIT;
  510. }
  511. if (bListen)
  512. {
  513. LINGER Linger;
  514. // set up socket w/ max listening connections
  515. err = g_listen(sNew,LISTEN_BACKLOG);
  516. if (SOCKET_ERROR == err)
  517. {
  518. err = g_WSAGetLastError();
  519. DPF(0,"init listen socket / listen error - err = %d\n",err);
  520. goto ERROR_EXIT;
  521. }
  522. // set for hard disconnect
  523. Linger.l_onoff=1;
  524. Linger.l_linger=0;
  525. if( SOCKET_ERROR == g_setsockopt( sNew,SOL_SOCKET,SO_LINGER,
  526. (char FAR *)&Linger,sizeof(Linger) ) )
  527. {
  528. err = g_WSAGetLastError();
  529. DPF(0,"Failed to set linger option on the socket = %d\n",err);
  530. }
  531. }
  532. // success!
  533. *psock = sNew;
  534. return DP_OK;
  535. ERROR_EXIT:
  536. // clean up and bail
  537. err = g_WSAGetLastError();
  538. DPF(0,"dphelp - could not get helper socket :: err = %d\n",err);
  539. if (INVALID_SOCKET != sNew)
  540. {
  541. g_closesocket(sNew);
  542. }
  543. return E_FAIL;
  544. } // GetSocket
  545. void CloseSocket(SOCKET * psSocket)
  546. {
  547. UINT err;
  548. if (INVALID_SOCKET != *psSocket)
  549. {
  550. if (SOCKET_ERROR == g_closesocket(*psSocket))
  551. {
  552. err = g_WSAGetLastError();
  553. DPF(1,"dphelp : killsocket - socket close err = %d\n",err);
  554. }
  555. *psSocket = INVALID_SOCKET;
  556. }
  557. return ;
  558. } // CloseSocket
  559. extern int
  560. InitIPv6Library(void);
  561. HRESULT DPlayHelp_Init()
  562. {
  563. DWORD dwThreadID;
  564. HRESULT hr;
  565. // start winsock, and get the default ip addr for this system
  566. hr = StartupIP();
  567. if (FAILED(hr))
  568. {
  569. return hr; // StartupIP will have printed an error
  570. }
  571. InitIPv6Library();
  572. // get the listen socket
  573. hr = GetSocket(&gsDatagramListener,SOCK_DGRAM,SERVER_DGRAM_PORT,TRUE,FALSE);
  574. if (FAILED(hr))
  575. {
  576. goto ERROR_EXIT; // GetSocket will have printed an error
  577. }
  578. // get the forward socket
  579. hr = GetSocket(&gsForwardSocket,SOCK_DGRAM,0,FALSE,FALSE);
  580. if (FAILED(hr))
  581. {
  582. goto ERROR_EXIT; // GetSocket will have printed an error
  583. }
  584. // get us a enum sessions stream listener
  585. hr = GetSocket(&gsStreamListener,SOCK_STREAM,SERVER_STREAM_PORT,FALSE,TRUE);
  586. if (FAILED(hr))
  587. {
  588. goto ERROR_EXIT; // GetSocket will have printed an error
  589. }
  590. ghDatagramReceiveThread = CreateThread(NULL,0,ListenThreadProc,NULL,0,&dwThreadID);
  591. if (!ghDatagramReceiveThread)
  592. {
  593. DPF_ERR("could not create udp listen thread");
  594. hr = E_FAIL;
  595. goto ERROR_EXIT; // GetSocket will have printed an error
  596. }
  597. ghStreamReceiveThread = CreateThread(NULL,0,StreamReceiveThreadProc,NULL,0,&dwThreadID);
  598. if (!ghStreamReceiveThread)
  599. {
  600. DPF_ERR("could not create tcp listen thread");
  601. hr = E_FAIL;
  602. goto ERROR_EXIT; // GetSocket will have printed an error
  603. }
  604. DPF(5,"DPLAYHELP : init succeeded");
  605. gbInit = TRUE;
  606. return DP_OK;
  607. ERROR_EXIT:
  608. CloseSocket(&gsDatagramListener);
  609. CloseSocket(&gsForwardSocket);
  610. CloseSocket(&gsStreamListener);
  611. return hr;
  612. } // DPlayHelp_Init
  613. void DPlayHelp_FreeServerList()
  614. {
  615. LPSPNODE pNodeKill,pNodeNext;
  616. pNodeNext = gNodeList;
  617. // search the whole list
  618. while (pNodeNext)
  619. {
  620. // kill this node
  621. pNodeKill = pNodeNext;
  622. // but first, remember what's next
  623. pNodeNext = pNodeKill->pNextNode;
  624. // free up the node
  625. MemFree(pNodeKill);
  626. }
  627. CloseSocket(&gsDatagramListener);
  628. CloseSocket(&gsForwardSocket);
  629. // close stream receive
  630. RemoveSocketFromList(gsStreamListener);
  631. gbReceiveShutdown = TRUE;
  632. // drop the lock so the threads can exit - they might be waiting on
  633. // the lock for cleanup
  634. LEAVE_DPLAYSVR();
  635. // wait for the threads to go away
  636. if (ghDatagramReceiveThread)
  637. WaitForSingleObject(ghDatagramReceiveThread, INFINITE);
  638. if (ghStreamReceiveThread)
  639. WaitForSingleObject(ghStreamReceiveThread, INFINITE);
  640. ENTER_DPLAYSVR();
  641. if (ghDatagramReceiveThread)
  642. {
  643. DPF(5,"datagram receive thread exited!");
  644. CloseHandle(ghDatagramReceiveThread);
  645. ghDatagramReceiveThread = NULL;
  646. }
  647. if (ghStreamReceiveThread)
  648. {
  649. DPF(5,"stream receive thread exited!");
  650. CloseHandle(ghStreamReceiveThread);
  651. ghStreamReceiveThread = NULL;
  652. }
  653. return ;
  654. } // DPlayHelp_FreeServerList