NatPunchthroughClient.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file
  11. /// \brief Contains the NAT-punchthrough plugin for the client.
  12. ///
  13. #include "NativeFeatureIncludes.h"
  14. #if _RAKNET_SUPPORT_NatPunchthroughClient==1
  15. #ifndef __NAT_PUNCHTHROUGH_CLIENT_H
  16. #define __NAT_PUNCHTHROUGH_CLIENT_H
  17. #include "RakNetTypes.h"
  18. #include "Export.h"
  19. #include "PluginInterface2.h"
  20. #include "PacketPriority.h"
  21. #include "SocketIncludes.h"
  22. #include "DS_List.h"
  23. #include "RakString.h"
  24. #include "DS_Queue.h"
  25. // Trendnet TEW-632BRP sometimes starts at port 1024 and increments sequentially.
  26. // Zonnet zsr1134we. Replies go out on the net, but are always absorbed by the remote router??
  27. // Dlink ebr2310 to Trendnet ok
  28. // Trendnet TEW-652BRP to Trendnet 632BRP OK
  29. // Trendnet TEW-632BRP to Trendnet 632BRP OK
  30. // Buffalo WHR-HP-G54 OK
  31. // Netgear WGR614 ok
  32. namespace RakNet
  33. {
  34. /// Forward declarations
  35. class RakPeerInterface;
  36. struct Packet;
  37. #if _RAKNET_SUPPORT_PacketLogger==1
  38. class PacketLogger;
  39. #endif
  40. /// \ingroup NAT_PUNCHTHROUGH_GROUP
  41. struct RAK_DLL_EXPORT PunchthroughConfiguration
  42. {
  43. /// internal: (15 ms * 2 tries + 30 wait) * 5 ports * 8 players = 2.4 seconds
  44. /// external: (50 ms * 8 sends + 200 wait) * 2 port * 8 players = 9.6 seconds
  45. /// Total: 8 seconds
  46. PunchthroughConfiguration() {
  47. TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL=15;
  48. TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL=50;
  49. UDP_SENDS_PER_PORT_INTERNAL=2;
  50. UDP_SENDS_PER_PORT_EXTERNAL=8;
  51. INTERNAL_IP_WAIT_AFTER_ATTEMPTS=30;
  52. MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK=5; /// set to 0 to not do lan connects
  53. MAX_PREDICTIVE_PORT_RANGE=2;
  54. EXTERNAL_IP_WAIT_BETWEEN_PORTS=200;
  55. EXTERNAL_IP_WAIT_AFTER_FIRST_TTL=100;
  56. EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS=EXTERNAL_IP_WAIT_BETWEEN_PORTS;
  57. retryOnFailure=false;
  58. }
  59. /// How much time between each UDP send
  60. RakNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL;
  61. RakNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL;
  62. /// How many tries for one port before giving up and going to the next port
  63. int UDP_SENDS_PER_PORT_INTERNAL;
  64. int UDP_SENDS_PER_PORT_EXTERNAL;
  65. /// After giving up on one internal port, how long to wait before trying the next port
  66. int INTERNAL_IP_WAIT_AFTER_ATTEMPTS;
  67. /// How many external ports to try past the last known starting port
  68. int MAX_PREDICTIVE_PORT_RANGE;
  69. /// After sending TTL, how long to wait until first punch attempt
  70. int EXTERNAL_IP_WAIT_AFTER_FIRST_TTL;
  71. /// After giving up on one external port, how long to wait before trying the next port
  72. int EXTERNAL_IP_WAIT_BETWEEN_PORTS;
  73. /// After trying all external ports, how long to wait before returning ID_NAT_PUNCHTHROUGH_FAILED
  74. int EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS;
  75. /// Maximum number of internal IP address to try to connect to.
  76. /// Cannot be greater than MAXIMUM_NUMBER_OF_INTERNAL_IDS
  77. /// Should be high enough to try all internal IP addresses on the majority of computers
  78. int MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK;
  79. /// If the first punchthrough attempt fails, try again
  80. /// This sometimes works because the remote router was looking for an incoming message on a higher numbered port before responding to a lower numbered port from the other system
  81. bool retryOnFailure;
  82. };
  83. /// \ingroup NAT_PUNCHTHROUGH_GROUP
  84. struct RAK_DLL_EXPORT NatPunchthroughDebugInterface
  85. {
  86. NatPunchthroughDebugInterface() {}
  87. virtual ~NatPunchthroughDebugInterface() {}
  88. virtual void OnClientMessage(const char *msg)=0;
  89. };
  90. /// \ingroup NAT_PUNCHTHROUGH_GROUP
  91. struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_Printf : public NatPunchthroughDebugInterface
  92. {
  93. virtual void OnClientMessage(const char *msg);
  94. };
  95. #if _RAKNET_SUPPORT_PacketLogger==1
  96. /// \ingroup NAT_PUNCHTHROUGH_GROUP
  97. struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_PacketLogger : public NatPunchthroughDebugInterface
  98. {
  99. // Set to non-zero to write to the packetlogger!
  100. PacketLogger *pl;
  101. NatPunchthroughDebugInterface_PacketLogger() {pl=0;}
  102. ~NatPunchthroughDebugInterface_PacketLogger() {}
  103. virtual void OnClientMessage(const char *msg);
  104. };
  105. #endif
  106. /// \brief Client code for NATPunchthrough
  107. /// \details Maintain connection to NatPunchthroughServer to process incoming connection attempts through NatPunchthroughClient<BR>
  108. /// Client will send datagrams to port to estimate next port<BR>
  109. /// Will simultaneously connect with another client once ports are estimated.
  110. /// \sa NatTypeDetectionClient
  111. /// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html
  112. /// \ingroup NAT_PUNCHTHROUGH_GROUP
  113. class RAK_DLL_EXPORT NatPunchthroughClient : public PluginInterface2
  114. {
  115. public:
  116. // GetInstance() and DestroyInstance(instance*)
  117. STATIC_FACTORY_DECLARATIONS(NatPunchthroughClient)
  118. NatPunchthroughClient();
  119. ~NatPunchthroughClient();
  120. /// If the instance of RakPeer running NATPunchthroughServer was bound to two IP addresses, then you can call FindRouterPortStride()
  121. /// This will determine the stride that your router uses when assigning ports, if your router is full-cone
  122. /// This function is also called automatically when you call OpenNAT - however, calling it earlier when you are connected to the facilitator will speed up the process
  123. /// \param[in] destination The system to punch. Must already be connected to \a facilitator
  124. void FindRouterPortStride(const SystemAddress &facilitator);
  125. /// Punchthrough a NAT. Doesn't connect, just tries to setup the routing table
  126. /// \param[in] destination The system to punch. Must already be connected to \a facilitator
  127. /// \param[in] facilitator A system we are already connected to running the NatPunchthroughServer plugin
  128. /// \sa OpenNATGroup()
  129. /// You will get ID_NAT_PUNCHTHROUGH_SUCCEEDED on success
  130. /// You will get ID_NAT_TARGET_NOT_CONNECTED, ID_NAT_TARGET_UNRESPONSIVE, ID_NAT_CONNECTION_TO_TARGET_LOST, ID_NAT_ALREADY_IN_PROGRESS, or ID_NAT_PUNCHTHROUGH_FAILED on failures of various types
  131. /// However, if you lose connection to the facilitator, you may not necessarily get above
  132. bool OpenNAT(RakNetGUID destination, const SystemAddress &facilitator);
  133. /*
  134. /// \deprecated See FullyConnectedMesh2::StartVerifiedJoin() which is more flexible
  135. /// Same as calling OpenNAT for a list of systems, but reply is delayed until all systems pass.
  136. /// This is useful for peer to peer games where you want to connect to every system in the remote session, not just one particular system
  137. /// \note For cloud computing, all systems in the group must be connected to the same facilitator since we're only specifying one
  138. /// You will get ID_NAT_GROUP_PUNCH_SUCCEEDED on success
  139. /// You will get ID_NAT_TARGET_NOT_CONNECTED, ID_NAT_ALREADY_IN_PROGRESS, or ID_NAT_GROUP_PUNCH_FAILED on failures of various types
  140. /// However, if you lose connection to the facilitator, you may not necessarily get above
  141. bool OpenNATGroup(DataStructures::List<RakNetGUID> destinationSystems, const SystemAddress &facilitator);
  142. */
  143. /// Modify the system configuration if desired
  144. /// Don't modify the variables in the structure while punchthrough is in progress
  145. PunchthroughConfiguration* GetPunchthroughConfiguration(void);
  146. /// Sets a callback to be called with debug messages
  147. /// \param[in] i Pointer to an interface. The pointer is stored, so don't delete it while in progress. Pass 0 to clear.
  148. void SetDebugInterface(NatPunchthroughDebugInterface *i);
  149. /// Get the port mappings you should pass to UPNP (for miniupnpc-1.6.20120410, for the function UPNP_AddPortMapping)
  150. void GetUPNPPortMappings(char *externalPort, char *internalPort, const SystemAddress &natPunchthroughServerAddress);
  151. /// \internal For plugin handling
  152. virtual void Update(void);
  153. /// \internal For plugin handling
  154. virtual PluginReceiveResult OnReceive(Packet *packet);
  155. /// \internal For plugin handling
  156. virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
  157. /// \internal For plugin handling
  158. virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
  159. virtual void OnAttach(void);
  160. virtual void OnDetach(void);
  161. virtual void OnRakPeerShutdown(void);
  162. void Clear(void);
  163. struct SendPing
  164. {
  165. RakNet::Time nextActionTime;
  166. SystemAddress targetAddress;
  167. SystemAddress facilitator;
  168. SystemAddress internalIds[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
  169. RakNetGUID targetGuid;
  170. bool weAreSender;
  171. int attemptCount;
  172. int retryCount;
  173. int punchingFixedPortAttempts; // only used for TestMode::PUNCHING_FIXED_PORT
  174. uint16_t sessionId;
  175. bool sentTTL;
  176. // Give priority to internal IP addresses because if we are on a LAN, we don't want to try to connect through the internet
  177. enum TestMode
  178. {
  179. TESTING_INTERNAL_IPS,
  180. WAITING_FOR_INTERNAL_IPS_RESPONSE,
  181. //SEND_WITH_TTL,
  182. TESTING_EXTERNAL_IPS_FACILITATOR_PORT_TO_FACILITATOR_PORT,
  183. TESTING_EXTERNAL_IPS_1024_TO_FACILITATOR_PORT,
  184. TESTING_EXTERNAL_IPS_FACILITATOR_PORT_TO_1024,
  185. TESTING_EXTERNAL_IPS_1024_TO_1024,
  186. WAITING_AFTER_ALL_ATTEMPTS,
  187. // The trendnet remaps the remote port to 1024.
  188. // If you continue punching on a different port for the same IP it bans you and the communication becomes unidirectioal
  189. PUNCHING_FIXED_PORT,
  190. // try port 1024-1028
  191. } testMode;
  192. } sp;
  193. protected:
  194. unsigned short mostRecentExternalPort;
  195. //void OnNatGroupPunchthroughRequest(Packet *packet);
  196. void OnFailureNotification(Packet *packet);
  197. //void OnNatGroupPunchthroughReply(Packet *packet);
  198. void OnGetMostRecentPort(Packet *packet);
  199. void OnConnectAtTime(Packet *packet);
  200. unsigned int GetPendingOpenNATIndex(RakNetGUID destination, const SystemAddress &facilitator);
  201. void SendPunchthrough(RakNetGUID destination, const SystemAddress &facilitator);
  202. void QueueOpenNAT(RakNetGUID destination, const SystemAddress &facilitator);
  203. void SendQueuedOpenNAT(void);
  204. void SendTTL(const SystemAddress &sa);
  205. void SendOutOfBand(SystemAddress sa, MessageID oobId);
  206. void OnPunchthroughFailure(void);
  207. void OnReadyForNextPunchthrough(void);
  208. void PushFailure(void);
  209. bool RemoveFromFailureQueue(void);
  210. void PushSuccess(void);
  211. PunchthroughConfiguration pc;
  212. NatPunchthroughDebugInterface *natPunchthroughDebugInterface;
  213. // The first time we fail a NAT attempt, we add it to failedAttemptList and try again, since sometimes trying again later fixes the problem
  214. // The second time we fail, we return ID_NAT_PUNCHTHROUGH_FAILED
  215. struct AddrAndGuid
  216. {
  217. SystemAddress addr;
  218. RakNetGUID guid;
  219. };
  220. DataStructures::List<AddrAndGuid> failedAttemptList;
  221. struct DSTAndFac
  222. {
  223. RakNetGUID destination;
  224. SystemAddress facilitator;
  225. };
  226. DataStructures::Queue<DSTAndFac> queuedOpenNat;
  227. void IncrementExternalAttemptCount(RakNet::Time time, RakNet::Time delta);
  228. unsigned short portStride;
  229. enum
  230. {
  231. HAS_PORT_STRIDE,
  232. UNKNOWN_PORT_STRIDE,
  233. CALCULATING_PORT_STRIDE,
  234. INCAPABLE_PORT_STRIDE
  235. } hasPortStride;
  236. RakNet::Time portStrideCalTimeout;
  237. /*
  238. struct TimeAndGuid
  239. {
  240. RakNet::Time time;
  241. RakNetGUID guid;
  242. };
  243. DataStructures::List<TimeAndGuid> groupRequestsInProgress;
  244. struct GroupPunchRequest
  245. {
  246. SystemAddress facilitator;
  247. DataStructures::List<RakNetGUID> pendingList;
  248. DataStructures::List<RakNetGUID> passedListGuid;
  249. DataStructures::List<SystemAddress> passedListAddress;
  250. DataStructures::List<RakNetGUID> failedList;
  251. DataStructures::List<RakNetGUID> ignoredList;
  252. };
  253. DataStructures::List<GroupPunchRequest*> groupPunchRequests;
  254. void UpdateGroupPunchOnNatResult(SystemAddress facilitator, RakNetGUID targetSystem, SystemAddress targetSystemAddress, int result); // 0=failed, 1=success, 2=ignore
  255. */
  256. };
  257. } // namespace RakNet
  258. #endif
  259. #endif // _RAKNET_SUPPORT_*
粤ICP备19079148号