3 /// Class wrapper to encapsulate the Blackberry USB logical socket
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.
25 #include "protostructs.h"
37 Socket::Socket(Device
&dev
, int writeEndpoint
, int readEndpoint
)
39 m_writeEp(writeEndpoint
),
40 m_readEp(readEndpoint
),
50 // trap exceptions in the destructor
52 // a non-default socket has been opened, close it
55 catch( std::runtime_error
&re
) {
56 // do nothing... log it?
57 dout("Exception caught in ~Socket: " << re
.what());
64 /// Open a logical socket on the device.
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
70 /// The packet sequence is normal for most socket operations.
72 /// - Down: command packet with OPEN_SOCKET
73 /// - Up: optional sequence handshake packet
74 /// - Up: command response, which repeats the socket and flag data
77 /// \exception Barry::BError
79 void Socket::Open(uint16_t socket
, uint8_t flag
)
83 throw BError("Socket: already open");
87 Barry::Protocol::Packet packet
;
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
);
96 if( !Send(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
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
128 /// Closes a non-default socket (i.e. non-zero socket number)
130 /// The packet sequence is just like Open(), except the command is
133 /// \exception Barry::BError
137 if( m_socket
!= 0 ) {
138 // only close non-default sockets
140 // build close command
141 Barry::Protocol::Packet packet
;
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
);
150 if( !Send(command
, response
) ) {
151 // reset so this won't be called again
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
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
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
195 /// Sends 'send' data to device, and waits for response, using
196 /// "read first, write second" order observed in capture.
199 /// - true on success
200 /// - false on failure, use GetLastStatus() for kernel
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
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
)
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");
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
);
306 wpack
->command
= SB_COMMAND_DB_FRAGMENTED
;
308 wpack
->command
= SB_COMMAND_DB_DATA
;
310 // adjust the new fragment size
311 fragment
.ReleaseBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
317 void Socket::CheckSequence(const Data
&seq
)
319 // if( m_socket == 0 ) {
320 // // don't do any sequence checking on socket 0
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)
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");
345 dout("Bad sequence on socket 0: expected: "
347 << ". Packet sequence: " << sequenceId
);
356 // sends the send packet down to the device, fragmenting if
357 // necessary, and returns the response in receive, defragmenting
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()");
385 if( send
.GetSize() <= MAX_PACKET_SIZE
) {
386 // send non-fragmented
387 if( !Send(send
, inFrag
) )
392 unsigned int offset
= 0;
396 offset
= MakeNextFragment(send
, outFrag
, offset
);
397 if( !Send(outFrag
, inFrag
) )
400 MAKE_PACKET(rpack
, inFrag
);
401 // only process sequence handshakes... once we
402 // get to the last fragment, we fall through to normal
404 if( offset
&& inFrag
.GetSize() > 0 ) {
406 Protocol::CheckSize(inFrag
);
408 switch( rpack
->command
)
410 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
411 CheckSequence(inFrag
);
415 eout("Command: " << rpack
->command
<< inFrag
);
416 throw BError("Socket: unhandled packet in Packet()");
422 } while( offset
> 0 );
425 bool done
= false, frag
= false;
428 MAKE_PACKET(rpack
, inFrag
);
430 // check the packet's validity
431 if( inFrag
.GetSize() > 0 ) {
434 Protocol::CheckSize(inFrag
);
436 switch( rpack
->command
)
438 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
439 CheckSequence(inFrag
);
442 case SB_COMMAND_DB_DATA
:
444 AppendFragment(receive
, inFrag
);
452 case SB_COMMAND_DB_FRAGMENTED
:
453 AppendFragment(receive
, inFrag
);
457 case SB_COMMAND_DB_DONE
:
463 eout("Command: " << rpack
->command
<< inFrag
);
464 throw BError("Socket: unhandled packet in Packet()");
470 //std::cerr << "Blank! " << blankCount << std::endl;
471 if( blankCount
== 10 ) {
472 // only ask for more data on stalled sockets
474 throw BError("Socket: 10 blank packets received");
479 // not done yet, ask for another read
480 if( !Receive(inFrag
) )
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();
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
);