- fixed compile error on g++ 3.3 systems (missing stdint.h in probe.h)
[barry.git] / src / packet.cc
blob561816864e415657ef47ce8a7d7547fd10e7576a
1 ///
2 /// \file packet.cc
3 /// Low level protocol packet builder class.
4 /// Has knowledge of specific protocol commands in order
5 /// to hide protocol details behind an API.
6 ///
8 /*
9 Copyright (C) 2005-2006, Net Direct Inc. (http://www.netdirect.ca/)
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
24 #include "packet.h"
25 #include "controller.h"
26 #include "protocol.h"
27 #include "protostructs.h"
28 #include "data.h"
29 #include "endian.h"
30 #include "parser.h"
31 #include "builder.h"
32 #include "error.h"
34 #include "common.h"
37 #define __DEBUG_MODE__
38 #include "debug.h"
41 namespace Barry {
43 Packet::Packet(Controller &con, Data &send, Data &receive)
44 : m_con(con)
45 , m_send(send)
46 , m_receive(receive)
47 , m_last_dbop(0)
51 Packet::~Packet()
56 // ClearDatabase
58 /// Builds a command packet for the CLEAR_DATABASE command code, placing
59 /// the data in the send buffer.
60 ///
61 void Packet::ClearDatabase(unsigned int dbId)
63 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
64 Protocol::Packet &packet = *cpack;
66 packet.socket = htobs(m_con.m_socket.GetSocket());
67 packet.size = htobs(9);
68 packet.command = SB_COMMAND_DB_DATA;
69 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
70 packet.u.db.u.command.operation = SB_DBOP_CLEAR_DATABASE;
71 packet.u.db.u.command.databaseId = htobs(dbId);
73 m_send.ReleaseBuffer(9);
75 m_last_dbop = SB_DBOP_CLEAR_DATABASE;
79 // GetDBDB
81 /// Builds a command packet for the GET_DBDB command code, placing the
82 /// data in m_send.
83 ///
84 void Packet::GetDBDB()
86 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(7));
87 Protocol::Packet &packet = *cpack;
89 packet.socket = htobs(m_con.m_socket.GetSocket());
90 packet.size = htobs(7);
91 packet.command = SB_COMMAND_DB_DATA;
92 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
93 // packet.u.db.u.command.operation = SB_DBOP_GET_DBDB;
94 packet.u.db.u.command.operation = SB_DBOP_OLD_GET_DBDB;
96 m_send.ReleaseBuffer(7);
98 m_last_dbop = SB_DBOP_OLD_GET_DBDB;
102 // GetRecordStateTable
104 /// Builds a command packet in the send buffer for the
105 /// GET_RECORD_STATE_TABLE command.
107 void Packet::GetRecordStateTable(unsigned int dbId)
109 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
110 Protocol::Packet &packet = *cpack;
112 packet.socket = htobs(m_con.m_socket.GetSocket());
113 packet.size = htobs(9);
114 packet.command = SB_COMMAND_DB_DATA;
115 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
116 packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_STATE_TABLE;
117 packet.u.db.u.command.databaseId = htobs(dbId);
119 m_send.ReleaseBuffer(9);
121 m_last_dbop = SB_DBOP_GET_RECORD_STATE_TABLE;
125 // SetRecordFlags
127 /// Builds a command packet in the send buffer for the SET_RECORD_FLAGS
128 /// command code.
130 /// FIXME - this API call is incomplete, since there are unknown flags
131 /// in the SetRecordFlags protocol packet. Currently it is only
132 /// used to set all flags to zero.
134 void Packet::SetRecordFlags(unsigned int dbId, unsigned int stateTableIndex,
135 uint8_t flag1)
137 size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_FLAGS_SIZE;
138 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
139 Protocol::Packet &packet = *cpack;
141 packet.socket = htobs(m_con.m_socket.GetSocket());
142 packet.size = htobs(size);
143 packet.command = SB_COMMAND_DB_DATA;
144 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
145 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_FLAGS;
146 packet.u.db.u.command.databaseId = htobs(dbId);
147 packet.u.db.u.command.u.flags.unknown = flag1;
148 packet.u.db.u.command.u.flags.index = htobs(stateTableIndex);
149 memset(packet.u.db.u.command.u.flags.unknown2, 0, sizeof(packet.u.db.u.command.u.flags.unknown2));
151 m_send.ReleaseBuffer(size);
153 m_last_dbop = SB_DBOP_SET_RECORD_FLAGS;
157 // DeleteRecordByIndex
159 /// Builds a command packet in the send buffer for the DELETE_RECORD_BY_INDEX
160 /// command code.
162 void Packet::DeleteRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
164 size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_HEADER_SIZE;
165 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
166 Protocol::Packet &packet = *cpack;
168 packet.socket = htobs(m_con.m_socket.GetSocket());
169 packet.size = htobs(size);
170 packet.command = SB_COMMAND_DB_DATA;
171 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
172 packet.u.db.u.command.operation = SB_DBOP_DELETE_RECORD_BY_INDEX;
173 packet.u.db.u.command.databaseId = htobs(dbId);
174 packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
176 m_send.ReleaseBuffer(size);
178 m_last_dbop = SB_DBOP_DELETE_RECORD_BY_INDEX;
182 // GetRecordByIndex
184 /// Builds a command packet in the send buffer for the GET_RECORD_BY_INDEX
185 /// command code.
187 void Packet::GetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
189 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(11));
190 Protocol::Packet &packet = *cpack;
192 packet.socket = htobs(m_con.m_socket.GetSocket());
193 packet.size = htobs(11);
194 packet.command = SB_COMMAND_DB_DATA;
195 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
196 packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_BY_INDEX;
197 packet.u.db.u.command.databaseId = htobs(dbId);
198 packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
200 m_send.ReleaseBuffer(11);
202 m_last_dbop = SB_DBOP_GET_RECORD_BY_INDEX;
206 // SetRecordByIndex
208 /// Builds a command packet in the m_send buffer for the SET_RECORD_BY_INDEX
209 /// command code.
211 /// \return bool
212 /// - true means success
213 /// - false means no data available from Builder object
215 bool Packet::SetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex,
216 Builder &build)
218 // get new data if available
219 if( !build.Retrieve(dbId) )
220 return false;
222 // build packet data
223 size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_INDEXED_UPLOAD_HEADER_SIZE;
224 build.BuildFields(m_send, header_size);
225 size_t total_size = m_send.GetSize();
227 // fill in the header values
228 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
229 Protocol::Packet &packet = *cpack;
231 packet.socket = htobs(m_con.m_socket.GetSocket());
232 packet.size = htobs(total_size);
233 packet.command = SB_COMMAND_DB_DATA;
234 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
235 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_BY_INDEX;
236 packet.u.db.u.command.databaseId = htobs(dbId);
237 packet.u.db.u.command.u.index_upload.unknown = 0;
238 packet.u.db.u.command.u.index_upload.index = htobs(stateTableIndex);
240 m_send.ReleaseBuffer(total_size);
242 m_last_dbop = SB_DBOP_SET_RECORD_BY_INDEX;
243 return true;
247 // GetRecords
249 /// Builds a command packet in the send buffer for the GET_RECORDS
250 /// command code.
252 void Packet::GetRecords(unsigned int dbId)
254 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
255 Protocol::Packet &packet = *cpack;
257 packet.socket = htobs(m_con.m_socket.GetSocket());
258 packet.size = htobs(9);
259 packet.command = SB_COMMAND_DB_DATA;
260 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
261 packet.u.db.u.command.operation = SB_DBOP_OLD_GET_RECORDS;
262 packet.u.db.u.command.databaseId = htobs(dbId);
264 m_send.ReleaseBuffer(9);
266 m_last_dbop = SB_DBOP_OLD_GET_RECORDS;
270 // SetRecord
272 /// Builds a command packet in the m_send buffer for the SET_RECORD command
273 /// code.
275 /// \return bool
276 /// - true means success
277 /// - false means no data available from Builder object
279 bool Packet::SetRecord(unsigned int dbId, Builder &build)
281 // get new data if available
282 if( !build.Retrieve(dbId) )
283 return false;
285 // build packet data
286 size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_TAGGED_UPLOAD_HEADER_SIZE;
287 build.BuildHeader(m_send, header_size);
288 build.BuildFields(m_send, header_size);
289 size_t total_size = m_send.GetSize();
291 // fill in the header values
292 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
293 Protocol::Packet &packet = *cpack;
295 packet.socket = htobs(m_con.m_socket.GetSocket());
296 packet.size = htobs(total_size);
297 packet.command = SB_COMMAND_DB_DATA;
298 packet.u.db.tableCmd = m_con.GetCommand(Controller::DatabaseAccess);
299 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD;
300 packet.u.db.u.command.databaseId = htobs(dbId);
301 packet.u.db.u.command.u.tag_upload.unknown = 0;
302 packet.u.db.u.command.u.tag_upload.uniqueId = htobl(build.GetUniqueId());
303 packet.u.db.u.command.u.tag_upload.unknown2 = 1; // unknown observed value
305 m_send.ReleaseBuffer(total_size);
307 m_last_dbop = SB_DBOP_SET_RECORD;
308 return true;
313 // Command
315 /// Returns the command value of the receive packet. If receive isn't
316 /// large enough, throws BError.
318 unsigned int Packet::Command() const
320 Protocol::CheckSize(m_receive);
321 MAKE_PACKET(rpack, m_receive);
322 return rpack->command;
325 // throws FIXME if packet doesn't support it
326 unsigned int Packet::ReturnCode() const
328 if( Command() == SB_COMMAND_DB_DONE ) {
329 Protocol::CheckSize(m_receive, SB_PACKET_DBACCESS_HEADER_SIZE + SB_DBACCESS_RETURN_CODE_SIZE);
330 MAKE_PACKET(rpack, m_receive);
331 return rpack->u.db.u.return_code;
333 else {
334 throw BError("Attempting to extract a return code from the wrong response packet type");
339 // DBOperation
341 /// Returns the database operation code from the receive packet, assuming
342 /// that receive contains a response packet. If receive isn't large
343 /// enough, throws BError.
345 unsigned int Packet::DBOperation() const
347 Protocol::CheckSize(m_receive, SB_PACKET_RESPONSE_HEADER_SIZE);
348 MAKE_PACKET(rpack, m_receive);
349 return rpack->u.db.u.response.operation;
353 // Parse
355 /// Parses the data in the receive buffer, and attempts to be smart about it,
356 /// using the last send command as guidance for what to expect in the
357 /// response.
359 /// \returns bool true - packet was recognized and parse was attempted
360 /// false - packet was not recognized
362 bool Packet::Parse(Parser &parser)
364 size_t offset = 0;
365 MAKE_PACKET(rpack, m_receive);
367 switch( m_last_dbop )
369 case SB_DBOP_OLD_GET_RECORDS:
370 case SB_DBOP_GET_RECORD_BY_INDEX:
371 parser.Clear();
373 offset = SB_PACKET_RESPONSE_HEADER_SIZE + DBR_OLD_TAGGED_RECORD_HEADER_SIZE;
374 Protocol::CheckSize(m_receive, offset);
375 // FIXME - this may need adjustment for email records... they
376 // don't seem to have uniqueID's
377 parser.SetUniqueId(btohl(rpack->u.db.u.response.u.tagged.uniqueId));
379 parser.ParseHeader(m_receive, offset);
380 parser.ParseFields(m_receive, offset);
381 parser.Store();
382 return true;
384 default: // unknown command
385 return false;
389 } // namespace Barry