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"
36 Socket::Socket(Device
&dev
, int writeEndpoint
, int readEndpoint
)
38 m_writeEp(writeEndpoint
),
39 m_readEp(readEndpoint
),
49 // trap exceptions in the destructor
51 // a non-default socket has been opened, close it
54 catch( std::runtime_error
&re
) {
55 // do nothing... log it?
56 dout("Exception caught in ~Socket: " << re
.what());
63 /// Open a logical socket on the device.
65 /// Both the socket number and the flag are based on the response to the
66 /// SELECT_MODE command. See Controller::SelectMode() for more info
69 /// The packet sequence is normal for most socket operations.
71 /// - Down: command packet with OPEN_SOCKET
72 /// - Up: optional sequence handshake packet
73 /// - Up: command response, which repeats the socket and flag data
76 /// \exception Barry::BError
78 void Socket::Open(uint16_t socket
, uint8_t flag
)
82 throw BError("Socket: already open");
88 packet
.size
= SB_SOCKET_PACKET_SIZE
;
89 packet
.command
= SB_COMMAND_OPEN_SOCKET
;
90 packet
.u
.socket
.socket
= socket
;
91 packet
.u
.socket
.param
= flag
;
93 Data
send(&packet
, packet
.size
);
95 if( !Send(send
, receive
) ) {
97 throw BError(GetLastStatus(), "Error opening socket");
100 // starting fresh, reset sequence ID
102 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
103 CheckSequence(receive
);
105 // still need our ACK
109 CheckSize(receive
, SB_SOCKET_PACKET_SIZE
);
110 MAKE_PACKET(rpack
, receive
);
111 if( rpack
->command
!= SB_COMMAND_OPENED_SOCKET
||
112 rpack
->u
.socket
.socket
!= socket
||
113 rpack
->u
.socket
.param
!= flag
)
115 eout("Packet:\n" << receive
);
116 throw BError("Socket: Bad OPENED packet in Open");
119 // success! save the socket
127 /// Closes a non-default socket (i.e. non-zero socket number)
129 /// The packet sequence is just like Open(), except the command is
132 /// \exception Barry::BError
136 if( m_socket
!= 0 ) {
137 // only close non-default sockets
139 // build close command
140 Barry::Packet packet
;
142 packet
.size
= SB_SOCKET_PACKET_SIZE
;
143 packet
.command
= SB_COMMAND_CLOSE_SOCKET
;
144 packet
.u
.socket
.socket
= m_socket
;
145 packet
.u
.socket
.param
= m_flag
;
147 Data
command(&packet
, packet
.size
);
149 if( !Send(command
, response
) ) {
150 // reset so this won't be called again
154 eeout(command
, response
);
155 throw BError(GetLastStatus(), "Error closing socket");
158 // starting fresh, reset sequence ID
160 if( IS_COMMAND(response
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
161 CheckSequence(response
);
163 // still need our ACK
167 CheckSize(response
, SB_SOCKET_PACKET_SIZE
);
168 MAKE_PACKET(rpack
, response
);
169 if( rpack
->command
!= SB_COMMAND_CLOSED_SOCKET
||
170 rpack
->u
.socket
.socket
!= m_socket
||
171 rpack
->u
.socket
.param
!= m_flag
)
173 // reset so this won't be called again
177 eout("Packet:\n" << response
);
178 throw BError("Socket: Bad CLOSED packet in Close");
181 // and finally, there always seems to be an extra read of
182 // an empty packet at the end... just throw it away
183 // Receive(response);
185 // reset socket and flag
194 /// Sends 'send' data to device, and waits for response, using
195 /// "read first, write second" order observed in capture.
198 /// - true on success
199 /// - false on failure, use GetLastStatus() for kernel
202 bool Socket::Send(const Data
&send
, Data
&receive
)
204 // Special case: it seems that sending packets with a size that's an
205 // exact multiple of 0x40 causes the device to get confused.
207 // To get around that, it is observed in the captures that the size
208 // is sent in a special 3 byte packet before the real packet.
209 // Check for this case here.
211 if( (send
.GetSize() % 0x40) == 0 ) {
213 packet
.size
= send
.GetSize();
214 packet
.buffer
[2] = 0; // zero the top byte
215 Data
sizeCommand(&packet
, 3);
217 IO wr
= m_dev
.ABulkWrite(m_writeEp
, sizeCommand
);
221 IO rd
= m_dev
.ABulkRead(m_readEp
, receive
);
222 IO wr
= m_dev
.ABulkWrite(m_writeEp
, send
);
228 m_lastStatus
= rd
.GetStatus();
229 receive
.ReleaseBuffer(m_lastStatus
>= 0 ? rd
.GetSize() : 0);
230 return m_lastStatus
>= 0;
233 bool Socket::Receive(Data
&receive
)
235 IO rd
= m_dev
.ABulkRead(m_readEp
, receive
);
239 m_lastStatus
= rd
.GetStatus();
240 receive
.ReleaseBuffer(m_lastStatus
>= 0 ? rd
.GetSize() : 0);
241 return m_lastStatus
>= 0;
244 // appends fragment to whole... if whole is empty, simply copies, and
245 // sets command to DATA instead of FRAGMENTED. Always updates the
246 // packet size of whole, to reflect the total size
247 void Socket::AppendFragment(Data
&whole
, const Data
&fragment
)
249 if( whole
.GetSize() == 0 ) {
250 // empty, so just copy
254 // has some data already, so just append
255 int size
= whole
.GetSize();
256 unsigned char *buf
= whole
.GetBuffer(size
+ fragment
.GetSize());
257 MAKE_PACKET(fpack
, fragment
);
258 int fragsize
= fragment
.GetSize() - SB_FRAG_HEADER_SIZE
;
260 memcpy(buf
+size
, &fpack
->u
.db
.u
.fragment
, fragsize
);
261 whole
.ReleaseBuffer(size
+ fragsize
);
264 // update whole's size and command type for future sanity
265 Barry::Packet
*wpack
= (Barry::Packet
*) whole
.GetBuffer();
266 wpack
->size
= (uint16_t) whole
.GetSize();
267 wpack
->command
= SB_COMMAND_DB_DATA
;
268 // don't need to call ReleaseBuffer here, since we're not changing
269 // the real size size
272 // If offset is 0, starts fresh, taking the first fragment packet size chunk
273 // out of whole and creating a sendable packet in fragment. Returns the
274 // next offset if there is still more data, or 0 if finished.
275 unsigned int Socket::MakeNextFragment(const Data
&whole
, Data
&fragment
, unsigned int offset
)
278 if( whole
.GetSize() < SB_FRAG_HEADER_SIZE
) {
279 eout("Whole packet too short to fragment: " << whole
.GetSize());
280 throw BError("Socket: Whole packet too short to fragment");
284 unsigned int todo
= whole
.GetSize() - SB_FRAG_HEADER_SIZE
- offset
;
285 unsigned int nextOffset
= 0;
286 if( todo
> (MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
) ) {
287 todo
= MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
;
288 nextOffset
= offset
+ todo
;
291 // create fragment header
292 unsigned char *buf
= fragment
.GetBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
293 memcpy(buf
, whole
.GetData(), SB_FRAG_HEADER_SIZE
);
295 // copy over a fragment size of data
296 memcpy(buf
+ SB_FRAG_HEADER_SIZE
, whole
.GetData() + SB_FRAG_HEADER_SIZE
+ offset
, todo
);
298 // update fragment's size and command type
299 Barry::Packet
*wpack
= (Barry::Packet
*) buf
;
300 wpack
->size
= (uint16_t) (todo
+ SB_FRAG_HEADER_SIZE
);
302 wpack
->command
= SB_COMMAND_DB_FRAGMENTED
;
304 wpack
->command
= SB_COMMAND_DB_DATA
;
306 // adjust the new fragment size
307 fragment
.ReleaseBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
313 void Socket::CheckSequence(const Data
&seq
)
315 // if( m_socket == 0 ) {
316 // // don't do any sequence checking on socket 0
320 MAKE_PACKET(spack
, seq
);
321 if( (unsigned int) seq
.GetSize() < SB_SEQUENCE_PACKET_SIZE
) {
322 eout("Short sequence packet:\n" << seq
);
323 throw BError("Socket: invalid sequence packet");
326 // we'll cheat here... if the packet's sequence is 0, we'll
327 // silently restart, otherwise, fail
328 uint32_t sequenceId
= spack
->u
.sequence
.sequenceId
;
329 if( sequenceId
== 0 ) {
330 // silently restart (will advance below)
334 if( sequenceId
!= m_sequenceId
) {
335 if( m_socket
!= 0 ) {
336 eout("Socket sequence: " << m_sequenceId
337 << ". Packet sequence: " << sequenceId
);
338 throw BError("Socket: out of sequence");
341 dout("Bad sequence on socket 0: expected: "
343 << ". Packet sequence: " << sequenceId
);
352 // sends the send packet down to the device, fragmenting if
353 // necessary, and returns the response in receive, defragmenting
355 // Blocks until response received or timed out in Usb::Device
356 bool Socket::Packet(const Data
&send
, Data
&receive
)
359 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
360 // function that forces the socket number to the correct current value,
361 // but putting it here means a copy on every packet.
363 // force socket to our socket
364 Data send = sendorig;
365 Barry::Packet *sspack = (Barry::Packet *)send.GetBuffer(2);
366 sspack->socket = GetSocket();
369 MAKE_PACKET(spack
, send
);
370 if( send
.GetSize() < MIN_PACKET_SIZE
||
371 (spack
->command
!= SB_COMMAND_DB_DATA
&&
372 spack
->command
!= SB_COMMAND_DB_DONE
) )
374 // we don't do that around here
375 throw std::logic_error("Socket: unknown send data in Packet()");
381 if( send
.GetSize() <= MAX_PACKET_SIZE
) {
382 // send non-fragmented
383 if( !Send(send
, inFrag
) )
388 unsigned int offset
= 0;
392 offset
= MakeNextFragment(send
, outFrag
, offset
);
393 if( !Send(outFrag
, inFrag
) )
396 MAKE_PACKET(rpack
, inFrag
);
397 // only process sequence handshakes... once we
398 // get to the last fragment, we fall through to normal
400 if( offset
&& inFrag
.GetSize() > 0 ) {
404 switch( rpack
->command
)
406 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
407 CheckSequence(inFrag
);
411 eout("Command: " << rpack
->command
<< inFrag
);
412 throw BError("Socket: unhandled packet in Packet()");
418 } while( offset
> 0 );
421 bool done
= false, frag
= false;
424 MAKE_PACKET(rpack
, inFrag
);
426 // check the packet's validity
427 if( inFrag
.GetSize() > 0 ) {
432 switch( rpack
->command
)
434 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
435 CheckSequence(inFrag
);
438 case SB_COMMAND_DB_DATA
:
440 AppendFragment(receive
, inFrag
);
448 case SB_COMMAND_DB_FRAGMENTED
:
449 AppendFragment(receive
, inFrag
);
453 case SB_COMMAND_DB_DONE
:
459 eout("Command: " << rpack
->command
<< inFrag
);
460 throw BError("Socket: unhandled packet in Packet()");
466 //std::cerr << "Blank! " << blankCount << std::endl;
467 if( blankCount
== 10 ) {
468 // only ask for more data on stalled sockets
470 throw BError("Socket: 10 blank packets received");
475 // not done yet, ask for another read
476 if( !Receive(inFrag
) )
484 bool Socket::NextRecord(Data
&receive
)
486 Barry::Packet packet
;
487 packet
.socket
= GetSocket();
489 packet
.command
= SB_COMMAND_DB_DONE
;
490 packet
.u
.db
.tableCmd
= 0;
491 packet
.u
.db
.u
.command
.operation
= 0;
493 Data
command(&packet
, packet
.size
);
494 return Packet(command
, receive
);