1 2 /// \file 3 /// \brief Contains the NAT-punchthrough plugin for the client. 4 /// 5 /// This file is part of RakNet Copyright 2003 Jenkins Software LLC 6 /// 7 /// Raknet is available under the terms of the GPLv3 license, see /usr/local/share/licenses/raknet-3.9.2_10,1/GPLv3. 8 9 #include "NativeFeatureIncludes.h" 10 #if _RAKNET_SUPPORT_NatPunchthroughClient==1 11 12 #ifndef __NAT_PUNCHTHROUGH_CLIENT_H 13 #define __NAT_PUNCHTHROUGH_CLIENT_H 14 15 #include "RakNetTypes.h" 16 #include "Export.h" 17 #include "PluginInterface2.h" 18 #include "PacketPriority.h" 19 #include "SocketIncludes.h" 20 #include "DS_List.h" 21 #include "RakString.h" 22 23 // Trendnet TEW-632BRP sometimes starts at port 1024 and increments sequentially. 24 // Zonnet zsr1134we. Replies go out on the net, but are always absorbed by the remote router?? 25 // Dlink ebr2310 to Trendnet ok 26 // Trendnet TEW-652BRP to Trendnet 632BRP OK 27 // Trendnet TEW-632BRP to Trendnet 632BRP OK 28 // Buffalo WHR-HP-G54 OK 29 // Netgear WGR614 ok 30 31 class RakPeerInterface; 32 struct Packet; 33 #if _RAKNET_SUPPORT_PacketLogger==1 34 class PacketLogger; 35 #endif 36 37 /// \ingroup NAT_PUNCHTHROUGH_GROUP 38 struct RAK_DLL_EXPORT PunchthroughConfiguration 39 { 40 /// internal: (15 ms * 2 tries + 30 wait) * 5 ports * 8 players = 2.4 seconds 41 /// external: (50 ms * 8 sends + 100 wait) * 2 port * 8 players = 8 seconds 42 /// Total: 8 seconds PunchthroughConfigurationPunchthroughConfiguration43 PunchthroughConfiguration() { 44 TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL=15; 45 TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL=50; 46 UDP_SENDS_PER_PORT_INTERNAL=2; 47 UDP_SENDS_PER_PORT_EXTERNAL=8; 48 INTERNAL_IP_WAIT_AFTER_ATTEMPTS=30; 49 MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK=5; /// set to 0 to not do lan connects 50 MAX_PREDICTIVE_PORT_RANGE=2; 51 EXTERNAL_IP_WAIT_BETWEEN_PORTS=100; 52 EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS=EXTERNAL_IP_WAIT_BETWEEN_PORTS; 53 retryOnFailure=false; 54 } 55 56 /// How much time between each UDP send 57 RakNetTimeMS TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL; 58 RakNetTimeMS TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL; 59 60 /// How many tries for one port before giving up and going to the next port 61 int UDP_SENDS_PER_PORT_INTERNAL; 62 int UDP_SENDS_PER_PORT_EXTERNAL; 63 64 /// After giving up on one internal port, how long to wait before trying the next port 65 int INTERNAL_IP_WAIT_AFTER_ATTEMPTS; 66 67 /// How many external ports to try past the last known starting port 68 int MAX_PREDICTIVE_PORT_RANGE; 69 70 /// After giving up on one external port, how long to wait before trying the next port 71 int EXTERNAL_IP_WAIT_BETWEEN_PORTS; 72 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 76 /// Maximum number of internal IP address to try to connect to. 77 /// Cannot be greater than MAXIMUM_NUMBER_OF_INTERNAL_IDS 78 /// Should be high enough to try all internal IP addresses on the majority of computers 79 int MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK; 80 81 /// If the first punchthrough attempt fails, try again 82 /// 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 83 bool retryOnFailure; 84 }; 85 86 /// \ingroup NAT_PUNCHTHROUGH_GROUP 87 struct RAK_DLL_EXPORT NatPunchthroughDebugInterface 88 { NatPunchthroughDebugInterfaceNatPunchthroughDebugInterface89 NatPunchthroughDebugInterface() {} ~NatPunchthroughDebugInterfaceNatPunchthroughDebugInterface90 virtual ~NatPunchthroughDebugInterface() {} 91 virtual void OnClientMessage(const char *msg)=0; 92 }; 93 94 /// \ingroup NAT_PUNCHTHROUGH_GROUP 95 struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_Printf : public NatPunchthroughDebugInterface 96 { 97 virtual void OnClientMessage(const char *msg); 98 }; 99 100 #if _RAKNET_SUPPORT_PacketLogger==1 101 /// \ingroup NAT_PUNCHTHROUGH_GROUP 102 struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_PacketLogger : public NatPunchthroughDebugInterface 103 { 104 // Set to non-zero to write to the packetlogger! 105 PacketLogger *pl; 106 NatPunchthroughDebugInterface_PacketLoggerNatPunchthroughDebugInterface_PacketLogger107 NatPunchthroughDebugInterface_PacketLogger() {pl=0;} ~NatPunchthroughDebugInterface_PacketLoggerNatPunchthroughDebugInterface_PacketLogger108 ~NatPunchthroughDebugInterface_PacketLogger() {} 109 virtual void OnClientMessage(const char *msg); 110 }; 111 #endif 112 113 /// \brief Client code for NATPunchthrough 114 /// \details Maintain connection to NatPunchthroughServer to process incoming connection attempts through NatPunchthroughClient<BR> 115 /// Client will send datagrams to port to estimate next port<BR> 116 /// Will simultaneously connect with another client once ports are estimated. 117 /// \sa NatTypeDetectionClient 118 /// See also http://www.jenkinssoftware.com/raknet/manual/natpunchthrough.html 119 /// \ingroup NAT_PUNCHTHROUGH_GROUP 120 class RAK_DLL_EXPORT NatPunchthroughClient : public PluginInterface2 121 { 122 public: 123 NatPunchthroughClient(); 124 ~NatPunchthroughClient(); 125 126 /// Punchthrough a NAT. Doesn't connect, just tries to setup the routing table 127 bool OpenNAT(RakNetGUID destination, SystemAddress facilitator); 128 129 /// Modify the system configuration if desired 130 /// Don't modify the variables in the structure while punchthrough is in progress 131 PunchthroughConfiguration* GetPunchthroughConfiguration(void); 132 133 /// Sets a callback to be called with debug messages 134 /// \param[in] i Pointer to an interface. The pointer is stored, so don't delete it while in progress. Pass 0 to clear. 135 void SetDebugInterface(NatPunchthroughDebugInterface *i); 136 137 /// Returns the port on the router that incoming messages will be sent to 138 /// UPNP needs to know this (See UPNP project) 139 /// \pre Must have connected to the facilitator first 140 /// \return Port that incoming messages will be sent to, from other clients. This probably won't be the same port RakNet was started on. 141 unsigned short GetUPNPExternalPort(void) const; 142 143 /// Returns our internal port that RakNet was started on 144 /// Equivalent to calling rakPeer->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port 145 /// \return Port that incoming messages will arrive on, on our actual system. 146 unsigned short GetUPNPInternalPort(void) const; 147 148 /// Returns our locally bound system address 149 /// Equivalent to calling rakPeer->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).ToString(false); 150 /// \return Internal address that UPNP should forward messages to 151 RakNet::RakString GetUPNPInternalAddress(void) const; 152 153 /// \internal For plugin handling 154 virtual void Update(void); 155 156 /// \internal For plugin handling 157 virtual PluginReceiveResult OnReceive(Packet *packet); 158 159 /// \internal For plugin handling 160 virtual void OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming); 161 162 /// \internal For plugin handling 163 virtual void OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); 164 165 virtual void OnAttach(void); 166 virtual void OnDetach(void); 167 virtual void OnRakPeerShutdown(void); 168 void Clear(void); 169 170 protected: 171 unsigned short mostRecentNewExternalPort; 172 void OnGetMostRecentPort(Packet *packet); 173 void OnConnectAtTime(Packet *packet); 174 unsigned int GetPendingOpenNATIndex(RakNetGUID destination, SystemAddress facilitator); 175 void SendPunchthrough(RakNetGUID destination, SystemAddress facilitator); 176 void SendTTL(SystemAddress sa); 177 void SendOutOfBand(SystemAddress sa, MessageID oobId); 178 void OnPunchthroughFailure(void); 179 void OnReadyForNextPunchthrough(void); 180 void PushFailure(void); 181 bool RemoveFromFailureQueue(void); 182 void PushSuccess(void); 183 //void ProcessNextPunchthroughQueue(void); 184 185 /* 186 struct PendingOpenNAT 187 { 188 RakNetGUID destination; 189 SystemAddress facilitator; 190 }; 191 DataStructures::List<PendingOpenNAT> pendingOpenNAT; 192 */ 193 194 struct SendPing 195 { 196 RakNetTime nextActionTime; 197 SystemAddress targetAddress; 198 SystemAddress facilitator; 199 SystemAddress internalIds[MAXIMUM_NUMBER_OF_INTERNAL_IDS]; 200 RakNetGUID targetGuid; 201 bool weAreSender; 202 int attemptCount; 203 int retryCount; 204 int punchingFixedPortAttempts; // only used for TestMode::PUNCHING_FIXED_PORT 205 uint16_t sessionId; 206 // Give priority to internal IP addresses because if we are on a LAN, we don't want to try to connect through the internet 207 enum TestMode 208 { 209 TESTING_INTERNAL_IPS, 210 WAITING_FOR_INTERNAL_IPS_RESPONSE, 211 TESTING_EXTERNAL_IPS_FROM_FACILITATOR_PORT, 212 TESTING_EXTERNAL_IPS_FROM_1024, 213 WAITING_AFTER_ALL_ATTEMPTS, 214 215 // The trendnet remaps the remote port to 1024. 216 // If you continue punching on a different port for the same IP it bans you and the communication becomes unidirectioal 217 PUNCHING_FIXED_PORT, 218 219 // try port 1024-1028 220 } testMode; 221 } sp; 222 223 PunchthroughConfiguration pc; 224 NatPunchthroughDebugInterface *natPunchthroughDebugInterface; 225 226 // The first time we fail a NAT attempt, we add it to failedAttemptList and try again, since sometimes trying again later fixes the problem 227 // The second time we fail, we return ID_NAT_PUNCHTHROUGH_FAILED 228 struct AddrAndGuid 229 { 230 SystemAddress addr; 231 RakNetGUID guid; 232 }; 233 DataStructures::List<AddrAndGuid> failedAttemptList; 234 }; 235 236 #endif 237 238 #endif // _RAKNET_SUPPORT_* 239