3 /// Class wrapper to encapsulate the Blackberry USB logical socket
7 Copyright (C) 2005-2008, 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>
40 Socket::Socket( Device
&dev
,
41 int writeEndpoint
, int readEndpoint
,
42 uint8_t zeroSocketSequenceStart
)
44 m_writeEp(writeEndpoint
),
45 m_readEp(readEndpoint
),
47 m_zeroSocketSequence(zeroSocketSequenceStart
),
58 // trap exceptions in the destructor
60 // a non-default socket has been opened, close it
63 catch( std::runtime_error
&re
) {
64 // do nothing... log it?
65 dout("Exception caught in ~Socket: " << re
.what());
69 void Socket::SendOpen(uint16_t socket
, Data
&receive
)
72 Barry::Protocol::Packet packet
;
74 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
75 packet
.command
= SB_COMMAND_OPEN_SOCKET
;
76 packet
.u
.socket
.socket
= htobs(socket
);
77 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
79 // save sequence for later close, and inc
80 m_flag
= m_zeroSocketSequence
;
82 Data
send(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
85 } catch( Usb::Error
& ) {
91 Protocol::CheckSize(receive
);
92 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
93 CheckSequence(receive
);
99 // receive now holds the Open response
102 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
103 void Socket::SendPasswordHash(uint16_t socket
, const char *password
, Data
&receive
)
105 unsigned char pwdigest
[SHA_DIGEST_LENGTH
];
106 unsigned char prefixedhash
[SHA_DIGEST_LENGTH
+ 4];
108 // first, hash the password by itself
109 SHA1((unsigned char *) password
, strlen(password
), pwdigest
);
111 // prefix the resulting hash with the provided seed
112 uint32_t seed
= htobl(m_challengeSeed
);
113 memcpy(&prefixedhash
[0], &seed
, sizeof(uint32_t));
114 memcpy(&prefixedhash
[4], pwdigest
, SHA_DIGEST_LENGTH
);
117 SHA1((unsigned char *) prefixedhash
, SHA_DIGEST_LENGTH
+ 4, pwdigest
);
120 size_t size
= SB_SOCKET_PACKET_HEADER_SIZE
+ PASSWORD_CHALLENGE_SIZE
;
122 // build open command
123 Barry::Protocol::Packet packet
;
125 packet
.size
= htobs(size
);
126 packet
.command
= SB_COMMAND_PASSWORD
;
127 packet
.u
.socket
.socket
= htobs(socket
);
128 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
129 packet
.u
.socket
.u
.password
.remaining_tries
= 0;
130 packet
.u
.socket
.u
.password
.unknown
= 0;
131 packet
.u
.socket
.u
.password
.param
= htobs(0x14); // FIXME - what does this mean?
132 memcpy(packet
.u
.socket
.u
.password
.u
.hash
, pwdigest
,
133 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
135 // blank password hashes as we don't need these anymore
136 memset(pwdigest
, 0, sizeof(pwdigest
));
137 memset(prefixedhash
, 0, sizeof(prefixedhash
));
139 // save sequence for later close, and inc
140 m_flag
= m_zeroSocketSequence
;
142 Data
send(&packet
, size
);
145 // blank password hash as we don't need this anymore either
146 memset(packet
.u
.socket
.u
.password
.u
.hash
, 0,
147 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
151 Protocol::CheckSize(receive
);
152 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
153 CheckSequence(receive
);
155 // still need our ACK
159 // receive now holds the Password response
166 /// Open a logical socket on the device.
168 /// Both the socket number and the flag are based on the response to the
169 /// SELECT_MODE command. See Controller::SelectMode() for more info
172 /// The packet sequence is normal for most socket operations.
174 /// - Down: command packet with OPEN_SOCKET
175 /// - Up: optional sequence handshake packet
176 /// - Up: command response, which repeats the socket and flag data
179 /// \exception Barry::Error
180 /// Thrown on protocol error.
182 /// \exception Barry::BadPassword
183 /// Thrown on invalid password, or not enough retries left
186 void Socket::Open(uint16_t socket
, const char *password
)
188 if( m_socket
!= 0 ) {
190 throw Error("Socket: already open");
193 // Things get a little funky here, as we may be left in an
194 // intermediate state in the case of a failed password.
195 // This function should support being called as many times
196 // as needed to handle the password
199 ZeroPacket
packet(send
, receive
);
203 m_remainingTries
= 0;
205 SendOpen(socket
, receive
);
207 // check for password challenge, or success
208 if( packet
.Command() == SB_COMMAND_PASSWORD_CHALLENGE
) {
210 m_challengeSeed
= packet
.ChallengeSeed();
211 m_remainingTries
= packet
.RemainingTries();
214 // fall through to challenge code...
218 // half open, device is expecting a password hash... do we
221 throw BadPassword("No password specified.", m_remainingTries
, false);
224 // only allow password attempts if there are 6 or more
225 // tries remaining... we want to give the user at least
226 // 5 chances on a Windows machine before the device
228 if( m_remainingTries
< 6 ) {
229 throw BadPassword("Fewer than 6 password tries "
230 "remaining in device. Refusing to proceed, "
231 "to avoid device zapping itself. Use a "
232 "Windows client, or re-cradle the device.",
237 SendPasswordHash(socket
, password
, receive
);
239 if( packet
.Command() == SB_COMMAND_PASSWORD_FAILED
) {
241 m_challengeSeed
= packet
.ChallengeSeed();
242 m_remainingTries
= packet
.RemainingTries();
243 throw BadPassword("Password rejected by device.", m_remainingTries
, false);
246 // if we get this far, we are no longer in half-open password
247 // mode, so we can reset our flags
250 // fall through to success check...
253 if( packet
.Command() != SB_COMMAND_OPENED_SOCKET
||
254 packet
.SocketResponse() != socket
||
255 packet
.SocketSequence() != m_flag
)
257 eout("Packet:\n" << receive
);
258 throw Error("Socket: Bad OPENED packet in Open");
261 // success! save the socket
268 /// Closes a non-default socket (i.e. non-zero socket number)
270 /// The packet sequence is just like Open(), except the command is
273 /// \exception Barry::Error
277 if( m_socket
!= 0 ) {
278 // only close non-default sockets
280 // build close command
281 Barry::Protocol::Packet packet
;
283 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
284 packet
.command
= SB_COMMAND_CLOSE_SOCKET
;
285 packet
.u
.socket
.socket
= htobs(m_socket
);
286 packet
.u
.socket
.sequence
= m_flag
;
288 Data
command(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
291 Send(command
, response
);
293 catch( Usb::Error
& ) {
294 // reset so this won't be called again
298 eeout(command
, response
);
302 // starting fresh, reset sequence ID
303 Protocol::CheckSize(response
);
304 if( IS_COMMAND(response
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
305 CheckSequence(response
);
307 // still need our ACK
311 Protocol::CheckSize(response
, SB_SOCKET_PACKET_HEADER_SIZE
);
312 MAKE_PACKET(rpack
, response
);
313 if( rpack
->command
!= SB_COMMAND_CLOSED_SOCKET
||
314 btohs(rpack
->u
.socket
.socket
) != m_socket
||
315 rpack
->u
.socket
.sequence
!= m_flag
)
317 // reset so this won't be called again
321 eout("Packet:\n" << response
);
322 throw Error("Socket: Bad CLOSED packet in Close");
325 // // and finally, there always seems to be an extra read of
326 // // an empty packet at the end... just throw it away
328 // Receive(response, 1);
330 // catch( Usb::Timeout & ) {
333 // reset socket and flag
343 /// Sends 'send' data to device, no receive.
347 /// \exception Usb::Error on underlying bus errors.
349 void Socket::Send(Data
&send
, int timeout
)
351 // Special case: it seems that sending packets with a size that's an
352 // exact multiple of 0x40 causes the device to get confused.
354 // To get around that, it is observed in the captures that the size
355 // is sent in a special 3 byte packet before the real packet.
356 // Check for this case here.
358 if( (send
.GetSize() % 0x40) == 0 ) {
359 Protocol::SizePacket packet
;
360 packet
.size
= htobs(send
.GetSize());
361 packet
.buffer
[2] = 0; // zero the top byte
362 Data
sizeCommand(&packet
, 3);
364 m_dev
.BulkWrite(m_writeEp
, sizeCommand
);
367 // If this is a socket 0 packet, force the send packet data's
368 // socket 0 sequence number to something correct.
369 if( m_socket
== 0 && send
.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE
) {
370 MAKE_PACKETPTR_BUF(spack
, send
.GetBuffer());
371 spack
->u
.socket
.sequence
= m_zeroSocketSequence
;
372 m_zeroSocketSequence
++;
375 m_dev
.BulkWrite(m_writeEp
, send
);
381 /// Sends 'send' data to device, and waits for response.
385 /// \exception Usb::Error on underlying bus errors.
387 void Socket::Send(Data
&send
, Data
&receive
, int timeout
)
390 m_dev
.BulkRead(m_readEp
, receive
, timeout
);
391 ddout("Socket::Send: Endpoint " << m_readEp
<< "\nReceived:\n" << receive
);
394 void Socket::Send(Barry::Packet
&packet
, int timeout
)
396 Send(packet
.m_send
, packet
.m_receive
, timeout
);
399 void Socket::Receive(Data
&receive
, int timeout
)
401 m_dev
.BulkRead(m_readEp
, receive
, timeout
);
403 ddout("Socket::Receive: Endpoint " << m_readEp
<< "\nReceived:\n" << receive
);
406 // appends fragment to whole... if whole is empty, simply copies, and
407 // sets command to DATA instead of FRAGMENTED. Always updates the
408 // packet size of whole, to reflect the total size
409 void Socket::AppendFragment(Data
&whole
, const Data
&fragment
)
411 if( whole
.GetSize() == 0 ) {
412 // empty, so just copy
416 // has some data already, so just append
417 int size
= whole
.GetSize();
418 unsigned char *buf
= whole
.GetBuffer(size
+ fragment
.GetSize());
419 MAKE_PACKET(fpack
, fragment
);
420 int fragsize
= fragment
.GetSize() - SB_FRAG_HEADER_SIZE
;
422 memcpy(buf
+size
, &fpack
->u
.db
.u
.fragment
, fragsize
);
423 whole
.ReleaseBuffer(size
+ fragsize
);
426 // update whole's size and command type for future sanity
427 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) whole
.GetBuffer();
428 wpack
->size
= htobs((uint16_t) whole
.GetSize());
429 wpack
->command
= SB_COMMAND_DB_DATA
;
430 // don't need to call ReleaseBuffer here, since we're not changing
431 // the real size size
434 // If offset is 0, starts fresh, taking the first fragment packet size chunk
435 // out of whole and creating a sendable packet in fragment. Returns the
436 // next offset if there is still more data, or 0 if finished.
437 unsigned int Socket::MakeNextFragment(const Data
&whole
, Data
&fragment
, unsigned int offset
)
440 if( whole
.GetSize() < SB_FRAG_HEADER_SIZE
) {
441 eout("Whole packet too short to fragment: " << whole
.GetSize());
442 throw Error("Socket: Whole packet too short to fragment");
446 unsigned int todo
= whole
.GetSize() - SB_FRAG_HEADER_SIZE
- offset
;
447 unsigned int nextOffset
= 0;
448 if( todo
> (MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
) ) {
449 todo
= MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
;
450 nextOffset
= offset
+ todo
;
453 // create fragment header
454 unsigned char *buf
= fragment
.GetBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
455 memcpy(buf
, whole
.GetData(), SB_FRAG_HEADER_SIZE
);
457 // copy over a fragment size of data
458 memcpy(buf
+ SB_FRAG_HEADER_SIZE
, whole
.GetData() + SB_FRAG_HEADER_SIZE
+ offset
, todo
);
460 // update fragment's size and command type
461 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) buf
;
462 wpack
->size
= htobs((uint16_t) (todo
+ SB_FRAG_HEADER_SIZE
));
464 wpack
->command
= SB_COMMAND_DB_FRAGMENTED
;
466 wpack
->command
= SB_COMMAND_DB_DATA
;
468 // adjust the new fragment size
469 fragment
.ReleaseBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
475 void Socket::CheckSequence(const Data
&seq
)
477 // if( m_socket == 0 ) {
478 // // don't do any sequence checking on socket 0
482 MAKE_PACKET(spack
, seq
);
483 if( (unsigned int) seq
.GetSize() < SB_SEQUENCE_PACKET_SIZE
) {
484 eout("Short sequence packet:\n" << seq
);
485 throw Error("Socket: invalid sequence packet");
488 // we'll cheat here... if the packet's sequence is 0, we'll
489 // silently restart, otherwise, fail
490 uint32_t sequenceId
= btohl(spack
->u
.sequence
.sequenceId
);
491 if( sequenceId
== 0 ) {
492 // silently restart (will advance below)
496 if( sequenceId
!= m_sequenceId
) {
497 if( m_socket
!= 0 ) {
498 eout("Socket sequence: " << m_sequenceId
499 << ". Packet sequence: " << sequenceId
);
500 throw Error("Socket: out of sequence");
503 dout("Bad sequence on socket 0: expected: "
505 << ". Packet sequence: " << sequenceId
);
514 // sends the send packet down to the device, fragmenting if
515 // necessary, and returns the response in receive, defragmenting
517 // Blocks until response received or timed out in Usb::Device
518 void Socket::Packet(Data
&send
, Data
&receive
, int timeout
)
521 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
522 // function that forces the socket number to the correct current value,
523 // but putting it here means a copy on every packet.
525 // force socket to our socket
526 Data send = sendorig;
527 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
528 sspack->socket = htobs(GetSocket());
531 MAKE_PACKET(spack
, send
);
532 if( send
.GetSize() < MIN_PACKET_SIZE
||
533 (spack
->command
!= SB_COMMAND_DB_DATA
&&
534 spack
->command
!= SB_COMMAND_DB_DONE
) )
536 // we don't do that around here
537 throw std::logic_error("Socket: unknown send data in Packet()");
543 if( send
.GetSize() <= MAX_PACKET_SIZE
) {
544 // send non-fragmented
545 Send(send
, inFrag
, timeout
);
549 unsigned int offset
= 0;
553 offset
= MakeNextFragment(send
, outFrag
, offset
);
554 Send(outFrag
, inFrag
, timeout
);
556 MAKE_PACKET(rpack
, inFrag
);
557 // only process sequence handshakes... once we
558 // get to the last fragment, we fall through to normal
560 if( offset
&& inFrag
.GetSize() > 0 ) {
562 Protocol::CheckSize(inFrag
);
564 switch( rpack
->command
)
566 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
567 CheckSequence(inFrag
);
571 std::ostringstream oss
;
572 oss
<< "Socket: unhandled packet in Packet() (send): 0x" << std::hex
<< (unsigned int)rpack
->command
;
574 throw Error(oss
.str());
581 } while( offset
> 0 );
584 bool done
= false, frag
= false;
587 MAKE_PACKET(rpack
, inFrag
);
589 // check the packet's validity
590 if( inFrag
.GetSize() > 0 ) {
593 Protocol::CheckSize(inFrag
);
595 switch( rpack
->command
)
597 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
598 CheckSequence(inFrag
);
601 case SB_COMMAND_DB_DATA
:
603 AppendFragment(receive
, inFrag
);
611 case SB_COMMAND_DB_FRAGMENTED
:
612 AppendFragment(receive
, inFrag
);
616 case SB_COMMAND_DB_DONE
:
622 std::ostringstream oss
;
623 oss
<< "Socket: unhandled packet in Packet() (read): 0x" << std::hex
<< (unsigned int)rpack
->command
;
625 throw Error(oss
.str());
632 //std::cerr << "Blank! " << blankCount << std::endl;
633 if( blankCount
== 10 ) {
634 // only ask for more data on stalled sockets
636 throw Error("Socket: 10 blank packets received");
641 // not done yet, ask for another read
647 void Socket::Packet(Barry::Packet
&packet
, int timeout
)
649 Packet(packet
.m_send
, packet
.m_receive
, timeout
);
652 void Socket::NextRecord(Data
&receive
)
654 Barry::Protocol::Packet packet
;
655 packet
.socket
= htobs(GetSocket());
656 packet
.size
= htobs(7);
657 packet
.command
= SB_COMMAND_DB_DONE
;
658 packet
.u
.db
.tableCmd
= 0;
659 packet
.u
.db
.u
.command
.operation
= 0;
661 Data
command(&packet
, 7);
662 Packet(command
, receive
);