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
NatTypeDetectionServer.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_NatTypeDetectionServer==1
18
19 #include "slikenet/NatTypeDetectionServer.h"
20 #include "slikenet/SocketLayer.h"
21 #include "slikenet/smartptr.h"
22 #include "slikenet/SocketIncludes.h"
23 #include "slikenet/peerinterface.h"
24 #include "slikenet/MessageIdentifiers.h"
25 #include "slikenet/GetTime.h"
26 #include "slikenet/BitStream.h"
27 #include "slikenet/SocketDefines.h"
28 #include "slikenet/linux_adapter.h"
29 #include "slikenet/osx_adapter.h"
30
31 // #define NTDS_VERBOSE
32
33 using namespace SLNet;
34
35 STATIC_FACTORY_DEFINITIONS(NatTypeDetectionServer,NatTypeDetectionServer);
36
37 NatTypeDetectionServer::NatTypeDetectionServer()
38 {
39 s1p2=s2p3=s3p4=s4p5=0;
40 }
41 NatTypeDetectionServer::~NatTypeDetectionServer()
42 {
43 Shutdown();
44 }
45 void NatTypeDetectionServer::Startup(
46 const char *nonRakNetIP2,
47 const char *nonRakNetIP3,
48 const char *nonRakNetIP4
49 #ifdef __native_client__
50 ,_PP_Instance_ chromeInstance
51 #endif
52 )
53 {
54 DataStructures::List<RakNetSocket2* > sockets;
55 rakPeerInterface->GetSockets(sockets);
56 char str[64];
57 sockets[0]->GetBoundAddress().ToString(false,str,static_cast<size_t>(64));
58 s1p2=
59 CreateNonblockingBoundSocket(str,
60 #ifdef __native_client__
61 chromeInstance,
62 #endif
63 this);
64
65 s2p3=
66 CreateNonblockingBoundSocket(nonRakNetIP2,
67 #ifdef __native_client__
68 chromeInstance,
69 #endif
70 this);
71
72
73 s3p4=
74 CreateNonblockingBoundSocket(nonRakNetIP3,
75 #ifdef __native_client__
76 chromeInstance,
77 #endif
78 this);
79
80 s4p5=
81 CreateNonblockingBoundSocket(nonRakNetIP4,
82 #ifdef __native_client__
83 chromeInstance,
84 #endif
85 this);
86
87 strcpy_s(s3p4Address, nonRakNetIP3);
88
89
90 #if !defined(__native_client__) && !defined(WINDOWS_STORE_RT)
91 if (s3p4->IsBerkleySocket())
92 ((RNS2_Berkley*) s3p4)->CreateRecvPollingThread(0);
93 #endif
94 }
95 void NatTypeDetectionServer::Shutdown()
96 {
97 if (s1p2!=0)
98 {
99 SLNet::OP_DELETE(s1p2,_FILE_AND_LINE_);
100 s1p2=0;
101 }
102 if (s2p3!=0)
103 {
104 SLNet::OP_DELETE(s2p3,_FILE_AND_LINE_);
105 s2p3=0;
106 }
107 if (s3p4!=0)
108 {
109 #if !defined(__native_client__) && !defined(WINDOWS_STORE_RT)
110 if (s3p4->IsBerkleySocket())
111 ((RNS2_Berkley *)s3p4)->BlockOnStopRecvPollingThread();
112 #endif
113
114 SLNet::OP_DELETE(s3p4,_FILE_AND_LINE_);
115 s3p4=0;
116 }
117 if (s4p5!=0)
118 {
119 SLNet::OP_DELETE(s4p5,_FILE_AND_LINE_);
120 s4p5=0;
121 }
122 bufferedPacketsMutex.Lock();
123 while (bufferedPackets.Size())
124 SLNet::OP_DELETE(bufferedPackets.Pop(), _FILE_AND_LINE_);
125 bufferedPacketsMutex.Unlock();
126 }
127 void NatTypeDetectionServer::Update(void)
128 {
129 int i=0;
130 SLNet::TimeMS time = SLNet::GetTimeMS();
131 SLNet::BitStream bs;
132 SystemAddress boundAddress;
133
134 RNS2RecvStruct *recvStruct;
135 bufferedPacketsMutex.Lock();
136 if (bufferedPackets.Size()>0)
137 recvStruct=bufferedPackets.Pop();
138 else
139 recvStruct=0;
140 bufferedPacketsMutex.Unlock();
141 while (recvStruct)
142 {
143 SystemAddress senderAddr = recvStruct->systemAddress;
144 char *data = recvStruct->data;
145 if (data[0]==NAT_TYPE_PORT_RESTRICTED && recvStruct->socket==s3p4)
146 {
147 SLNet::BitStream bsIn((unsigned char*) data,recvStruct->bytesRead,false);
148 RakNetGUID senderGuid;
149 bsIn.IgnoreBytes(sizeof(MessageID));
150 bool readSuccess = bsIn.Read(senderGuid);
151 RakAssert(readSuccess);
152 if (readSuccess)
153 {
154 unsigned int j = GetDetectionAttemptIndex(senderGuid);
155 if (j!=(unsigned int)-1)
156 {
157 bs.Reset();
158 bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_RESULT);
159 // If different, then symmetric
160 if (senderAddr!=natDetectionAttempts[j].systemAddress)
161 {
162
163 #ifdef NTDS_VERBOSE
164 printf("Determined client is symmetric\n");
165 #endif
166 bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
167 }
168 else
169 {
170 // else port restricted
171 #ifdef NTDS_VERBOSE
172
173 printf("Determined client is port restricted\n");
174 #endif
175 bs.Write((unsigned char) NAT_TYPE_PORT_RESTRICTED);
176 }
177
178 rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[j].systemAddress,false);
179
180 // Done
181 natDetectionAttempts.RemoveAtIndexFast(j);
182 }
183 else
184 {
185 // RakAssert("j==0 in Update when looking up GUID in NatTypeDetectionServer.cpp. Either a bug or a late resend" && 0);
186 }
187 }
188 else
189 {
190 // RakAssert("Didn't read GUID in Update in NatTypeDetectionServer.cpp. Message format error" && 0);
191 }
192 }
193
194 DeallocRNS2RecvStruct(recvStruct, _FILE_AND_LINE_);
195 bufferedPacketsMutex.Lock();
196 if (bufferedPackets.Size()>0)
197 recvStruct=bufferedPackets.Pop();
198 else
199 recvStruct=0;
200 bufferedPacketsMutex.Unlock();
201 }
202
203 /*
204
205 // Only socket that receives messages is s3p4, to see if the external address is different than that of the connection to rakPeerInterface
206 char data[ MAXIMUM_MTU_SIZE ];
207 int len;
208 SystemAddress senderAddr;
209 len=NatTypeRecvFrom(data, s3p4, senderAddr);
210 // Client is asking us if this is port restricted. Only client requests of this type come in on s3p4
211 while (len>0 && data[0]==NAT_TYPE_PORT_RESTRICTED)
212 {
213 SLNet::BitStream bsIn((unsigned char*) data,len,false);
214 RakNetGUID senderGuid;
215 bsIn.IgnoreBytes(sizeof(MessageID));
216 bool readSuccess = bsIn.Read(senderGuid);
217 RakAssert(readSuccess);
218 if (readSuccess)
219 {
220 unsigned int i = GetDetectionAttemptIndex(senderGuid);
221 if (i!=(unsigned int)-1)
222 {
223 bs.Reset();
224 bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_RESULT);
225 // If different, then symmetric
226 if (senderAddr!=natDetectionAttempts[i].systemAddress)
227 {
228
229 #ifdef NTDS_VERBOSE
230 printf("Determined client is symmetric\n");
231 #endif
232 bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
233 }
234 else
235 {
236 // else port restricted
237
238 #ifdef NTDS_VERBOSE
239 printf("Determined client is port restricted\n");
240 #endif
241 bs.Write((unsigned char) NAT_TYPE_PORT_RESTRICTED);
242 }
243
244 rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
245
246 // Done
247 natDetectionAttempts.RemoveAtIndexFast(i);
248 }
249 else
250 {
251 // RakAssert("i==0 in Update when looking up GUID in NatTypeDetectionServer.cpp. Either a bug or a late resend" && 0);
252 }
253 }
254 else
255 {
256 // RakAssert("Didn't read GUID in Update in NatTypeDetectionServer.cpp. Message format error" && 0);
257 }
258
259 len=NatTypeRecvFrom(data, s3p4, senderAddr);
260 }
261 */
262
263
264 while (i < (int) natDetectionAttempts.Size())
265 {
266 if (time > natDetectionAttempts[i].nextStateTime)
267 {
268 RNS2_SendParameters bsp;
269 natDetectionAttempts[i].detectionState=(NATDetectionState)((int)natDetectionAttempts[i].detectionState+1);
270 natDetectionAttempts[i].nextStateTime=time+natDetectionAttempts[i].timeBetweenAttempts;
271 SystemAddress saOut;
272 unsigned char c;
273 bs.Reset();
274 switch (natDetectionAttempts[i].detectionState)
275 {
276 case STATE_TESTING_NONE_1:
277 case STATE_TESTING_NONE_2:
278 c = NAT_TYPE_NONE;
279
280 #ifdef NTDS_VERBOSE
281 printf("Testing NAT_TYPE_NONE\n");
282 #endif
283 // S4P5 sends to C2. If arrived, no NAT. Done. (Else S4P5 potentially banned, do not use again).
284 saOut=natDetectionAttempts[i].systemAddress;
285 saOut.SetPortHostOrder(natDetectionAttempts[i].c2Port);
286 // SocketLayer::SendTo_PC( s4p5, (const char*) &c, 1, saOut, __FILE__, __LINE__ );
287 bsp.data = (char*) &c;
288 bsp.length = 1;
289 bsp.systemAddress = saOut;
290 s4p5->Send(&bsp, _FILE_AND_LINE_);
291 break;
292 case STATE_TESTING_FULL_CONE_1:
293 case STATE_TESTING_FULL_CONE_2:
294
295 #ifdef NTDS_VERBOSE
296 printf("Testing NAT_TYPE_FULL_CONE\n");
297 #endif
298 rakPeerInterface->WriteOutOfBandHeader(&bs);
299 bs.Write((unsigned char) ID_NAT_TYPE_DETECT);
300 bs.Write((unsigned char) NAT_TYPE_FULL_CONE);
301 // S2P3 sends to C1 (Different address, different port, to previously used port on client). If received, Full-cone nat. Done. (Else S2P3 potentially banned, do not use again).
302 saOut=natDetectionAttempts[i].systemAddress;
303 saOut.SetPortHostOrder(natDetectionAttempts[i].systemAddress.GetPort());
304 // SocketLayer::SendTo_PC( s2p3, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__ );
305 bsp.data = (char*) bs.GetData();
306 bsp.length = bs.GetNumberOfBytesUsed();
307 bsp.systemAddress = saOut;
308 s2p3->Send(&bsp, _FILE_AND_LINE_);
309 break;
310 case STATE_TESTING_ADDRESS_RESTRICTED_1:
311 case STATE_TESTING_ADDRESS_RESTRICTED_2:
312
313 #ifdef NTDS_VERBOSE
314 printf("Testing NAT_TYPE_ADDRESS_RESTRICTED\n");
315 #endif
316 rakPeerInterface->WriteOutOfBandHeader(&bs);
317 bs.Write((unsigned char) ID_NAT_TYPE_DETECT);
318 bs.Write((unsigned char) NAT_TYPE_ADDRESS_RESTRICTED);
319 // S1P2 sends to C1 (Same address, different port, to previously used port on client). If received, address-restricted cone nat. Done.
320 saOut=natDetectionAttempts[i].systemAddress;
321 saOut.SetPortHostOrder(natDetectionAttempts[i].systemAddress.GetPort());
322 //SocketLayer::SendTo_PC( s1p2, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__ );
323 bsp.data = (char*) bs.GetData();
324 bsp.length = bs.GetNumberOfBytesUsed();
325 bsp.systemAddress = saOut;
326 s1p2->Send(&bsp, _FILE_AND_LINE_);
327 break;
328 case STATE_TESTING_PORT_RESTRICTED_1:
329 case STATE_TESTING_PORT_RESTRICTED_2:
330 // C1 sends to S3P4. If address of C1 as seen by S3P4 is the same as the address of C1 as seen by S1P1, then port-restricted cone nat. Done
331
332 #ifdef NTDS_VERBOSE
333 printf("Testing NAT_TYPE_PORT_RESTRICTED\n");
334 #endif
335 bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_REQUEST);
336 bs.Write(RakString::NonVariadic(s3p4Address));
337 bs.Write(s3p4->GetBoundAddress().GetPort());
338 rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
339 break;
340 default:
341
342 #ifdef NTDS_VERBOSE
343 printf("Warning, exceeded final check STATE_TESTING_PORT_RESTRICTED_2.\nExpected that client would have sent NAT_TYPE_PORT_RESTRICTED on s3p4.\nDefaulting to Symmetric\n");
344 #endif
345 bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_RESULT);
346 bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
347 rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
348 natDetectionAttempts.RemoveAtIndexFast(i);
349 i--;
350 break;
351 }
352
353 }
354 i++;
355 }
356 }
357 PluginReceiveResult NatTypeDetectionServer::OnReceive(Packet *packet)
358 {
359 switch (packet->data[0])
360 {
361 case ID_NAT_TYPE_DETECTION_REQUEST:
362 OnDetectionRequest(packet);
363 return RR_STOP_PROCESSING_AND_DEALLOCATE;
364 }
365 return RR_CONTINUE_PROCESSING;
366 }
367 void NatTypeDetectionServer::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
368 {
369 (void) lostConnectionReason;
370 (void) rakNetGUID;
371
372 unsigned int i = GetDetectionAttemptIndex(systemAddress);
373 if (i==(unsigned int)-1)
374 return;
375 natDetectionAttempts.RemoveAtIndexFast(i);
376 }
377 void NatTypeDetectionServer::OnDetectionRequest(Packet *packet)
378 {
379 unsigned int i = GetDetectionAttemptIndex(packet->systemAddress);
380
381 SLNet::BitStream bsIn(packet->data, packet->length, false);
382 bsIn.IgnoreBytes(1);
383 bool isRequest=false;
384 bsIn.Read(isRequest);
385 if (isRequest)
386 {
387 if (i!=(unsigned int)-1)
388 return; // Already in progress
389
390 NATDetectionAttempt nda;
391 nda.detectionState=STATE_NONE;
392 nda.systemAddress=packet->systemAddress;
393 nda.guid=packet->guid;
394 bsIn.Read(nda.c2Port);
395 nda.nextStateTime=0;
396 nda.timeBetweenAttempts=rakPeerInterface->GetLastPing(nda.systemAddress)*3+50;
397 natDetectionAttempts.Push(nda, _FILE_AND_LINE_);
398 }
399 else
400 {
401 if (i==(unsigned int)-1)
402 return; // Unknown
403 // They are done
404 natDetectionAttempts.RemoveAtIndexFast(i);
405 }
406
407 }
408 unsigned int NatTypeDetectionServer::GetDetectionAttemptIndex(const SystemAddress &sa)
409 {
410 for (unsigned int i=0; i < natDetectionAttempts.Size(); i++)
411 {
412 if (natDetectionAttempts[i].systemAddress==sa)
413 return i;
414 }
415 return (unsigned int) -1;
416 }
417 unsigned int NatTypeDetectionServer::GetDetectionAttemptIndex(RakNetGUID guid)
418 {
419 for (unsigned int i=0; i < natDetectionAttempts.Size(); i++)
420 {
421 if (natDetectionAttempts[i].guid==guid)
422 return i;
423 }
424 return (unsigned int) -1;
425 }
426
427 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
428 void NatTypeDetectionServer::DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line)
429 {
430 SLNet::OP_DELETE(s, file, line);
431 }
432 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
433 RNS2RecvStruct *NatTypeDetectionServer::AllocRNS2RecvStruct(const char *file, unsigned int line)
434 {
435 return SLNet::OP_NEW<RNS2RecvStruct>(file,line);
436 }
437
438 void NatTypeDetectionServer::OnRNS2Recv(RNS2RecvStruct *recvStruct)
439 {
440 bufferedPacketsMutex.Lock();
441 bufferedPackets.Push(recvStruct,_FILE_AND_LINE_);
442 bufferedPacketsMutex.Unlock();
443 }
444
445 #endif // _RAKNET_SUPPORT_*