packet.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       packet.cc
00003 ///             Low level protocol packet builder class.
00004 ///             Has knowledge of specific protocol commands in order
00005 ///             to hide protocol details behind an API.
00006 ///
00007 
00008 /*
00009     Copyright (C) 2005-2008, Net Direct Inc. (http://www.netdirect.ca/)
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020     See the GNU General Public License in the COPYING file at the
00021     root directory of this project for more details.
00022 */
00023 
00024 #include "packet.h"
00025 #include "m_desktop.h"
00026 #include "protocol.h"
00027 #include "protostructs.h"
00028 #include "data.h"
00029 #include "endian.h"
00030 #include "parser.h"
00031 #include "builder.h"
00032 #include "error.h"
00033 #include <string.h>
00034 
00035 #define __DEBUG_MODE__
00036 #include "debug.h"
00037 
00038 
00039 namespace Barry {
00040 
00041 //////////////////////////////////////////////////////////////////////////////
00042 // Packet base class
00043 
00044 //
00045 // Command
00046 //
00047 /// Returns the command value of the receive packet.  If receive isn't
00048 /// large enough, throws Error.
00049 ///
00050 unsigned int Packet::Command() const
00051 {
00052         Protocol::CheckSize(m_receive);
00053         MAKE_PACKET(rpack, m_receive);
00054         return rpack->command;
00055 }
00056 
00057 
00058 //////////////////////////////////////////////////////////////////////////////
00059 // ZeroPacket class
00060 
00061 ZeroPacket::ZeroPacket(Data &send, Data &receive)
00062         : Packet(send, receive)
00063 {
00064 }
00065 
00066 ZeroPacket::~ZeroPacket()
00067 {
00068 }
00069 
00070 //
00071 // GetAttribute
00072 //
00073 /// Builds a command packet for the initial socket-0 handshakes
00074 /// that fetch certain (some unknown) attributes.  The attributes
00075 /// appear to exist in an object/attribute sequence, so that's
00076 /// how we address them here.
00077 ///
00078 void ZeroPacket::GetAttribute(unsigned int object, unsigned int attribute)
00079 {
00080         size_t size = SB_SOCKET_PACKET_HEADER_SIZE + ATTRIBUTE_FETCH_COMMAND_SIZE;
00081         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
00082         Protocol::Packet &packet = *cpack;
00083 
00084         packet.socket = 0;
00085         packet.size = htobs(size);
00086         packet.command = SB_COMMAND_FETCH_ATTRIBUTE;
00087         packet.u.socket.socket = htobs(0x00ff); // default non-socket request
00088         packet.u.socket.sequence = 0;           // filled in by Socket class
00089         packet.u.socket.u.fetch.object = htobs(object);
00090         packet.u.socket.u.fetch.attribute = htobs(attribute);
00091 
00092         m_send.ReleaseBuffer(size);
00093 }
00094 
00095 unsigned int ZeroPacket::ObjectID() const
00096 {
00097         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
00098         MAKE_PACKET(rpack, m_receive);
00099         return btohs(rpack->u.socket.u.fetch.object);
00100 }
00101 
00102 unsigned int ZeroPacket::AttributeID() const
00103 {
00104         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
00105         MAKE_PACKET(rpack, m_receive);
00106         return btohs(rpack->u.socket.u.fetch.attribute);
00107 }
00108 
00109 uint32_t ZeroPacket::ChallengeSeed() const
00110 {
00111         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE +
00112                 PASSWORD_CHALLENGE_SEED_SIZE);
00113         MAKE_PACKET(rpack, m_receive);
00114         return btohl(rpack->u.socket.u.password.u.seed);
00115 }
00116 
00117 unsigned int ZeroPacket::RemainingTries() const
00118 {
00119         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE +
00120                 PASSWORD_CHALLENGE_HEADER_SIZE);
00121         MAKE_PACKET(rpack, m_receive);
00122         // this is a byte, so no byte swapping needed
00123         return rpack->u.socket.u.password.remaining_tries;
00124 }
00125 
00126 unsigned int ZeroPacket::SocketResponse() const
00127 {
00128         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
00129         MAKE_PACKET(rpack, m_receive);
00130         return btohs(rpack->u.socket.socket);
00131 }
00132 
00133 unsigned char ZeroPacket::SocketSequence() const
00134 {
00135         Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
00136         MAKE_PACKET(rpack, m_receive);
00137         return rpack->u.socket.sequence;        // sequence is a byte
00138 }
00139 
00140 
00141 
00142 //////////////////////////////////////////////////////////////////////////////
00143 // DBPacket class
00144 
00145 DBPacket::DBPacket(Mode::Desktop &con, Data &send, Data &receive)
00146         : Packet(send, receive)
00147         , m_con(con)
00148         , m_last_dbop(0)
00149 {
00150 }
00151 
00152 DBPacket::~DBPacket()
00153 {
00154 }
00155 
00156 //
00157 // ClearDatabase
00158 //
00159 /// Builds a command packet for the CLEAR_DATABASE command code, placing
00160 /// the data in the send buffer.
00161 ///
00162 void DBPacket::ClearDatabase(unsigned int dbId)
00163 {
00164         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
00165         Protocol::Packet &packet = *cpack;
00166 
00167         // socket class should override this for us
00168 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00169         packet.size = htobs(9);
00170         packet.command = SB_COMMAND_DB_DATA;
00171         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00172         packet.u.db.u.command.operation = SB_DBOP_CLEAR_DATABASE;
00173         packet.u.db.u.command.databaseId = htobs(dbId);
00174 
00175         m_send.ReleaseBuffer(9);
00176 
00177         m_last_dbop = SB_DBOP_CLEAR_DATABASE;
00178 }
00179 
00180 //
00181 // GetDBDB
00182 //
00183 /// Builds a command packet for the GET_DBDB command code, placing the
00184 /// data in m_send.
00185 ///
00186 void DBPacket::GetDBDB()
00187 {
00188         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(7));
00189         Protocol::Packet &packet = *cpack;
00190 
00191         // socket class should override this for us
00192 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00193         packet.size = htobs(7);
00194         packet.command = SB_COMMAND_DB_DATA;
00195         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00196 //      packet.u.db.u.command.operation = SB_DBOP_GET_DBDB;
00197         packet.u.db.u.command.operation = SB_DBOP_OLD_GET_DBDB;
00198 
00199         m_send.ReleaseBuffer(7);
00200 
00201         m_last_dbop = SB_DBOP_OLD_GET_DBDB;
00202 }
00203 
00204 //
00205 // GetRecordStateTable
00206 //
00207 /// Builds a command packet in the send buffer for the
00208 /// GET_RECORD_STATE_TABLE command.
00209 ///
00210 void DBPacket::GetRecordStateTable(unsigned int dbId)
00211 {
00212         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
00213         Protocol::Packet &packet = *cpack;
00214 
00215         // socket class should override this for us
00216 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00217         packet.size = htobs(9);
00218         packet.command = SB_COMMAND_DB_DATA;
00219         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00220         packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_STATE_TABLE;
00221         packet.u.db.u.command.databaseId = htobs(dbId);
00222 
00223         m_send.ReleaseBuffer(9);
00224 
00225         m_last_dbop = SB_DBOP_GET_RECORD_STATE_TABLE;
00226 }
00227 
00228 //
00229 // SetRecordFlags
00230 //
00231 /// Builds a command packet in the send buffer for the SET_RECORD_FLAGS
00232 /// command code.
00233 ///
00234 /// FIXME - this API call is incomplete, since there are unknown flags
00235 ///         in the SetRecordFlags protocol packet.  Currently it is only
00236 ///         used to set all flags to zero.
00237 ///
00238 void DBPacket::SetRecordFlags(unsigned int dbId, unsigned int stateTableIndex,
00239                             uint8_t flag1)
00240 {
00241         size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_FLAGS_SIZE;
00242         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
00243         Protocol::Packet &packet = *cpack;
00244 
00245         // socket class should override this for us
00246 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00247         packet.size = htobs(size);
00248         packet.command = SB_COMMAND_DB_DATA;
00249         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00250         packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_FLAGS;
00251         packet.u.db.u.command.databaseId = htobs(dbId);
00252         packet.u.db.u.command.u.flags.unknown = flag1;
00253         packet.u.db.u.command.u.flags.index = htobs(stateTableIndex);
00254         memset(packet.u.db.u.command.u.flags.unknown2, 0, sizeof(packet.u.db.u.command.u.flags.unknown2));
00255 
00256         m_send.ReleaseBuffer(size);
00257 
00258         m_last_dbop = SB_DBOP_SET_RECORD_FLAGS;
00259 }
00260 
00261 //
00262 // DeleteRecordByIndex
00263 //
00264 /// Builds a command packet in the send buffer for the DELETE_RECORD_BY_INDEX
00265 /// command code.
00266 ///
00267 void DBPacket::DeleteRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
00268 {
00269         size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_HEADER_SIZE;
00270         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
00271         Protocol::Packet &packet = *cpack;
00272 
00273         // socket class should override this for us
00274 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00275         packet.size = htobs(size);
00276         packet.command = SB_COMMAND_DB_DATA;
00277         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00278         packet.u.db.u.command.operation = SB_DBOP_DELETE_RECORD_BY_INDEX;
00279         packet.u.db.u.command.databaseId = htobs(dbId);
00280         packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
00281 
00282         m_send.ReleaseBuffer(size);
00283 
00284         m_last_dbop = SB_DBOP_DELETE_RECORD_BY_INDEX;
00285 }
00286 
00287 //
00288 // GetRecordByIndex
00289 //
00290 /// Builds a command packet in the send buffer for the GET_RECORD_BY_INDEX
00291 /// command code.
00292 ///
00293 void DBPacket::GetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
00294 {
00295         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(11));
00296         Protocol::Packet &packet = *cpack;
00297 
00298         // socket class should override this for us
00299 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00300         packet.size = htobs(11);
00301         packet.command = SB_COMMAND_DB_DATA;
00302         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00303         packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_BY_INDEX;
00304         packet.u.db.u.command.databaseId = htobs(dbId);
00305         packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
00306 
00307         m_send.ReleaseBuffer(11);
00308 
00309         m_last_dbop = SB_DBOP_GET_RECORD_BY_INDEX;
00310 }
00311 
00312 //
00313 // SetRecordByIndex
00314 //
00315 /// Builds a command packet in the m_send buffer for the SET_RECORD_BY_INDEX
00316 /// command code.
00317 ///
00318 /// \return     bool
00319 ///             - true means success
00320 ///             - false means no data available from Builder object
00321 ///
00322 bool DBPacket::SetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex,
00323                               Builder &build)
00324 {
00325         // get new data if available
00326         if( !build.Retrieve(dbId) )
00327                 return false;
00328 
00329         // build packet data
00330         size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_INDEXED_UPLOAD_HEADER_SIZE;
00331         build.BuildFields(m_send, header_size);
00332         size_t total_size = m_send.GetSize();
00333 
00334         // fill in the header values
00335         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
00336         Protocol::Packet &packet = *cpack;
00337 
00338         // socket class should override this for us
00339 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00340         packet.size = htobs(total_size);
00341         packet.command = SB_COMMAND_DB_DATA;
00342         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00343         packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_BY_INDEX;
00344         packet.u.db.u.command.databaseId = htobs(dbId);
00345         packet.u.db.u.command.u.index_upload.unknown = 0;
00346         packet.u.db.u.command.u.index_upload.index = htobs(stateTableIndex);
00347 
00348         m_send.ReleaseBuffer(total_size);
00349 
00350         m_last_dbop = SB_DBOP_SET_RECORD_BY_INDEX;
00351         return true;
00352 }
00353 
00354 //
00355 // GetRecords
00356 //
00357 /// Builds a command packet in the send buffer for the GET_RECORDS
00358 /// command code.
00359 ///
00360 void DBPacket::GetRecords(unsigned int dbId)
00361 {
00362         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
00363         Protocol::Packet &packet = *cpack;
00364 
00365         // socket class should override this for us
00366 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00367         packet.size = htobs(9);
00368         packet.command = SB_COMMAND_DB_DATA;
00369         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00370         packet.u.db.u.command.operation = SB_DBOP_OLD_GET_RECORDS;
00371         packet.u.db.u.command.databaseId = htobs(dbId);
00372 
00373         m_send.ReleaseBuffer(9);
00374 
00375         m_last_dbop = SB_DBOP_OLD_GET_RECORDS;
00376 }
00377 
00378 //
00379 // SetRecord
00380 //
00381 /// Builds a command packet in the m_send buffer for the SET_RECORD command
00382 /// code.
00383 ///
00384 /// \return     bool
00385 ///             - true means success
00386 ///             - false means no data available from Builder object
00387 ///
00388 bool DBPacket::SetRecord(unsigned int dbId, Builder &build)
00389 {
00390         // get new data if available
00391         if( !build.Retrieve(dbId) )
00392                 return false;
00393 
00394         // build packet data
00395         size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_TAGGED_UPLOAD_HEADER_SIZE;
00396         build.BuildHeader(m_send, header_size);
00397         build.BuildFields(m_send, header_size);
00398         size_t total_size = m_send.GetSize();
00399 
00400         // fill in the header values
00401         MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
00402         Protocol::Packet &packet = *cpack;
00403 
00404         // socket class should override this for us
00405 //      packet.socket = htobs(m_con.m_socket->GetSocket());
00406         packet.size = htobs(total_size);
00407         packet.command = SB_COMMAND_DB_DATA;
00408         packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
00409         packet.u.db.u.command.operation = SB_DBOP_SET_RECORD;
00410         packet.u.db.u.command.databaseId = htobs(dbId);
00411         packet.u.db.u.command.u.tag_upload.rectype = build.GetRecType();
00412         packet.u.db.u.command.u.tag_upload.uniqueId = htobl(build.GetUniqueId());
00413         packet.u.db.u.command.u.tag_upload.unknown2 = 1;        // unknown observed value
00414 
00415         m_send.ReleaseBuffer(total_size);
00416 
00417         m_last_dbop = SB_DBOP_SET_RECORD;
00418         return true;
00419 }
00420 
00421 
00422 // throws FIXME if packet doesn't support it
00423 unsigned int DBPacket::ReturnCode() const
00424 {
00425         if( Command() == SB_COMMAND_DB_DONE ) {
00426                 Protocol::CheckSize(m_receive, SB_PACKET_DBACCESS_HEADER_SIZE + SB_DBACCESS_RETURN_CODE_SIZE);
00427                 MAKE_PACKET(rpack, m_receive);
00428                 return rpack->u.db.u.return_code;
00429         }
00430         else {
00431                 throw Error("Attempting to extract a return code from the wrong response packet type");
00432         }
00433 }
00434 
00435 //
00436 // DBOperation
00437 //
00438 /// Returns the database operation code from the receive packet, assuming
00439 /// that receive contains a response packet.  If receive isn't large
00440 /// enough, throws Error.
00441 ///
00442 unsigned int DBPacket::DBOperation() const
00443 {
00444         Protocol::CheckSize(m_receive, SB_PACKET_RESPONSE_HEADER_SIZE);
00445         MAKE_PACKET(rpack, m_receive);
00446         return rpack->u.db.u.response.operation;
00447 }
00448 
00449 //
00450 // Parse
00451 //
00452 /// Parses the data in the receive buffer, and attempts to be smart about it,
00453 /// using the last send command as guidance for what to expect in the
00454 /// response.
00455 ///
00456 /// \returns    bool    true - packet was recognized and parse was attempted
00457 ///                     false - packet was not recognized
00458 ///
00459 bool DBPacket::Parse(Parser &parser)
00460 {
00461         size_t offset = 0;
00462         MAKE_PACKET(rpack, m_receive);
00463 
00464         switch( m_last_dbop )
00465         {
00466         case SB_DBOP_OLD_GET_RECORDS:
00467         case SB_DBOP_GET_RECORD_BY_INDEX:
00468                 parser.Clear();
00469 
00470                 offset = SB_PACKET_RESPONSE_HEADER_SIZE + DBR_OLD_TAGGED_RECORD_HEADER_SIZE;
00471                 Protocol::CheckSize(m_receive, offset);
00472                 // FIXME - this may need adjustment for email records... they
00473                 // don't seem to have uniqueID's
00474                 parser.SetIds(rpack->u.db.u.response.u.tagged.rectype,
00475                         btohl(rpack->u.db.u.response.u.tagged.uniqueId));
00476 
00477                 parser.ParseHeader(m_receive, offset);
00478                 parser.ParseFields(m_receive, offset);
00479                 parser.Store();
00480                 return true;
00481 
00482         default:        // unknown command
00483                 return false;
00484         }
00485 }
00486 
00487 } // namespace Barry
00488 

Generated on Wed Sep 24 21:27:32 2008 for Barry by  doxygen 1.5.1