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
HTTPConnection2.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-2017, 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_HTTPConnection2==1 && _RAKNET_SUPPORT_TCPInterface==1
18
19 #include "slikenet/HTTPConnection2.h"
20 #include "slikenet/TCPInterface.h"
21
22 using namespace SLNet;
23
24 STATIC_FACTORY_DEFINITIONS(HTTPConnection2,HTTPConnection2);
25
26 HTTPConnection2::HTTPConnection2()
27 {
28 }
29 HTTPConnection2::~HTTPConnection2()
30 {
31
32 }
33 bool HTTPConnection2::TransmitRequest(const char* stringToTransmit, const char* host, unsigned short port, bool useSSL, int ipVersion, SystemAddress useAddress, void *userData)
34 {
35 Request *request = SLNet::OP_NEW<Request>(_FILE_AND_LINE_);
36 request->host=host;
37 request->chunked = false;
38 if (useAddress!=UNASSIGNED_SYSTEM_ADDRESS)
39 {
40 request->hostEstimatedAddress=useAddress;
41 if (IsConnected(useAddress)==false)
42 {
43 SLNet::OP_DELETE(request, _FILE_AND_LINE_);
44 return false;
45 }
46 }
47 else
48 {
49 if (request->hostEstimatedAddress.FromString(host, '|', ipVersion)==false)
50 {
51 SLNet::OP_DELETE(request, _FILE_AND_LINE_);
52 return false;
53 }
54 }
55 request->hostEstimatedAddress.SetPortHostOrder(port);
56 request->port=port;
57 request->stringToTransmit=stringToTransmit;
58 request->contentLength=-1;
59 request->contentOffset=0;
60 request->useSSL=useSSL;
61 request->ipVersion=ipVersion;
62 request->userData=userData;
63
64 if (IsConnected(request->hostEstimatedAddress))
65 {
66 sentRequestsMutex.Lock();
67 if (sentRequests.Size()==0)
68 {
69 request->hostCompletedAddress=request->hostEstimatedAddress;
70 sentRequests.Push(request, _FILE_AND_LINE_);
71 sentRequestsMutex.Unlock();
72
73 SendRequest(request);
74 }
75 else
76 {
77 // Request pending, push it
78 pendingRequestsMutex.Lock();
79 pendingRequests.Push(request, _FILE_AND_LINE_);
80 pendingRequestsMutex.Unlock();
81
82 sentRequestsMutex.Unlock();
83 }
84 }
85 else
86 {
87 pendingRequestsMutex.Lock();
88 pendingRequests.Push(request, _FILE_AND_LINE_);
89 pendingRequestsMutex.Unlock();
90
91 if (ipVersion!=6)
92 {
93 tcpInterface->Connect(host, port, false, AF_INET);
94 }
95 else
96 {
97 #if RAKNET_SUPPORT_IPV6
98 tcpInterface->Connect(host, port, false, AF_INET6);
99 #else
100 RakAssert("HTTPConnection2::TransmitRequest needs define RAKNET_SUPPORT_IPV6" && 0);
101 #endif
102 }
103 }
104 return true;
105 }
106 bool HTTPConnection2::GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, ptrdiff_t &contentOffset )
107 {
108 void *userData;
109 return GetResponse(stringTransmitted, hostTransmitted, responseReceived, hostReceived, contentOffset, &userData);
110
111 }
112 bool HTTPConnection2::GetResponse( RakString &stringTransmitted, RakString &hostTransmitted, RakString &responseReceived, SystemAddress &hostReceived, ptrdiff_t &contentOffset, void **userData )
113 {
114 completedRequestsMutex.Lock();
115 if (completedRequests.Size()>0)
116 {
117 Request *completedRequest = completedRequests[0];
118 completedRequests.RemoveAtIndexFast(0);
119 completedRequestsMutex.Unlock();
120
121 responseReceived = completedRequest->stringReceived;
122 hostReceived = completedRequest->hostCompletedAddress;
123 stringTransmitted = completedRequest->stringToTransmit;
124 hostTransmitted = completedRequest->host;
125 contentOffset = completedRequest->contentOffset;
126 *userData = completedRequest->userData;
127
128 SLNet::OP_DELETE(completedRequest, _FILE_AND_LINE_);
129 return true;
130 }
131 else
132 {
133 completedRequestsMutex.Unlock();
134 }
135 return false;
136 }
137 bool HTTPConnection2::IsBusy(void) const
138 {
139 return pendingRequests.Size()>0 || sentRequests.Size()>0;
140 }
141 bool HTTPConnection2::HasResponse(void) const
142 {
143 return completedRequests.Size()>0;
144 }
145 int ReadChunkSize( char *txtStart, char **txtEnd )
146 {
147 // char lengthStr[32];
148 // memset(lengthStr, 0, 32);
149 // memcpy(lengthStr, txtStart, txtEnd - txtStart);
150 return strtoul(txtStart, txtEnd,16);
151 // return atoi(lengthStr);
152 }
153 void ReadChunkBlock( size_t &currentChunkSize, size_t &bytesReadSoFar, char *txtIn, RakString &txtOut)
154 {
155 size_t bytesToRead;
156 size_t sLen;
157
158 do
159 {
160 bytesToRead = currentChunkSize - bytesReadSoFar;
161 sLen = strlen(txtIn);
162 if (sLen < bytesToRead)
163 bytesToRead = sLen;
164 txtOut.AppendBytes(txtIn, bytesToRead);
165 txtIn += bytesToRead;
166 bytesReadSoFar += bytesToRead;
167 if (*txtIn == 0)
168 {
169 // currentChunkSize=0;
170 return;
171 }
172 // char *newLine = strstr(txtIn, "\r\n");
173 if (txtIn[0] && txtIn[0]=='\r' && txtIn[1] && txtIn[1]=='\n' )
174 txtIn += 2; // Newline
175 char *newLine;
176 currentChunkSize = ReadChunkSize(txtIn, &newLine);
177 RakAssert(currentChunkSize < 50000); // Sanity check
178 if (currentChunkSize == 0)
179 return;
180 if (newLine == 0)
181 return;
182 bytesReadSoFar=0;
183 txtIn = newLine + 2;
184 } while (txtIn);
185 }
186 PluginReceiveResult HTTPConnection2::OnReceive(Packet *packet)
187 {
188 unsigned int i;
189
190 bool locked=true;
191 sentRequestsMutex.Lock();
192 for (i=0; i < sentRequests.Size(); i++)
193 {
194 Request *sentRequest = sentRequests[i];
195 if (sentRequest->hostCompletedAddress==packet->systemAddress)
196 {
197 sentRequests.RemoveAtIndexFast(i);
198 locked=false;
199 sentRequestsMutex.Unlock();
200
201 /*
202 static FILE * pFile = 0;
203 if (pFile==0)
204 {
205 long lSize;
206 char * buffer;
207 size_t result;
208
209 pFile = fopen ( "string_received.txt" , "rb" );
210 if (pFile==NULL) {fputs ("File error",stderr); exit (1);}
211
212 // obtain file size:
213 fseek (pFile , 0 , SEEK_END);
214 lSize = ftell (pFile);
215 rewind (pFile);
216
217 // allocate memory to contain the whole file:
218 buffer = (char*) malloc (sizeof(char)*lSize);
219 if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}
220
221 // copy the file into the buffer:
222 result = fread (buffer,1,lSize,pFile);
223 if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
224
225 packet->data=(unsigned char*) buffer;
226 packet->length=lSize;
227 }
228 */
229
230
231 const char *isFirstChunk = strstr((char*) packet->data, "Transfer-Encoding: chunked");
232 if (isFirstChunk)
233 {
234 //printf((char*) packet->data);
235
236 locked=false;
237 sentRequestsMutex.Unlock();
238
239 sentRequest->chunked = true;
240 char *chunkStrStart = strstr((char*) packet->data, "\r\n\r\n");
241 RakAssert(chunkStrStart);
242
243 chunkStrStart += 4; // strlen("\r\n\r\n");
244 char *body_header; // = strstr(chunkStrStart, "\r\n");
245 sentRequest->thisChunkSize = ReadChunkSize(chunkStrStart, &body_header);
246 sentRequest->bytesReadForThisChunk = 0;
247 sentRequest->contentOffset = 0;
248
249 if (sentRequest->thisChunkSize == 0)
250 {
251 // Done
252 completedRequestsMutex.Lock();
253 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
254 completedRequestsMutex.Unlock();
255
256 // If there is another command waiting for this server, send it
257 SendPendingRequestToConnectedSystem(packet->systemAddress);
258 }
259 else
260 {
261
262 // char *offset = strstr((char*) packet->data+1, "2000");
263
264 body_header+=2;
265 ReadChunkBlock(sentRequest->thisChunkSize, sentRequest->bytesReadForThisChunk, body_header, sentRequest->stringReceived);
266
267 if (sentRequest->thisChunkSize==0)
268 {
269 // Done
270 completedRequestsMutex.Lock();
271 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
272 completedRequestsMutex.Unlock();
273
274 // If there is another command waiting for this server, send it
275 SendPendingRequestToConnectedSystem(packet->systemAddress);
276 }
277 else
278 {
279 // Not done
280 sentRequestsMutex.Lock();
281 sentRequests.Push(sentRequest, _FILE_AND_LINE_);
282 sentRequestsMutex.Unlock();
283 }
284 }
285 }
286 else if (sentRequest->chunked)
287 {
288 ReadChunkBlock(sentRequest->thisChunkSize, sentRequest->bytesReadForThisChunk, (char*) packet->data, sentRequest->stringReceived);
289
290 if (sentRequest->thisChunkSize==0)
291 {
292 // Done
293 completedRequestsMutex.Lock();
294 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
295 completedRequestsMutex.Unlock();
296
297 // If there is another command waiting for this server, send it
298 SendPendingRequestToConnectedSystem(packet->systemAddress);
299 }
300 else
301 {
302 // Not done
303 sentRequestsMutex.Lock();
304 sentRequests.Push(sentRequest, _FILE_AND_LINE_);
305 sentRequestsMutex.Unlock();
306 }
307
308 }
309 else
310 {
311 sentRequest->stringReceived+=packet->data;
312
313 if (sentRequest->contentLength==-1)
314 {
315 const char *length_header = strstr(sentRequest->stringReceived.C_String(), "Content-Length: ");
316 if(length_header)
317 {
318 length_header += 16; // strlen("Content-Length: ");
319
320 unsigned int clLength;
321 for (clLength=0; length_header[clLength] && length_header[clLength] >= '0' && length_header[clLength] <= '9'; clLength++)
322 ;
323 if (clLength>0 && (length_header[clLength]=='\r' || length_header[clLength]=='\n'))
324 {
325 sentRequest->contentLength = RakString::ReadIntFromSubstring(length_header, 0, clLength);
326 }
327 }
328 }
329
330 // If we know the content length, find \r\n\r\n
331 if (sentRequest->contentLength != -1)
332 {
333 if (sentRequest->contentLength > 0)
334 {
335 const char *body_header = strstr(sentRequest->stringReceived.C_String(), "\r\n\r\n");
336 if (body_header)
337 {
338 body_header += 4; // strlen("\r\n\r\n");
339 size_t slen = strlen(body_header);
340 //RakAssert(slen <= (size_t) sentRequest->contentLength);
341 if (slen >= (size_t) sentRequest->contentLength)
342 {
343 sentRequest->contentOffset = body_header - sentRequest->stringReceived.C_String();
344 completedRequestsMutex.Lock();
345 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
346 completedRequestsMutex.Unlock();
347
348 // If there is another command waiting for this server, send it
349 SendPendingRequestToConnectedSystem(packet->systemAddress);
350 }
351 else
352 {
353 sentRequestsMutex.Lock();
354 sentRequests.Push(sentRequest, _FILE_AND_LINE_);
355 sentRequestsMutex.Unlock();
356 }
357 }
358
359 else
360 {
361 sentRequestsMutex.Lock();
362 sentRequests.Push(sentRequest, _FILE_AND_LINE_);
363 sentRequestsMutex.Unlock();
364 }
365 }
366 else
367 {
368 sentRequest->contentOffset=-1;
369 completedRequestsMutex.Lock();
370 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
371 completedRequestsMutex.Unlock();
372
373 // If there is another command waiting for this server, send it
374 SendPendingRequestToConnectedSystem(packet->systemAddress);
375 }
376 }
377 else
378 {
379 const char *firstNewlineSet = strstr(sentRequest->stringReceived.C_String(), "\r\n\r\n");
380 if (firstNewlineSet!=0)
381 {
382 ptrdiff_t offset = firstNewlineSet - sentRequest->stringReceived.C_String();
383 if (sentRequest->stringReceived.C_String()[offset+4]==0)
384 sentRequest->contentOffset=-1;
385 else
386 sentRequest->contentOffset=offset+4;
387 completedRequestsMutex.Lock();
388 completedRequests.Push(sentRequest, _FILE_AND_LINE_);
389 completedRequestsMutex.Unlock();
390
391 // If there is another command waiting for this server, send it
392 SendPendingRequestToConnectedSystem(packet->systemAddress);
393 }
394 else
395 {
396 sentRequestsMutex.Lock();
397 sentRequests.Push(sentRequest, _FILE_AND_LINE_);
398 sentRequestsMutex.Unlock();
399 }
400 }
401 }
402
403
404 break;
405 }
406 }
407
408 if (locked==true)
409 sentRequestsMutex.Unlock();
410
411 return RR_CONTINUE_PROCESSING;
412 }
413
414 void HTTPConnection2::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
415 {
416 (void) rakNetGUID;
417 (void) isIncoming; // unknown
418
419 SendPendingRequestToConnectedSystem(systemAddress);
420 }
421 void HTTPConnection2::SendPendingRequestToConnectedSystem(SystemAddress sa)
422 {
423 if (sa==UNASSIGNED_SYSTEM_ADDRESS)
424 return;
425
426 unsigned int requestsSent=0;
427
428 // Search through requests to find a match for this instance of TCPInterface and SystemAddress
429 unsigned int i;
430 i=0;
431 pendingRequestsMutex.Lock();
432 while (i < pendingRequests.Size())
433 {
434 Request *request = pendingRequests[i];
435 if (request->hostEstimatedAddress==sa)
436 {
437 pendingRequests.RemoveAtIndex(i);
438 // Send this request
439 request->hostCompletedAddress=sa;
440
441 sentRequestsMutex.Lock();
442 sentRequests.Push(request, _FILE_AND_LINE_);
443 sentRequestsMutex.Unlock();
444
445 pendingRequestsMutex.Unlock();
446
447 #if OPEN_SSL_CLIENT_SUPPORT==1
448 if (request->useSSL)
449 tcpInterface->StartSSLClient(sa);
450 #endif
451
452 SendRequest(request);
453 requestsSent++;
454 pendingRequestsMutex.Lock();
455 break;
456 }
457 else
458 {
459 i++;
460 }
461 }
462 pendingRequestsMutex.Unlock();
463
464 if (requestsSent==0)
465 {
466 pendingRequestsMutex.Lock();
467 if (pendingRequests.Size() > 0)
468 {
469 // Just assign
470 Request *request = pendingRequests[0];
471 pendingRequests.RemoveAtIndex(0);
472
473 request->hostCompletedAddress=sa;
474
475 sentRequestsMutex.Lock();
476 sentRequests.Push(request, _FILE_AND_LINE_);
477 sentRequestsMutex.Unlock();
478 pendingRequestsMutex.Unlock();
479
480 // Send
481 #if OPEN_SSL_CLIENT_SUPPORT==1
482 if (request->useSSL)
483 tcpInterface->StartSSLClient(sa);
484 #endif
485
486
487 SendRequest(request);
488 }
489 else
490 {
491 pendingRequestsMutex.Unlock();
492 }
493 }
494 }
495 void HTTPConnection2::RemovePendingRequest(SystemAddress sa)
496 {
497 unsigned int i;
498 i=0;
499 pendingRequestsMutex.Lock();
500 for (i=0; i < pendingRequests.Size(); i++)
501 {
502 Request *request = pendingRequests[i];
503 if (request->hostEstimatedAddress==sa)
504 {
505 pendingRequests.RemoveAtIndex(i);
506 SLNet::OP_DELETE(request, _FILE_AND_LINE_);
507 }
508 else
509 i++;
510 }
511
512 pendingRequestsMutex.Unlock();
513 }
514 void HTTPConnection2::SendNextPendingRequest(void)
515 {
516 // Send a pending request
517 pendingRequestsMutex.Lock();
518 if (pendingRequests.Size()>0)
519 {
520 Request *pendingRequest = pendingRequests.Peek();
521 pendingRequestsMutex.Unlock();
522
523 if (pendingRequest->ipVersion!=6)
524 {
525 tcpInterface->Connect(pendingRequest->host.C_String(), pendingRequest->port, false, AF_INET);
526 }
527 else
528 {
529 #if RAKNET_SUPPORT_IPV6
530 tcpInterface->Connect(pendingRequest->host.C_String(), pendingRequest->port, false, AF_INET6);
531 #else
532 RakAssert("HTTPConnection2::TransmitRequest needs define RAKNET_SUPPORT_IPV6" && 0);
533 #endif
534 }
535 }
536 else
537 {
538 pendingRequestsMutex.Unlock();
539 }
540 }
541
542 void HTTPConnection2::OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason)
543 {
544 (void) failedConnectionAttemptReason;
545 if (packet->systemAddress==UNASSIGNED_SYSTEM_ADDRESS)
546 return;
547
548 RemovePendingRequest(packet->systemAddress);
549
550 SendNextPendingRequest();
551 }
552 void HTTPConnection2::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
553 {
554 (void) lostConnectionReason;
555 (void) rakNetGUID;
556
557 if (systemAddress==UNASSIGNED_SYSTEM_ADDRESS)
558 return;
559
560 // Update sent requests to completed requests
561 unsigned int i;
562 i=0;
563 sentRequestsMutex.Lock();
564 while (i < sentRequests.Size())
565 {
566 if (sentRequests[i]->hostCompletedAddress==systemAddress)
567 {
568 Request *sentRequest = sentRequests[i];
569 if (sentRequest->chunked==false && sentRequest->stringReceived.IsEmpty()==false)
570 {
571 if (strstr(sentRequest->stringReceived.C_String(), "Content-Length: "))
572 {
573 char *body_header = strstr((char*) sentRequest->stringReceived.C_String(), "\r\n\r\n");
574 if (body_header)
575 {
576 body_header += 4; // strlen("\r\n\r\n");
577 sentRequest->contentOffset = body_header - sentRequest->stringReceived.C_String();
578 }
579 else
580 {
581 sentRequest->contentOffset = 0;
582 }
583
584 }
585 else
586 {
587 sentRequest->contentOffset = 0;
588 }
589 }
590
591
592 completedRequestsMutex.Lock();
593 completedRequests.Push(sentRequests[i], _FILE_AND_LINE_);
594 completedRequestsMutex.Unlock();
595
596 sentRequests.RemoveAtIndexFast(i);
597 }
598 else
599 {
600 i++;
601 }
602 }
603 sentRequestsMutex.Unlock();
604
605 SendNextPendingRequest();
606 }
607 bool HTTPConnection2::IsConnected(SystemAddress sa)
608 {
609 SystemAddress remoteSystems[64];
610 unsigned short numberOfSystems=64;
611 tcpInterface->GetConnectionList(remoteSystems, &numberOfSystems);
612 for (unsigned int i=0; i < numberOfSystems; i++)
613 {
614 if (remoteSystems[i]==sa)
615 {
616 return true;
617 }
618 }
619 return false;
620 }
621 void HTTPConnection2::SendRequest(Request *request)
622 {
623 tcpInterface->Send(request->stringToTransmit.C_String(), (unsigned int) request->stringToTransmit.GetLength(), request->hostCompletedAddress, false);
624 }
625
626 #endif // #if _RAKNET_SUPPORT_HTTPConnection2==1 && _RAKNET_SUPPORT_TCPInterface==1