• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

LightweightDatabaseServer.cpp

Go to the documentation of this file.
00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_LightweightDatabaseServer==1
00003 
00004 #include "LightweightDatabaseServer.h"
00005 #include "MessageIdentifiers.h"
00006 #include "BitStream.h"
00007 #include "StringCompressor.h"
00008 #include "RakPeerInterface.h"
00009 #include "TableSerializer.h"
00010 #include "RakAssert.h"
00011 #include "GetTime.h"
00012 #include "Rand.h"
00013 
00014 static const int SEND_PING_INTERVAL=15000;
00015 static const int DROP_SERVER_INTERVAL=75000;
00016 
00017 #ifdef _MSC_VER
00018 #pragma warning( push )
00019 #endif
00020 
00021 int LightweightDatabaseServer::DatabaseTableComp( const char* const &key1, const char* const &key2 )
00022 {
00023         return strcmp(key1, key2);
00024 }
00025 
00026 LightweightDatabaseServer::LightweightDatabaseServer()
00027 {
00028 
00029 }
00030 LightweightDatabaseServer::~LightweightDatabaseServer()
00031 {
00032         Clear();
00033 }
00034 DataStructures::Table *LightweightDatabaseServer::GetTable(const char *tableName)
00035 {
00036         if (tableName==0)
00037         {
00038                 if (database.Size()>0)
00039                         return &(database[0]->table);
00040                 return 0;
00041         }
00042         if (database.Has(tableName))
00043                 return &(database.Get(tableName)->table);
00044         return 0;
00045 }
00046 DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *LightweightDatabaseServer::GetTableRows(const char *tableName)
00047 {
00048         if (database.Has(tableName))
00049                 database.Get(tableName)->table.GetRows().GetListHead();
00050         return 0;
00051 }
00052 DataStructures::Table* LightweightDatabaseServer::AddTable(const char *tableName,
00053                                                                                                                                                           bool allowRemoteQuery,
00054                                                                                                                                                           bool allowRemoteUpdate,
00055                                                                                                                                                           bool allowRemoteRemove,
00056                                                                                                                                                           const char *queryPassword,
00057                                                                                                                                                           const char *updatePassword,
00058                                                                                                                                                           const char *removePassword,
00059                                                                                                                                                           bool oneRowPerSystemAddress,
00060                                                                                                                                                           bool onlyUpdateOwnRows,
00061                                                                                                                                                           bool removeRowOnPingFailure,
00062                                                                                                                                                           bool removeRowOnDisconnect,
00063                                                                                                                                                           bool autogenerateRowIDs)
00064 {
00065         if (tableName==0 || tableName[0]==0)
00066                 return 0;
00067         if (database.Has(tableName))
00068                 return 0;
00069         DatabaseTable *databaseTable = RakNet::OP_NEW<DatabaseTable>( __FILE__, __LINE__ );
00070 
00071         strncpy(databaseTable->tableName, tableName, _SIMPLE_DATABASE_TABLE_NAME_LENGTH-1);
00072         databaseTable->tableName[_SIMPLE_DATABASE_TABLE_NAME_LENGTH-1]=0;
00073 
00074         if (allowRemoteUpdate)
00075         {
00076                 strncpy(databaseTable->updatePassword, updatePassword, _SIMPLE_DATABASE_PASSWORD_LENGTH-1);
00077                 databaseTable->updatePassword[_SIMPLE_DATABASE_PASSWORD_LENGTH-1]=0;
00078         }
00079         else
00080                 databaseTable->updatePassword[0]=0;
00081 
00082         if (allowRemoteQuery)
00083         {
00084                 strncpy(databaseTable->queryPassword, queryPassword, _SIMPLE_DATABASE_PASSWORD_LENGTH-1);
00085                 databaseTable->queryPassword[_SIMPLE_DATABASE_PASSWORD_LENGTH-1]=0;
00086         }
00087         else
00088                 databaseTable->queryPassword[0]=0;
00089 
00090         if (allowRemoteRemove)
00091         {
00092                 strncpy(databaseTable->removePassword, removePassword, _SIMPLE_DATABASE_PASSWORD_LENGTH-1);
00093                 databaseTable->removePassword[_SIMPLE_DATABASE_PASSWORD_LENGTH-1]=0;
00094         }
00095         else
00096                 databaseTable->removePassword[0]=0;
00097 
00098         if (allowRemoteUpdate)
00099         {
00100                 databaseTable->allowRemoteUpdate=true;
00101                 databaseTable->oneRowPerSystemAddress=oneRowPerSystemAddress;
00102                 databaseTable->onlyUpdateOwnRows=onlyUpdateOwnRows;
00103                 databaseTable->removeRowOnPingFailure=removeRowOnPingFailure;
00104                 databaseTable->removeRowOnDisconnect=removeRowOnDisconnect;
00105         }
00106         else
00107         {
00108                 // All these parameters are related to IP tracking, which is not done if remote updates are not allowed
00109                 databaseTable->allowRemoteUpdate=true;
00110                 databaseTable->oneRowPerSystemAddress=false;
00111                 databaseTable->onlyUpdateOwnRows=false;
00112                 databaseTable->removeRowOnPingFailure=false;
00113                 databaseTable->removeRowOnDisconnect=false;
00114         }
00115 
00116         databaseTable->nextRowId=0;
00117         databaseTable->nextRowPingCheck=0;
00118 
00119         databaseTable->autogenerateRowIDs=autogenerateRowIDs;
00120         databaseTable->allowRemoteRemove=allowRemoteRemove;
00121         databaseTable->allowRemoteQuery=allowRemoteQuery;
00122 
00123         database.SetNew(databaseTable->tableName, databaseTable);
00124 
00125         if ( oneRowPerSystemAddress || onlyUpdateOwnRows || removeRowOnPingFailure || removeRowOnDisconnect)
00126         {
00127                 databaseTable->SystemAddressColumnIndex=databaseTable->table.AddColumn(SYSTEM_ID_COLUMN_NAME, DataStructures::Table::BINARY);
00128                 databaseTable->SystemGuidColumnIndex=databaseTable->table.AddColumn(SYSTEM_GUID_COLUMN_NAME, DataStructures::Table::BINARY);
00129         }
00130         else
00131         {
00132                 databaseTable->SystemAddressColumnIndex=(unsigned) -1;
00133                 databaseTable->SystemGuidColumnIndex=(unsigned) -1;
00134         }
00135         if (databaseTable->removeRowOnPingFailure)
00136         {
00137                 databaseTable->lastPingResponseColumnIndex=databaseTable->table.AddColumn(LAST_PING_RESPONSE_COLUMN_NAME, DataStructures::Table::NUMERIC);
00138                 databaseTable->nextPingSendColumnIndex=databaseTable->table.AddColumn(NEXT_PING_SEND_COLUMN_NAME, DataStructures::Table::NUMERIC);
00139         }
00140         else
00141         {
00142                 databaseTable->lastPingResponseColumnIndex=(unsigned) -1;
00143                 databaseTable->nextPingSendColumnIndex=(unsigned) -1;
00144         }
00145 
00146         return &(databaseTable->table);
00147 }
00148 bool LightweightDatabaseServer::RemoveTable(const char *tableName)
00149 {
00150         LightweightDatabaseServer::DatabaseTable *databaseTable;
00151         databaseTable = database.Get(tableName);
00152         if (databaseTable==0)
00153                 return false;
00154         // Be sure to call Delete on database before I do the actual pointer deletion since the key won't be valid after that time.
00155         database.Delete(tableName);
00156         databaseTable->table.Clear();
00157         RakNet::OP_DELETE(databaseTable, __FILE__, __LINE__);
00158         return true;
00159 }
00160 void LightweightDatabaseServer::Clear(void)
00161 {
00162         unsigned i;
00163 
00164         for (i=0; i < database.Size(); i++)
00165         {
00166                 database[i]->table.Clear();
00167                 RakNet::OP_DELETE(database[i], __FILE__, __LINE__);
00168         }
00169 
00170         database.Clear();
00171 }
00172 unsigned LightweightDatabaseServer::GetAndIncrementRowID(const char *tableName)
00173         {
00174         LightweightDatabaseServer::DatabaseTable *databaseTable;
00175         databaseTable = database.Get(tableName);
00176         RakAssert(databaseTable);
00177         RakAssert(databaseTable->autogenerateRowIDs==true);
00178         return ++(databaseTable->nextRowId) - 1;
00179         }
00180 
00181 void LightweightDatabaseServer::Update(void)
00182 {
00183         RakNetTime time=0;
00184         DatabaseTable *databaseTable;
00185         DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur;
00186         unsigned i,j;
00187         DataStructures::Table::Row* row;
00188         DataStructures::List<unsigned> removeList;
00189         SystemAddress systemAddress;
00190 
00191         // periodic ping if removing system that do not respond to pings.
00192         for (i=0; i < database.Size(); i++)
00193         {
00194                 databaseTable=database[i];
00195 
00196                 if (databaseTable->removeRowOnPingFailure)
00197                 {
00198                         // Reading the time is slow - only do it once if necessary.
00199                         if (time==0)
00200                                 time = RakNet::GetTime();
00201 
00202                         if (databaseTable->nextRowPingCheck < time)
00203                         {
00204                                 databaseTable->nextRowPingCheck=time+1000+(randomMT()%1000);
00205                                 const DataStructures::BPlusTree<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> &rows = databaseTable->table.GetRows();
00206                                 cur = rows.GetListHead();
00207                                 while (cur)
00208                                 {
00209                                         // Mark dropped entities
00210                                         for (j=0; j < (unsigned)cur->size; j++)
00211                                         {
00212                                                 row = cur->data[j];
00213                                                 row->cells[databaseTable->SystemAddressColumnIndex]->Get((char*)&systemAddress, 0);
00214                                                 if (rakPeerInterface->IsConnected(systemAddress)==false)
00215                                                 {
00216                                                         if (time > time - (unsigned int) row->cells[databaseTable->lastPingResponseColumnIndex]->i &&
00217                                                                 time - (unsigned int) row->cells[databaseTable->lastPingResponseColumnIndex]->i > (unsigned int) DROP_SERVER_INTERVAL)
00218                                                         {
00219                                                                 removeList.Insert(cur->keys[j], __FILE__, __LINE__);
00220                                                         }
00221                                                         else
00222                                                         {
00223                                                                 if (row->cells[databaseTable->nextPingSendColumnIndex]->i < (int) time)
00224                                                                 {
00225                                                                         char str1[64];
00226                                                                         systemAddress.ToString(false, str1);
00227                                                                         rakPeerInterface->Ping(str1, systemAddress.port, false);
00228                                                                         row->cells[databaseTable->nextPingSendColumnIndex]->i=(double)(time+SEND_PING_INTERVAL+(randomMT()%1000));
00229                                                                 }
00230                                                         }
00231                                                 }
00232                                         }
00233                                         cur=cur->next;
00234                                 }
00235 
00236                                 // Remove dropped entities
00237                                 for (j=0; j < removeList.Size(); j++)
00238                                         databaseTable->table.RemoveRow(removeList[i]);
00239                                 removeList.Clear(true, __FILE__,__LINE__);
00240 
00241                         }
00242                 }
00243         }
00244 }
00245 PluginReceiveResult LightweightDatabaseServer::OnReceive(Packet *packet)
00246         {
00247         switch (packet->data[0])
00248                 {
00249                 case ID_DATABASE_QUERY_REQUEST:
00250                         OnQueryRequest(packet);
00251                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
00252                 case ID_DATABASE_UPDATE_ROW:
00253                         OnUpdateRow(packet);
00254                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
00255                 case ID_DATABASE_REMOVE_ROW:
00256                         OnRemoveRow(packet);
00257                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
00258                 case ID_PONG:
00259                         OnPong(packet);
00260                         return RR_CONTINUE_PROCESSING;
00261                 }
00262         return RR_CONTINUE_PROCESSING;
00263         }
00264 void LightweightDatabaseServer::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
00265 {
00266         (void) rakNetGUID;
00267         (void) lostConnectionReason;
00268 
00269         RemoveRowsFromIP(systemAddress);
00270 }
00271 void LightweightDatabaseServer::OnQueryRequest(Packet *packet)
00272 {
00273         RakNet::BitStream inBitstream(packet->data, packet->length, false);
00274         LightweightDatabaseServer::DatabaseTable *databaseTable = DeserializeClientHeader(&inBitstream, rakPeerInterface, packet, 0);
00275         if (databaseTable==0)
00276                 return;
00277         if (databaseTable->allowRemoteQuery==false)
00278                 return;
00279         unsigned char numColumnSubset;
00280         RakNet::BitStream outBitstream;
00281         unsigned i;
00282         if (inBitstream.Read(numColumnSubset)==false)
00283                 return;
00284         unsigned char columnName[256];
00285         unsigned columnIndicesSubset[256];
00286         unsigned columnIndicesCount;
00287         for (i=0,columnIndicesCount=0; i < numColumnSubset; i++)
00288                 {
00289                 stringCompressor->DecodeString((char*)columnName, 256, &inBitstream);
00290                 unsigned colIndex = databaseTable->table.ColumnIndex((char*)columnName);
00291                 if (colIndex!=(unsigned)-1)
00292                         columnIndicesSubset[columnIndicesCount++]=colIndex;
00293                 }
00294         unsigned char numNetworkedFilters;
00295         if (inBitstream.Read(numNetworkedFilters)==false)
00296                 return;
00297         DatabaseFilter networkedFilters[256];
00298         for (i=0; i < numNetworkedFilters; i++)
00299                 {
00300                 if (networkedFilters[i].Deserialize(&inBitstream)==false)
00301                         return;
00302                 }
00303 
00304         unsigned rowIds[256];
00305         unsigned char numRowIDs;
00306         if (inBitstream.Read(numRowIDs)==false)
00307                 return;
00308         for (i=0; i < numRowIDs; i++)
00309                 inBitstream.Read(rowIds[i]);
00310 
00311         // Convert the safer and more robust networked database filter to the more efficient form the table actually uses.
00312         DataStructures::Table::FilterQuery tableFilters[256];
00313         unsigned numTableFilters=0;
00314         for (i=0; i < numNetworkedFilters; i++)
00315                 {
00316                 tableFilters[numTableFilters].columnIndex=databaseTable->table.ColumnIndex(networkedFilters[i].columnName);
00317                 if (tableFilters[numTableFilters].columnIndex==(unsigned)-1)
00318                         continue;
00319                 if (networkedFilters[i].columnType!=databaseTable->table.GetColumns()[tableFilters[numTableFilters].columnIndex].columnType)
00320                         continue;
00321                 tableFilters[numTableFilters].operation=networkedFilters[i].operation;
00322                 // It's important that I store a pointer to the class here or the destructor of the class will deallocate the cell twice
00323                 tableFilters[numTableFilters++].cellValue=&(networkedFilters[i].cellValue);
00324                 }
00325 
00326         DataStructures::Table queryResult;
00327         databaseTable->table.QueryTable(columnIndicesSubset, columnIndicesCount, tableFilters, numTableFilters, rowIds, numRowIDs, &queryResult);
00328         outBitstream.Write((MessageID)ID_DATABASE_QUERY_REPLY);
00329         TableSerializer::SerializeTable(&queryResult, &outBitstream);
00330         SendUnified(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
00331 }
00332 void LightweightDatabaseServer::OnUpdateRow(Packet *packet)
00333         {
00334         RakNet::BitStream inBitstream(packet->data, packet->length, false);
00335         LightweightDatabaseServer::DatabaseTable *databaseTable = DeserializeClientHeader(&inBitstream, rakPeerInterface, packet, 1);
00336         if (databaseTable==0)
00337                 {
00338                 printf("ERROR: LightweightDatabaseServer::OnUpdateRow databaseTable==0\n");
00339                 return;
00340                 }
00341         if (databaseTable->allowRemoteUpdate==false)
00342                 {
00343                 printf("Warning: LightweightDatabaseServer::OnUpdateRow databaseTable->allowRemoteUpdate==false\n");
00344                 return;
00345                 }
00346         unsigned char updateMode;
00347         bool hasRowId=false;
00348         unsigned rowId;
00349         unsigned i;
00350         DataStructures::Table::Row *row;
00351         inBitstream.Read(updateMode);
00352         inBitstream.Read(hasRowId);
00353         if (hasRowId)
00354                 inBitstream.Read(rowId);
00355         else
00356                 rowId=(unsigned) -1; // Not used here but remove the debugging check
00357         unsigned char numCellUpdates;
00358         if (inBitstream.Read(numCellUpdates)==false)
00359                 return;
00360         // Read the updates for the row
00361         DatabaseCellUpdate cellUpdates[256];
00362         for (i=0; i < numCellUpdates; i++)
00363                 {
00364                 if (cellUpdates[i].Deserialize(&inBitstream)==false)
00365                         {
00366                         printf("ERROR: LightweightDatabaseServer::OnUpdateRow cellUpdates deserialize failed i=%i numCellUpdates=%i\n",i,numCellUpdates);
00367                         return;
00368                         }
00369                 }
00370 
00371         if ((RowUpdateMode)updateMode==RUM_UPDATE_EXISTING_ROW)
00372         {
00373                 if (hasRowId==false)
00374                 {
00375                         unsigned rowKey;
00376                         row = GetRowFromIP(databaseTable, packet->systemAddress, &rowKey);
00377                         if (row==0)
00378                                 printf("ERROR: LightweightDatabaseServer::OnUpdateRow updateMode==RUM_UPDATE_EXISTING_ROW hasRowId==false");
00379                 }
00380                 else
00381                 {
00382 
00383                         row = databaseTable->table.GetRowByID(rowId);
00384                         if (row==0 || (databaseTable->onlyUpdateOwnRows && RowHasIP(row, packet->systemAddress, databaseTable->SystemAddressColumnIndex)==false))
00385                         {
00386                                 if (row==0)
00387                                         printf("ERROR: LightweightDatabaseServer::OnUpdateRow row = databaseTable->table.GetRowByID(rowId); row==0\n");
00388                                 else
00389                                         printf("ERROR: LightweightDatabaseServer::OnUpdateRow row = databaseTable->table.GetRowByID(rowId); databaseTable->onlyUpdateOwnRows && RowHasIP\n");
00390 
00391                                 return; // You can't update some other system's row
00392                         }
00393                 }
00394         }
00395         else if ((RowUpdateMode)updateMode==RUM_UPDATE_OR_ADD_ROW)
00396                 {
00397                 if (hasRowId)
00398                         row = databaseTable->table.GetRowByID(rowId);
00399                 else
00400                         {
00401                         unsigned rowKey;
00402                         row = GetRowFromIP(databaseTable, packet->systemAddress, &rowKey);
00403                         }
00404 
00405                 if (row==0)
00406                         {
00407                         row=AddRow(databaseTable, packet->systemAddress, packet->guid, hasRowId, rowId);
00408                         if (row==0)
00409                                 {
00410                                 printf("ERROR: LightweightDatabaseServer::OnUpdateRow updateMode==RUM_UPDATE_OR_ADD_ROW; row=AddRow; row==0\n");
00411                                 return;
00412                                 }
00413                         }
00414                 else
00415                         {
00416                         // Existing row
00417                         if (databaseTable->onlyUpdateOwnRows && RowHasIP(row, packet->systemAddress, databaseTable->SystemAddressColumnIndex)==false)
00418                                 {
00419                                 SystemAddress sysAddr;
00420                                 memcpy(&sysAddr, row->cells[databaseTable->SystemAddressColumnIndex]->c, SystemAddress::size());
00421 
00422                                 char str1[64], str2[64];
00423                                 packet->systemAddress.ToString(true, str1);
00424                                 sysAddr.ToString(true, str2);
00425                                 printf("ERROR: LightweightDatabaseServer::OnUpdateRow updateMode==RUM_UPDATE_OR_ADD_ROW; databaseTable->onlyUpdateOwnRows && RowHasIP. packet->systemAddress=%s sysAddr=%s\n",
00426                                         str1, str2);
00427 
00428                                 return; // You can't update some other system's row
00429                                 }
00430                         }
00431                 }
00432         else
00433                 {
00434                 RakAssert((RowUpdateMode)updateMode==RUM_ADD_NEW_ROW);
00435 
00436                 row=AddRow(databaseTable, packet->systemAddress, packet->guid, hasRowId, rowId);
00437                 if (row==0)
00438                         {
00439                         printf("ERROR: LightweightDatabaseServer::OnUpdateRow updateMode==RUM_ADD_NEW_ROW; row==0\n");
00440                         return;
00441                         }
00442                 }
00443 
00444         unsigned columnIndex;
00445         for (i=0; i < numCellUpdates; i++)
00446                 {
00447                 columnIndex=databaseTable->table.ColumnIndex(cellUpdates[i].columnName);
00448                 RakAssert(columnIndex!=(unsigned)-1); // Unknown column name
00449                 if (columnIndex!=(unsigned)-1 &&
00450                         (databaseTable->onlyUpdateOwnRows==false ||
00451                         (columnIndex!=databaseTable->lastPingResponseColumnIndex &&
00452                         columnIndex!=databaseTable->nextPingSendColumnIndex &&
00453                         columnIndex!=databaseTable->SystemAddressColumnIndex &&
00454                         columnIndex!=databaseTable->SystemGuidColumnIndex)))
00455                         {
00456                         if (cellUpdates[i].cellValue.isEmpty)
00457                                 row->cells[columnIndex]->Clear();
00458                         else if (cellUpdates[i].columnType==databaseTable->table.GetColumnType(columnIndex))
00459                                 {
00460                                 if (cellUpdates[i].columnType==DataStructures::Table::NUMERIC)
00461                                         {
00462                                         row->UpdateCell(columnIndex, cellUpdates[i].cellValue.i);
00463                                         }
00464                                 else if (cellUpdates[i].columnType==DataStructures::Table::BINARY)
00465                                         {
00466                                         row->UpdateCell(columnIndex, (int) cellUpdates[i].cellValue.i, cellUpdates[i].cellValue.c);
00467                                         }
00468                                 else
00469                                         {
00470                                         RakAssert(cellUpdates[i].columnType==DataStructures::Table::STRING);
00471                                         row->UpdateCell(columnIndex, cellUpdates[i].cellValue.c);
00472                                         }
00473                                 }
00474                         }
00475                 }
00476         }
00477 void LightweightDatabaseServer::OnRemoveRow(Packet *packet)
00478         {
00479         RakNet::BitStream inBitstream(packet->data, packet->length, false);
00480         LightweightDatabaseServer::DatabaseTable *databaseTable = DeserializeClientHeader(&inBitstream, rakPeerInterface, packet, 0);
00481         if (databaseTable==0)
00482                 return;
00483         if (databaseTable->allowRemoteRemove==false)
00484                 return;
00485         unsigned rowId;
00486         inBitstream.Read(rowId);
00487         databaseTable->table.RemoveRow(rowId);
00488         }
00489 void LightweightDatabaseServer::OnPong(Packet *packet)
00490 {
00491         unsigned databaseIndex;
00492         DatabaseTable *databaseTable;
00493         unsigned curIndex;
00494         SystemAddress systemAddress;
00495         RakNetTime time=0;
00496         for (databaseIndex=0; databaseIndex < database.Size(); databaseIndex++)
00497         {
00498                 databaseTable=database[databaseIndex];
00499                 if (databaseTable->removeRowOnPingFailure)
00500                 {
00501                         if ((unsigned int) databaseTable->SystemAddressColumnIndex==(unsigned int)-1)
00502                                 continue;
00503                         if (time==0)
00504                                 time=RakNet::GetTime();
00505 
00506                         const DataStructures::BPlusTree<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> &rows = databaseTable->table.GetRows();
00507                         DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = rows.GetListHead();
00508 
00509                         while (cur)
00510                         {
00511                                 for (curIndex=0; curIndex < (unsigned) cur->size; curIndex++)
00512                                 {
00513                                         cur->data[curIndex]->cells[databaseTable->SystemAddressColumnIndex]->Get((char*)&systemAddress,0);
00514                                         if (systemAddress==packet->systemAddress)
00515                                         {
00516                                                 cur->data[curIndex]->cells[databaseTable->lastPingResponseColumnIndex]->i=(int)time;
00517                                         }
00518                                 }
00519                                 cur=cur->next;
00520                         }
00521                 }
00522         }
00523 }
00524 
00525 LightweightDatabaseServer::DatabaseTable * LightweightDatabaseServer::DeserializeClientHeader(RakNet::BitStream *inBitstream, RakPeerInterface *peer, Packet *packet, int mode)
00526         {
00527         RakNet::BitStream outBitstream;
00528         bool hasPassword=false;
00529         char password[_SIMPLE_DATABASE_PASSWORD_LENGTH];
00530         inBitstream->IgnoreBits(8);
00531         char tableName[_SIMPLE_DATABASE_TABLE_NAME_LENGTH];
00532         stringCompressor->DecodeString(tableName, _SIMPLE_DATABASE_TABLE_NAME_LENGTH, inBitstream);
00533         DatabaseTable *databaseTable = database.Get(tableName);
00534         if (databaseTable==0)
00535                 {
00536                 outBitstream.Write((MessageID)ID_DATABASE_UNKNOWN_TABLE);
00537                 peer->Send(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
00538                 return 0;
00539                 }
00540         const char *dbPass;
00541         if (mode==0)
00542                 dbPass=databaseTable->queryPassword;
00543         else if (mode==1)
00544                 dbPass=databaseTable->updatePassword;
00545         else
00546                 dbPass=databaseTable->removePassword;
00547 
00548         inBitstream->Read(hasPassword);
00549         if (hasPassword)
00550                 {
00551                 if (stringCompressor->DecodeString(password, _SIMPLE_DATABASE_PASSWORD_LENGTH, inBitstream)==false)
00552                         return 0;
00553                         if (databaseTable->queryPassword[0] && strcmp(password, dbPass)!=0)
00554                         {
00555                                 outBitstream.Write((MessageID)ID_DATABASE_INCORRECT_PASSWORD);
00556                                 peer->Send(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
00557                                 // Short ban to prevent brute force password attempts
00558                                 char str1[64];
00559                                 packet->systemAddress.ToString(false, str1);
00560                                 peer->AddToBanList(str1, 1000);
00561                                 // Don't send a disconnection notification so it closes the connection right away.
00562                                 peer->CloseConnection(packet->systemAddress, false, 0);
00563                                 return 0;
00564                         }
00565                 }
00566         else if (dbPass[0])
00567                 {
00568                 outBitstream.Write((MessageID)ID_DATABASE_INCORRECT_PASSWORD);
00569                 peer->Send(&outBitstream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
00570                 return 0;
00571                 }
00572 
00573         return databaseTable;
00574         }
00575 
00576 DataStructures::Table::Row * LightweightDatabaseServer::GetRowFromIP(DatabaseTable *databaseTable, SystemAddress systemAddress, unsigned *rowKey)
00577 {
00578         const DataStructures::BPlusTree<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> &rows = databaseTable->table.GetRows();
00579         DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = rows.GetListHead();
00580         DataStructures::Table::Row* row;
00581         unsigned i;
00582         if ((unsigned int) databaseTable->SystemAddressColumnIndex==(unsigned int)-1)
00583                 return 0;
00584         while (cur)
00585         {
00586                 for (i=0; i < (unsigned)cur->size; i++)
00587                 {
00588                         row = cur->data[i];
00589                         if (RowHasIP(row, systemAddress, databaseTable->SystemAddressColumnIndex ))
00590                         {
00591                                 if (rowKey)
00592                                         *rowKey=cur->keys[i];
00593                                 return row;
00594                         }
00595                 }
00596                 cur=cur->next;
00597         }
00598         return 0;
00599 }
00600 bool LightweightDatabaseServer::RowHasIP(DataStructures::Table::Row *row, SystemAddress systemAddress, unsigned SystemAddressColumnIndex)
00601 {
00602         if ((unsigned int) SystemAddressColumnIndex==(unsigned int)-1)
00603                 return false;
00604 
00605         SystemAddress sysAddr;
00606         memcpy(&sysAddr, row->cells[SystemAddressColumnIndex]->c, SystemAddress::size());
00607         return sysAddr==systemAddress;
00608 
00609         // Doesn't work in release for some reason
00610         //RakAssert(row->cells[SystemAddressColumnIndex]->isEmpty==false);
00611         //if (memcmp(row->cells[SystemAddressColumnIndex]->c, &systemAddress, SystemAddress::size())==0)
00612         //      return true;
00613         // return false;
00614 }
00615 DataStructures::Table::Row * LightweightDatabaseServer::AddRow(LightweightDatabaseServer::DatabaseTable *databaseTable, SystemAddress systemAddress, RakNetGUID guid, bool hasRowId, unsigned rowId)
00616         {
00617         DataStructures::Table::Row *row;
00618         if (databaseTable->oneRowPerSystemAddress && GetRowFromIP(databaseTable, systemAddress, 0))
00619                 return 0; // This system already has a row.
00620 
00621         if (databaseTable->autogenerateRowIDs==false)
00622                 {
00623                 // For a new row:
00624                 // rowID required but not specified OR
00625                 // rowId specified but already in the table
00626                 // Then exit
00627                 if (hasRowId==false || databaseTable->table.GetRowByID(rowId))
00628                         return 0;
00629                 }
00630         else
00631                 rowId=databaseTable->nextRowId++;
00632 
00633         // Add new row
00634         row = databaseTable->table.AddRow(rowId);
00635 
00636         // Set IP and last update time
00637         if ( databaseTable->oneRowPerSystemAddress || databaseTable->onlyUpdateOwnRows || databaseTable->removeRowOnPingFailure || databaseTable->removeRowOnDisconnect)
00638                 {
00639                 row->cells[databaseTable->SystemAddressColumnIndex]->Set((char*)&systemAddress, (int) SystemAddress::size());
00640                 row->cells[databaseTable->SystemGuidColumnIndex]->Set((char*)&guid, sizeof(guid));
00641                 }
00642         if (databaseTable->removeRowOnPingFailure)
00643                 {
00644                 RakNetTime time = RakNet::GetTime();
00645                 row->cells[databaseTable->lastPingResponseColumnIndex]->Set((int) time);
00646                 row->cells[databaseTable->nextPingSendColumnIndex]->Set((int) time+SEND_PING_INTERVAL);
00647                 }
00648 
00649         return row;
00650         }
00651 void LightweightDatabaseServer::RemoveRowsFromIP(SystemAddress systemAddress)
00652 {
00653         // Remove rows for tables that do so on a system disconnect
00654         DatabaseTable *databaseTable;
00655         DataStructures::List<unsigned> removeList;
00656         DataStructures::Table::Row* row;
00657         DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur;
00658         unsigned i,j;
00659         for (i=0; i < database.Size(); i++)
00660         {
00661                 databaseTable=database[i];
00662                 if ((unsigned int) databaseTable->SystemAddressColumnIndex!=(unsigned int)-1)
00663                 {
00664                         const DataStructures::BPlusTree<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> &rows = databaseTable->table.GetRows();
00665                         cur = rows.GetListHead();
00666                         while (cur)
00667                         {
00668                                 // Mark dropped entities
00669                                 for (j=0; j < (unsigned)cur->size; j++)
00670                                 {
00671                                         if (RowHasIP(cur->data[j], systemAddress, databaseTable->SystemAddressColumnIndex))
00672                                         {
00673                                                 if (databaseTable->removeRowOnDisconnect)
00674                                                 {
00675                                                         removeList.Insert(cur->keys[j], __FILE__, __LINE__);
00676                                                 }
00677                                                 else if (databaseTable->removeRowOnPingFailure)
00678                                                 {
00679                                                         row = cur->data[j];
00680                                                         row->cells[databaseTable->nextPingSendColumnIndex]->i=(double)(RakNet::GetTime()+SEND_PING_INTERVAL+(randomMT()%1000));
00681                                                 }
00682                                         }
00683                                 }
00684                                 cur=cur->next;
00685                         }
00686                 }
00687 
00688                 for (j=0; j < removeList.Size(); j++)
00689                         databaseTable->table.RemoveRow(removeList[j]);
00690                 removeList.Clear(true, __FILE__,__LINE__);
00691         }
00692 }
00693 #ifdef _MSC_VER
00694 #pragma warning( pop )
00695 #endif
00696 
00697 #endif // _RAKNET_SUPPORT_*

Generated on Thu Sep 30 2010 01:27:24 for RakNet by  doxygen 1.7.1