Updated Debian binary package: manpages, ppp, warnings
[barry/pauldeden.git] / src / packet.cc
blobaab45888984c04f38b8717bf22e9144447bfb56f
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-2008, 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 "m_desktop.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"
33 #include <string.h>
35 #define __DEBUG_MODE__
36 #include "debug.h"
39 namespace Barry {
41 //////////////////////////////////////////////////////////////////////////////
42 // Packet base class
45 // Command
47 /// Returns the command value of the receive packet. If receive isn't
48 /// large enough, throws Error.
49 ///
50 unsigned int Packet::Command() const
52 Protocol::CheckSize(m_receive);
53 MAKE_PACKET(rpack, m_receive);
54 return rpack->command;
58 //////////////////////////////////////////////////////////////////////////////
59 // ZeroPacket class
61 ZeroPacket::ZeroPacket(Data &send, Data &receive)
62 : Packet(send, receive)
66 ZeroPacket::~ZeroPacket()
71 // GetAttribute
73 /// Builds a command packet for the initial socket-0 handshakes
74 /// that fetch certain (some unknown) attributes. The attributes
75 /// appear to exist in an object/attribute sequence, so that's
76 /// how we address them here.
77 ///
78 void ZeroPacket::GetAttribute(unsigned int object, unsigned int attribute)
80 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + ATTRIBUTE_FETCH_COMMAND_SIZE;
81 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
82 Protocol::Packet &packet = *cpack;
84 packet.socket = 0;
85 packet.size = htobs(size);
86 packet.command = SB_COMMAND_FETCH_ATTRIBUTE;
87 packet.u.socket.socket = htobs(0x00ff); // default non-socket request
88 packet.u.socket.sequence = 0; // filled in by Socket class
89 packet.u.socket.u.fetch.object = htobs(object);
90 packet.u.socket.u.fetch.attribute = htobs(attribute);
92 m_send.ReleaseBuffer(size);
95 unsigned int ZeroPacket::ObjectID() const
97 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
98 MAKE_PACKET(rpack, m_receive);
99 return btohs(rpack->u.socket.u.fetch.object);
102 unsigned int ZeroPacket::AttributeID() const
104 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
105 MAKE_PACKET(rpack, m_receive);
106 return btohs(rpack->u.socket.u.fetch.attribute);
109 uint32_t ZeroPacket::ChallengeSeed() const
111 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE +
112 PASSWORD_CHALLENGE_SEED_SIZE);
113 MAKE_PACKET(rpack, m_receive);
114 return btohl(rpack->u.socket.u.password.u.seed);
117 unsigned int ZeroPacket::RemainingTries() const
119 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE +
120 PASSWORD_CHALLENGE_HEADER_SIZE);
121 MAKE_PACKET(rpack, m_receive);
122 // this is a byte, so no byte swapping needed
123 return rpack->u.socket.u.password.remaining_tries;
126 unsigned int ZeroPacket::SocketResponse() const
128 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
129 MAKE_PACKET(rpack, m_receive);
130 return btohs(rpack->u.socket.socket);
133 unsigned char ZeroPacket::SocketSequence() const
135 Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
136 MAKE_PACKET(rpack, m_receive);
137 return rpack->u.socket.sequence; // sequence is a byte
142 //////////////////////////////////////////////////////////////////////////////
143 // DBPacket class
145 DBPacket::DBPacket(Mode::Desktop &con, Data &send, Data &receive)
146 : Packet(send, receive)
147 , m_con(con)
148 , m_last_dbop(0)
152 DBPacket::~DBPacket()
157 // ClearDatabase
159 /// Builds a command packet for the CLEAR_DATABASE command code, placing
160 /// the data in the send buffer.
162 void DBPacket::ClearDatabase(unsigned int dbId)
164 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
165 Protocol::Packet &packet = *cpack;
167 // socket class should override this for us
168 // packet.socket = htobs(m_con.m_socket->GetSocket());
169 packet.size = htobs(9);
170 packet.command = SB_COMMAND_DB_DATA;
171 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
172 packet.u.db.u.command.operation = SB_DBOP_CLEAR_DATABASE;
173 packet.u.db.u.command.databaseId = htobs(dbId);
175 m_send.ReleaseBuffer(9);
177 m_last_dbop = SB_DBOP_CLEAR_DATABASE;
181 // GetDBDB
183 /// Builds a command packet for the GET_DBDB command code, placing the
184 /// data in m_send.
186 void DBPacket::GetDBDB()
188 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(7));
189 Protocol::Packet &packet = *cpack;
191 // socket class should override this for us
192 // packet.socket = htobs(m_con.m_socket->GetSocket());
193 packet.size = htobs(7);
194 packet.command = SB_COMMAND_DB_DATA;
195 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
196 // packet.u.db.u.command.operation = SB_DBOP_GET_DBDB;
197 packet.u.db.u.command.operation = SB_DBOP_OLD_GET_DBDB;
199 m_send.ReleaseBuffer(7);
201 m_last_dbop = SB_DBOP_OLD_GET_DBDB;
205 // GetRecordStateTable
207 /// Builds a command packet in the send buffer for the
208 /// GET_RECORD_STATE_TABLE command.
210 void DBPacket::GetRecordStateTable(unsigned int dbId)
212 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
213 Protocol::Packet &packet = *cpack;
215 // socket class should override this for us
216 // packet.socket = htobs(m_con.m_socket->GetSocket());
217 packet.size = htobs(9);
218 packet.command = SB_COMMAND_DB_DATA;
219 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
220 packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_STATE_TABLE;
221 packet.u.db.u.command.databaseId = htobs(dbId);
223 m_send.ReleaseBuffer(9);
225 m_last_dbop = SB_DBOP_GET_RECORD_STATE_TABLE;
229 // SetRecordFlags
231 /// Builds a command packet in the send buffer for the SET_RECORD_FLAGS
232 /// command code.
234 /// FIXME - this API call is incomplete, since there are unknown flags
235 /// in the SetRecordFlags protocol packet. Currently it is only
236 /// used to set all flags to zero.
238 void DBPacket::SetRecordFlags(unsigned int dbId, unsigned int stateTableIndex,
239 uint8_t flag1)
241 size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_FLAGS_SIZE;
242 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
243 Protocol::Packet &packet = *cpack;
245 // socket class should override this for us
246 // packet.socket = htobs(m_con.m_socket->GetSocket());
247 packet.size = htobs(size);
248 packet.command = SB_COMMAND_DB_DATA;
249 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
250 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_FLAGS;
251 packet.u.db.u.command.databaseId = htobs(dbId);
252 packet.u.db.u.command.u.flags.unknown = flag1;
253 packet.u.db.u.command.u.flags.index = htobs(stateTableIndex);
254 memset(packet.u.db.u.command.u.flags.unknown2, 0, sizeof(packet.u.db.u.command.u.flags.unknown2));
256 m_send.ReleaseBuffer(size);
258 m_last_dbop = SB_DBOP_SET_RECORD_FLAGS;
262 // DeleteRecordByIndex
264 /// Builds a command packet in the send buffer for the DELETE_RECORD_BY_INDEX
265 /// command code.
267 void DBPacket::DeleteRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
269 size_t size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_RECORD_HEADER_SIZE;
270 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
271 Protocol::Packet &packet = *cpack;
273 // socket class should override this for us
274 // packet.socket = htobs(m_con.m_socket->GetSocket());
275 packet.size = htobs(size);
276 packet.command = SB_COMMAND_DB_DATA;
277 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
278 packet.u.db.u.command.operation = SB_DBOP_DELETE_RECORD_BY_INDEX;
279 packet.u.db.u.command.databaseId = htobs(dbId);
280 packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
282 m_send.ReleaseBuffer(size);
284 m_last_dbop = SB_DBOP_DELETE_RECORD_BY_INDEX;
288 // GetRecordByIndex
290 /// Builds a command packet in the send buffer for the GET_RECORD_BY_INDEX
291 /// command code.
293 void DBPacket::GetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex)
295 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(11));
296 Protocol::Packet &packet = *cpack;
298 // socket class should override this for us
299 // packet.socket = htobs(m_con.m_socket->GetSocket());
300 packet.size = htobs(11);
301 packet.command = SB_COMMAND_DB_DATA;
302 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
303 packet.u.db.u.command.operation = SB_DBOP_GET_RECORD_BY_INDEX;
304 packet.u.db.u.command.databaseId = htobs(dbId);
305 packet.u.db.u.command.u.record.recordIndex = htobs(stateTableIndex);
307 m_send.ReleaseBuffer(11);
309 m_last_dbop = SB_DBOP_GET_RECORD_BY_INDEX;
313 // SetRecordByIndex
315 /// Builds a command packet in the m_send buffer for the SET_RECORD_BY_INDEX
316 /// command code.
318 /// \return bool
319 /// - true means success
320 /// - false means no data available from Builder object
322 bool DBPacket::SetRecordByIndex(unsigned int dbId, unsigned int stateTableIndex,
323 Builder &build)
325 // get new data if available
326 if( !build.Retrieve(dbId) )
327 return false;
329 // build packet data
330 size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_INDEXED_UPLOAD_HEADER_SIZE;
331 build.BuildFields(m_send, header_size);
332 size_t total_size = m_send.GetSize();
334 // fill in the header values
335 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
336 Protocol::Packet &packet = *cpack;
338 // socket class should override this for us
339 // packet.socket = htobs(m_con.m_socket->GetSocket());
340 packet.size = htobs(total_size);
341 packet.command = SB_COMMAND_DB_DATA;
342 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
343 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD_BY_INDEX;
344 packet.u.db.u.command.databaseId = htobs(dbId);
345 packet.u.db.u.command.u.index_upload.unknown = 0;
346 packet.u.db.u.command.u.index_upload.index = htobs(stateTableIndex);
348 m_send.ReleaseBuffer(total_size);
350 m_last_dbop = SB_DBOP_SET_RECORD_BY_INDEX;
351 return true;
355 // GetRecords
357 /// Builds a command packet in the send buffer for the GET_RECORDS
358 /// command code.
360 void DBPacket::GetRecords(unsigned int dbId)
362 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(9));
363 Protocol::Packet &packet = *cpack;
365 // socket class should override this for us
366 // packet.socket = htobs(m_con.m_socket->GetSocket());
367 packet.size = htobs(9);
368 packet.command = SB_COMMAND_DB_DATA;
369 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
370 packet.u.db.u.command.operation = SB_DBOP_OLD_GET_RECORDS;
371 packet.u.db.u.command.databaseId = htobs(dbId);
373 m_send.ReleaseBuffer(9);
375 m_last_dbop = SB_DBOP_OLD_GET_RECORDS;
379 // SetRecord
381 /// Builds a command packet in the m_send buffer for the SET_RECORD command
382 /// code.
384 /// \return bool
385 /// - true means success
386 /// - false means no data available from Builder object
388 bool DBPacket::SetRecord(unsigned int dbId, Builder &build)
390 // get new data if available
391 if( !build.Retrieve(dbId) )
392 return false;
394 // build packet data
395 size_t header_size = SB_PACKET_COMMAND_HEADER_SIZE + DBC_TAGGED_UPLOAD_HEADER_SIZE;
396 build.BuildHeader(m_send, header_size);
397 build.BuildFields(m_send, header_size);
398 size_t total_size = m_send.GetSize();
400 // fill in the header values
401 MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(total_size));
402 Protocol::Packet &packet = *cpack;
404 // socket class should override this for us
405 // packet.socket = htobs(m_con.m_socket->GetSocket());
406 packet.size = htobs(total_size);
407 packet.command = SB_COMMAND_DB_DATA;
408 packet.u.db.tableCmd = m_con.GetDBCommand(Mode::Desktop::DatabaseAccess);
409 packet.u.db.u.command.operation = SB_DBOP_SET_RECORD;
410 packet.u.db.u.command.databaseId = htobs(dbId);
411 packet.u.db.u.command.u.tag_upload.rectype = build.GetRecType();
412 packet.u.db.u.command.u.tag_upload.uniqueId = htobl(build.GetUniqueId());
413 packet.u.db.u.command.u.tag_upload.unknown2 = 1; // unknown observed value
415 m_send.ReleaseBuffer(total_size);
417 m_last_dbop = SB_DBOP_SET_RECORD;
418 return true;
422 // throws FIXME if packet doesn't support it
423 unsigned int DBPacket::ReturnCode() const
425 if( Command() == SB_COMMAND_DB_DONE ) {
426 Protocol::CheckSize(m_receive, SB_PACKET_DBACCESS_HEADER_SIZE + SB_DBACCESS_RETURN_CODE_SIZE);
427 MAKE_PACKET(rpack, m_receive);
428 return rpack->u.db.u.return_code;
430 else {
431 throw Error("Attempting to extract a return code from the wrong response packet type");
436 // DBOperation
438 /// Returns the database operation code from the receive packet, assuming
439 /// that receive contains a response packet. If receive isn't large
440 /// enough, throws Error.
442 unsigned int DBPacket::DBOperation() const
444 Protocol::CheckSize(m_receive, SB_PACKET_RESPONSE_HEADER_SIZE);
445 MAKE_PACKET(rpack, m_receive);
446 return rpack->u.db.u.response.operation;
450 // Parse
452 /// Parses the data in the receive buffer, and attempts to be smart about it,
453 /// using the last send command as guidance for what to expect in the
454 /// response.
456 /// \returns bool true - packet was recognized and parse was attempted
457 /// false - packet was not recognized
459 bool DBPacket::Parse(Parser &parser)
461 size_t offset = 0;
462 MAKE_PACKET(rpack, m_receive);
464 switch( m_last_dbop )
466 case SB_DBOP_OLD_GET_RECORDS:
467 case SB_DBOP_GET_RECORD_BY_INDEX:
468 parser.Clear();
470 offset = SB_PACKET_RESPONSE_HEADER_SIZE + DBR_OLD_TAGGED_RECORD_HEADER_SIZE;
471 Protocol::CheckSize(m_receive, offset);
472 // FIXME - this may need adjustment for email records... they
473 // don't seem to have uniqueID's
474 parser.SetIds(rpack->u.db.u.response.u.tagged.rectype,
475 btohl(rpack->u.db.u.response.u.tagged.uniqueId));
477 parser.ParseHeader(m_receive, offset);
478 parser.ParseFields(m_receive, offset);
479 parser.Store();
480 return true;
482 default: // unknown command
483 return false;
487 } // namespace Barry