![]() |
Beaming Scene Service
2.0
RakNet wrapper for managing data communications between multiple Beaming clients
|
00001 00010 #include "TCPInterface.h" 00011 #include "HTTPConnection.h" 00012 #include "PHPConnections.h" 00013 #include "RakSleep.h" 00014 #include "RakString.h" 00015 #include "GetTime.h" 00016 #include "DS_Table.h" 00017 #include <cstring> 00018 #include <cstdlib> 00019 #include <cstdio> 00020 #include <iostream> 00021 #include <stdio.h> 00022 #include "Kbhit.h" 00023 #include "Getche.h" 00024 #include "client.h" 00025 #include <stdlib.h> 00026 #include <time.h> 00027 #if defined(_WIN32) 00028 #include <windows.h> 00029 #else 00030 #include<unistd.h> 00031 //#include<cstdlib> 00032 #endif 00033 #include "TCPInterface.h" 00034 #include "HTTPConnection.h" 00035 #include "PHPConnections.h" 00036 00037 // Allocate rather than create on the stack or the RakString mutex crashes on shutdown 00038 TCPInterface *tcp; 00039 HTTPConnection *httpConnection; 00040 PHPConnections *phpConnections; 00041 00042 enum ReadResultEnum 00043 { 00044 RR_EMPTY_TABLE, 00045 RR_READ_TABLE, 00046 RR_TIMEOUT, 00047 }; 00048 00049 ReadResultEnum ReadResult(RakNet::RakString &httpResult) 00050 { 00051 RakNetTimeMS endTime=RakNet::GetTimeMS()+10000; 00052 httpResult.Clear(); 00053 while (RakNet::GetTimeMS()<endTime) 00054 { 00055 Packet *packet = tcp->Receive(); 00056 if(packet) 00057 { 00058 httpConnection->ProcessTCPPacket(packet); 00059 tcp->DeallocatePacket(packet); 00060 } 00061 00062 if (httpConnection->HasRead()) 00063 { 00064 httpResult = httpConnection->Read(); 00065 // Good response, let the PHPConnections class handle the data 00066 // If resultCode is not an empty string, then we got something other than a table 00067 // (such as delete row success notification, or the message is for HTTP only and not for this class). 00068 HTTPReadResult readResult = phpConnections->ProcessHTTPRead(httpResult); 00069 00070 if (readResult==HTTP_RESULT_GOT_TABLE) 00071 { 00072 //printf("RR_READ_TABLE\n"); 00073 return RR_READ_TABLE; 00074 } 00075 else if (readResult==HTTP_RESULT_EMPTY) 00076 { 00077 //printf("HTTP_RESULT_EMPTY\n"); 00078 return RR_EMPTY_TABLE; 00079 } 00080 } 00081 00082 // Update our two classes so they can do time-based updates 00083 httpConnection->Update(); 00084 phpConnections->Update(); 00085 00086 // Prevent 100% cpu usage 00087 RakSleep(1); 00088 } 00089 00090 return RR_TIMEOUT; 00091 } 00092 00093 bool HaltOnUnexpectedResult(ReadResultEnum result, ReadResultEnum expected) 00094 { 00095 if (result!=expected) 00096 { 00097 printf("TEST FAILED. Expected "); 00098 00099 switch (expected) 00100 { 00101 00102 case RR_EMPTY_TABLE: 00103 printf("no results"); 00104 break; 00105 case RR_TIMEOUT: 00106 printf("timeout"); 00107 break; 00108 case RR_READ_TABLE: 00109 printf("to download result"); 00110 break; 00111 } 00112 00113 switch (result) 00114 { 00115 case RR_EMPTY_TABLE: 00116 printf(". No results were downloaded"); 00117 break; 00118 case RR_READ_TABLE: 00119 printf(". Got a result"); 00120 break; 00121 case RR_TIMEOUT: 00122 printf(". Timeout"); 00123 break; 00124 } 00125 printf("\n"); 00126 return true; 00127 } 00128 00129 return false; 00130 } 00131 00132 void DownloadTable() 00133 { 00134 phpConnections->DownloadTable("beammedown"); 00135 } 00136 void UploadTable(RakNet::RakString clientName, unsigned short clientPort) 00137 { 00138 phpConnections->UploadTable("beammeup", clientName, clientPort, false); 00139 } 00140 void UploadAndDownloadTable(RakNet::RakString clientName, unsigned short clientPort) 00141 { 00142 phpConnections->UploadAndDownloadTable("beammeup", "beammedown", clientName, clientPort, false); 00143 } 00144 bool PassTestOnEmptyDownloadedTable() 00145 { 00146 const DataStructures::Table *clients = phpConnections->GetLastDownloadedTable(); 00147 00148 if (clients->GetRowCount()==0) 00149 { 00150 printf("Test passed.\n"); 00151 return true; 00152 } 00153 printf("TEST FAILED. Empty table should have been downloaded.\n"); 00154 return false; 00155 } 00156 bool VerifyDownloadMatchesUpload(int requiredRowCount, int testRowIndex) 00157 { 00158 const DataStructures::Table *clients = phpConnections->GetLastDownloadedTable(); 00159 if (clients->GetRowCount()!=(unsigned int)requiredRowCount) 00160 { 00161 printf("TEST FAILED. Expected %i result rows, got %i\n", requiredRowCount, clients->GetRowCount()); 00162 return false; 00163 } 00164 RakNet::RakString columnName; 00165 RakNet::RakString value; 00166 unsigned int i; 00167 DataStructures::Table::Row *row = clients->GetRowByIndex(testRowIndex,NULL); 00168 const DataStructures::List<DataStructures::Table::ColumnDescriptor>& columns = clients->GetColumns(); 00169 unsigned int colIndex; 00170 // +4 comes from automatic fields 00171 // _CLIENT_PORT 00172 // _CLIENT_NAME 00173 // _SYSTEM_ADDRESS 00174 // __SEC_AFTER_EPOCH_SINCE_LAST_UPDATE 00175 if (phpConnections->GetFieldCount()+4!=clients->GetColumnCount()) 00176 { 00177 printf("TEST FAILED. Expected %i columns, got %i\n", phpConnections->GetFieldCount()+4, clients->GetColumnCount()); 00178 printf("Expected columns:\n"); 00179 for (colIndex=0; colIndex < phpConnections->GetFieldCount(); colIndex++) 00180 { 00181 phpConnections->GetField(colIndex, columnName, value); 00182 printf("%i. %s\n", colIndex+1, columnName.C_String()); 00183 } 00184 printf("%i. _CLIENT_PORT\n", colIndex++); 00185 printf("%i. _CLIENT_NAME\n", colIndex++); 00186 printf("%i. _System_Address\n", colIndex++); 00187 printf("%i. __SEC_AFTER_EPOCH_SINCE_LAST_UPDATE\n", colIndex++); 00188 00189 printf("Got columns:\n"); 00190 for (colIndex=0; colIndex < columns.Size(); colIndex++) 00191 { 00192 printf("%i. %s\n", colIndex+1, columns[colIndex].columnName); 00193 } 00194 00195 return false; 00196 } 00197 for (i=0; i < phpConnections->GetFieldCount(); i++) 00198 { 00199 phpConnections->GetField(i, columnName, value); 00200 for (colIndex=0; colIndex < columns.Size(); colIndex++) 00201 { 00202 if (strcmp(columnName.C_String(), columns[colIndex].columnName)==0) 00203 break; 00204 } 00205 if (colIndex==columns.Size()) 00206 { 00207 printf("TEST FAILED. Expected column with name %s\n", columnName.C_String()); 00208 return false; 00209 } 00210 00211 if (strcmp(value.C_String(), row->cells[colIndex]->c)!=0) 00212 { 00213 printf("TEST FAILED. Expected row with value '%s' at index %i for column %s. Got '%s'.\n", value.C_String(), i, columnName.C_String(), row->cells[colIndex]->c); 00214 return false; 00215 } 00216 } 00217 00218 printf("Test passed.\n"); 00219 return true; 00220 } 00221 void PrintHttpResult(RakNet::RakString httpResult) 00222 { 00223 printf("--- Last result read ---\n"); 00224 printf("%s", httpResult.C_String()); 00225 } 00226 void PrintFieldColumns(void) 00227 { 00228 unsigned int colIndex; 00229 RakNet::RakString columnName; 00230 RakNet::RakString value; 00231 for (colIndex=0; colIndex < phpConnections->GetFieldCount(); colIndex++) 00232 { 00233 phpConnections->GetField(colIndex, columnName, value); 00234 printf("%i. %s\n", colIndex+1, columnName.C_String()); 00235 } 00236 } 00237 bool RunTest() 00238 { 00239 RakNet::RakString httpResult; 00240 ReadResultEnum rr; 00241 char ch[32]; 00242 printf("Warning, table must be clear before starting the test.\n"); 00243 printf("Press enter to start\n"); 00244 gets(ch); 00245 00246 printf("*** Testing initial table is empty.\n"); 00247 // Table should start empty 00248 DownloadTable(); 00249 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00250 {PrintHttpResult(httpResult); return false;} 00251 if (PassTestOnEmptyDownloadedTable()==false) 00252 {PrintHttpResult(httpResult); return false;} 00253 00254 printf("*** Downloading again, to ensure download does not modify the table.\n"); 00255 // Downloading should not modify the table 00256 DownloadTable(); 00257 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00258 {PrintHttpResult(httpResult); return false;} 00259 if (PassTestOnEmptyDownloadedTable()==false) 00260 {PrintHttpResult(httpResult); return false;} 00261 00262 printf("*** Testing upload.\n"); 00263 // Upload values likely to mess up PHP 00264 phpConnections->SetField("TestField1","0"); 00265 phpConnections->SetField("TestField2",""); 00266 phpConnections->SetField("TestField3"," "); 00267 phpConnections->SetField("TestField4","!@#$%^&*("); 00268 phpConnections->SetField("TestField5","A somewhat big long string as these things typically go.\nIt even has a linebreak!"); 00269 phpConnections->SetField("TestField6","="); 00270 phpConnections->UploadTable("beammeup", "FirstClientUpload", 80, false); 00271 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00272 {PrintHttpResult(httpResult); return false;} 00273 if (PassTestOnEmptyDownloadedTable()==false) 00274 {PrintHttpResult(httpResult); return false;} 00275 00276 printf("*** Testing download, should match upload exactly.\n"); 00277 // Download what we just uploaded 00278 DownloadTable(); 00279 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00280 {PrintHttpResult(httpResult); return false;} 00281 // Check results 00282 if (VerifyDownloadMatchesUpload(1,0)==false) 00283 {PrintHttpResult(httpResult); return false;} 00284 00285 printf("*** Testing that download works twice in a row.\n"); 00286 // Make sure download works twice 00287 DownloadTable(); 00288 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00289 {PrintHttpResult(httpResult); return false;} 00290 // Check results 00291 if (VerifyDownloadMatchesUpload(1,0)==false) 00292 {PrintHttpResult(httpResult); return false;} 00293 00294 printf("*** Testing reuploading a client to modify fields.\n"); 00295 // Modify fields 00296 phpConnections->SetField("TestField1","zero"); 00297 phpConnections->SetField("TestField2","empty"); 00298 phpConnections->SetField("TestField3","space"); 00299 phpConnections->SetField("TestField4","characters"); 00300 phpConnections->SetField("TestField5","A shorter string"); 00301 phpConnections->SetField("TestField6","Test field 6"); 00302 phpConnections->UploadTable("beammeup", "FirstClientUpload", 80, false); 00303 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00304 {PrintHttpResult(httpResult); return false;} 00305 if (PassTestOnEmptyDownloadedTable()==false) 00306 {PrintHttpResult(httpResult); return false;} 00307 00308 printf("*** Testing that downloading returns modified fields.\n"); 00309 // Download what we just uploaded 00310 DownloadTable(); 00311 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00312 {PrintHttpResult(httpResult); return false;} 00313 // Check results 00314 if (VerifyDownloadMatchesUpload(1,0)==false) 00315 {PrintHttpResult(httpResult); return false;} 00316 00317 printf("*** Testing that downloading works twice.\n"); 00318 // Make sure download works twice 00319 DownloadTable(); 00320 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00321 {PrintHttpResult(httpResult); return false;} 00322 // Check results 00323 if (VerifyDownloadMatchesUpload(1,0)==false) 00324 {PrintHttpResult(httpResult); return false;} 00325 00326 printf("*** Testing upload of a second client.\n"); 00327 // Upload another client 00328 phpConnections->SetField("TestField1","0"); 00329 phpConnections->SetField("TestField2",""); 00330 phpConnections->SetField("TestField3"," "); 00331 phpConnections->SetField("TestField4","Client two characters !@#$%^&*("); 00332 phpConnections->UploadTable("beammeup", "SecondClientUpload", 80, false); 00333 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00334 {PrintHttpResult(httpResult); return false;} 00335 if (PassTestOnEmptyDownloadedTable()==false) 00336 {PrintHttpResult(httpResult); return false;} 00337 /*RakNetTimeMS startTime = RakNet::GetTimeMS(); 00338 00339 printf("*** Testing 20 repeated downloads.\n"); 00340 printf("Field columns\n"); 00341 PrintFieldColumns(); 00342 00343 // Download repeatedly 00344 unsigned int downloadCount=0; 00345 while (downloadCount < 20) 00346 { 00347 printf("*** (%i) Downloading 'FirstClientUpload'\n", downloadCount+1); 00348 // Download again (First client) 00349 DownloadTable(); 00350 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00351 {PrintHttpResult(httpResult); return false;} 00352 // Check results 00353 // DOn't have this stored anymore 00354 // if (VerifyDownloadMatchesUpload(2,0)==false) 00355 // {PrintHttpResult(httpResult); return false;} 00356 00357 printf("*** (%i) Downloading 'SecondClientUpload'\n", downloadCount+1); 00358 // Download again (second client) 00359 DownloadTable(); 00360 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00361 {PrintHttpResult(httpResult); return false;} 00362 // Check results 00363 if (VerifyDownloadMatchesUpload(2,1)==false) 00364 {PrintHttpResult(httpResult); return false;} 00365 00366 downloadCount++; 00367 00368 RakSleep(1000); 00369 } 00370 00371 printf("*** Waiting for 70 seconds to have elapsed...\n"); 00372 RakSleep(70000 - (RakNet::GetTimeMS()-startTime)); 00373 00374 00375 printf("*** Testing that table is now clear.\n"); 00376 // Table should be cleared 00377 DownloadTable(); 00378 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00379 {PrintHttpResult(httpResult); return false;} 00380 if (PassTestOnEmptyDownloadedTable()==false) 00381 {PrintHttpResult(httpResult); return false;} 00382 00383 printf("*** Testing upload and download. No clients should be downloaded.\n"); 00384 phpConnections->ClearFields(); 00385 phpConnections->SetField("TestField1","NULL"); 00386 UploadAndDownloadTable("FirstClientUpload", 80); 00387 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00388 {PrintHttpResult(httpResult); return false;} 00389 if (PassTestOnEmptyDownloadedTable()==false) 00390 {PrintHttpResult(httpResult); return false;} 00391 00392 printf("*** Testing upload and download. One client should be downloaded.\n"); 00393 UploadAndDownloadTable("ThirdClientUpload", 80); 00394 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_READ_TABLE)) 00395 {PrintHttpResult(httpResult); return false;} 00396 if (VerifyDownloadMatchesUpload(1,0)==false) 00397 {PrintHttpResult(httpResult); return false;}*/ 00398 00399 return true; 00400 } 00401 00402 void OutputBody(HTTPConnection& http, const char *path, const char *data, TCPInterface& tcp); 00403 00404 int main(int argc, char**argv) 00405 { 00406 char connectedclients[1024]; 00407 char *guid, *node, *tmpid, *nodeid; 00408 char allnodes[2048], node_info[256]; 00409 int loop = 0, index = 1; 00410 char nodes[512]; 00411 bool quit = false; 00412 char ch; 00413 char iddata[128]; 00414 char website[256]; 00415 char pathToPHP[256]; 00416 RakNet::RakString httpResult; 00417 ReadResultEnum rr; 00418 char ipdetails[128]; 00419 00420 srand((unsigned)time(0)); 00421 //connect using startclient 00422 int connected = startclient("128.16.7.66", 12050/*"193.205.82.196", 50000*/,"UCL","VISITOR","m016.cfg",false); 00423 #if defined(_WIN32) 00424 Sleep(100); 00425 #else 00426 sleep(2); 00427 #endif 00428 if (!connected) 00429 { exit(1); } 00430 00431 printf("Starts streaming to php webpage: http://web4.cs.ucl.ac.uk/research/vr/Projects/BEAMING/wole/BeamingSceneService/List/Connections.php\n"); 00432 printf("Commands:\n(Q)uit\n"); 00433 //printf("connected = %i\n", connected); 00434 00435 00436 strcpy(iddata,""); 00437 00438 printf("Streaming to http://web4.cs.ucl.ac.uk/research/vr/Projects/BEAMING/wole/BeamingSceneService/List/Connections.php ...\n"); 00439 00440 tcp = RakNet::OP_NEW<TCPInterface>(__FILE__,__LINE__); 00441 httpConnection = RakNet::OP_NEW<HTTPConnection>(__FILE__,__LINE__); 00442 phpConnections = RakNet::OP_NEW<PHPConnections>(__FILE__,__LINE__); 00443 // RakNetTime lastTouched = 0; 00444 // Start the TCP thread. This is used for general TCP communication, whether it is for webpages, sending emails, or telnet 00445 tcp->Start(0, 64); 00446 00447 strcpy(website, "web4.cs.ucl.ac.uk"); 00448 strcpy(pathToPHP, "research/vr/Projects/BEAMING/wole/BeamingSceneService/List/Connections.php"); 00449 00450 if (website[strlen(website)-1]!='/' && pathToPHP[0]!='/') 00451 { 00452 memmove(pathToPHP+1, pathToPHP, strlen(pathToPHP)+1); 00453 pathToPHP[0]='/'; 00454 } 00455 00456 // This creates an HTTP connection using TCPInterface. It allows you to Post messages to and parse messages from webservers. 00457 // The connection attempt is asynchronous, and is handled automatically as HTTPConnection::Update() is called 00458 httpConnection->Init(tcp, website); 00459 00460 // This adds specific parsing functionality to HTTPConnection, in order to communicate with Connections.php 00461 phpConnections->Init(httpConnection, pathToPHP); 00462 00463 while (!quit) 00464 { 00465 //check incoming packets 00466 check(); 00467 //get information on all connected clients. 00468 //printf("number of connected clients %i\n",getPeersID(connectedclients)); 00469 getPeersID(connectedclients); 00470 //printf("%s\n",connectedclients); 00471 for (guid = strtok (connectedclients, ";"); guid != NULL; 00472 guid = strtok (guid + strlen (guid) + 1, ";")) 00473 { 00474 strncpy (iddata, guid, sizeof (iddata)); 00475 //for each connected guid in the database, get the nodes information. 00476 getNodesInfo(iddata,allnodes); 00477 //printf("%s\n",allnodes); 00478 for (node = strtok (allnodes, ";"); node != NULL; 00479 node = strtok (node + strlen (node) + 1, ";")) 00480 { 00481 strncpy (node_info, node, sizeof (node_info)); 00482 //phpConnections->SetField(RakNet::RakString("Node ") + RakNet::RakString("%d",loop),RakNet::RakString(node)); 00483 for (tmpid = strtok (node_info, ","); tmpid != NULL; 00484 tmpid = strtok (tmpid + strlen (tmpid) + 1, ",")) 00485 { 00486 switch (loop) 00487 { 00488 case 0:// first token is the client name (in the case of AVATAR type, avatar id) 00489 phpConnections->SetField("Client Name",tmpid); 00490 break; 00491 case 1:// second token is the node_id 00492 phpConnections->SetField("Node ID",tmpid); 00493 break; 00494 case 2: //third token is the TYPE 00495 phpConnections->SetField("Node Type",tmpid); 00496 break; 00497 case 3: //fouth token is the config 00498 phpConnections->SetField("Config",tmpid); 00499 break; 00500 } 00501 loop++; 00502 } //end for 00503 loop=0; //reset 00504 getIPinfo(iddata,ipdetails); 00505 phpConnections->SetField("_System_Address",ipdetails); 00506 phpConnections->UploadTable("beammeup", RakNet::RakString("%s Node %d",guid,index), 80, false); 00507 if (HaltOnUnexpectedResult(rr=ReadResult(httpResult), RR_EMPTY_TABLE)) 00508 { 00509 PrintHttpResult(httpResult); 00510 //return false; 00511 } 00512 index++; 00513 RakSleep(10); 00514 } //end for 00515 index = 1; 00516 } //end for 00517 RakSleep(1000); //sleep for 2 seconds before uploading next set of records 00518 if (kbhit()) 00519 { 00520 ch=getch(); 00521 if (ch=='q' || ch=='Q') 00522 { 00523 printf("Quitting.\n"); 00524 quit=true; 00525 } 00526 }// end if kbhit() 00527 }//end while 00528 00529 // The destructor of each of these references the other, so delete in this order 00530 RakNet::OP_DELETE(phpConnections,__FILE__,__LINE__); 00531 RakNet::OP_DELETE(httpConnection,__FILE__,__LINE__); 00532 RakNet::OP_DELETE(tcp,__FILE__,__LINE__); 00533 printf("Web streaming disabled.\n"); 00534 00535 //remove all nodes and clean up on exit 00536 removeAllNodes(); 00537 stop(); 00538 }