FirewallWait.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /******************************************************************************
  19. *
  20. * FILE
  21. * $Archive: /Commando/Code/Commando/FirewallWait.cpp $
  22. *
  23. * DESCRIPTION
  24. * Firewall negotiation wait condition.
  25. *
  26. * PROGRAMMER
  27. * $Author: Tom_s $
  28. *
  29. * VERSION INFO
  30. * $Revision: 16 $
  31. * $Modtime: 3/04/02 11:45a $
  32. *
  33. ******************************************************************************/
  34. #include "always.h"
  35. #include "FirewallWait.h"
  36. #include "nat.h"
  37. #include "string_ids.h"
  38. #include "translatedb.h"
  39. #include "natter.h"
  40. #include <WWOnline\WOLSession.h>
  41. #include <WWDebug\WWDebug.h>
  42. #ifdef _MSC_VER
  43. #pragma warning (push,3)
  44. #endif
  45. #include "systimer.h"
  46. #ifdef _MSC_VER
  47. #pragma warning (pop)
  48. #endif
  49. /*
  50. ** Wait code for firewall/NAT detection.
  51. **
  52. **
  53. **
  54. */
  55. RefPtr<FirewallDetectWait> FirewallDetectWait::Create(void)
  56. {
  57. return new FirewallDetectWait();
  58. }
  59. FirewallDetectWait::FirewallDetectWait(void) :
  60. SingleWait(TRANSLATION(IDS_FIREWALL_NEGOTIATING_FIREWALL), 60000),
  61. mEvent(NULL),
  62. mPingsRemaining(UINT_MAX)
  63. {
  64. mWOLSession = WWOnline::Session::GetInstance(false);
  65. assert(mWOLSession.IsValid());
  66. }
  67. FirewallDetectWait::~FirewallDetectWait()
  68. {
  69. WWDEBUG_SAY(("FirewallDetectWait: End - %S\n", mEndText));
  70. mWOLSession->EnablePinging(true);
  71. if (mEvent)
  72. {
  73. CloseHandle(mEvent);
  74. }
  75. }
  76. void FirewallDetectWait::WaitBeginning(void)
  77. {
  78. WWDEBUG_SAY(("FirewallDetectWait: Beginning\n"));
  79. mEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  80. if (mEvent == NULL)
  81. {
  82. WWDEBUG_SAY(("FirewallDetectWait: Can't create event\n"));
  83. EndWait(Error, TRANSLATION(IDS_FIREWALL_CREATE_EVENT_FAILED));
  84. }
  85. else
  86. {
  87. mWOLSession->EnablePinging(false);
  88. mTimeout = 15000;
  89. }
  90. }
  91. WaitCondition::WaitResult FirewallDetectWait::GetResult(void)
  92. {
  93. if (mEndResult == Waiting)
  94. {
  95. // Wait for pending pings to finish first
  96. unsigned int pingsWaiting = mWOLSession->GetPendingPingCount();
  97. if (mPingsRemaining != pingsWaiting)
  98. {
  99. mPingsRemaining = pingsWaiting;
  100. mTimeout = 60000;
  101. FirewallHelper.Detect_Firewall(mEvent);
  102. }
  103. if (mPingsRemaining == 0)
  104. {
  105. DWORD result = WaitForSingleObject(mEvent, 0);
  106. if (result == WAIT_OBJECT_0)
  107. {
  108. WWDEBUG_SAY(("FirewallDetectWait: ConditionMet\n"));
  109. WOLNATInterface.Save_Firewall_Info_To_Registry();
  110. EndWait(ConditionMet, TRANSLATION(IDS_FIREWALL_NEGOTIATION_COMPLETE));
  111. }
  112. else if (result == WAIT_FAILED)
  113. {
  114. WWDEBUG_SAY(("FirewallDetectWait: WAIT_FAILED\n"));
  115. EndWait(Error, TRANSLATION(IDS_FIREWALL_NEGOTIATION_FAILED));
  116. }
  117. }
  118. }
  119. if (mEndResult != Waiting)
  120. {
  121. mWOLSession->EnablePinging(true);
  122. }
  123. return mEndResult;
  124. }
  125. /*
  126. ** Wait code for clients when trying to open up a firewall for a server connection.
  127. **
  128. */
  129. RefPtr<FirewallConnectWait> FirewallConnectWait::Create(void)
  130. {
  131. return new FirewallConnectWait;
  132. }
  133. FirewallConnectWait::FirewallConnectWait(void) :
  134. SingleWait(TRANSLATION(IDS_FIREWALL_NEGOTIATING_WITH_SERVER)),
  135. mEvent(NULL),
  136. mCancelEvent(NULL),
  137. mSuccessFlag(FirewallHelperClass::FW_RESULT_UNKNOWN),
  138. mQueueCount(0),
  139. mLastQueueCount(0),
  140. mPingsRemaining(UINT_MAX)
  141. {
  142. mWOLSession = WWOnline::Session::GetInstance(false);
  143. assert(mWOLSession.IsValid());
  144. }
  145. FirewallConnectWait::~FirewallConnectWait()
  146. {
  147. WWDEBUG_SAY(("FirewallConnectWait: End - %S\n", mEndText));
  148. mWOLSession->EnablePinging(true);
  149. if (mEvent)
  150. {
  151. CloseHandle(mEvent);
  152. }
  153. if (mCancelEvent)
  154. {
  155. CloseHandle(mCancelEvent);
  156. }
  157. }
  158. void FirewallConnectWait::WaitBeginning(void)
  159. {
  160. WWDEBUG_SAY(("FirewallConnectWait: Beginning\n"));
  161. mEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  162. mCancelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  163. if (mEvent == NULL)
  164. {
  165. WWDEBUG_SAY(("FirewallConnectWait: Can't create event\n"));
  166. EndWait(Error, TRANSLATION(IDS_FIREWALL_CREATE_EVENT_FAILED));
  167. }
  168. else
  169. {
  170. mWOLSession->EnablePinging(false);
  171. WOLNATInterface.Tell_Server_That_Client_Is_In_Channel();
  172. mTimeout = 15000;
  173. mStartTime = TIMEGETTIME();
  174. }
  175. }
  176. WaitCondition::WaitResult FirewallConnectWait::GetResult(void)
  177. {
  178. if (mEndResult == Waiting)
  179. {
  180. // Wait for pending pings to finish first
  181. unsigned int pingsWaiting = mWOLSession->GetPendingPingCount();
  182. if (mPingsRemaining != pingsWaiting)
  183. {
  184. mPingsRemaining = pingsWaiting;
  185. if (mPingsRemaining == 0)
  186. {
  187. FirewallHelper.Set_Client_Connect_Event(mEvent, mCancelEvent, &mSuccessFlag, (int*)&mQueueCount);
  188. mTimeout = 32000;
  189. mStartTime = TIMEGETTIME();
  190. }
  191. }
  192. if (mPingsRemaining == 0)
  193. {
  194. if ((TIMEGETTIME() - mStartTime) > mTimeout)
  195. {
  196. EndWait(TimeOut, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_TIMEOUT));
  197. }
  198. else
  199. {
  200. // Maybe change the wait text if there are players queued in front of us.
  201. if (mQueueCount != mLastQueueCount)
  202. {
  203. wchar_t temp[256];
  204. swprintf(temp, TRANSLATION(IDS_FIREWALL_QUEUE_NOTIFICATION), mQueueCount);
  205. WideStringClass text(temp, true);
  206. SetWaitText(text);
  207. mLastQueueCount = mQueueCount;
  208. mTimeout = max((unsigned)32000, ((mQueueCount * 32000) + 32000));
  209. mStartTime = TIMEGETTIME();
  210. }
  211. DWORD result = WaitForSingleObject(mEvent, 0);
  212. if (result == WAIT_OBJECT_0)
  213. {
  214. if (mSuccessFlag == FirewallHelperClass::FW_RESULT_SUCCEEDED)
  215. {
  216. WWDEBUG_SAY(("FirewallConnectWait: ConditionMet\n"));
  217. EndWait(ConditionMet, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_COMPLETE));
  218. }
  219. else
  220. {
  221. assert(mSuccessFlag == FirewallHelperClass::FW_RESULT_FAILED);
  222. WWDEBUG_SAY(("FirewallConnectWait: ConditionMet\n"));
  223. EndWait(Error, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_FAILED));
  224. }
  225. }
  226. else if (result == WAIT_FAILED)
  227. {
  228. WWDEBUG_SAY(("FirewallConnectWait: WAIT_FAILED\n"));
  229. EndWait(Error, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_FAILED));
  230. }
  231. }
  232. }
  233. }
  234. if (mEndResult != Waiting)
  235. {
  236. mWOLSession->EnablePinging(true);
  237. }
  238. return mEndResult;
  239. }
  240. //
  241. // Override base class end wait to check for cancel being pressed.
  242. //
  243. void FirewallConnectWait::EndWait(WaitResult result, const wchar_t* endText)
  244. {
  245. WWDEBUG_SAY(("FirewallConnectWait: EndWait\n"));
  246. if (result == UserCancel || result == TimeOut)
  247. {
  248. // Tell the firewall negotiation code to give up.
  249. SetEvent(mCancelEvent);
  250. }
  251. // Give the firewall code a little time to respond then remove it's cancel event anyway. It'll figure it out.
  252. for (int i=0 ; i<100 ; i++)
  253. {
  254. if (mSuccessFlag == FirewallHelperClass::FW_RESULT_CANCELLED)
  255. {
  256. break;
  257. }
  258. Sleep(1);
  259. }
  260. FirewallHelper.Set_Client_Connect_Event(NULL, NULL, NULL, NULL);
  261. SingleWait::EndWait(result, endText);
  262. }