3 /// Class wrapper to encapsulate the Blackberry USB logical socket
7 Copyright (C) 2005-2007, 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"
31 #include <openssl/sha.h>
39 Socket::Socket( Device
&dev
,
40 int writeEndpoint
, int readEndpoint
,
41 uint8_t zeroSocketSequenceStart
)
43 m_writeEp(writeEndpoint
),
44 m_readEp(readEndpoint
),
46 m_zeroSocketSequence(zeroSocketSequenceStart
),
57 // trap exceptions in the destructor
59 // a non-default socket has been opened, close it
62 catch( std::runtime_error
&re
) {
63 // do nothing... log it?
64 dout("Exception caught in ~Socket: " << re
.what());
68 void Socket::SendOpen(uint16_t socket
, Data
&receive
)
71 Barry::Protocol::Packet packet
;
73 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
74 packet
.command
= SB_COMMAND_OPEN_SOCKET
;
75 packet
.u
.socket
.socket
= htobs(socket
);
76 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
78 // save sequence for later close, and inc
79 m_flag
= m_zeroSocketSequence
;
81 Data
send(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
84 } catch( Usb::Error
& ) {
90 Protocol::CheckSize(receive
);
91 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
92 CheckSequence(receive
);
98 // receive now holds the Open response
101 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
102 void Socket::SendPasswordHash(uint16_t socket
, const char *password
, Data
&receive
)
104 unsigned char pwdigest
[SHA_DIGEST_LENGTH
];
105 unsigned char prefixedhash
[SHA_DIGEST_LENGTH
+ 4];
107 // first, hash the password by itself
108 SHA1((unsigned char *) password
, strlen(password
), pwdigest
);
110 // prefix the resulting hash with the provided seed
111 uint32_t seed
= htobl(m_challengeSeed
);
112 memcpy(&prefixedhash
[0], &seed
, sizeof(uint32_t));
113 memcpy(&prefixedhash
[4], pwdigest
, SHA_DIGEST_LENGTH
);
116 SHA1((unsigned char *) prefixedhash
, SHA_DIGEST_LENGTH
+ 4, pwdigest
);
119 size_t size
= SB_SOCKET_PACKET_HEADER_SIZE
+ PASSWORD_CHALLENGE_SIZE
;
121 // build open command
122 Barry::Protocol::Packet packet
;
124 packet
.size
= htobs(size
);
125 packet
.command
= SB_COMMAND_PASSWORD
;
126 packet
.u
.socket
.socket
= htobs(socket
);
127 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
128 packet
.u
.socket
.u
.password
.remaining_tries
= 0;
129 packet
.u
.socket
.u
.password
.unknown
= 0;
130 packet
.u
.socket
.u
.password
.param
= htobs(0x14); // FIXME - what does this mean?
131 memcpy(packet
.u
.socket
.u
.password
.u
.hash
, pwdigest
,
132 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
134 // blank password hashes as we don't need these anymore
135 memset(pwdigest
, 0, sizeof(pwdigest
));
136 memset(prefixedhash
, 0, sizeof(prefixedhash
));
138 // save sequence for later close, and inc
139 m_flag
= m_zeroSocketSequence
;
141 Data
send(&packet
, size
);
144 // blank password hash as we don't need this anymore either
145 memset(packet
.u
.socket
.u
.password
.u
.hash
, 0,
146 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
150 Protocol::CheckSize(receive
);
151 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
152 CheckSequence(receive
);
154 // still need our ACK
158 // receive now holds the Password response
165 /// Open a logical socket on the device.
167 /// Both the socket number and the flag are based on the response to the
168 /// SELECT_MODE command. See Controller::SelectMode() for more info
171 /// The packet sequence is normal for most socket operations.
173 /// - Down: command packet with OPEN_SOCKET
174 /// - Up: optional sequence handshake packet
175 /// - Up: command response, which repeats the socket and flag data
178 /// \exception Barry::Error
179 /// Thrown on protocol error.
181 /// \exception Barry::BadPassword
182 /// Thrown on invalid password, or not enough retries left
185 void Socket::Open(uint16_t socket
, const char *password
)
187 if( m_socket
!= 0 ) {
189 throw Error("Socket: already open");
192 // Things get a little funky here, as we may be left in an
193 // intermediate state in the case of a failed password.
194 // This function should support being called as many times
195 // as needed to handle the password
198 ZeroPacket
packet(send
, receive
);
202 m_remainingTries
= 0;
204 SendOpen(socket
, receive
);
206 // check for password challenge, or success
207 if( packet
.Command() == SB_COMMAND_PASSWORD_CHALLENGE
) {
209 m_challengeSeed
= packet
.ChallengeSeed();
210 m_remainingTries
= packet
.RemainingTries();
213 // fall through to challenge code...
217 // half open, device is expecting a password hash... do we
220 throw BadPassword("No password specified.", m_remainingTries
, false);
223 // only allow password attempts if there are 6 or more
224 // tries remaining... we want to give the user at least
225 // 5 chances on a Windows machine before the device
227 if( m_remainingTries
< 6 ) {
228 throw BadPassword("Fewer than 6 password tries "
229 "remaining in device. Refusing to proceed, "
230 "to avoid device zapping itself. Use a "
231 "Windows client, or re-cradle the device.",
236 SendPasswordHash(socket
, password
, receive
);
238 if( packet
.Command() == SB_COMMAND_PASSWORD_FAILED
) {
240 m_challengeSeed
= packet
.ChallengeSeed();
241 m_remainingTries
= packet
.RemainingTries();
242 throw BadPassword("Password rejected by device.", m_remainingTries
, false);
245 // if we get this far, we are no longer in half-open password
246 // mode, so we can reset our flags
249 // fall through to success check...
252 if( packet
.Command() != SB_COMMAND_OPENED_SOCKET
||
253 packet
.SocketResponse() != socket
||
254 packet
.SocketSequence() != m_flag
)
256 eout("Packet:\n" << receive
);
257 throw Error("Socket: Bad OPENED packet in Open");
260 // success! save the socket
267 /// Closes a non-default socket (i.e. non-zero socket number)
269 /// The packet sequence is just like Open(), except the command is
272 /// \exception Barry::Error
276 if( m_socket
!= 0 ) {
277 // only close non-default sockets
279 // build close command
280 Barry::Protocol::Packet packet
;
282 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
283 packet
.command
= SB_COMMAND_CLOSE_SOCKET
;
284 packet
.u
.socket
.socket
= htobs(m_socket
);
285 packet
.u
.socket
.sequence
= m_flag
;
287 Data
command(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
290 Send(command
, response
);
292 catch( Usb::Error
& ) {
293 // reset so this won't be called again
297 eeout(command
, response
);
301 // starting fresh, reset sequence ID
302 Protocol::CheckSize(response
);
303 if( IS_COMMAND(response
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
304 CheckSequence(response
);
306 // still need our ACK
310 Protocol::CheckSize(response
, SB_SOCKET_PACKET_HEADER_SIZE
);
311 MAKE_PACKET(rpack
, response
);
312 if( rpack
->command
!= SB_COMMAND_CLOSED_SOCKET
||
313 btohs(rpack
->u
.socket
.socket
) != m_socket
||
314 rpack
->u
.socket
.sequence
!= m_flag
)
316 // reset so this won't be called again
320 eout("Packet:\n" << response
);
321 throw Error("Socket: Bad CLOSED packet in Close");
324 // and finally, there always seems to be an extra read of
325 // an empty packet at the end... just throw it away
326 // Receive(response);
328 // reset socket and flag
338 /// Sends 'send' data to device, no receive.
342 /// \exception Usb::Error on underlying bus errors.
344 void Socket::Send(Data
&send
, int timeout
)
346 // Special case: it seems that sending packets with a size that's an
347 // exact multiple of 0x40 causes the device to get confused.
349 // To get around that, it is observed in the captures that the size
350 // is sent in a special 3 byte packet before the real packet.
351 // Check for this case here.
353 if( (send
.GetSize() % 0x40) == 0 ) {
354 Protocol::SizePacket packet
;
355 packet
.size
= htobs(send
.GetSize());
356 packet
.buffer
[2] = 0; // zero the top byte
357 Data
sizeCommand(&packet
, 3);
359 m_dev
.BulkWrite(m_writeEp
, sizeCommand
);
362 // If this is a socket 0 packet, force the send packet data's
363 // socket 0 sequence number to something correct.
364 if( m_socket
== 0 && send
.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE
) {
365 MAKE_PACKETPTR_BUF(spack
, send
.GetBuffer());
366 spack
->u
.socket
.sequence
= m_zeroSocketSequence
;
367 m_zeroSocketSequence
++;
370 m_dev
.BulkWrite(m_writeEp
, send
);
376 /// Sends 'send' data to device, and waits for response.
380 /// \exception Usb::Error on underlying bus errors.
382 void Socket::Send(Data
&send
, Data
&receive
, int timeout
)
385 m_dev
.BulkRead(m_readEp
, receive
, timeout
);
386 ddout("Socket::Send: Endpoint " << m_readEp
<< "\nReceived:\n" << receive
);
389 void Socket::Send(Barry::Packet
&packet
, int timeout
)
391 Send(packet
.m_send
, packet
.m_receive
, timeout
);
394 void Socket::Receive(Data
&receive
, int timeout
)
396 m_dev
.BulkRead(m_readEp
, receive
, timeout
);
398 ddout("Socket::Receive: Endpoint " << m_readEp
<< "\nReceived:\n" << receive
);
401 // appends fragment to whole... if whole is empty, simply copies, and
402 // sets command to DATA instead of FRAGMENTED. Always updates the
403 // packet size of whole, to reflect the total size
404 void Socket::AppendFragment(Data
&whole
, const Data
&fragment
)
406 if( whole
.GetSize() == 0 ) {
407 // empty, so just copy
411 // has some data already, so just append
412 int size
= whole
.GetSize();
413 unsigned char *buf
= whole
.GetBuffer(size
+ fragment
.GetSize());
414 MAKE_PACKET(fpack
, fragment
);
415 int fragsize
= fragment
.GetSize() - SB_FRAG_HEADER_SIZE
;
417 memcpy(buf
+size
, &fpack
->u
.db
.u
.fragment
, fragsize
);
418 whole
.ReleaseBuffer(size
+ fragsize
);
421 // update whole's size and command type for future sanity
422 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) whole
.GetBuffer();
423 wpack
->size
= htobs((uint16_t) whole
.GetSize());
424 wpack
->command
= SB_COMMAND_DB_DATA
;
425 // don't need to call ReleaseBuffer here, since we're not changing
426 // the real size size
429 // If offset is 0, starts fresh, taking the first fragment packet size chunk
430 // out of whole and creating a sendable packet in fragment. Returns the
431 // next offset if there is still more data, or 0 if finished.
432 unsigned int Socket::MakeNextFragment(const Data
&whole
, Data
&fragment
, unsigned int offset
)
435 if( whole
.GetSize() < SB_FRAG_HEADER_SIZE
) {
436 eout("Whole packet too short to fragment: " << whole
.GetSize());
437 throw Error("Socket: Whole packet too short to fragment");
441 unsigned int todo
= whole
.GetSize() - SB_FRAG_HEADER_SIZE
- offset
;
442 unsigned int nextOffset
= 0;
443 if( todo
> (MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
) ) {
444 todo
= MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
;
445 nextOffset
= offset
+ todo
;
448 // create fragment header
449 unsigned char *buf
= fragment
.GetBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
450 memcpy(buf
, whole
.GetData(), SB_FRAG_HEADER_SIZE
);
452 // copy over a fragment size of data
453 memcpy(buf
+ SB_FRAG_HEADER_SIZE
, whole
.GetData() + SB_FRAG_HEADER_SIZE
+ offset
, todo
);
455 // update fragment's size and command type
456 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) buf
;
457 wpack
->size
= htobs((uint16_t) (todo
+ SB_FRAG_HEADER_SIZE
));
459 wpack
->command
= SB_COMMAND_DB_FRAGMENTED
;
461 wpack
->command
= SB_COMMAND_DB_DATA
;
463 // adjust the new fragment size
464 fragment
.ReleaseBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
470 void Socket::CheckSequence(const Data
&seq
)
472 // if( m_socket == 0 ) {
473 // // don't do any sequence checking on socket 0
477 MAKE_PACKET(spack
, seq
);
478 if( (unsigned int) seq
.GetSize() < SB_SEQUENCE_PACKET_SIZE
) {
479 eout("Short sequence packet:\n" << seq
);
480 throw Error("Socket: invalid sequence packet");
483 // we'll cheat here... if the packet's sequence is 0, we'll
484 // silently restart, otherwise, fail
485 uint32_t sequenceId
= btohl(spack
->u
.sequence
.sequenceId
);
486 if( sequenceId
== 0 ) {
487 // silently restart (will advance below)
491 if( sequenceId
!= m_sequenceId
) {
492 if( m_socket
!= 0 ) {
493 eout("Socket sequence: " << m_sequenceId
494 << ". Packet sequence: " << sequenceId
);
495 throw Error("Socket: out of sequence");
498 dout("Bad sequence on socket 0: expected: "
500 << ". Packet sequence: " << sequenceId
);
509 // sends the send packet down to the device, fragmenting if
510 // necessary, and returns the response in receive, defragmenting
512 // Blocks until response received or timed out in Usb::Device
513 void Socket::Packet(Data
&send
, Data
&receive
, int timeout
)
516 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
517 // function that forces the socket number to the correct current value,
518 // but putting it here means a copy on every packet.
520 // force socket to our socket
521 Data send = sendorig;
522 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
523 sspack->socket = htobs(GetSocket());
526 MAKE_PACKET(spack
, send
);
527 if( send
.GetSize() < MIN_PACKET_SIZE
||
528 (spack
->command
!= SB_COMMAND_DB_DATA
&&
529 spack
->command
!= SB_COMMAND_DB_DONE
) )
531 // we don't do that around here
532 throw std::logic_error("Socket: unknown send data in Packet()");
538 if( send
.GetSize() <= MAX_PACKET_SIZE
) {
539 // send non-fragmented
540 Send(send
, inFrag
, timeout
);
544 unsigned int offset
= 0;
548 offset
= MakeNextFragment(send
, outFrag
, offset
);
549 Send(outFrag
, inFrag
, timeout
);
551 MAKE_PACKET(rpack
, inFrag
);
552 // only process sequence handshakes... once we
553 // get to the last fragment, we fall through to normal
555 if( offset
&& inFrag
.GetSize() > 0 ) {
557 Protocol::CheckSize(inFrag
);
559 switch( rpack
->command
)
561 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
562 CheckSequence(inFrag
);
566 eout("Command: " << std::setbase(16) << (unsigned int)rpack
->command
<< inFrag
);
567 throw Error("Socket: unhandled packet in Packet()");
573 } while( offset
> 0 );
576 bool done
= false, frag
= false;
579 MAKE_PACKET(rpack
, inFrag
);
581 // check the packet's validity
582 if( inFrag
.GetSize() > 0 ) {
585 Protocol::CheckSize(inFrag
);
587 switch( rpack
->command
)
589 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
590 CheckSequence(inFrag
);
593 case SB_COMMAND_DB_DATA
:
595 AppendFragment(receive
, inFrag
);
603 case SB_COMMAND_DB_FRAGMENTED
:
604 AppendFragment(receive
, inFrag
);
608 case SB_COMMAND_DB_DONE
:
614 eout("Command: " << std::setbase(16) << (unsigned int)rpack
->command
<< inFrag
);
615 throw Error("Socket: unhandled packet in Packet()");
621 //std::cerr << "Blank! " << blankCount << std::endl;
622 if( blankCount
== 10 ) {
623 // only ask for more data on stalled sockets
625 throw Error("Socket: 10 blank packets received");
630 // not done yet, ask for another read
636 void Socket::Packet(Barry::Packet
&packet
, int timeout
)
638 Packet(packet
.m_send
, packet
.m_receive
, timeout
);
641 void Socket::NextRecord(Data
&receive
)
643 Barry::Protocol::Packet packet
;
644 packet
.socket
= htobs(GetSocket());
645 packet
.size
= htobs(7);
646 packet
.command
= SB_COMMAND_DB_DONE
;
647 packet
.u
.db
.tableCmd
= 0;
648 packet
.u
.db
.u
.command
.operation
= 0;
650 Data
command(&packet
, 7);
651 Packet(command
, receive
);