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.

1171 lines
30 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: wsock2.c
  6. * Content: DirectPlay Winsock 2 SP support. Called from dpsp.c.
  7. * History:
  8. * Date By Reason
  9. * ==== == ======
  10. * 7/11//97 andyco created it
  11. * 2/13/98 aarono added async support.
  12. * 4/6/98 aarono mapped WSAECONNRESET to DPERR_CONNECTIONLOST
  13. * 6/6/98 aarono B#27187 fix ref counting on send blocks in sync error case
  14. * 7/9/99 aarono Cleaning up GetLastError misuse, must call right away,
  15. * before calling anything else, including DPF.
  16. * 1/12/2000 aarono added rsip support
  17. * 2/21/2000 aarono fix socket leaks
  18. **************************************************************************/
  19. // this module is for async connections and sends
  20. // only used w/ TCP:IP - IPX is dgram only, so we don't bother...
  21. // currently only used as the reply thread proc for async replies. see dpsp.c::sp_reply
  22. #define INCL_WINSOCK_API_TYPEDEFS 1 // includes winsock 2 fn proto's, for getprocaddress
  23. #include <winsock2.h>
  24. #include "dpsp.h"
  25. #if USE_RSIP
  26. #include "rsip.h"
  27. #elif USE_NATHELP
  28. #include "nathelp.h"
  29. #endif
  30. #include "mmsystem.h"
  31. #undef DPF_MODNAME
  32. #define DPF_MODNAME "AsyncSendThreadProc"
  33. extern HINSTANCE hWS2; // dynaload the ws2_32.dll, so if it's not installed
  34. // (e.g. win 95 gold) we still load
  35. // prototypes for our dynaload fn's
  36. LPFN_WSAWAITFORMULTIPLEEVENTS g_WSAWaitForMultipleEvents;
  37. LPFN_WSASEND g_WSASend;
  38. LPFN_WSASENDTO g_WSASendTo;
  39. LPFN_WSACLOSEEVENT g_WSACloseEvent;
  40. LPFN_WSACREATEEVENT g_WSACreateEvent;
  41. LPFN_WSAENUMNETWORKEVENTS g_WSAEnumNetworkEvents;
  42. LPFN_WSAEVENTSELECT g_WSAEventSelect;
  43. LPFN_GETSOCKOPT g_getsockopt;
  44. // attempt to load the winsock 2 dll, and get our proc addresses from it
  45. HRESULT InitWinsock2()
  46. {
  47. // load winsock library
  48. hWS2 = LoadLibrary("ws2_32.dll");
  49. if (!hWS2)
  50. {
  51. DPF(0,"Could not load ws2_32.dll\n");
  52. // reset our winsock 2 global
  53. goto LOADLIBRARYFAILED;
  54. }
  55. // get pointers to the entry points we need
  56. g_WSAWaitForMultipleEvents = (LPFN_WSAWAITFORMULTIPLEEVENTS)GetProcAddress(hWS2, "WSAWaitForMultipleEvents");
  57. if(!g_WSAWaitForMultipleEvents) goto GETPROCADDRESSFAILED;
  58. g_WSASend = (LPFN_WSASEND)GetProcAddress(hWS2, "WSASend");
  59. if (!g_WSASend) goto GETPROCADDRESSFAILED;
  60. g_WSASendTo = (LPFN_WSASENDTO)GetProcAddress(hWS2, "WSASendTo");
  61. if (!g_WSASendTo) goto GETPROCADDRESSFAILED;
  62. g_WSAEventSelect = ( LPFN_WSAEVENTSELECT )GetProcAddress(hWS2, "WSAEventSelect");
  63. if (!g_WSAEventSelect) goto GETPROCADDRESSFAILED;
  64. g_WSAEnumNetworkEvents = (LPFN_WSAENUMNETWORKEVENTS)GetProcAddress(hWS2, "WSAEnumNetworkEvents");
  65. if (!g_WSAEnumNetworkEvents) goto GETPROCADDRESSFAILED;
  66. g_WSACreateEvent = (LPFN_WSACREATEEVENT)GetProcAddress(hWS2, "WSACreateEvent");
  67. if (!g_WSACreateEvent) goto GETPROCADDRESSFAILED;
  68. g_WSACloseEvent = (LPFN_WSACLOSEEVENT)GetProcAddress(hWS2, "WSACloseEvent");
  69. if (!g_WSACloseEvent) goto GETPROCADDRESSFAILED;
  70. g_getsockopt = (LPFN_GETSOCKOPT)GetProcAddress(hWS2, "getsockopt");
  71. if (!g_getsockopt) goto GETPROCADDRESSFAILED;
  72. return DP_OK;
  73. GETPROCADDRESSFAILED:
  74. DPF(0,"Could not find required Winsock entry point");
  75. FreeLibrary(hWS2);
  76. hWS2 = NULL;
  77. // fall through
  78. LOADLIBRARYFAILED:
  79. g_WSAEventSelect = NULL;
  80. g_WSAEnumNetworkEvents = NULL;
  81. g_WSACreateEvent = NULL;
  82. g_WSACloseEvent = NULL;
  83. return DPERR_UNAVAILABLE;
  84. } // InitWinsock2
  85. // remove the reply node from the list
  86. void DeleteReplyNode(LPGLOBALDATA pgd,LPREPLYLIST prd, BOOL bKillSocket)
  87. {
  88. LPREPLYLIST prdPrev;
  89. ENTER_DPSP();
  90. // 1st, remove prd from the list
  91. // is it the root?
  92. if (prd == pgd->pReplyList) pgd->pReplyList = pgd->pReplyList->pNextReply;
  93. else
  94. {
  95. BOOL bFound = FALSE;
  96. // it's not the root - take it out of the middle
  97. prdPrev = pgd->pReplyList;
  98. while (prdPrev && !bFound)
  99. {
  100. if (prdPrev->pNextReply == prd)
  101. {
  102. prdPrev->pNextReply = prd->pNextReply;
  103. bFound = TRUE;
  104. }
  105. else
  106. {
  107. prdPrev = prdPrev->pNextReply;
  108. }
  109. } // while
  110. ASSERT(bFound);
  111. } // not the root
  112. // now clean up prd
  113. // nuke the socket
  114. if (bKillSocket)
  115. KillSocket(prd->sSocket,TRUE,FALSE);
  116. // free up the node
  117. if (prd->lpMessage) SP_MemFree(prd->lpMessage);
  118. SP_MemFree(prd);
  119. LEAVE_DPSP();
  120. return ;
  121. } // DeleteReplyNode
  122. VOID MoveReplyNodeToCloseList(LPGLOBALDATA pgd,LPREPLYLIST prd)
  123. {
  124. LPREPLYLIST pPrev, pNode;
  125. DPF(8,"==>MoveReplyToCloseList prd %x\n",prd);
  126. pNode=pgd->pReplyList;
  127. pPrev=CONTAINING_RECORD(&pgd->pReplyList, REPLYLIST, pNextReply);
  128. while(pNode){
  129. if(prd==pNode){
  130. pPrev->pNextReply = pNode->pNextReply;
  131. pNode->pNextReply = pgd->pReplyCloseList;
  132. pgd->pReplyCloseList = pNode;
  133. pNode->tSent=timeGetTime();
  134. break;
  135. }
  136. pPrev=pNode;
  137. pNode=pNode->pNextReply;
  138. }
  139. DPF(8,"<==MoveReplyToCloseList prd %x\n",prd);
  140. }
  141. /*
  142. ** AsyncConnectAndSend
  143. *
  144. * CALLED BY: AsyncSendThreadProc
  145. *
  146. * DESCRIPTION:
  147. *
  148. * if necessary, creates a non-blocking socket, and initiates a connection
  149. * to address specified in prd
  150. * once connection has been completed, does a synchronous (blocking) send and
  151. * removes prd from the global list
  152. */
  153. HRESULT AsyncConnectAndSend(LPGLOBALDATA pgd,LPREPLYLIST prd)
  154. {
  155. UINT err;
  156. HRESULT hr;
  157. UINT addrlen = sizeof(SOCKADDR);
  158. BOOL bConnectionExists = FALSE;
  159. BOOL bKillConnection = TRUE;
  160. if (INVALID_SOCKET == prd->sSocket)
  161. {
  162. u_long lNonBlock = 1; // passed to ioctlsocket to make socket non-blocking
  163. DPID dpidPlayer=0;
  164. #ifdef FULLDUPLEX_SUPPORT
  165. // if client wants us to reuse a connection, it would have indicated so and the connection
  166. // would have been added to our send list by now. See if it exists.
  167. // TODO - we don't want to search the list everytime - find a better way
  168. bConnectionExists = FindSocketInBag(pgd, &prd->sockaddr, &prd->sSocket, &dpidPlayer);
  169. #endif // FULLDUPLEX_SUPPORT
  170. if (!bConnectionExists)
  171. {
  172. SOCKET sSocket;
  173. // socket didn't exist in our send list, let's send it on a new temporary connection
  174. DEBUGPRINTADDR(4, "Sending async reply on a new connection to - ", &(prd->sockaddr));
  175. // need to get the new socket
  176. hr = CreateSocket(pgd,&sSocket,SOCK_STREAM,0,INADDR_ANY,&err,FALSE);
  177. if (FAILED(hr))
  178. {
  179. DPF(0,"create async socket failed - err = %d\n",err);
  180. return hr;
  181. }
  182. prd->sSocket = sSocket;
  183. // set socket to non-blocking
  184. err = ioctlsocket(prd->sSocket,FIONBIO,&lNonBlock);
  185. if (SOCKET_ERROR == err)
  186. {
  187. err = WSAGetLastError();
  188. DPF(0,"could not set non-blocking mode on socket err = %d!",err);
  189. DPF(0,"will revert to synchronous behavior. bummer");
  190. }
  191. err=g_WSAEventSelect(prd->sSocket, pgd->hSelectEvent, FD_WRITE|FD_CONNECT|FD_CLOSE);
  192. if (SOCKET_ERROR == err)
  193. {
  194. err = WSAGetLastError();
  195. DPF(0,"could not do event select on socket err = %d!",err);
  196. DPF(0,"giving up on send..\n");
  197. goto CLEANUP_EXIT;
  198. }
  199. // now, start the connect
  200. SetReturnAddress(prd->lpMessage,pgd->sSystemStreamSocket,SERVICE_SADDR_PUBLIC(pgd));
  201. err = connect(prd->sSocket,&prd->sockaddr,addrlen);
  202. if (SOCKET_ERROR == err)
  203. {
  204. err = WSAGetLastError();
  205. if (WSAEWOULDBLOCK == err)
  206. {
  207. // this is expected. the operation needs time to complete.
  208. // select will tell us when the socket is good to go.
  209. return DP_OK;
  210. }
  211. // else it's a real error!
  212. DPF(0,"async reply - connect failed - error = %d\n",err);
  213. DEBUGPRINTADDR(0,"async reply - connect failed - addr = ",(LPSOCKADDR)&(prd->sockaddr));
  214. goto CLEANUP_EXIT;
  215. }
  216. }
  217. else
  218. {
  219. // we found our connection, let's reuse it
  220. // set it to non-blocking
  221. DEBUGPRINTADDR(6, "Sending async reply on an existing connection to - ", &(prd->sockaddr));
  222. err = ioctlsocket(prd->sSocket,FIONBIO,&lNonBlock);
  223. if (SOCKET_ERROR == err)
  224. {
  225. err = WSAGetLastError();
  226. DPF(0,"could not set non-blocking mode on socket err = %d!",err);
  227. DPF(0,"will revert to synchronous behavior. bummer");
  228. }
  229. // once we have a player id, the session has started. let's hold on to the connection
  230. // we have and reuse it for the rest of the session
  231. if (dpidPlayer) bKillConnection = FALSE;
  232. } // FindSocketInBag
  233. } // INVALID_SOCKET
  234. // once we get here, we should have a connected socket ready to send!
  235. err = 0;
  236. // keep spitting bits at the socket until we finish or get an error
  237. while ((prd->dwBytesLeft != 0) && (SOCKET_ERROR != err))
  238. {
  239. DPF(5, "AsyncConnectAndSend: Sending %u bytes via socket 0x%x.",
  240. prd->dwBytesLeft, prd->sSocket);
  241. DEBUGPRINTADDR(5, "AsyncConnectAndSend: Sending message over connection to - ", &prd->sockaddr);
  242. err = send(prd->sSocket,prd->pbSend,prd->dwBytesLeft,0);
  243. if (SOCKET_ERROR != err)
  244. {
  245. // some bytes went out on the wire
  246. prd->dwBytesLeft -= err; // we just sent err bytes
  247. prd->pbSend += err; // advance our send buffer by err bytes
  248. }
  249. }
  250. // now, we've either finished the send, or we have an error
  251. if (SOCKET_ERROR == err)
  252. {
  253. err = WSAGetLastError();
  254. if (WSAEWOULDBLOCK == err)
  255. {
  256. DPF(8,"async send - total sent %d left to send %d\n",prd->pbSend,prd->dwBytesLeft);
  257. // this means we couldn't send any bytes w/o blocking
  258. // that's ok. we'll let select tell us when it's ready to not block
  259. return DP_OK;
  260. }
  261. // else it's a real eror!
  262. // any other error, we give up and clean up this reply
  263. DPF(0,"async send - send failed - error = %d\n",err);
  264. DEBUGPRINTADDR(0,"async send - send failed - addr = ",(LPSOCKADDR)&(prd->sockaddr));
  265. }
  266. else ASSERT(0 == prd->dwBytesLeft); // if it's not an error, we better have sent it all
  267. DPF(8,"async send - total left to send %d (done)\n",prd->dwBytesLeft);
  268. // fall through
  269. CLEANUP_EXIT:
  270. err = g_WSAEventSelect(prd->sSocket,pgd->hSelectEvent,0);
  271. if(SOCKET_ERROR == err){
  272. err = WSAGetLastError();
  273. DPF(8,"async send - error %d deselecting socket %s\n",err,prd->sSocket);
  274. }
  275. if (bConnectionExists && bKillConnection)
  276. {
  277. // close the connection after we're done
  278. RemoveSocketFromReceiveList(pgd,prd->sSocket);
  279. RemoveSocketFromBag(pgd,prd->sSocket);
  280. // so DeleteReplyNode won't try to kill socket again
  281. prd->sSocket = INVALID_SOCKET;
  282. }
  283. // remove the node from the list
  284. MoveReplyNodeToCloseList(pgd,prd);
  285. return DP_OK;
  286. } // AsyncConnectAndSend
  287. #if 0
  288. // walk the reply list, tell winsock to watch any of the nodes which has a valid socket
  289. // (i.e. has a connection or send pending)
  290. HRESULT DoEventSelect(LPGLOBALDATA pgd,WSAEVENT hSelectEvent)
  291. {
  292. UINT err;
  293. LPREPLYLIST prd;
  294. ENTER_DPSP();
  295. prd = pgd->pReplyList;
  296. while (prd)
  297. {
  298. if (INVALID_SOCKET != prd->sSocket)
  299. {
  300. // have winscok tell us when anything good (connection complete, ready to write more data)
  301. // happens on this socket
  302. err = g_WSAEventSelect(prd->sSocket,hSelectEvent,FD_WRITE | FD_CONNECT | FD_CLOSE);
  303. if (SOCKET_ERROR == err)
  304. {
  305. err = WSAGetLastError();
  306. DPF(0,"could not do event select ! err = %d!",err);
  307. // keep trying...
  308. }
  309. } // invalid_socket
  310. prd = prd->pNextReply;
  311. }
  312. LEAVE_DPSP();
  313. return DP_OK;
  314. } // DoEventSelect
  315. #endif
  316. // wsaeventselect woke us up. one or more of our sockets had something happen
  317. // (e.g. connect completed, send ready for more data, etc.)
  318. // walk the reply list, find nodes who need to be serviced
  319. void ServiceReplyList(LPGLOBALDATA pgd,WSAEVENT hEvent)
  320. {
  321. UINT err;
  322. LPREPLYLIST prd,prdNext;
  323. WSANETWORKEVENTS WSANetEvents;
  324. ENTER_DPSP();
  325. Top:
  326. prd = pgd->pReplyList;
  327. while (prd)
  328. {
  329. // save this now - asyncconnectandsend could destroy prd
  330. prdNext = prd->pNextReply;
  331. if (INVALID_SOCKET != prd->sSocket)
  332. {
  333. // go ask winsock if this socket had anything intersting happen
  334. err = g_WSAEnumNetworkEvents(prd->sSocket,NULL,&WSANetEvents);
  335. if (SOCKET_ERROR == err)
  336. {
  337. err = WSAGetLastError();
  338. DPF(0,"could not enum events!! err = %d!",err);
  339. // keep trying...
  340. }
  341. else
  342. {
  343. BOOL bError=FALSE;
  344. // no error - go see what we got
  345. DPF(8,"Got NetEvents %x for socket %d\n",WSANetEvents.lNetworkEvents, prd->sSocket);
  346. DEBUGPRINTSOCK(8," socket addr -\n", &prd->sSocket);
  347. if ((WSANetEvents.lNetworkEvents & FD_CONNECT) || (WSANetEvents.lNetworkEvents & FD_WRITE))
  348. {
  349. DWORD dwPlayerTo;
  350. // was there an error?
  351. if (WSANetEvents.iErrorCode[FD_CONNECT_BIT])
  352. {
  353. // we got a connect error!
  354. DPF(0,"async reply - WSANetEvents - connect failed - error = %d\n",
  355. WSANetEvents.iErrorCode[FD_CONNECT_BIT]);
  356. DEBUGPRINTADDR(0,"async reply - connect failed - addr = ",
  357. (LPSOCKADDR)&(prd->sockaddr));
  358. dwPlayerTo = prd->dwPlayerTo;
  359. DeleteReplyNode(pgd,prd,TRUE);
  360. RemovePendingAsyncSends(pgd, dwPlayerTo);
  361. goto Top;
  362. }
  363. if (WSANetEvents.iErrorCode[FD_WRITE_BIT])
  364. {
  365. // we got a send error!
  366. DPF(0,"async reply - WSANetEvents - send failed - error = %d\n",
  367. WSANetEvents.iErrorCode[FD_WRITE_BIT]);
  368. DEBUGPRINTADDR(0,"async reply - send failed - addr = ",
  369. (LPSOCKADDR)&(prd->sockaddr));
  370. dwPlayerTo = prd->dwPlayerTo;
  371. DeleteReplyNode(pgd,prd,TRUE);
  372. RemovePendingAsyncSends(pgd, dwPlayerTo);
  373. goto Top;
  374. }
  375. if(WSANetEvents.lNetworkEvents & FD_CLOSE){
  376. dwPlayerTo = prd->dwPlayerTo;
  377. DeleteReplyNode(pgd,prd,TRUE);
  378. RemovePendingAsyncSends(pgd, dwPlayerTo);
  379. goto Top;
  380. }
  381. // note - we try + send even if there was an error. seems like it's worth a shot...
  382. // go try + send
  383. AsyncConnectAndSend(pgd,prd);
  384. }
  385. }
  386. } // invalid_socket
  387. else
  388. {
  389. // it it's an invalid socket, we need to init our connect and send
  390. AsyncConnectAndSend(pgd,prd);
  391. }
  392. prd = prdNext;
  393. }
  394. LEAVE_DPSP();
  395. return ;
  396. } // ServiceReplyList
  397. VOID ServiceReplyCloseList(LPGLOBALDATA pgd, DWORD tNow, BOOL fWait)
  398. {
  399. UINT err;
  400. LPREPLYLIST prdPrev,prd,prdNext;
  401. DPF(8,"==>ServiceReplyCloseList\n");
  402. prdPrev = CONTAINING_RECORD(&pgd->pReplyCloseList, REPLYLIST, pNextReply);
  403. prd = pgd->pReplyCloseList;
  404. while (prd)
  405. {
  406. prdNext = prd->pNextReply;
  407. if((tNow-prd->tSent) > LINGER_TIME || fWait){
  408. while((tNow-prd->tSent) < LINGER_TIME){
  409. Sleep(500);
  410. tNow=timeGetTime();
  411. }
  412. // close that puppy
  413. KillSocket(prd->sSocket,TRUE,TRUE);
  414. // free up the node
  415. if (prd->lpMessage) SP_MemFree(prd->lpMessage);
  416. SP_MemFree(prd);
  417. prdPrev->pNextReply = prdNext;
  418. prd = prdNext;
  419. } else {
  420. prdPrev=prd;
  421. prd=prdNext;
  422. }
  423. }
  424. DPF(8,"<==ServiceReplyCloseList\n");
  425. }
  426. // this thread works on doing async sends
  427. DWORD WINAPI AsyncSendThreadProc(LPVOID pvCast)
  428. {
  429. HRESULT hr=DP_OK;
  430. LPGLOBALDATA pgd = (LPGLOBALDATA) pvCast;
  431. HANDLE hHandleList[3];
  432. DWORD rc;
  433. DWORD tWait;
  434. WSAEVENT hSelectEvent; // event used by WSASelectEvent
  435. DWORD tLast;
  436. DWORD tNow;
  437. #if (USE_RSIP || USE_NATHELP)
  438. DWORD tLastRsip;
  439. #endif
  440. DPF(8,"Entered AsyncSendThreadProc\n");
  441. // get the event 4 selectevent
  442. hSelectEvent = g_WSACreateEvent();
  443. pgd->hSelectEvent = hSelectEvent;
  444. if (WSA_INVALID_EVENT == hSelectEvent)
  445. {
  446. rc = WSAGetLastError();
  447. DPF(0,"could not create winsock event - rc = %d\n",rc);
  448. ExitThread(0);
  449. return 0;
  450. }
  451. hHandleList[0] = hSelectEvent;
  452. hHandleList[1] = pgd->hReplyEvent;
  453. // This extra handle is here because of a Windows 95 bug. Windows
  454. // will occasionally miss when it walks the handle table, causing
  455. // my thread to wait on the wrong handles. By putting a guaranteed
  456. // invalid handle at the end of our array, the kernel will do a
  457. // forced re-walk of the handle table and find the correct handles.
  458. hHandleList[2] = INVALID_HANDLE_VALUE;
  459. tNow=timeGetTime();
  460. tLast=tNow;
  461. #if (USE_RSIP || USE_NATHELP)
  462. tLastRsip=tNow;
  463. #endif
  464. #if USE_RSIP
  465. ASSERT(2*LINGER_TIME < RSIP_RENEW_TEST_INTERVAL);
  466. #endif
  467. while (1)
  468. {
  469. // tell winsock to watch all of our reply nodes. it will set our event
  470. // when something cool happens...
  471. //DoEventSelect(pgd,hSelectEvent); -- do on creation only, its sticky.
  472. wait:
  473. // we only poll every 2 linger times because it really isn't a resource
  474. // contraint expect at close, which will not linger as much.
  475. tWait=(tLast+2*LINGER_TIME)-tNow;
  476. if((int)tWait < 0){
  477. tWait=0;
  478. }
  479. ASSERT(!(tWait &0x80000000));
  480. // wait on our event. when it's set, we either split, or empty the reply list
  481. rc = WaitForMultipleObjectsEx(2,hHandleList,FALSE,tWait,TRUE);
  482. tNow=timeGetTime();
  483. if(rc == WAIT_TIMEOUT){
  484. #if (USE_RSIP || USE_NATHELP)
  485. #if USE_RSIP
  486. if(pgd->sRsip != INVALID_SOCKET){
  487. if((tNow - tLastRsip) >= RSIP_RENEW_TEST_INTERVAL)
  488. {
  489. tLastRsip=tNow;
  490. rsipPortExtend(pgd, tNow);
  491. rsipCacheClear(pgd, tNow);
  492. }
  493. } else {
  494. tLastRsip=tNow;
  495. }
  496. #endif
  497. #if USE_NATHELP
  498. if(pgd->pINatHelp){
  499. if((tNow - tLastRsip) >= pgd->NatHelpCaps.dwRecommendedGetCapsInterval)
  500. {
  501. natGetCapsUpdate(pgd);
  502. tLastRsip = timeGetTime();
  503. }
  504. } else {
  505. tLastRsip=tNow;
  506. }
  507. #endif
  508. #endif
  509. tLast=tNow;
  510. ENTER_DPSP();
  511. if(pgd->pReplyCloseList)
  512. {
  513. ServiceReplyCloseList(pgd,tNow,FALSE);
  514. }
  515. LEAVE_DPSP();
  516. goto wait;
  517. }
  518. if ((DWORD)-1 == rc)
  519. {
  520. DWORD dwError = GetLastError();
  521. // rut roh! errror on the wait
  522. DPF(0,"!!!!! error on WaitForMultipleObjects -- async reply bailing -- dwError = %d",dwError);
  523. goto CLEANUP_EXIT;
  524. }
  525. if (rc == WAIT_OBJECT_0) // a-josbor: need to reset this manual event
  526. {
  527. ResetEvent(hSelectEvent);
  528. }
  529. // ok. someone woke us up. it could be 1. shutdown, or 2. one
  530. // of our sockets needs attention (i.e. a connect completed), or 3. someone
  531. // put a new reply node on the list
  532. // shutdown?
  533. if (pgd->bShutdown)
  534. {
  535. goto CLEANUP_EXIT;
  536. }
  537. DPF(8,"In AsyncSendThreadProc, servicing event %d\n", rc - WAIT_OBJECT_0);
  538. // otherwise, it must be a socket in need or a new replynode
  539. ServiceReplyList(pgd,hSelectEvent);
  540. } // 1
  541. CLEANUP_EXIT:
  542. ENTER_DPSP();
  543. // cleanout reply list
  544. while (pgd->pReplyList) DeleteReplyNode(pgd,pgd->pReplyList,TRUE);
  545. ServiceReplyCloseList(pgd,tNow,TRUE);
  546. ASSERT(pgd->pReplyCloseList==NULL);
  547. CloseHandle(pgd->hReplyEvent);
  548. pgd->hReplyEvent = 0;
  549. LEAVE_DPSP();
  550. g_WSACloseEvent(hSelectEvent);
  551. DPF(6,"replythreadproc exit");
  552. return 0;
  553. } // AsyncSendThreadProc
  554. HRESULT GetMaxUdpBufferSize(SOCKET socket, UINT * piMaxUdpDg)
  555. {
  556. INT iBufferSize;
  557. INT err;
  558. ASSERT(piMaxUdpDg);
  559. iBufferSize = sizeof(UINT);
  560. err = g_getsockopt(socket, SOL_SOCKET, SO_MAX_MSG_SIZE, (LPBYTE)piMaxUdpDg, &iBufferSize);
  561. if (SOCKET_ERROR == err)
  562. {
  563. DPF(0,"getsockopt for SO_MAX_MSG_SIZE returned err = %d", WSAGetLastError());
  564. return DPERR_UNAVAILABLE;
  565. }
  566. return DP_OK;
  567. }
  568. #ifdef SENDEX
  569. DWORD wsaoDecRef(LPSENDINFO pSendInfo)
  570. {
  571. #define pgd (pSendInfo->pgd)
  572. DWORD count;
  573. EnterCriticalSection(&pgd->csSendEx);
  574. count=(--pSendInfo->RefCount);
  575. if(!count){
  576. Delete(&pSendInfo->PendingSendQ);
  577. pgd->dwBytesPending -= pSendInfo->dwMessageSize;
  578. pgd->dwMessagesPending -= 1;
  579. LeaveCriticalSection(&pgd->csSendEx);
  580. DPF(8,"wsaoDecRef pSendInfo %x, Refcount=0 , SC context %x, status=%x \n",pSendInfo, pSendInfo->dwUserContext,pSendInfo->Status);
  581. if(pSendInfo->dwFlags & SI_INTERNALBUFF){
  582. SP_MemFree(pSendInfo->SendArray[0].buf);
  583. } else {
  584. if(pSendInfo->dwSendFlags & DPSEND_ASYNC){
  585. pSendInfo->lpISP->lpVtbl->SendComplete(pSendInfo->lpISP,(LPVOID)pSendInfo->dwUserContext,pSendInfo->Status);
  586. }
  587. }
  588. pgd->pSendInfoPool->Release(pgd->pSendInfoPool, pSendInfo);
  589. } else {
  590. DPF(8,"wsaoDecRef pSendInfo %x, Refcount= %d\n",pSendInfo,pSendInfo->RefCount);
  591. LeaveCriticalSection(&pgd->csSendEx);
  592. }
  593. if(count& 0x80000000){
  594. DEBUG_BREAK();
  595. }
  596. return count;
  597. #undef pgd
  598. }
  599. VOID CompleteSend(LPSENDINFO pSendInfo)
  600. {
  601. if(pSendInfo->pConn){
  602. EnterCriticalSection(&pSendInfo->pgd->csFast);
  603. pSendInfo->pConn->bSendOutstanding = FALSE;
  604. LeaveCriticalSection(&pSendInfo->pgd->csFast);
  605. QueueNextSend(pSendInfo->pgd, pSendInfo->pConn);
  606. DecRefConn(pSendInfo->pgd, pSendInfo->pConn);
  607. }
  608. wsaoDecRef(pSendInfo);
  609. }
  610. void CALLBACK SendComplete(
  611. DWORD dwError,
  612. DWORD cbTransferred,
  613. LPWSAOVERLAPPED lpOverlapped,
  614. DWORD dwFlags
  615. )
  616. {
  617. LPSENDINFO lpSendInfo=(LPSENDINFO)CONTAINING_RECORD(lpOverlapped,SENDINFO,wsao);
  618. DPF(8,"DPWSOCK:SendComplete, lpSendInfo %x\n",lpSendInfo);
  619. if(dwError){
  620. DPF(0,"DPWSOCK: send completion error, dwError=x%x\n",dwError);
  621. lpSendInfo->Status=DPERR_GENERIC;
  622. }
  623. CompleteSend(lpSendInfo);
  624. }
  625. HRESULT DoSend(LPGLOBALDATA pgd, LPSENDINFO pSendInfo)
  626. {
  627. #define fAsync (pSendInfo->dwSendFlags & DPSEND_ASYNC)
  628. DWORD dwBytesSent;
  629. UINT err;
  630. HRESULT hr=DP_OK;
  631. if (pSendInfo->dwFlags & SI_RELIABLE)
  632. {
  633. // Reliable Send
  634. DPF(8,"WSASend, pSendInfo %x\n",pSendInfo);
  635. #if DUMPBYTES
  636. {
  637. PCHAR pBuf;
  638. UINT buflen;
  639. UINT i=0;
  640. pBuf = ((LPWSABUF)&pSendInfo->SendArray[pSendInfo->iFirstBuf+pSendInfo->cBuffers-1])->buf;
  641. buflen = ((LPWSABUF)&pSendInfo->SendArray[pSendInfo->iFirstBuf+pSendInfo->cBuffers-1])->len;
  642. while (((i + 16) < buflen) && (i < 4*16)){
  643. DPF(9, "%08x %08x %08x %08x",*(PUINT)(&pBuf[i]),*(PUINT)(&pBuf[i+4]),*(PUINT)(&pBuf[i+8]),*(PUINT)(&pBuf[i+12]));
  644. i += 16;
  645. }
  646. }
  647. #endif
  648. // send the message
  649. err = g_WSASend(pSendInfo->sSocket,
  650. (LPWSABUF)&pSendInfo->SendArray[pSendInfo->iFirstBuf],
  651. pSendInfo->cBuffers,
  652. &dwBytesSent,
  653. 0, /*flags*/
  654. (fAsync)?(&pSendInfo->wsao):NULL,
  655. (fAsync)?(SendComplete):NULL);
  656. if(!err){
  657. DPF(8,"WSASend, sent synchronously, pSendInfo %x\n",pSendInfo);
  658. wsaoDecRef(pSendInfo);
  659. hr=DP_OK;
  660. } else {
  661. if (SOCKET_ERROR == err)
  662. {
  663. err = WSAGetLastError();
  664. if(err==WSA_IO_PENDING){
  665. hr=DPERR_PENDING;
  666. wsaoDecRef(pSendInfo);
  667. DPF(8,"ASYNC SEND Pending pSendInfo %x\n",pSendInfo);
  668. } else {
  669. DPF(8,"WSASend Error %d\n",err);
  670. ASSERT(err != WSAEWOULDBLOCK); // vadime assures this never happens. (aarono 9-12-00)
  671. if(err==WSAECONNRESET){
  672. hr=DPERR_CONNECTIONLOST;
  673. } else {
  674. hr=DPERR_GENERIC;
  675. }
  676. if(fAsync){
  677. // Got an error, need to dump 2 refs.
  678. pSendInfo->Status=hr;
  679. wsaoDecRef(pSendInfo);
  680. }
  681. CompleteSend(pSendInfo);
  682. // we got a socket from the bag. send failed,
  683. // so we're cruising it from the bag
  684. if(!(pSendInfo->dwFlags & SI_INTERNALBUFF))
  685. {
  686. DPF(0,"send error - err = %d\n",err);
  687. }
  688. }
  689. }
  690. }
  691. } else {
  692. // Datagram Send
  693. DEBUGPRINTADDR(5,"unreliable send - sending to ",&pSendInfo->sockaddr);
  694. // send the message
  695. err = g_WSASendTo(pSendInfo->sSocket,
  696. (LPWSABUF)&pSendInfo->SendArray[pSendInfo->iFirstBuf],
  697. pSendInfo->cBuffers,
  698. &dwBytesSent,
  699. 0, /*flags*/
  700. (LPSOCKADDR)&pSendInfo->sockaddr,
  701. sizeof(SOCKADDR),
  702. (fAsync)?(&pSendInfo->wsao):NULL,
  703. (fAsync)?(SendComplete):NULL);
  704. if(!err){
  705. hr=DP_OK;
  706. wsaoDecRef(pSendInfo);
  707. } else {
  708. if (SOCKET_ERROR == err)
  709. {
  710. err = WSAGetLastError();
  711. if(err==WSA_IO_PENDING){
  712. hr=DPERR_PENDING;
  713. wsaoDecRef(pSendInfo);
  714. } else {
  715. hr=DPERR_GENERIC;
  716. if(fAsync){
  717. // some error, force completion.
  718. pSendInfo->Status=DPERR_GENERIC;
  719. wsaoDecRef(pSendInfo);
  720. }
  721. wsaoDecRef(pSendInfo);
  722. DPF(0,"send error - err = %d\n",err);
  723. }
  724. } else {
  725. DEBUG_BREAK();// SHOULD NEVER HAPPEN
  726. }
  727. }
  728. }
  729. return hr;
  730. #undef fAsync
  731. }
  732. // Alert thread provides a thread for send completions to run on.
  733. DWORD WINAPI SPSendThread(LPVOID lpv)
  734. {
  735. LPGLOBALDATA pgd=(LPGLOBALDATA) lpv;
  736. LPSENDINFO pSendInfo;
  737. DWORD rcWait=WAIT_IO_COMPLETION;
  738. BILINK *pBilink;
  739. BOOL bSent;
  740. pgd->BogusHandle=INVALID_HANDLE_VALUE; // workaround win95 wait for multiple bug.
  741. while(!pgd->bStopSendThread){
  742. rcWait=g_WSAWaitForMultipleEvents(1,&pgd->hSendWait,FALSE,INFINITE,TRUE);
  743. #ifdef DEBUG
  744. if(rcWait==WAIT_IO_COMPLETION){
  745. DPF(8,"ooooh, IO completion\n");
  746. }
  747. #endif
  748. do {
  749. bSent = FALSE;
  750. EnterCriticalSection(&pgd->csSendEx);
  751. pBilink=pgd->ReadyToSendQ.next;
  752. if(pBilink != &pgd->ReadyToSendQ){
  753. Delete(pBilink);
  754. LeaveCriticalSection(&pgd->csSendEx);
  755. pSendInfo=CONTAINING_RECORD(pBilink, SENDINFO, ReadyToSendQ);
  756. DoSend(pgd, pSendInfo);
  757. bSent=TRUE;
  758. } else {
  759. LeaveCriticalSection(&pgd->csSendEx);
  760. }
  761. } while (bSent);
  762. }
  763. pgd->bSendThreadRunning=FALSE;
  764. return FALSE;
  765. #undef hWait
  766. }
  767. void QueueForSend(LPGLOBALDATA pgd,LPSENDINFO pSendInfo)
  768. {
  769. EnterCriticalSection(&pgd->csSendEx);
  770. if(pSendInfo->pConn){
  771. // Note csFast is taken for pConn to be non-NULL
  772. AddRefConn(pSendInfo->pConn);
  773. pSendInfo->pConn->bSendOutstanding = TRUE;
  774. }
  775. InsertBefore(&pSendInfo->ReadyToSendQ,&pgd->ReadyToSendQ);
  776. LeaveCriticalSection(&pgd->csSendEx);
  777. SetEvent(pgd->hSendWait);
  778. }
  779. // some common code for InternalReliableSendEx and UnreliableSendEx
  780. VOID CommonInitForSend(LPGLOBALDATA pgd,LPDPSP_SENDEXDATA psd,LPSENDINFO pSendInfo)
  781. {
  782. pSendInfo->pConn = NULL;
  783. pSendInfo->dwMessageSize= psd->dwMessageSize;
  784. pSendInfo->dwUserContext= (DWORD_PTR)psd->lpDPContext;
  785. pSendInfo->RefCount = 2; // one for completion, 1 for this routine
  786. pSendInfo->pgd = pgd;
  787. pSendInfo->lpISP = psd->lpISP;
  788. pSendInfo->Status = DP_OK;
  789. pSendInfo->idTo = psd->idPlayerTo;
  790. pSendInfo->idFrom = psd->idPlayerFrom;
  791. pSendInfo->dwSendFlags = psd->dwFlags;
  792. if(psd->lpdwSPMsgID){
  793. *psd->lpdwSPMsgID=0;
  794. }
  795. EnterCriticalSection(&pgd->csSendEx);
  796. InsertBefore(&pSendInfo->PendingSendQ,&pgd->PendingSendQ);
  797. pgd->dwBytesPending += psd->dwMessageSize;
  798. pgd->dwMessagesPending += 1;
  799. LeaveCriticalSection(&pgd->csSendEx);
  800. }
  801. VOID UnpendSendInfo(LPGLOBALDATA pgd, LPSENDINFO pSendInfo)
  802. {
  803. EnterCriticalSection(&pgd->csSendEx);
  804. Delete(&pSendInfo->PendingSendQ);
  805. pgd->dwBytesPending -= pSendInfo->dwMessageSize;
  806. pgd->dwMessagesPending -= 1;
  807. LeaveCriticalSection(&pgd->csSendEx);
  808. }
  809. HRESULT UnreliableSendEx(LPDPSP_SENDEXDATA psd, LPSENDINFO pSendInfo)
  810. {
  811. SOCKADDR sockaddr;
  812. INT iAddrLen = sizeof(sockaddr);
  813. HRESULT hr=DP_OK;
  814. UINT err;
  815. DWORD dwSize = sizeof(SPPLAYERDATA);
  816. LPSPPLAYERDATA ppdTo;
  817. DWORD dwDataSize = sizeof(GLOBALDATA);
  818. LPGLOBALDATA pgd;
  819. BOOL bSendHeader;
  820. // get the global data
  821. hr =psd->lpISP->lpVtbl->GetSPData(psd->lpISP,(LPVOID *)&pgd,&dwDataSize,DPGET_LOCAL);
  822. if (FAILED(hr) || (dwDataSize != sizeof(GLOBALDATA) ))
  823. {
  824. DPF_ERR("couldn't get SP data from DirectPlay - failing");
  825. return E_FAIL;
  826. }
  827. if (pgd->iMaxUdpDg && (psd->dwMessageSize >= pgd->iMaxUdpDg))
  828. {
  829. return DPERR_SENDTOOBIG;
  830. }
  831. // get to address
  832. if (0 == psd->idPlayerTo)
  833. {
  834. sockaddr = pgd->saddrNS;
  835. }
  836. else
  837. {
  838. hr = GetSPPlayerData(pgd,psd->lpISP,psd->idPlayerTo,&ppdTo,&dwSize);
  839. if (FAILED(hr))
  840. {
  841. ASSERT(FALSE);
  842. return hr;
  843. }
  844. sockaddr = *(DGRAM_PSOCKADDR(ppdTo));
  845. }
  846. // put the token + size on front of the mesage
  847. SetMessageHeader((LPVOID)(pSendInfo->SendArray[0].buf),psd->dwMessageSize+sizeof(MESSAGEHEADER),TOKEN);
  848. bSendHeader=TRUE;
  849. if (psd->bSystemMessage)
  850. {
  851. SetReturnAddress(pSendInfo->SendArray[0].buf,SERVICE_SOCKET(pgd),SERVICE_SADDR_PUBLIC(pgd));
  852. } // reply
  853. else
  854. {
  855. // see if we can send this message w/ no header
  856. // if the message is smaller than a dword, or, if it's a valid sp header (fooling us
  857. // on the other end, don't send any header
  858. if ( !((psd->dwMessageSize >= sizeof(DWORD)) && !(VALID_SP_MESSAGE(pSendInfo->SendArray[0].buf))) )
  859. {
  860. bSendHeader=FALSE;
  861. }
  862. }
  863. CommonInitForSend(pgd,psd,pSendInfo);
  864. pSendInfo->dwFlags |= SI_DATAGRAM;
  865. pSendInfo->sSocket = pgd->sSystemDGramSocket;
  866. pSendInfo->sockaddr = sockaddr;
  867. if(bSendHeader){
  868. pSendInfo->iFirstBuf=0;
  869. pSendInfo->cBuffers =psd->cBuffers+1;
  870. } else {
  871. pSendInfo->iFirstBuf=1;
  872. pSendInfo->cBuffers=psd->cBuffers;
  873. }
  874. if(psd->dwFlags & DPSEND_ASYNC){
  875. QueueForSend(pgd,pSendInfo);
  876. hr=DPERR_PENDING;
  877. } else {
  878. hr=DoSend(pgd,pSendInfo);
  879. if(hr==DP_OK || hr==DPERR_PENDING){
  880. wsaoDecRef(pSendInfo);
  881. } else {
  882. UnpendSendInfo(pgd, pSendInfo);
  883. }
  884. }
  885. return hr;
  886. } // UnreliableSendEx
  887. #endif //SendEx
  888. BOOL SetExclusivePortAccess(SOCKET sNew)
  889. {
  890. BOOL bReturn = TRUE;
  891. BOOL bValue;
  892. UINT err;
  893. // turn on exclusive port use to avoid hijacking, note this only works on NT4 SP4 and later.
  894. // on other OSes this will fail, but that is ok, we will ignore.
  895. DPF(5, "Turning reuse OFF and exclusive access ON for socket 0x%p", sNew);
  896. bValue = FALSE;
  897. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_REUSEADDR, (CHAR FAR *)&bValue, sizeof(bValue)))
  898. {
  899. err = WSAGetLastError();
  900. DPF(1,"WARN: Failed to set shared port use to FALSE - continue : err = %d\n",err);
  901. bReturn = FALSE;
  902. }
  903. bValue = TRUE;
  904. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (CHAR FAR *)&bValue, sizeof(bValue)))
  905. {
  906. err = WSAGetLastError();
  907. DPF(1,"WARN: Failed to set exclusive port use to TRUE - continue : err = %d\n",err);
  908. bReturn = FALSE;
  909. }
  910. return bReturn;
  911. }
  912. BOOL SetSharedPortAccess(SOCKET sNew)
  913. {
  914. BOOL bReturn = TRUE;
  915. BOOL bValue;
  916. UINT err;
  917. // turn on port sharing.
  918. DPF(5, "Turning exclusive access OFF and reuse ON for socket 0x%p", sNew);
  919. bValue = FALSE;
  920. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (CHAR FAR *)&bValue, sizeof(bValue)))
  921. {
  922. err = WSAGetLastError();
  923. DPF(1,"WARN: Failed to set exclusive port use to FALSE - continue : err = %d\n",err);
  924. bReturn = FALSE;
  925. }
  926. bValue = TRUE;
  927. if (SOCKET_ERROR == setsockopt(sNew, SOL_SOCKET, SO_REUSEADDR, (CHAR FAR *)&bValue, sizeof(bValue)))
  928. {
  929. err = WSAGetLastError();
  930. DPF(1,"WARN: Failed to set shared port use to TRUE - continue : err = %d\n",err);
  931. bReturn = FALSE;
  932. }
  933. return TRUE;
  934. }