- fixed compile error on g++ 3.3 systems (missing stdint.h in probe.h)
[barry.git] / src / socket.cc
blob2ce85387bb5d0be0e53475baec92c4412d9b6888
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2006, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "socket.h"
23 #include "usbwrap.h"
24 #include "protocol.h"
25 #include "protostructs.h"
26 #include "debug.h"
27 #include "data.h"
28 #include "error.h"
29 #include "packet.h"
32 using namespace Usb;
35 namespace Barry {
37 Socket::Socket(Device &dev, int writeEndpoint, int readEndpoint)
38 : m_dev(dev),
39 m_writeEp(writeEndpoint),
40 m_readEp(readEndpoint),
41 m_socket(0),
42 m_flag(0),
43 m_sequenceId(0),
44 m_lastStatus(0)
48 Socket::~Socket()
50 // trap exceptions in the destructor
51 try {
52 // a non-default socket has been opened, close it
53 Close();
55 catch( std::runtime_error &re ) {
56 // do nothing... log it?
57 dout("Exception caught in ~Socket: " << re.what());
62 // Open
64 /// Open a logical socket on the device.
65 ///
66 /// Both the socket number and the flag are based on the response to the
67 /// SELECT_MODE command. See Controller::SelectMode() for more info
68 /// on this.
69 ///
70 /// The packet sequence is normal for most socket operations.
71 ///
72 /// - Down: command packet with OPEN_SOCKET
73 /// - Up: optional sequence handshake packet
74 /// - Up: command response, which repeats the socket and flag data
75 /// as confirmation
76 ///
77 /// \exception Barry::BError
78 ///
79 void Socket::Open(uint16_t socket, uint8_t flag)
81 if( m_socket != 0 ) {
82 // already open
83 throw BError("Socket: already open");
86 // build open command
87 Barry::Protocol::Packet packet;
88 packet.socket = 0;
89 packet.size = SB_SOCKET_PACKET_SIZE;
90 packet.command = SB_COMMAND_OPEN_SOCKET;
91 packet.u.socket.socket = socket;
92 packet.u.socket.param = flag;
94 Data send(&packet, packet.size);
95 Data receive;
96 if( !Send(send, receive) ) {
97 eeout(send, receive);
98 throw BError(GetLastStatus(), "Error opening socket");
101 // starting fresh, reset sequence ID
102 Protocol::CheckSize(receive);
103 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
104 CheckSequence(receive);
106 // still need our ACK
107 Receive(receive);
110 Protocol::CheckSize(receive, SB_SOCKET_PACKET_SIZE);
111 MAKE_PACKET(rpack, receive);
112 if( rpack->command != SB_COMMAND_OPENED_SOCKET ||
113 rpack->u.socket.socket != socket ||
114 rpack->u.socket.param != flag )
116 eout("Packet:\n" << receive);
117 throw BError("Socket: Bad OPENED packet in Open");
120 // success! save the socket
121 m_socket = socket;
122 m_flag = flag;
126 // Close
128 /// Closes a non-default socket (i.e. non-zero socket number)
130 /// The packet sequence is just like Open(), except the command is
131 /// CLOSE_SOCKET.
133 /// \exception Barry::BError
135 void Socket::Close()
137 if( m_socket != 0 ) {
138 // only close non-default sockets
140 // build close command
141 Barry::Protocol::Packet packet;
142 packet.socket = 0;
143 packet.size = SB_SOCKET_PACKET_SIZE;
144 packet.command = SB_COMMAND_CLOSE_SOCKET;
145 packet.u.socket.socket = m_socket;
146 packet.u.socket.param = m_flag;
148 Data command(&packet, packet.size);
149 Data response;
150 if( !Send(command, response) ) {
151 // reset so this won't be called again
152 m_socket = 0;
153 m_flag = 0;
155 eeout(command, response);
156 throw BError(GetLastStatus(), "Error closing socket");
159 // starting fresh, reset sequence ID
160 Protocol::CheckSize(response);
161 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
162 CheckSequence(response);
164 // still need our ACK
165 Receive(response);
168 Protocol::CheckSize(response, SB_SOCKET_PACKET_SIZE);
169 MAKE_PACKET(rpack, response);
170 if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
171 rpack->u.socket.socket != m_socket ||
172 rpack->u.socket.param != m_flag )
174 // reset so this won't be called again
175 m_socket = 0;
176 m_flag = 0;
178 eout("Packet:\n" << response);
179 throw BError("Socket: Bad CLOSED packet in Close");
182 // and finally, there always seems to be an extra read of
183 // an empty packet at the end... just throw it away
184 // Receive(response);
186 // reset socket and flag
187 m_socket = 0;
188 m_flag = 0;
193 // Send
195 /// Sends 'send' data to device, and waits for response, using
196 /// "read first, write second" order observed in capture.
198 /// \returns bool
199 /// - true on success
200 /// - false on failure, use GetLastStatus() for kernel
201 /// URB error code
203 bool Socket::Send(const Data &send, Data &receive)
205 // Special case: it seems that sending packets with a size that's an
206 // exact multiple of 0x40 causes the device to get confused.
208 // To get around that, it is observed in the captures that the size
209 // is sent in a special 3 byte packet before the real packet.
210 // Check for this case here.
212 if( (send.GetSize() % 0x40) == 0 ) {
213 Protocol::SizePacket packet;
214 packet.size = send.GetSize();
215 packet.buffer[2] = 0; // zero the top byte
216 Data sizeCommand(&packet, 3);
218 m_dev.BulkWrite(m_writeEp, sizeCommand);
221 m_dev.BulkWrite(m_writeEp, send);
222 m_dev.BulkRead(m_readEp, receive);
224 // the stable libusb doesn't give us the actual size read,
225 // so parse the first bit of the packet for the size field
226 m_lastStatus = m_dev.GetLastError();
227 receive.ReleaseBuffer(receive.GetBufSize());
228 unsigned int bufsize = Protocol::GetSize(receive);
229 if( bufsize < receive.GetBufSize() )
230 receive.ReleaseBuffer(bufsize);
231 return m_lastStatus >= 0;
234 bool Socket::Receive(Data &receive)
236 m_dev.BulkRead(m_readEp, receive);
238 // the stable libusb doesn't give us the actual size read,
239 // so parse the first bit of the packet for the size field
240 m_lastStatus = m_dev.GetLastError();
241 receive.ReleaseBuffer(receive.GetBufSize());
242 unsigned int bufsize = Protocol::GetSize(receive);
243 if( bufsize < receive.GetBufSize() )
244 receive.ReleaseBuffer(bufsize);
245 return m_lastStatus >= 0;
248 // appends fragment to whole... if whole is empty, simply copies, and
249 // sets command to DATA instead of FRAGMENTED. Always updates the
250 // packet size of whole, to reflect the total size
251 void Socket::AppendFragment(Data &whole, const Data &fragment)
253 if( whole.GetSize() == 0 ) {
254 // empty, so just copy
255 whole = fragment;
257 else {
258 // has some data already, so just append
259 int size = whole.GetSize();
260 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
261 MAKE_PACKET(fpack, fragment);
262 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
264 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
265 whole.ReleaseBuffer(size + fragsize);
268 // update whole's size and command type for future sanity
269 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
270 wpack->size = (uint16_t) whole.GetSize();
271 wpack->command = SB_COMMAND_DB_DATA;
272 // don't need to call ReleaseBuffer here, since we're not changing
273 // the real size size
276 // If offset is 0, starts fresh, taking the first fragment packet size chunk
277 // out of whole and creating a sendable packet in fragment. Returns the
278 // next offset if there is still more data, or 0 if finished.
279 unsigned int Socket::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
281 // sanity check
282 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
283 eout("Whole packet too short to fragment: " << whole.GetSize());
284 throw BError("Socket: Whole packet too short to fragment");
287 // calculate size
288 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
289 unsigned int nextOffset = 0;
290 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
291 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
292 nextOffset = offset + todo;
295 // create fragment header
296 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
297 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
299 // copy over a fragment size of data
300 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
302 // update fragment's size and command type
303 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
304 wpack->size = (uint16_t) (todo + SB_FRAG_HEADER_SIZE);
305 if( nextOffset )
306 wpack->command = SB_COMMAND_DB_FRAGMENTED;
307 else
308 wpack->command = SB_COMMAND_DB_DATA;
310 // adjust the new fragment size
311 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
313 // return next round
314 return nextOffset;
317 void Socket::CheckSequence(const Data &seq)
319 // if( m_socket == 0 ) {
320 // // don't do any sequence checking on socket 0
321 // return;
322 // }
324 MAKE_PACKET(spack, seq);
325 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
326 eout("Short sequence packet:\n" << seq);
327 throw BError("Socket: invalid sequence packet");
330 // we'll cheat here... if the packet's sequence is 0, we'll
331 // silently restart, otherwise, fail
332 uint32_t sequenceId = spack->u.sequence.sequenceId;
333 if( sequenceId == 0 ) {
334 // silently restart (will advance below)
335 m_sequenceId = 0;
337 else {
338 if( sequenceId != m_sequenceId ) {
339 if( m_socket != 0 ) {
340 eout("Socket sequence: " << m_sequenceId
341 << ". Packet sequence: " << sequenceId);
342 throw BError("Socket: out of sequence");
344 else {
345 dout("Bad sequence on socket 0: expected: "
346 << msequenceId
347 << ". Packet sequence: " << sequenceId);
352 // advance!
353 m_sequenceId++;
356 // sends the send packet down to the device, fragmenting if
357 // necessary, and returns the response in receive, defragmenting
358 // if needed
359 // Blocks until response received or timed out in Usb::Device
360 bool Socket::Packet(const Data &send, Data &receive)
363 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
364 // function that forces the socket number to the correct current value,
365 // but putting it here means a copy on every packet.
367 // force socket to our socket
368 Data send = sendorig;
369 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
370 sspack->socket = GetSocket();
373 MAKE_PACKET(spack, send);
374 if( send.GetSize() < MIN_PACKET_SIZE ||
375 (spack->command != SB_COMMAND_DB_DATA &&
376 spack->command != SB_COMMAND_DB_DONE) )
378 // we don't do that around here
379 throw std::logic_error("Socket: unknown send data in Packet()");
382 Data inFrag;
383 receive.Zap();
385 if( send.GetSize() <= MAX_PACKET_SIZE ) {
386 // send non-fragmented
387 if( !Send(send, inFrag) )
388 return false;
390 else {
391 // send fragmented
392 unsigned int offset = 0;
393 Data outFrag;
395 do {
396 offset = MakeNextFragment(send, outFrag, offset);
397 if( !Send(outFrag, inFrag) )
398 return false;
400 MAKE_PACKET(rpack, inFrag);
401 // only process sequence handshakes... once we
402 // get to the last fragment, we fall through to normal
403 // processing below
404 if( offset && inFrag.GetSize() > 0 ) {
406 Protocol::CheckSize(inFrag);
408 switch( rpack->command )
410 case SB_COMMAND_SEQUENCE_HANDSHAKE:
411 CheckSequence(inFrag);
412 break;
414 default:
415 eout("Command: " << rpack->command << inFrag);
416 throw BError("Socket: unhandled packet in Packet()");
417 break;
422 } while( offset > 0 );
425 bool done = false, frag = false;
426 int blankCount = 0;
427 while( !done ) {
428 MAKE_PACKET(rpack, inFrag);
430 // check the packet's validity
431 if( inFrag.GetSize() > 0 ) {
432 blankCount = 0;
434 Protocol::CheckSize(inFrag);
436 switch( rpack->command )
438 case SB_COMMAND_SEQUENCE_HANDSHAKE:
439 CheckSequence(inFrag);
440 break;
442 case SB_COMMAND_DB_DATA:
443 if( frag ) {
444 AppendFragment(receive, inFrag);
446 else {
447 receive = inFrag;
449 done = true;
450 break;
452 case SB_COMMAND_DB_FRAGMENTED:
453 AppendFragment(receive, inFrag);
454 frag = true;
455 break;
457 case SB_COMMAND_DB_DONE:
458 receive = inFrag;
459 done = true;
460 break;
462 default:
463 eout("Command: " << rpack->command << inFrag);
464 throw BError("Socket: unhandled packet in Packet()");
465 break;
468 else {
469 blankCount++;
470 //std::cerr << "Blank! " << blankCount << std::endl;
471 if( blankCount == 10 ) {
472 // only ask for more data on stalled sockets
473 // for so long
474 throw BError("Socket: 10 blank packets received");
478 if( !done ) {
479 // not done yet, ask for another read
480 if( !Receive(inFrag) )
481 return false;
485 return true;
488 bool Socket::Packet(Barry::Packet &packet)
490 return Packet(packet.m_send, packet.m_receive);
493 bool Socket::NextRecord(Data &receive)
495 Barry::Protocol::Packet packet;
496 packet.socket = GetSocket();
497 packet.size = 7;
498 packet.command = SB_COMMAND_DB_DONE;
499 packet.u.db.tableCmd = 0;
500 packet.u.db.u.command.operation = 0;
502 Data command(&packet, packet.size);
503 return Packet(command, receive);
507 } // namespace Barry