SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UDPProxyClient.cpp
Go to the documentation of this file.
1 /*
2 * Original work: 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 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
16 #include "slikenet/NativeFeatureIncludes.h"
17 #if _RAKNET_SUPPORT_UDPProxyClient==1
18
19 #include "slikenet/UDPProxyClient.h"
20 #include "slikenet/BitStream.h"
21 #include "slikenet/UDPProxyCommon.h"
22 #include "slikenet/peerinterface.h"
23 #include "slikenet/MessageIdentifiers.h"
24 #include "slikenet/GetTime.h"
25
26 using namespace SLNet;
27 static const int DEFAULT_UNRESPONSIVE_PING_TIME_COORDINATOR=1000;
28
29 // bool operator<( const DataStructures::MLKeyRef<UDPProxyClient::ServerWithPing> &inputKey, const UDPProxyClient::ServerWithPing &cls ) {return inputKey.Get().serverAddress < cls.serverAddress;}
30 // bool operator>( const DataStructures::MLKeyRef<UDPProxyClient::ServerWithPing> &inputKey, const UDPProxyClient::ServerWithPing &cls ) {return inputKey.Get().serverAddress > cls.serverAddress;}
31 // bool operator==( const DataStructures::MLKeyRef<UDPProxyClient::ServerWithPing> &inputKey, const UDPProxyClient::ServerWithPing &cls ) {return inputKey.Get().serverAddress == cls.serverAddress;}
32
33 STATIC_FACTORY_DEFINITIONS(UDPProxyClient,UDPProxyClient);
34
35 UDPProxyClient::UDPProxyClient()
36 {
37 resultHandler=0;
38 }
39 UDPProxyClient::~UDPProxyClient()
40 {
41 Clear();
42 }
43 void UDPProxyClient::SetResultHandler(UDPProxyClientResultHandler *rh)
44 {
45 resultHandler=rh;
46 }
47 bool UDPProxyClient::RequestForwarding(SystemAddress proxyCoordinator, SystemAddress sourceAddress, RakNetGUID targetGuid, SLNet::TimeMS timeoutOnNoDataMS, SLNet::BitStream *serverSelectionBitstream)
48 {
49 // Return false if not connected
50 ConnectionState cs = rakPeerInterface->GetConnectionState(proxyCoordinator);
51 if (cs!=IS_CONNECTED)
52 return false;
53
54 // Pretty much a bug not to set the result handler, as otherwise you won't know if the operation succeeed or not
55 RakAssert(resultHandler!=0);
56 if (resultHandler==0)
57 return false;
58
59 BitStream outgoingBs;
60 outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
61 outgoingBs.Write((MessageID)ID_UDP_PROXY_FORWARDING_REQUEST_FROM_CLIENT_TO_COORDINATOR);
62 outgoingBs.Write(sourceAddress);
63 outgoingBs.Write(false);
64 outgoingBs.Write(targetGuid);
65 outgoingBs.Write(timeoutOnNoDataMS);
66 if (serverSelectionBitstream && serverSelectionBitstream->GetNumberOfBitsUsed()>0)
67 {
68 outgoingBs.Write(true);
69 outgoingBs.Write(serverSelectionBitstream);
70 }
71 else
72 {
73 outgoingBs.Write(false);
74 }
75 rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, proxyCoordinator, false);
76
77 return true;
78 }
79 bool UDPProxyClient::RequestForwarding(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddressAsSeenFromCoordinator, SLNet::TimeMS timeoutOnNoDataMS, SLNet::BitStream *serverSelectionBitstream)
80 {
81 // Return false if not connected
82 ConnectionState cs = rakPeerInterface->GetConnectionState(proxyCoordinator);
83 if (cs!=IS_CONNECTED)
84 return false;
85
86 // Pretty much a bug not to set the result handler, as otherwise you won't know if the operation succeeed or not
87 RakAssert(resultHandler!=0);
88 if (resultHandler==0)
89 return false;
90
91 BitStream outgoingBs;
92 outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
93 outgoingBs.Write((MessageID)ID_UDP_PROXY_FORWARDING_REQUEST_FROM_CLIENT_TO_COORDINATOR);
94 outgoingBs.Write(sourceAddress);
95 outgoingBs.Write(true);
96 outgoingBs.Write(targetAddressAsSeenFromCoordinator);
97 outgoingBs.Write(timeoutOnNoDataMS);
98 if (serverSelectionBitstream && serverSelectionBitstream->GetNumberOfBitsUsed()>0)
99 {
100 outgoingBs.Write(true);
101 outgoingBs.Write(serverSelectionBitstream);
102 }
103 else
104 {
105 outgoingBs.Write(false);
106 }
107 rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, proxyCoordinator, false);
108
109 return true;
110 }
111 void UDPProxyClient::Update(void)
112 {
113 unsigned int idx1=0;
114 while (idx1 < pingServerGroups.Size())
115 {
116 PingServerGroup *psg = pingServerGroups[idx1];
117
118 if (psg->serversToPing.Size() > 0 &&
119 SLNet::GetTimeMS() > psg->startPingTime+DEFAULT_UNRESPONSIVE_PING_TIME_COORDINATOR)
120 {
121 // If they didn't reply within DEFAULT_UNRESPONSIVE_PING_TIME_COORDINATOR, just give up on them
122 psg->SendPingedServersToCoordinator(rakPeerInterface);
123
124 SLNet::OP_DELETE(psg,_FILE_AND_LINE_);
125 pingServerGroups.RemoveAtIndex(idx1);
126 }
127 else
128 idx1++;
129 }
130
131 }
132 PluginReceiveResult UDPProxyClient::OnReceive(Packet *packet)
133 {
134 if (packet->data[0]==ID_UNCONNECTED_PONG)
135 {
136 unsigned int idx1, idx2;
137 PingServerGroup *psg;
138 for (idx1=0; idx1 < pingServerGroups.Size(); idx1++)
139 {
140 psg = pingServerGroups[idx1];
141 for (idx2=0; idx2 < psg->serversToPing.Size(); idx2++)
142 {
143 if (psg->serversToPing[idx2].serverAddress==packet->systemAddress)
144 {
145 SLNet::BitStream bsIn(packet->data,packet->length,false);
146 bsIn.IgnoreBytes(sizeof(MessageID));
147 SLNet::TimeMS sentTime;
148 bsIn.Read(sentTime);
149 SLNet::TimeMS curTime = SLNet::GetTimeMS();
150 int ping;
151 if (curTime>sentTime)
152 ping=(int) (curTime-sentTime);
153 else
154 ping=0;
155 psg->serversToPing[idx2].ping=(unsigned short) ping;
156
157 // If all servers to ping are now pinged, reply to coordinator
158 if (psg->AreAllServersPinged())
159 {
160 psg->SendPingedServersToCoordinator(rakPeerInterface);
161 SLNet::OP_DELETE(psg,_FILE_AND_LINE_);
162 pingServerGroups.RemoveAtIndex(idx1);
163 }
164
165 return RR_STOP_PROCESSING_AND_DEALLOCATE;
166 }
167 }
168
169 }
170 }
171 else if (packet->data[0]==ID_UDP_PROXY_GENERAL && packet->length>1)
172 {
173 switch (packet->data[1])
174 {
175 case ID_UDP_PROXY_PING_SERVERS_FROM_COORDINATOR_TO_CLIENT:
176 {
177 OnPingServers(packet);
178 }
179 break;
180 case ID_UDP_PROXY_FORWARDING_SUCCEEDED:
181 case ID_UDP_PROXY_ALL_SERVERS_BUSY:
182 case ID_UDP_PROXY_IN_PROGRESS:
183 case ID_UDP_PROXY_NO_SERVERS_ONLINE:
184 case ID_UDP_PROXY_RECIPIENT_GUID_NOT_CONNECTED_TO_COORDINATOR:
185 case ID_UDP_PROXY_FORWARDING_NOTIFICATION:
186 {
187 RakNetGUID targetGuid;
188 SystemAddress senderAddress, targetAddress;
189 SLNet::BitStream incomingBs(packet->data, packet->length, false);
190 incomingBs.IgnoreBytes(sizeof(MessageID)*2);
191 incomingBs.Read(senderAddress);
192 incomingBs.Read(targetAddress);
193 incomingBs.Read(targetGuid);
194
195 switch (packet->data[1])
196 {
197 case ID_UDP_PROXY_FORWARDING_NOTIFICATION:
198 case ID_UDP_PROXY_FORWARDING_SUCCEEDED:
199 case ID_UDP_PROXY_IN_PROGRESS:
200 {
201 unsigned short forwardingPort;
202 SLNet::RakString serverIP;
203 incomingBs.Read(serverIP);
204 incomingBs.Read(forwardingPort);
205 if (packet->data[1]==ID_UDP_PROXY_FORWARDING_SUCCEEDED)
206 {
207 if (resultHandler)
208 resultHandler->OnForwardingSuccess(serverIP.C_String(), forwardingPort, packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
209 }
210 else if (packet->data[1]==ID_UDP_PROXY_IN_PROGRESS)
211 {
212 if (resultHandler)
213 resultHandler->OnForwardingInProgress(serverIP.C_String(), forwardingPort, packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
214 }
215 else
216 {
217 // Send a datagram to the proxy, so if we are behind a router, that router adds an entry to the routing table.
218 // Otherwise the router would block the incoming datagrams from source
219 // It doesn't matter if the message actually arrives as long as it goes through the router
220 rakPeerInterface->Ping(serverIP.C_String(), forwardingPort, false);
221
222 if (resultHandler)
223 resultHandler->OnForwardingNotification(serverIP.C_String(), forwardingPort, packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
224 }
225 }
226 break;
227 case ID_UDP_PROXY_ALL_SERVERS_BUSY:
228 if (resultHandler)
229 resultHandler->OnAllServersBusy(packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
230 break;
231 case ID_UDP_PROXY_NO_SERVERS_ONLINE:
232 if (resultHandler)
233 resultHandler->OnNoServersOnline(packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
234 break;
235 case ID_UDP_PROXY_RECIPIENT_GUID_NOT_CONNECTED_TO_COORDINATOR:
236 {
237 if (resultHandler)
238 resultHandler->OnRecipientNotConnected(packet->systemAddress, senderAddress, targetAddress, targetGuid, this);
239 break;
240 }
241 }
242
243 }
244 return RR_STOP_PROCESSING_AND_DEALLOCATE;
245 }
246 }
247 return RR_CONTINUE_PROCESSING;
248 }
249 void UDPProxyClient::OnRakPeerShutdown(void)
250 {
251 Clear();
252 }
253 void UDPProxyClient::OnPingServers(Packet *packet)
254 {
255 SLNet::BitStream incomingBs(packet->data, packet->length, false);
256 incomingBs.IgnoreBytes(2);
257
258 PingServerGroup *psg = SLNet::OP_NEW<PingServerGroup>(_FILE_AND_LINE_);
259
260 ServerWithPing swp;
261 incomingBs.Read(psg->sata.senderClientAddress);
262 incomingBs.Read(psg->sata.targetClientAddress);
263 // #med - might be possible to drop - see pull request 35 - however kept as is to ensure ABI
264 // compatibility to RakNet in MaxNet 0.x - see #39
265 RakNetGUID targetGuid;
266 incomingBs.Read(targetGuid);
267 psg->startPingTime= SLNet::GetTimeMS();
268 psg->coordinatorAddressForPings=packet->systemAddress;
269 unsigned short serverListSize;
270 incomingBs.Read(serverListSize);
271 SystemAddress serverAddress;
272 unsigned short serverListIndex;
273 char ipStr[64];
274 for (serverListIndex=0; serverListIndex<serverListSize; serverListIndex++)
275 {
276 incomingBs.Read(swp.serverAddress);
277 swp.ping=DEFAULT_UNRESPONSIVE_PING_TIME_COORDINATOR;
278 psg->serversToPing.Push(swp, _FILE_AND_LINE_ );
279 swp.serverAddress.ToString(false,ipStr,static_cast<size_t>(64));
280 rakPeerInterface->Ping(ipStr,swp.serverAddress.GetPort(),false,0);
281 }
282 pingServerGroups.Push(psg,_FILE_AND_LINE_);
283 }
284
285 bool UDPProxyClient::PingServerGroup::AreAllServersPinged(void) const
286 {
287 unsigned int serversToPingIndex;
288 for (serversToPingIndex=0; serversToPingIndex < serversToPing.Size(); serversToPingIndex++)
289 {
290 if (serversToPing[serversToPingIndex].ping==DEFAULT_UNRESPONSIVE_PING_TIME_COORDINATOR)
291 return false;
292 }
293 return true;
294 }
295
296 void UDPProxyClient::PingServerGroup::SendPingedServersToCoordinator(RakPeerInterface *rakPeer)
297 {
298 BitStream outgoingBs;
299 outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
300 outgoingBs.Write((MessageID)ID_UDP_PROXY_PING_SERVERS_REPLY_FROM_CLIENT_TO_COORDINATOR);
301 outgoingBs.Write(sata.senderClientAddress);
302 outgoingBs.Write(sata.targetClientAddress);
303 unsigned short serversToPingSize = (unsigned short) serversToPing.Size();
304 outgoingBs.Write(serversToPingSize);
305 unsigned int serversToPingIndex;
306 for (serversToPingIndex=0; serversToPingIndex < serversToPingSize; serversToPingIndex++)
307 {
308 outgoingBs.Write(serversToPing[serversToPingIndex].serverAddress);
309 outgoingBs.Write(serversToPing[serversToPingIndex].ping);
310 }
311 rakPeer->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, coordinatorAddressForPings, false);
312 }
313 void UDPProxyClient::Clear(void)
314 {
315 for (unsigned int i=0; i < pingServerGroups.Size(); i++)
316 SLNet::OP_DELETE(pingServerGroups[i],_FILE_AND_LINE_);
317 pingServerGroups.Clear(false, _FILE_AND_LINE_);
318 }
319
320
321 #endif // _RAKNET_SUPPORT_*
322