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.

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