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.

764 lines
21 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. SOCKET gsDatagramListener = INVALID_SOCKET; // we listen for datagrams on this socket
  55. SOCKET gsForwardSocket = INVALID_SOCKET;
  56. SOCKET gsStreamListener; // we listen for tcp connections on this socket
  57. LPSPNODE gNodeList;
  58. BOOL gbInit;
  59. HANDLE ghDatagramReceiveThread,ghStreamReceiveThread;
  60. BOOL gbReceiveShutdown; // receive thread will exit when TRUE
  61. // pointers to Winsock routines returned from GetProcAddress
  62. cb_accept g_accept;
  63. cb_bind g_bind;
  64. cb_closesocket g_closesocket;
  65. cb_gethostbyname g_gethostbyname;
  66. cb_gethostname g_gethostname;
  67. cb_getpeername g_getpeername;
  68. cb_getsockname g_getsockname;
  69. cb_inet_ntoa g_inet_ntoa;
  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. SOCKADDR_IN * pin = (SOCKADDR_IN *)psockaddr;
  90. DPF(nLevel,"%s af = AF_INET : address = %s : port = %d\n",pStr,
  91. g_inet_ntoa(pin->sin_addr),g_htons(pin->sin_port));
  92. } // DebugPrintAddr
  93. #undef DPF_MODNAME
  94. #define DPF_MODNAME "DebugPrintSocket"
  95. void DebugPrintSocket(UINT level,LPSTR pStr,SOCKET * pSock)
  96. {
  97. SOCKADDR sockaddr;
  98. int addrlen=sizeof(sockaddr);
  99. g_getsockname(*pSock,&sockaddr,&addrlen);
  100. DEBUGPRINTADDR(level,pStr,&sockaddr);
  101. }
  102. #endif // debug
  103. // this is called every time we add a new server node to our list...
  104. HRESULT GetDefaultHostAddr(DWORD * puHostAddr)
  105. {
  106. // a-josbor: we used to get the first interface and use that, but WebTV taught
  107. // us that that can be dangerous. So we just use the loopback address.
  108. // It's guaranteed to be there. Or so they say...
  109. *puHostAddr = 0x0100007f; // loopback 127.0.0.1 (<bleeping> little-endian)
  110. return DP_OK;
  111. } // GetDefaultHostAddr
  112. // the functions DPlayHelp_xxx are called from dphelp.c
  113. //
  114. // add a new node to our list of servers which want to have enum
  115. // requests forwarded to them...
  116. HRESULT DPlayHelp_AddServer(LPDPHELPDATA phd)
  117. {
  118. LPSPNODE pNode;
  119. BOOL bFoundIt=FALSE;
  120. HRESULT hr;
  121. if (!gbInit)
  122. {
  123. hr = DPlayHelp_Init();
  124. if (FAILED(hr))
  125. {
  126. DPF_ERR("dphelp : could not init wsock ! not adding server");
  127. return (hr);
  128. }
  129. }
  130. // see if we're already watching this process
  131. // if we are, we won't start a watcher thread (below)
  132. pNode = gNodeList;
  133. // search the list
  134. while (pNode && !bFoundIt)
  135. {
  136. if (pNode->pid == phd->pid) bFoundIt = TRUE;
  137. pNode = pNode->pNextNode;
  138. }
  139. //
  140. // now, build a new server node
  141. pNode = MemAlloc(sizeof(SPNODE));
  142. if (!pNode)
  143. {
  144. DPF_ERR("could not add new server node OUT OF MEMORY");
  145. return (DPERR_OUTOFMEMORY);
  146. }
  147. pNode->pid = phd->pid;
  148. // build the sockaddr
  149. // dwReserved1 of the phd is the port that the server is listening on
  150. pNode->sockaddr.sin_family = AF_INET;
  151. // find the default ip to use w/ this host
  152. hr = GetDefaultHostAddr(&(pNode->sockaddr.sin_addr.s_addr));
  153. if (FAILED(hr))
  154. {
  155. DPF_ERR("could not get host IP address");
  156. MemFree(pNode);
  157. return (DPERR_UNAVAILABLE);
  158. }
  159. pNode->sockaddr.sin_port = phd->port;
  160. DPF(5,"dphelp :: adding new server node : pid = %d, port = %d\n",phd->pid,g_htons(phd->port));
  161. // link our new node onto the beginning of the list
  162. pNode->pNextNode = gNodeList;
  163. gNodeList = pNode;
  164. // see if we need to start our watcher thread
  165. if (!bFoundIt)
  166. {
  167. //
  168. // set up a thread to keep on eye on this process.
  169. // we'll let the thread notify us when the process goes away
  170. WatchNewPid(phd);
  171. }
  172. return (DP_OK);
  173. } // DPlayHelp_AddServer
  174. //
  175. // delete the server node from proc pid from our list
  176. // called by "ThreadProc" from DPHELP.c when the process that
  177. // goes away, or from the client side when a session goes away.
  178. //
  179. // if bFreeAll is TRUE, we delete all server nodes for process
  180. // phd->pid. otherwise, we just delete the first server node whose
  181. // port matches phd->port
  182. //
  183. BOOL FAR PASCAL DPlayHelp_DeleteServer(LPDPHELPDATA phd,BOOL bFreeAll)
  184. {
  185. BOOL bFoundIt = FALSE;
  186. LPSPNODE pNode,pNodePrev,pNodeNext;
  187. pNode = gNodeList;
  188. pNodePrev = NULL;
  189. pNodeNext = NULL;
  190. // search the whole list
  191. while (pNode && !bFoundIt)
  192. {
  193. // if we have the right pid, and it's either FreeAll or the right port - cruise it!
  194. if ((pNode->pid == phd->pid) && (bFreeAll || (pNode->sockaddr.sin_port == phd->port)) )
  195. {
  196. // remove it from the list
  197. if (pNodePrev) pNodePrev->pNextNode = pNode->pNextNode;
  198. else gNodeList = pNode->pNextNode;
  199. if (bFreeAll)
  200. {
  201. // pick up the next one b4 we free pNode
  202. pNodeNext = pNode->pNextNode;
  203. }
  204. else
  205. {
  206. // mark us as done
  207. bFoundIt = TRUE;
  208. pNodeNext = NULL;
  209. }
  210. DPF(5,"dphelp :: deleting server node : pid = %d\n",pNode->pid);
  211. // free up the node
  212. MemFree(pNode);
  213. pNode = pNodeNext;
  214. // pNodePrev doesn't change here...
  215. }
  216. else
  217. {
  218. // just get the next one
  219. pNodePrev = pNode;
  220. pNode = pNode->pNextNode;
  221. }
  222. }
  223. return FALSE;
  224. } // DPlayHelp_DeleteServer
  225. //
  226. // poke an ip addr into a message blob
  227. // code stolen from \orange\dplay\wsock\winsock.c
  228. void IP_SetAddr(LPVOID pmsg,SOCKADDR_IN * paddrSrc)
  229. {
  230. LPSOCKADDR_IN paddrDest; // tempo variable, makes casting less ugly
  231. LPMESSAGEHEADER phead;
  232. phead = (LPMESSAGEHEADER)pmsg;
  233. paddrDest = (SOCKADDR_IN *)&(phead->sockaddr);
  234. // poke the new ip addr into the message header
  235. paddrDest->sin_addr.s_addr = paddrSrc->sin_addr.s_addr;
  236. return;
  237. } // IP_SetAddr
  238. //
  239. // we get a message. presumably its an enumrequest. forward it to all registered clients.
  240. // we "home" the message (store the received ip addr w/ it) here, 'cause otherwise the clients
  241. // would all think it came from us. we change the token to srvr_token so the clients know it
  242. // came from us (so they don't home it again)
  243. void HandleIncomingMessage(LPBYTE pBuffer,DWORD dwBufferSize,SOCKADDR_IN * psockaddr)
  244. {
  245. LPSPNODE pNode = gNodeList;
  246. UINT addrlen = sizeof(SOCKADDR_IN);
  247. UINT err;
  248. ASSERT(VALID_SP_MESSAGE(pBuffer));
  249. // reset the old token
  250. *( (DWORD *)pBuffer) &= ~TOKEN_MASK;
  251. // set the new token
  252. *( (DWORD *)pBuffer) |= HELPER_TOKEN;
  253. // home it
  254. IP_SetAddr((LPVOID)pBuffer,psockaddr);
  255. // now, forward the message to all registered servers
  256. while (pNode)
  257. {
  258. DEBUGPRINTADDR(7,"dplay helper :: forwarding enum request to",(SOCKADDR *)&(pNode->sockaddr));
  259. // send out the enum message
  260. err = g_sendto(gsForwardSocket,pBuffer,dwBufferSize,0,(LPSOCKADDR)&(pNode->sockaddr),
  261. addrlen);
  262. if (SOCKET_ERROR == err)
  263. {
  264. err = g_WSAGetLastError();
  265. DPF(0,"dphelp : send failed err = %d\n",err);
  266. }
  267. pNode = pNode->pNextNode;
  268. }
  269. return ;
  270. } // HandleIncomingMessage
  271. //
  272. // BUF_SIZE is our initial guess at a receive buffer size
  273. // if we get an enum request bigger than this, we'll realloc our
  274. // buffer, and receive successfully if they send again
  275. // (the only way this could happen is if they have password > ~ 1000
  276. // bytes).
  277. #define BUF_SIZE 1024
  278. //
  279. // listen on our socket for enum requests
  280. DWORD WINAPI ListenThreadProc(LPVOID pvUnused)
  281. {
  282. UINT err;
  283. LPBYTE pBuffer=NULL;
  284. INT addrlen=sizeof(SOCKADDR);
  285. SOCKADDR sockaddr; // the from address
  286. DWORD dwBufSize = BUF_SIZE;
  287. DPF(2,"dphelp :: starting udp listen thread ");
  288. pBuffer = MemAlloc(BUF_SIZE);
  289. if (!pBuffer)
  290. {
  291. DPF_ERR("could not alloc dgram receive buffer");
  292. ExitThread(0);
  293. return 0;
  294. }
  295. while (1)
  296. {
  297. err = g_recvfrom(gsDatagramListener,pBuffer,dwBufSize,0,&sockaddr,&addrlen);
  298. if (SOCKET_ERROR == err)
  299. {
  300. err = g_WSAGetLastError();
  301. if (WSAEMSGSIZE == err)
  302. {
  303. LPBYTE pNewBuffer;
  304. // buffer too small!
  305. dwBufSize *= 2;
  306. DPF(9,"\n udp recv thread - resizing buffer newsize = %d\n",dwBufSize);
  307. pNewBuffer = MemReAlloc(pBuffer,dwBufSize);
  308. if (!pNewBuffer)
  309. {
  310. DPF_ERR("could not realloc dgram receive buffer");
  311. goto ERROR_EXIT;
  312. }
  313. pBuffer = pNewBuffer;
  314. // we can't do anything with this message, since it was truncated...
  315. } // WSAEMSGSIZE
  316. else
  317. {
  318. #ifdef DEBUG
  319. if (WSAEINTR != err)
  320. {
  321. // WSAEINTR is what winsock uses to break a blocking socket out of
  322. // its wait. it means someone killed this socket.
  323. // if it's not that, then it's a real error.
  324. DPF(0,"\n udp recv error - err = %d socket = %d",err,(DWORD)gsDatagramListener);
  325. }
  326. else
  327. {
  328. DPF(9,"\n udp recv error - err = %d socket = %d",err,(DWORD)gsDatagramListener);
  329. }
  330. #endif // DEBUG
  331. // we bail on errors other than WSAEMSGSIZE
  332. goto ERROR_EXIT;
  333. }
  334. } // SOCKET_ERROR
  335. else if ((err >= sizeof(DWORD)) && VALID_SP_MESSAGE(pBuffer))
  336. {
  337. // now, if we succeeded, err is the # of bytes read
  338. DEBUGPRINTADDR(9,"dplay helper :: received enum request from ",(SOCKADDR *)&sockaddr);
  339. // take the dplay lock so no one messes w/ our list of registered serves while we're
  340. // trying to send to them...
  341. ENTER_DPLAYSVR();
  342. HandleIncomingMessage(pBuffer,err,(SOCKADDR_IN *)&sockaddr);
  343. // give up the lock
  344. LEAVE_DPLAYSVR();
  345. }
  346. else
  347. {
  348. ASSERT(FALSE);
  349. // ?
  350. }
  351. } // 1
  352. ERROR_EXIT:
  353. DPF(2,"UDP Listen thread exiting");
  354. if (pBuffer) MemFree(pBuffer);
  355. // all done
  356. ExitThread(0);
  357. return 0;
  358. } // UDPListenThreadProc
  359. // startup winsock and find the default ip addr for this machine
  360. HRESULT StartupIP()
  361. {
  362. UINT err;
  363. WSADATA wsaData;
  364. HINSTANCE hWinsock;
  365. // load winsock library
  366. hWinsock = LoadLibrary("wsock32.dll");
  367. if (!hWinsock)
  368. {
  369. DPF(0,"Could not load wsock32.dll\n");
  370. goto LOADLIBRARYFAILED;
  371. }
  372. // get pointers to the entry points we need
  373. g_accept = (cb_accept) GetProcAddress(hWinsock, "accept");
  374. if (!g_accept)
  375. goto GETPROCADDRESSFAILED;
  376. g_bind = (cb_bind) GetProcAddress(hWinsock, "bind");
  377. if (!g_bind)
  378. goto GETPROCADDRESSFAILED;
  379. g_closesocket = (cb_closesocket) GetProcAddress(hWinsock, "closesocket");
  380. if (!g_closesocket)
  381. goto GETPROCADDRESSFAILED;
  382. g_gethostbyname = (cb_gethostbyname) GetProcAddress(hWinsock, "gethostbyname");
  383. if (!g_gethostbyname)
  384. goto GETPROCADDRESSFAILED;
  385. g_gethostname = (cb_gethostname) GetProcAddress(hWinsock, "gethostname");
  386. if (!g_gethostname)
  387. goto GETPROCADDRESSFAILED;
  388. g_getpeername = (cb_getpeername) GetProcAddress(hWinsock, "getpeername");
  389. if (!g_getpeername)
  390. goto GETPROCADDRESSFAILED;
  391. g_getsockname = (cb_getsockname) GetProcAddress(hWinsock, "getsockname");
  392. if (!g_getsockname)
  393. goto GETPROCADDRESSFAILED;
  394. g_htons = (cb_htons) GetProcAddress(hWinsock, "htons");
  395. if (!g_htons)
  396. goto GETPROCADDRESSFAILED;
  397. g_inet_ntoa = (cb_inet_ntoa) GetProcAddress(hWinsock, "inet_ntoa");
  398. if (!g_inet_ntoa)
  399. goto GETPROCADDRESSFAILED;
  400. g_listen = (cb_listen) GetProcAddress(hWinsock, "listen");
  401. if (!g_listen)
  402. goto GETPROCADDRESSFAILED;
  403. g_recv = (cb_recv) GetProcAddress(hWinsock, "recv");
  404. if (!g_recv)
  405. goto GETPROCADDRESSFAILED;
  406. g_recvfrom = (cb_recvfrom) GetProcAddress(hWinsock, "recvfrom");
  407. if (!g_recvfrom)
  408. goto GETPROCADDRESSFAILED;
  409. g_select = (cb_select) GetProcAddress(hWinsock, "select");
  410. if (!g_select)
  411. goto GETPROCADDRESSFAILED;
  412. g_send = (cb_send) GetProcAddress(hWinsock, "send");
  413. if (!g_send)
  414. goto GETPROCADDRESSFAILED;
  415. g_sendto = (cb_sendto) GetProcAddress(hWinsock, "sendto");
  416. if (!g_sendto)
  417. goto GETPROCADDRESSFAILED;
  418. g_setsockopt = (cb_setsockopt) GetProcAddress(hWinsock, "setsockopt");
  419. if (!g_setsockopt)
  420. goto GETPROCADDRESSFAILED;
  421. g_shutdown = (cb_shutdown) GetProcAddress(hWinsock, "shutdown");
  422. if (!g_shutdown)
  423. goto GETPROCADDRESSFAILED;
  424. g_socket = (cb_socket) GetProcAddress(hWinsock, "socket");
  425. if (!g_socket)
  426. goto GETPROCADDRESSFAILED;
  427. g_WSAFDIsSet = (cb_WSAFDIsSet) GetProcAddress(hWinsock, "__WSAFDIsSet");
  428. if (!g_WSAFDIsSet)
  429. goto GETPROCADDRESSFAILED;
  430. g_WSAGetLastError = (cb_WSAGetLastError) GetProcAddress(hWinsock, "WSAGetLastError");
  431. if (!g_WSAGetLastError)
  432. goto GETPROCADDRESSFAILED;
  433. g_WSAStartup = (cb_WSAStartup) GetProcAddress(hWinsock, "WSAStartup");
  434. if (!g_WSAStartup)
  435. goto GETPROCADDRESSFAILED;
  436. // start up sockets, asking for version 1.1
  437. err = g_WSAStartup(MAKEWORD(1,1), &wsaData);
  438. if (err)
  439. {
  440. DPF(0,"dphelp :: could not start winsock err = %d\n",err);
  441. goto WSASTARTUPFAILED;
  442. }
  443. DPF(3,"dphelp :: started up winsock succesfully");
  444. return DP_OK;
  445. GETPROCADDRESSFAILED:
  446. DPF(0,"Could not find required Winsock entry point");
  447. WSASTARTUPFAILED:
  448. FreeLibrary(hWinsock);
  449. LOADLIBRARYFAILED:
  450. return DPERR_UNAVAILABLE;
  451. } // StartupIP
  452. // helper function to create the socket we listen on
  453. HRESULT GetSocket(SOCKET * psock,DWORD type,PORT port,BOOL bBroadcast,BOOL bListen)
  454. {
  455. SOCKADDR_IN sockaddr;
  456. UINT err;
  457. SOCKET sNew;
  458. sNew = g_socket( AF_INET, type, 0);
  459. if (INVALID_SOCKET == sNew)
  460. {
  461. goto ERROR_EXIT;
  462. }
  463. // set up the sockaddr to bind to
  464. sockaddr.sin_family = PF_INET;
  465. sockaddr.sin_addr.s_addr = INADDR_ANY;
  466. sockaddr.sin_port = port;
  467. // do the bind
  468. if( SOCKET_ERROR == g_bind( sNew, (LPSOCKADDR)&sockaddr, sizeof(sockaddr) ) )
  469. {
  470. goto ERROR_EXIT;
  471. }
  472. if (bBroadcast)
  473. {
  474. BOOL bTrue = TRUE;
  475. if( SOCKET_ERROR == g_setsockopt( sNew,SOL_SOCKET,SO_BROADCAST,(char FAR *)&bTrue,
  476. sizeof(bTrue) ) )
  477. {
  478. err = g_WSAGetLastError();
  479. DPF(0," dphelp - create - could not set broadcast err = %d\n",err);
  480. // not really tragic, since for AF_INET it's not required to set broadcast
  481. // b4 receiving w/ MS winsock...
  482. }
  483. }
  484. if (bListen)
  485. {
  486. LINGER Linger;
  487. // set up socket w/ max listening connections
  488. err = g_listen(sNew,LISTEN_BACKLOG);
  489. if (SOCKET_ERROR == err)
  490. {
  491. err = g_WSAGetLastError();
  492. DPF(0,"init listen socket / listen error - err = %d\n",err);
  493. goto ERROR_EXIT;
  494. }
  495. // set for hard disconnect
  496. Linger.l_onoff=1;
  497. Linger.l_linger=0;
  498. if( SOCKET_ERROR == g_setsockopt( sNew,SOL_SOCKET,SO_LINGER,
  499. (char FAR *)&Linger,sizeof(Linger) ) )
  500. {
  501. err = g_WSAGetLastError();
  502. DPF(0,"Failed to set linger option on the socket = %d\n",err);
  503. }
  504. }
  505. // success!
  506. *psock = sNew;
  507. return DP_OK;
  508. ERROR_EXIT:
  509. // clean up and bail
  510. err = g_WSAGetLastError();
  511. DPF(0,"dphelp - could not get helper socket :: err = %d\n",err);
  512. if (INVALID_SOCKET != sNew)
  513. {
  514. g_closesocket(sNew);
  515. }
  516. return E_FAIL;
  517. } // GetSocket
  518. void CloseSocket(SOCKET * psSocket)
  519. {
  520. UINT err;
  521. if (INVALID_SOCKET != *psSocket)
  522. {
  523. if (SOCKET_ERROR == g_closesocket(*psSocket))
  524. {
  525. err = g_WSAGetLastError();
  526. DPF(1,"dphelp : killsocket - socket close err = %d\n",err);
  527. }
  528. *psSocket = INVALID_SOCKET;
  529. }
  530. return ;
  531. } // CloseSocket
  532. HRESULT DPlayHelp_Init()
  533. {
  534. DWORD dwThreadID;
  535. HRESULT hr;
  536. // start winsock, and get the default ip addr for this system
  537. hr = StartupIP();
  538. if (FAILED(hr))
  539. {
  540. return hr; // StartupIP will have printed an error
  541. }
  542. // get the listen socket
  543. hr = GetSocket(&gsDatagramListener,SOCK_DGRAM,SERVER_DGRAM_PORT,TRUE,FALSE);
  544. if (FAILED(hr))
  545. {
  546. goto ERROR_EXIT; // GetSocket will have printed an error
  547. }
  548. // get the forward socket
  549. hr = GetSocket(&gsForwardSocket,SOCK_DGRAM,0,FALSE,FALSE);
  550. if (FAILED(hr))
  551. {
  552. goto ERROR_EXIT; // GetSocket will have printed an error
  553. }
  554. // get us a enum sessions stream listener
  555. hr = GetSocket(&gsStreamListener,SOCK_STREAM,SERVER_STREAM_PORT,FALSE,TRUE);
  556. if (FAILED(hr))
  557. {
  558. goto ERROR_EXIT; // GetSocket will have printed an error
  559. }
  560. ghDatagramReceiveThread = CreateThread(NULL,0,ListenThreadProc,NULL,0,&dwThreadID);
  561. if (!ghDatagramReceiveThread)
  562. {
  563. DPF_ERR("could not create udp listen thread");
  564. hr = E_FAIL;
  565. goto ERROR_EXIT; // GetSocket will have printed an error
  566. }
  567. ghStreamReceiveThread = CreateThread(NULL,0,StreamReceiveThreadProc,NULL,0,&dwThreadID);
  568. if (!ghStreamReceiveThread)
  569. {
  570. DPF_ERR("could not create tcp listen thread");
  571. hr = E_FAIL;
  572. goto ERROR_EXIT; // GetSocket will have printed an error
  573. }
  574. DPF(5,"DPLAYHELP : init succeeded");
  575. gbInit = TRUE;
  576. return DP_OK;
  577. ERROR_EXIT:
  578. CloseSocket(&gsDatagramListener);
  579. CloseSocket(&gsForwardSocket);
  580. CloseSocket(&gsStreamListener);
  581. return hr;
  582. } // DPlayHelp_Init
  583. void DPlayHelp_FreeServerList()
  584. {
  585. LPSPNODE pNodeKill,pNodeNext;
  586. pNodeNext = gNodeList;
  587. // search the whole list
  588. while (pNodeNext)
  589. {
  590. // kill this node
  591. pNodeKill = pNodeNext;
  592. // but first, remember what's next
  593. pNodeNext = pNodeKill->pNextNode;
  594. // free up the node
  595. MemFree(pNodeKill);
  596. }
  597. CloseSocket(&gsDatagramListener);
  598. CloseSocket(&gsForwardSocket);
  599. // close stream receive
  600. RemoveSocketFromList(gsStreamListener);
  601. gbReceiveShutdown = TRUE;
  602. // drop the lock so the threads can exit - they might be waiting on
  603. // the lock for cleanup
  604. LEAVE_DPLAYSVR();
  605. // wait for the threads to go away
  606. if (ghDatagramReceiveThread)
  607. WaitForSingleObject(ghDatagramReceiveThread, INFINITE);
  608. if (ghStreamReceiveThread)
  609. WaitForSingleObject(ghStreamReceiveThread, INFINITE);
  610. ENTER_DPLAYSVR();
  611. if (ghDatagramReceiveThread)
  612. {
  613. DPF(5,"datagram receive thread exited!");
  614. CloseHandle(ghDatagramReceiveThread);
  615. ghDatagramReceiveThread = NULL;
  616. }
  617. if (ghStreamReceiveThread)
  618. {
  619. DPF(5,"stream receive thread exited!");
  620. CloseHandle(ghStreamReceiveThread);
  621. ghStreamReceiveThread = NULL;
  622. }
  623. return ;
  624. } // DPlayHelp_FreeServerList
  625.