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.
26 #include "protostructs.h"
30 #include <openssl/sha.h>
39 //////////////////////////////////////////////////////////////////////////////
42 SocketZero::SocketZero( SocketRoutingQueue
&queue
,
44 uint8_t zeroSocketSequenceStart
)
47 m_writeEp(writeEndpoint
),
49 m_zeroSocketSequence(zeroSocketSequenceStart
),
57 SocketZero::SocketZero( Device
&dev
,
58 int writeEndpoint
, int readEndpoint
,
59 uint8_t zeroSocketSequenceStart
)
62 m_writeEp(writeEndpoint
),
63 m_readEp(readEndpoint
),
64 m_zeroSocketSequence(zeroSocketSequenceStart
),
72 SocketZero::~SocketZero()
74 // nothing to close for socket zero
78 ///////////////////////////////////////
79 // Socket Zero static calls
81 // appends fragment to whole... if whole is empty, simply copies, and
82 // sets command to DATA instead of FRAGMENTED. Always updates the
83 // packet size of whole, to reflect the total size
84 void SocketZero::AppendFragment(Data
&whole
, const Data
&fragment
)
86 if( whole
.GetSize() == 0 ) {
87 // empty, so just copy
91 // has some data already, so just append
92 int size
= whole
.GetSize();
93 unsigned char *buf
= whole
.GetBuffer(size
+ fragment
.GetSize());
94 MAKE_PACKET(fpack
, fragment
);
95 int fragsize
= fragment
.GetSize() - SB_FRAG_HEADER_SIZE
;
97 memcpy(buf
+size
, &fpack
->u
.db
.u
.fragment
, fragsize
);
98 whole
.ReleaseBuffer(size
+ fragsize
);
101 // update whole's size and command type for future sanity
102 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) whole
.GetBuffer();
103 wpack
->size
= htobs((uint16_t) whole
.GetSize());
104 wpack
->command
= SB_COMMAND_DB_DATA
;
105 // don't need to call ReleaseBuffer here, since we're not changing
106 // the real data size, and ReleaseBuffer was called above during copy
109 // If offset is 0, starts fresh, taking the first fragment packet size chunk
110 // out of whole and creating a sendable packet in fragment. Returns the
111 // next offset if there is still more data, or 0 if finished.
112 unsigned int SocketZero::MakeNextFragment(const Data
&whole
, Data
&fragment
, unsigned int offset
)
115 if( whole
.GetSize() < SB_FRAG_HEADER_SIZE
) {
116 eout("Whole packet too short to fragment: " << whole
.GetSize());
117 throw Error("Socket: Whole packet too short to fragment");
121 unsigned int todo
= whole
.GetSize() - SB_FRAG_HEADER_SIZE
- offset
;
122 unsigned int nextOffset
= 0;
123 if( todo
> (MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
) ) {
124 todo
= MAX_PACKET_SIZE
- SB_FRAG_HEADER_SIZE
;
125 nextOffset
= offset
+ todo
;
128 // create fragment header
129 unsigned char *buf
= fragment
.GetBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
130 memcpy(buf
, whole
.GetData(), SB_FRAG_HEADER_SIZE
);
132 // copy over a fragment size of data
133 memcpy(buf
+ SB_FRAG_HEADER_SIZE
, whole
.GetData() + SB_FRAG_HEADER_SIZE
+ offset
, todo
);
135 // update fragment's size and command type
136 Barry::Protocol::Packet
*wpack
= (Barry::Protocol::Packet
*) buf
;
137 wpack
->size
= htobs((uint16_t) (todo
+ SB_FRAG_HEADER_SIZE
));
139 wpack
->command
= SB_COMMAND_DB_FRAGMENTED
;
141 wpack
->command
= SB_COMMAND_DB_DATA
;
143 // adjust the new fragment size
144 fragment
.ReleaseBuffer(SB_FRAG_HEADER_SIZE
+ todo
);
151 ///////////////////////////////////////
152 // SocketZero private API
155 // FIXME - not sure yet whether sequence ID's are per socket or not... if
156 // they are per socket, then this global sequence behaviour will not work,
157 // and we need to track m_sequenceId on a Socket level.
159 void SocketZero::CheckSequence(uint16_t socket
, const Data
&seq
)
161 MAKE_PACKET(spack
, seq
);
162 if( (unsigned int) seq
.GetSize() < SB_SEQUENCE_PACKET_SIZE
) {
163 eout("Short sequence packet:\n" << seq
);
164 throw Error("Socket: invalid sequence packet");
167 // we'll cheat here... if the packet's sequence is 0, we'll
168 // silently restart, otherwise, fail
169 uint32_t sequenceId
= btohl(spack
->u
.sequence
.sequenceId
);
170 if( sequenceId
== 0 ) {
171 // silently restart (will advance below)
175 if( sequenceId
!= m_sequenceId
) {
177 std::ostringstream oss
;
178 oss
<< "Socket 0x" << std::hex
<< (unsigned int)socket
179 << ": out of sequence. "
180 << "(Global sequence: " << m_sequenceId
181 << ". Packet sequence: " << sequenceId
184 throw Error(oss
.str());
187 dout("Bad sequence on socket 0: expected: "
189 << ". Packet sequence: " << sequenceId
);
198 void SocketZero::SendOpen(uint16_t socket
, Data
&receive
)
200 // build open command
201 Barry::Protocol::Packet packet
;
203 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
204 packet
.command
= SB_COMMAND_OPEN_SOCKET
;
205 packet
.u
.socket
.socket
= htobs(socket
);
206 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
208 Data
send(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
212 } catch( Usb::Error
& ) {
213 eeout(send
, receive
);
218 Protocol::CheckSize(receive
);
219 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
220 CheckSequence(0, receive
);
222 // still need our ACK
226 // receive now holds the Open response
229 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
230 void SocketZero::SendPasswordHash(uint16_t socket
, const char *password
, Data
&receive
)
232 unsigned char pwdigest
[SHA_DIGEST_LENGTH
];
233 unsigned char prefixedhash
[SHA_DIGEST_LENGTH
+ 4];
235 // first, hash the password by itself
236 SHA1((unsigned char *) password
, strlen(password
), pwdigest
);
238 // prefix the resulting hash with the provided seed
239 uint32_t seed
= htobl(m_challengeSeed
);
240 memcpy(&prefixedhash
[0], &seed
, sizeof(uint32_t));
241 memcpy(&prefixedhash
[4], pwdigest
, SHA_DIGEST_LENGTH
);
244 SHA1((unsigned char *) prefixedhash
, SHA_DIGEST_LENGTH
+ 4, pwdigest
);
247 size_t size
= SB_SOCKET_PACKET_HEADER_SIZE
+ PASSWORD_CHALLENGE_SIZE
;
249 // build open command
250 Barry::Protocol::Packet packet
;
252 packet
.size
= htobs(size
);
253 packet
.command
= SB_COMMAND_PASSWORD
;
254 packet
.u
.socket
.socket
= htobs(socket
);
255 packet
.u
.socket
.sequence
= m_zeroSocketSequence
;// overwritten by Send()
256 packet
.u
.socket
.u
.password
.remaining_tries
= 0;
257 packet
.u
.socket
.u
.password
.unknown
= 0;
258 packet
.u
.socket
.u
.password
.param
= htobs(0x14); // FIXME - what does this mean?
259 memcpy(packet
.u
.socket
.u
.password
.u
.hash
, pwdigest
,
260 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
262 // blank password hashes as we don't need these anymore
263 memset(pwdigest
, 0, sizeof(pwdigest
));
264 memset(prefixedhash
, 0, sizeof(prefixedhash
));
266 Data
send(&packet
, size
);
270 // blank password hash as we don't need this anymore either
271 memset(packet
.u
.socket
.u
.password
.u
.hash
, 0,
272 sizeof(packet
.u
.socket
.u
.password
.u
.hash
));
276 Protocol::CheckSize(receive
);
277 if( IS_COMMAND(receive
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
278 CheckSequence(0, receive
);
280 // still need our ACK
284 // receive now holds the Password response
287 void SocketZero::RawSend(Data
&send
, int timeout
)
289 Usb::Device
*dev
= m_queue
? m_queue
->GetUsbDevice() : m_dev
;
291 // Special case: it seems that sending packets with a size that's an
292 // exact multiple of 0x40 causes the device to get confused.
294 // To get around that, it is observed in the captures that the size
295 // is sent in a special 3 byte packet before the real packet.
296 // Check for this case here.
298 if( (send
.GetSize() % 0x40) == 0 ) {
299 Protocol::SizePacket packet
;
300 packet
.size
= htobs(send
.GetSize());
301 packet
.buffer
[2] = 0; // zero the top byte
302 Data
sizeCommand(&packet
, 3);
304 dev
->BulkWrite(m_writeEp
, sizeCommand
);
307 dev
->BulkWrite(m_writeEp
, send
);
310 void SocketZero::RawReceive(Data
&receive
, int timeout
)
314 if( !m_queue
->DefaultRead(receive
, timeout
) )
315 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
318 m_dev
->BulkRead(m_readEp
, receive
, timeout
);
320 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
321 << "\nReceived:\n" << receive
);
322 } while( SequencePacket(receive
) );
328 /// Returns true if this is a sequence packet that should be ignored.
329 /// This function is used in SocketZero::RawReceive() in order
330 /// to determine whether to keep reading or not. By default,
331 /// this function checks whether the packet is a sequence packet
332 /// or not, and returns true if so. Also, if it is a sequence
333 /// packet, it checks the validity of the sequence number.
335 /// If sequence packets become important in the future, this
336 /// function could be changed to call a user-defined callback,
337 /// in order to handle these things out of band.
339 bool SocketZero::SequencePacket(const Data
&data
)
341 if( data
.GetSize() >= MIN_PACKET_SIZE
) {
342 if( IS_COMMAND(data
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
343 CheckSequence(0, data
);
347 return false; // not a sequence packet
351 ///////////////////////////////////////
352 // SocketZero public API
354 void SocketZero::SetRoutingQueue(SocketRoutingQueue
&queue
)
356 // replace the current queue pointer
360 void SocketZero::UnlinkRoutingQueue()
365 void SocketZero::Send(Data
&send
, int timeout
)
367 // force the socket number to 0
368 if( send
.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE
) {
369 MAKE_PACKETPTR_BUF(spack
, send
.GetBuffer());
373 // This is a socket 0 packet, so force the send packet data's
374 // socket 0 sequence number to something correct.
375 if( send
.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE
) {
376 MAKE_PACKETPTR_BUF(spack
, send
.GetBuffer());
377 spack
->u
.socket
.sequence
= m_zeroSocketSequence
;
378 m_zeroSocketSequence
++;
381 RawSend(send
, timeout
);
384 void SocketZero::Send(Data
&send
, Data
&receive
, int timeout
)
387 RawReceive(receive
, timeout
);
390 void SocketZero::Send(Barry::Packet
&packet
, int timeout
)
392 Send(packet
.m_send
, packet
.m_receive
, timeout
);
399 /// Open a logical socket on the device.
401 /// Both the socket number and the flag are based on the response to the
402 /// SELECT_MODE command. See Controller::SelectMode() for more info
405 /// The packet sequence is normal for most socket operations.
407 /// - Down: command packet with OPEN_SOCKET
408 /// - Up: optional sequence handshake packet
409 /// - Up: command response, which repeats the socket and flag data
412 /// \exception Barry::Error
413 /// Thrown on protocol error.
415 /// \exception Barry::BadPassword
416 /// Thrown on invalid password, or not enough retries left
419 SocketHandle
SocketZero::Open(uint16_t socket
, const char *password
)
421 // Things get a little funky here, as we may be left in an
422 // intermediate state in the case of a failed password.
423 // This function should support being called as many times
424 // as needed to handle the password
427 ZeroPacket
packet(send
, receive
);
429 // save sequence for later close
430 uint8_t closeFlag
= GetZeroSocketSequence();
434 m_remainingTries
= 0;
436 SendOpen(socket
, receive
);
438 // check for password challenge, or success
439 if( packet
.Command() == SB_COMMAND_PASSWORD_CHALLENGE
) {
441 m_challengeSeed
= packet
.ChallengeSeed();
442 m_remainingTries
= packet
.RemainingTries();
445 // fall through to challenge code...
449 // half open, device is expecting a password hash... do we
452 throw BadPassword("No password specified.", m_remainingTries
, false);
455 // only allow password attempts if there are 6 or more
456 // tries remaining... we want to give the user at least
457 // 5 chances on a Windows machine before the device
459 if( m_remainingTries
< 6 ) {
460 throw BadPassword("Fewer than 6 password tries "
461 "remaining in device. Refusing to proceed, "
462 "to avoid device zapping itself. Use a "
463 "Windows client, or re-cradle the device.",
468 // save sequence for later close (again after SendOpen())
469 closeFlag
= GetZeroSocketSequence();
471 SendPasswordHash(socket
, password
, receive
);
473 if( packet
.Command() == SB_COMMAND_PASSWORD_FAILED
) {
475 m_challengeSeed
= packet
.ChallengeSeed();
476 m_remainingTries
= packet
.RemainingTries();
477 throw BadPassword("Password rejected by device.", m_remainingTries
, false);
480 // if we get this far, we are no longer in half-open password
481 // mode, so we can reset our flags
484 // fall through to success check...
487 if( packet
.Command() != SB_COMMAND_OPENED_SOCKET
||
488 packet
.SocketResponse() != socket
||
489 packet
.SocketSequence() != closeFlag
)
491 eout("Packet:\n" << receive
);
492 throw Error("Socket: Bad OPENED packet in Open");
495 // success! save the socket
496 return SocketHandle(new Socket(*this, socket
, closeFlag
));
502 /// Closes a non-default socket (i.e. non-zero socket number)
504 /// The packet sequence is just like Open(), except the command is
507 /// \exception Barry::Error
509 void SocketZero::Close(Socket
&socket
)
511 if( socket
.GetSocket() == 0 )
512 return; // nothing to do
514 // build close command
515 Barry::Protocol::Packet packet
;
517 packet
.size
= htobs(SB_SOCKET_PACKET_HEADER_SIZE
);
518 packet
.command
= SB_COMMAND_CLOSE_SOCKET
;
519 packet
.u
.socket
.socket
= htobs(socket
.GetSocket());
520 packet
.u
.socket
.sequence
= socket
.GetCloseFlag();
522 Data
command(&packet
, SB_SOCKET_PACKET_HEADER_SIZE
);
525 Send(command
, response
);
527 catch( Usb::Error
& ) {
528 // reset so this won't be called again
529 socket
.ForceClosed();
531 eeout(command
, response
);
535 // starting fresh, reset sequence ID
536 Protocol::CheckSize(response
);
537 if( IS_COMMAND(response
, SB_COMMAND_SEQUENCE_HANDSHAKE
) ) {
538 CheckSequence(0, response
);
540 // still need our ACK
541 RawReceive(response
);
544 Protocol::CheckSize(response
, SB_SOCKET_PACKET_HEADER_SIZE
);
545 MAKE_PACKET(rpack
, response
);
546 if( rpack
->command
!= SB_COMMAND_CLOSED_SOCKET
||
547 btohs(rpack
->u
.socket
.socket
) != socket
.GetSocket() ||
548 rpack
->u
.socket
.sequence
!= socket
.GetCloseFlag() )
550 // reset so this won't be called again
551 socket
.ForceClosed();
553 eout("Packet:\n" << response
);
554 throw Error("Socket: Bad CLOSED packet in Close");
557 // // and finally, there always seems to be an extra read of
558 // // an empty packet at the end... just throw it away
560 // RawReceive(response, 1);
562 // catch( Usb::Timeout & ) {
565 // reset socket and flag
566 socket
.ForceClosed();
574 //////////////////////////////////////////////////////////////////////////////
577 Socket::Socket( SocketZero
&zero
,
582 , m_closeFlag(closeFlag
)
583 , m_registered(false)
589 // trap exceptions in the destructor
591 // a non-default socket has been opened, close it
594 catch( std::runtime_error
&re
) {
595 // do nothing... log it?
596 dout("Exception caught in ~Socket: " << re
.what());
601 ////////////////////////////////////
602 // Socket protected API
604 void Socket::CheckSequence(const Data
&seq
)
606 m_zero
->CheckSequence(m_socket
, seq
);
609 void Socket::ForceClosed()
616 ////////////////////////////////////
621 UnregisterInterest();
622 m_zero
->Close(*this);
629 /// Sends 'send' data to device, no receive.
633 /// \exception Usb::Error on underlying bus errors.
635 void Socket::Send(Data
&send
, int timeout
)
637 // force the socket number to this socket
638 if( send
.GetSize() >= SB_PACKET_HEADER_SIZE
) {
639 MAKE_PACKETPTR_BUF(spack
, send
.GetBuffer());
640 spack
->socket
= htobs(m_socket
);
642 m_zero
->RawSend(send
, timeout
);
648 /// Sends 'send' data to device, and waits for response.
652 /// \exception Usb::Error on underlying bus errors.
654 void Socket::Send(Data
&send
, Data
&receive
, int timeout
)
657 Receive(receive
, timeout
);
660 void Socket::Send(Barry::Packet
&packet
, int timeout
)
662 Send(packet
.m_send
, packet
.m_receive
, timeout
);
665 void Socket::Receive(Data
&receive
, int timeout
)
668 if( m_zero
->m_queue
) {
669 if( !m_zero
->m_queue
->SocketRead(m_socket
, receive
, timeout
) )
670 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
673 throw std::logic_error("NULL queue pointer in a registered socket read.");
677 m_zero
->RawReceive(receive
, timeout
);
681 // sends the send packet down to the device, fragmenting if
682 // necessary, and returns the response in receive, defragmenting
684 // Blocks until response received or timed out in Usb::Device
685 void Socket::Packet(Data
&send
, Data
&receive
, int timeout
)
688 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
689 // function that forces the socket number to the correct current value,
690 // but putting it here means a copy on every packet.
692 // force socket to our socket
693 Data send = sendorig;
694 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
695 sspack->socket = htobs(GetSocket());
698 MAKE_PACKET(spack
, send
);
699 if( send
.GetSize() < MIN_PACKET_SIZE
||
700 (spack
->command
!= SB_COMMAND_DB_DATA
&&
701 spack
->command
!= SB_COMMAND_DB_DONE
) )
703 // we don't do that around here
704 throw std::logic_error("Socket: unknown send data in Packet()");
710 if( send
.GetSize() <= MAX_PACKET_SIZE
) {
711 // send non-fragmented
712 Send(send
, inFrag
, timeout
);
716 unsigned int offset
= 0;
720 offset
= SocketZero::MakeNextFragment(send
, outFrag
, offset
);
721 Send(outFrag
, inFrag
, timeout
);
723 MAKE_PACKET(rpack
, inFrag
);
724 // only process sequence handshakes... once we
725 // get to the last fragment, we fall through to normal
727 if( offset
&& inFrag
.GetSize() > 0 ) {
729 Protocol::CheckSize(inFrag
);
731 switch( rpack
->command
)
733 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
734 CheckSequence(inFrag
);
738 std::ostringstream oss
;
739 oss
<< "Socket: unhandled packet in Packet() (send): 0x" << std::hex
<< (unsigned int)rpack
->command
;
741 throw Error(oss
.str());
748 } while( offset
> 0 );
751 bool done
= false, frag
= false;
754 MAKE_PACKET(rpack
, inFrag
);
756 // check the packet's validity
757 if( inFrag
.GetSize() > 0 ) {
760 Protocol::CheckSize(inFrag
);
762 switch( rpack
->command
)
764 case SB_COMMAND_SEQUENCE_HANDSHAKE
:
765 CheckSequence(inFrag
);
768 case SB_COMMAND_DB_DATA
:
770 SocketZero::AppendFragment(receive
, inFrag
);
778 case SB_COMMAND_DB_FRAGMENTED
:
779 SocketZero::AppendFragment(receive
, inFrag
);
783 case SB_COMMAND_DB_DONE
:
789 std::ostringstream oss
;
790 oss
<< "Socket: unhandled packet in Packet() (read): 0x" << std::hex
<< (unsigned int)rpack
->command
;
792 throw Error(oss
.str());
799 //std::cerr << "Blank! " << blankCount << std::endl;
800 if( blankCount
== 10 ) {
801 // only ask for more data on stalled sockets
803 throw Error("Socket: 10 blank packets received");
808 // not done yet, ask for another read
814 void Socket::Packet(Barry::Packet
&packet
, int timeout
)
816 Packet(packet
.m_send
, packet
.m_receive
, timeout
);
819 void Socket::NextRecord(Data
&receive
)
821 Barry::Protocol::Packet packet
;
822 packet
.socket
= htobs(GetSocket());
823 packet
.size
= htobs(7);
824 packet
.command
= SB_COMMAND_DB_DONE
;
825 packet
.u
.db
.tableCmd
= 0;
826 packet
.u
.db
.u
.command
.operation
= 0;
828 Data
command(&packet
, 7);
829 Packet(command
, receive
);
832 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler
,
835 if( !m_zero
->m_queue
)
836 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
839 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
841 m_zero
->m_queue
->RegisterInterest(m_socket
, handler
, context
);
845 void Socket::UnregisterInterest()
848 if( m_zero
->m_queue
)
849 m_zero
->m_queue
->UnregisterInterest(m_socket
);
850 m_registered
= false;