Beaming Scene Service  2.0
RakNet wrapper for managing data communications between multiple Beaming clients
netClient/phpClient.cpp
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Enumerations Enumerator Defines