Bumped copyright dates for 2013
[barry.git] / src / socket.cc
blob3247c73bd7d69a043234e08dcd858b26ba96f7d4
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2013, 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.
22 #include "i18n.h"
23 #include "socket.h"
24 #include "usbwrap.h"
25 #include "data.h"
26 #include "protocol.h"
27 #include "protostructs.h"
28 #include "endian.h"
29 #include "debug.h"
30 #include "packet.h"
31 #include "sha1.h"
32 #include <sstream>
33 #include <string.h>
35 using namespace Usb;
38 namespace Barry {
41 //////////////////////////////////////////////////////////////////////////////
42 // SocketZero class
44 SocketZero::SocketZero( SocketRoutingQueue &queue,
45 int writeEndpoint,
46 uint8_t zeroSocketSequenceStart)
47 : m_dev(0)
48 , m_queue(&queue)
49 , m_writeEp(writeEndpoint)
50 , m_readEp(0)
51 , m_zeroSocketSequence(zeroSocketSequenceStart)
52 , m_sequenceId(0)
53 , m_halfOpen(false)
54 , m_challengeSeed(0)
55 , m_remainingTries(0)
56 , m_modeSequencePacketSeen(false)
57 , m_pushback(false)
61 SocketZero::SocketZero( Device &dev,
62 int writeEndpoint, int readEndpoint,
63 uint8_t zeroSocketSequenceStart)
64 : m_dev(&dev)
65 , m_queue(0)
66 , m_writeEp(writeEndpoint)
67 , m_readEp(readEndpoint)
68 , m_zeroSocketSequence(zeroSocketSequenceStart)
69 , m_sequenceId(0)
70 , m_halfOpen(false)
71 , m_challengeSeed(0)
72 , m_remainingTries(0)
73 , m_modeSequencePacketSeen(false)
74 , m_pushback(false)
78 SocketZero::~SocketZero()
80 // nothing to close for socket zero
84 ///////////////////////////////////////
85 // Socket Zero static calls
87 // appends fragment to whole... if whole is empty, simply copies, and
88 // sets command to DATA instead of FRAGMENTED. Always updates the
89 // packet size of whole, to reflect the total size
90 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
92 if( whole.GetSize() == 0 ) {
93 // empty, so just copy
94 whole = fragment;
96 else {
97 // has some data already, so just append
98 int size = whole.GetSize();
99 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
100 MAKE_PACKET(fpack, fragment);
101 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
103 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
104 whole.ReleaseBuffer(size + fragsize);
107 // update whole's size and command type for future sanity
108 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
109 wpack->size = htobs((uint16_t) whole.GetSize());
110 wpack->command = SB_COMMAND_DB_DATA;
111 // don't need to call ReleaseBuffer here, since we're not changing
112 // the real data size, and ReleaseBuffer was called above during copy
115 // If offset is 0, starts fresh, taking the first fragment packet size chunk
116 // out of whole and creating a sendable packet in fragment. Returns the
117 // next offset if there is still more data, or 0 if finished.
118 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
120 // sanity check
121 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
122 eout("Whole packet too short to fragment: " << whole.GetSize());
123 throw Error(_("Socket: Whole packet too short to fragment"));
126 // calculate size
127 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
128 unsigned int nextOffset = 0;
129 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
130 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
131 nextOffset = offset + todo;
134 // create fragment header
135 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
136 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
138 // copy over a fragment size of data
139 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
141 // update fragment's size and command type
142 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
143 wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
144 if( nextOffset )
145 wpack->command = SB_COMMAND_DB_FRAGMENTED;
146 else
147 wpack->command = SB_COMMAND_DB_DATA;
149 // adjust the new fragment size
150 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
152 // return next round
153 return nextOffset;
157 ///////////////////////////////////////
158 // SocketZero private API
161 // FIXME - not sure yet whether sequence ID's are per socket or not... if
162 // they are per socket, then this global sequence behaviour will not work,
163 // and we need to track m_sequenceId on a Socket level.
165 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
167 MAKE_PACKET(spack, seq);
168 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
169 eout("Short sequence packet:\n" << seq);
170 throw Error(_("Socket: invalid sequence packet"));
173 // we'll cheat here... if the packet's sequence is 0, we'll
174 // silently restart, otherwise, fail
175 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
176 if( sequenceId == 0 ) {
177 // silently restart (will advance below)
178 m_sequenceId = 0;
180 else {
181 if( sequenceId != m_sequenceId ) {
182 if( socket != 0 ) {
183 std::string msg = string_vprintf(_("Socket 0x%x: out of sequence. (Global sequence: 0x%x. Packet sequence: 0x%x)"),
184 (unsigned int)socket,
185 (unsigned int)m_sequenceId,
186 (unsigned int)sequenceId);
187 eout(msg);
188 throw Error(msg);
190 else {
191 dout("Bad sequence on socket 0: expected: "
192 << m_sequenceId
193 << ". Packet sequence: " << sequenceId);
198 // advance!
199 m_sequenceId++;
202 void SocketZero::SendOpen(uint16_t socket, Data &receive)
204 // build open command
205 Barry::Protocol::Packet packet;
206 packet.socket = 0;
207 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
208 packet.command = SB_COMMAND_OPEN_SOCKET;
209 packet.u.socket.socket = htobs(socket);
210 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
212 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
213 try {
214 RawSend(send);
215 RawReceive(receive);
216 if( Protocol::IsSequencePacket(receive) ) {
217 m_modeSequencePacketSeen = true;
218 // during open, we could get a sequence packet in
219 // the middle, from the SelectMode operation
220 RawReceive(receive);
222 } catch( Usb::Error & ) {
223 eeout(send, receive);
224 throw;
227 // receive now holds the Open response
230 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
231 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
233 unsigned char pwdigest[SHA_DIGEST_LENGTH];
234 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
236 // first, hash the password by itself
237 SHA1((unsigned char *) password, strlen(password), pwdigest);
239 // prefix the resulting hash with the provided seed
240 uint32_t seed = htobl(m_challengeSeed);
241 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
242 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
244 // hash again
245 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
248 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
250 // build open command
251 Barry::Protocol::Packet packet;
252 packet.socket = 0;
253 packet.size = htobs(size);
254 packet.command = SB_COMMAND_PASSWORD;
255 packet.u.socket.socket = htobs(socket);
256 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
257 packet.u.socket.u.password.remaining_tries = 0;
258 packet.u.socket.u.password.unknown = 0;
259 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
260 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
261 sizeof(packet.u.socket.u.password.u.hash));
263 // blank password hashes as we don't need these anymore
264 memset(pwdigest, 0, sizeof(pwdigest));
265 memset(prefixedhash, 0, sizeof(prefixedhash));
267 Data send(&packet, size);
268 RawSend(send);
269 RawReceive(receive);
271 // blank password hash as we don't need this anymore either
272 memset(packet.u.socket.u.password.u.hash, 0,
273 sizeof(packet.u.socket.u.password.u.hash));
274 send.Zap();
276 // check sequence ID
277 if( Protocol::IsSequencePacket(receive) ) {
278 m_modeSequencePacketSeen = true;
280 CheckSequence(0, receive);
282 // still need our ACK
283 RawReceive(receive);
286 // receive now holds the Password response
289 void SocketZero::RawSend(Data &send, int timeout)
291 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
292 if( !dev )
293 throw Error(_("SocketZero: No device available for RawSend"));
295 // Special case: it seems that sending packets with a size that's an
296 // exact multiple of 0x40 causes the device to get confused.
298 // To get around that, it is observed in the captures that the size
299 // is sent in a special 3 byte packet before the real packet.
300 // Check for this case here.
302 if( (send.GetSize() % 0x40) == 0 ) {
303 Protocol::SizePacket packet;
304 packet.size = htobs(send.GetSize());
305 packet.buffer[2] = 0; // zero the top byte
306 Data sizeCommand(&packet, 3);
308 dev->BulkWrite(m_writeEp, sizeCommand, timeout);
311 dev->BulkWrite(m_writeEp, send, timeout);
314 void SocketZero::RawReceive(Data &receive, int timeout)
316 if( m_pushback ) {
317 receive = m_pushback_buffer;
318 m_pushback = false;
319 return;
322 if( m_queue ) {
323 if( !m_queue->DefaultRead(receive, timeout) )
324 throw Timeout(_("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)"));
326 else {
327 m_dev->BulkRead(m_readEp, receive, timeout);
330 ddout("SocketZero::RawReceive: Endpoint "
331 << (m_queue ? m_queue->GetReadEp() : m_readEp)
332 << "\nReceived:\n" << receive);
335 void SocketZero::Pushback(const Data &buf)
337 if( m_pushback )
338 throw Error(_("Multiple pushbacks in SocketZero!"));
340 m_pushback = true;
341 m_pushback_buffer = buf;
345 ///////////////////////////////////////
346 // SocketZero public API
348 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
350 // replace the current queue pointer
351 m_queue = &queue;
354 void SocketZero::UnlinkRoutingQueue()
356 m_queue = 0;
359 void SocketZero::Send(Data &send, int timeout)
361 // force the socket number to 0
362 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
363 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
364 spack->socket = 0;
367 // This is a socket 0 packet, so force the send packet data's
368 // socket 0 sequence number to something correct.
369 if( 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 RawSend(send, timeout);
378 void SocketZero::Send(Data &send, Data &receive, int timeout)
380 Send(send, timeout);
381 RawReceive(receive, timeout);
384 void SocketZero::Send(Barry::Packet &packet, int timeout)
386 Send(packet.m_send, *packet.m_receive, timeout);
389 void SocketZero::Receive(Data &receive, int timeout)
391 RawReceive(receive, timeout);
396 // Open
398 /// Open a logical socket on the device.
400 /// Both the socket number and the flag are based on the response to the
401 /// SELECT_MODE command. See Controller::SelectMode() for more info
402 /// on this.
404 /// The packet sequence is normal for most socket operations.
406 /// - Down: command packet with OPEN_SOCKET
407 /// - Up: optional sequence handshake packet
408 /// - Up: command response, which repeats the socket and flag data
409 /// as confirmation
411 /// \exception Barry::Error
412 /// Thrown on protocol error.
414 /// \exception Barry::BadPassword
415 /// Thrown on invalid password, or not enough retries left
416 /// on device.
418 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
420 return Open(SocketRoutingQueue::SocketDataHandlerPtr(),
421 socket, password);
424 // Open
426 /// Open a logical socket on the device.
428 /// Both the socket number and the flag are based on the response to the
429 /// SELECT_MODE command. See Controller::SelectMode() for more info
430 /// on this.
432 /// This version of open includes a socket routing queue handler to
433 /// avoid the race condition with incoming data being lost if
434 /// the handler is only registered after the socket is opened.
436 /// The packet sequence is normal for most socket operations.
438 /// - Down: command packet with OPEN_SOCKET
439 /// - Up: optional sequence handshake packet
440 /// - Up: command response, which repeats the socket and flag data
441 /// as confirmation
443 /// \exception Barry::Error
444 /// Thrown on protocol error.
446 /// \exception Barry::BadPassword
447 /// Thrown on invalid password, or not enough retries left
448 /// on device.
450 SocketHandle SocketZero::Open(
451 Barry::SocketRoutingQueue::SocketDataHandlerPtr handler,
452 uint16_t socket, const char *password)
454 // Things get a little funky here, as we may be left in an
455 // intermediate state in the case of a failed password.
456 // This function should support being called as many times
457 // as needed to handle the password
460 Data send, receive;
461 ZeroPacket packet(send, receive);
463 // save sequence for later close
464 uint8_t closeFlag = GetZeroSocketSequence();
466 // It's necessary to create the socket before performing any
467 // device IO as the device can start sending packets for a socket
468 // as soon as it's sent a SB_COMMAND_OPENED_SOCKET command.
470 // If something goes wrong and this method throws an error
471 // then the SocketHandle cleanup will destroy the socket,
472 // correctly unregistering it.
473 Socket *sock = new Socket(*this, socket, closeFlag);
474 SocketHandle sh(sock);
476 sock->Opening(handler);
478 if( !m_halfOpen ) {
479 // starting fresh
480 m_remainingTries = 0;
482 // this gets set to true if we see a starting sequence packet
483 // during any of our open and password commands... After
484 // a mode command (like "RIM Desktop", etc.) a starting
485 // sequence packet is sent, and may arrive before or after
486 // the socket open handshake.
487 m_modeSequencePacketSeen = false;
489 // go for it!
490 SendOpen(socket, receive);
492 // check for password challenge, or success
493 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
494 m_halfOpen = true;
495 m_challengeSeed = packet.ChallengeSeed();
496 m_remainingTries = packet.RemainingTries();
499 // fall through to challenge code...
502 if( m_halfOpen ) {
503 // half open, device is expecting a password hash... do we
504 // have a password?
505 if( !password ) {
506 throw BadPassword(_("No password specified."), m_remainingTries, false);
509 // only allow password attempts if there are
510 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
511 // we want to give the user at least some chance on a
512 // Windows machine before the device commits suicide.
513 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
514 throw BadPassword(string_vprintf(_("Fewer than %d password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device."), BARRY_MIN_PASSWORD_TRIES),
515 m_remainingTries,
516 true);
519 // save sequence for later close (again after SendOpen())
520 closeFlag = GetZeroSocketSequence();
522 SendPasswordHash(socket, password, receive);
524 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
525 m_halfOpen = true;
526 m_challengeSeed = packet.ChallengeSeed();
527 m_remainingTries = packet.RemainingTries();
528 throw BadPassword(_("Password rejected by device."), m_remainingTries, false);
531 // if we get this far, we are no longer in half-open password
532 // mode, so we can reset our flags
533 m_halfOpen = false;
535 // fall through to success check...
538 // If the device thinks that the socket was already open then
539 // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
541 // This happens most commonly when using raw channels which
542 // haven't been cleanly closed (such as by killing the process
543 // running Barry) and so the device still thinks the socket
544 // is open.
546 // Retrying the open will usually succeed, but relies on the
547 // device software re-creating the channel after it's closed
548 // so return an error here instead of automatically retrying.
549 if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
551 throw SocketCloseOnOpen(_("Socket: Device closed socket when trying to open (can be caused by the wrong password, or if the device thinks the socket is already open... please try again)"));
554 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
555 packet.SocketResponse() != socket ||
556 packet.SocketSequence() != closeFlag )
558 eout("Packet:\n" << receive);
559 throw Error(_("Socket: Bad OPENED packet in Open"));
562 // if no sequence packet has yet arrived, wait for it here
563 if( !m_modeSequencePacketSeen ) {
564 Data sequence;
565 RawReceive(sequence);
566 if( !Protocol::IsSequencePacket(sequence) ) {
567 // if this is not the sequence packet, then it might
568 // just be out of order (some devices do this when
569 // opening the JavaLoader mode), so as a last
570 // ditch effort, do one more read with a short
571 // timeout, and check that as well
572 Data late_sequence;
573 RawReceive(late_sequence, 500);
574 if( !Protocol::IsSequencePacket(late_sequence) ) {
575 throw Error(_("Could not find mode's starting sequence packet"));
578 // ok, so our ditch effort worked, but now we have
579 // a leftover packet on our hands... do a temporary
580 // pushback
581 Pushback(sequence);
585 // success!
586 sock->Opened();
588 return sh;
592 // Close
594 /// Closes a non-default socket (i.e. non-zero socket number)
596 /// The packet sequence is just like Open(), except the command is
597 /// CLOSE_SOCKET.
599 /// \exception Barry::Error
601 void SocketZero::Close(Socket &socket)
603 if( socket.GetSocket() == 0 )
604 return; // nothing to do
606 // build close command
607 Barry::Protocol::Packet packet;
608 packet.socket = 0;
609 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
610 packet.command = SB_COMMAND_CLOSE_SOCKET;
611 packet.u.socket.socket = htobs(socket.GetSocket());
612 packet.u.socket.sequence = socket.GetCloseFlag();
614 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
615 Data response;
616 try {
617 Send(command, response);
619 catch( Usb::Error & ) {
620 // reset so this won't be called again
621 socket.ForceClosed();
623 eeout(command, response);
624 throw;
627 // starting fresh, reset sequence ID
628 if( Protocol::IsSequencePacket(response) ) {
629 CheckSequence(0, response);
631 // still need our ACK
632 RawReceive(response);
635 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
636 MAKE_PACKET(rpack, response);
637 // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
638 // has closed the socket in response to our request.
640 // It's also possible for the reply to be
641 // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
642 // close the socket at the same time, such as if the channel
643 // API is being used by the device.
644 if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
645 rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
646 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
647 rpack->u.socket.sequence != socket.GetCloseFlag() )
649 // reset so this won't be called again
650 socket.ForceClosed();
652 eout("Packet:\n" << response);
653 throw BadPacket(rpack->command, _("Socket: Bad CLOSED packet in Close"));
656 if( socket.IsResetOnClose() ) {
657 Data send, receive;
658 ZeroPacket reset_packet(send, receive);
659 reset_packet.Reset();
661 Send(reset_packet);
662 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
663 throw BadPacket(reset_packet.CommandResponse(),
664 _("Socket: Missing RESET_REPLY in Close"));
668 // // and finally, there always seems to be an extra read of
669 // // an empty packet at the end... just throw it away
670 // try {
671 // RawReceive(response, 1);
672 // }
673 // catch( Usb::Timeout & ) {
674 // }
676 // reset socket and flag
677 socket.ForceClosed();
684 //////////////////////////////////////////////////////////////////////////////
685 // SocketBase class
687 SocketBase::~SocketBase()
691 void SocketBase::CheckSequence(const Data &seq)
693 // FIXME - needs implementation
697 // DBFragSend
699 /// Sends a fragmented Desktop / Database command packet.
700 /// Assumes that 'send' contains a valid packet, which may or may not
701 /// need fragmentation. If it does, fragmentation will be done
702 /// automatically.
704 void SocketBase::DBFragSend(Data &send, int timeout)
706 MAKE_PACKET(spack, send);
707 if( send.GetSize() < MIN_PACKET_SIZE ||
708 (spack->command != SB_COMMAND_DB_DATA &&
709 spack->command != SB_COMMAND_DB_DONE) )
711 // we don't do that around here
712 eout("unknown send data in DBFragSend(): " << send);
713 throw std::logic_error(_("Socket: unknown send data in DBFragSend()"));
716 if( send.GetSize() <= MAX_PACKET_SIZE ) {
717 // send non-fragmented
718 SyncSend(send, timeout);
720 else {
721 // send fragmented
722 unsigned int offset = 0;
723 Data outFrag;
725 do {
726 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
727 SyncSend(outFrag, timeout);
728 } while( offset > 0 );
734 // Send
736 /// SyncSends 'send' data to device, and waits for response.
738 /// \returns void
740 /// \exception Usb::Error on underlying bus errors.
742 void SocketBase::Send(Data &send, Data &receive, int timeout)
744 SyncSend(send, timeout);
745 Receive(receive, timeout);
748 void SocketBase::Send(Barry::Packet &packet, int timeout)
750 Send(packet.m_send, *packet.m_receive, timeout);
753 // sends the send packet down to the device, fragmenting if
754 // necessary, and returns the response in receive, defragmenting
755 // if needed
756 // Blocks until response received or timed out in Usb::Device
758 // This is primarily for Desktop Database packets... Javaloader
759 // packets use PacketData().
761 void SocketBase::Packet(Data &send, Data &receive, int timeout)
763 // assume the common case of no fragmentation,
764 // and use the receive buffer for input... allocate a frag buffer
765 // later if necessary
766 Data *inputBuf = &receive;
767 receive.Zap();
769 DBFragSend(send, timeout);
770 Receive(*inputBuf, timeout);
772 std::auto_ptr<Data> inFrag;
773 bool done = false, frag = false;
774 int blankCount = 0;
775 while( !done ) {
776 MAKE_PACKET(rpack, *inputBuf);
778 // check the packet's validity
779 if( inputBuf->GetSize() > 0 ) {
780 blankCount = 0;
782 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
784 switch( rpack->command )
786 case SB_COMMAND_SEQUENCE_HANDSHAKE:
787 CheckSequence(*inputBuf);
788 break;
790 case SB_COMMAND_DB_DATA:
791 if( frag ) {
792 SocketZero::AppendFragment(receive, *inputBuf);
794 else {
795 // no copy needed, already in receive,
796 // since inputBuf starts out that way
798 done = true;
799 break;
801 case SB_COMMAND_DB_FRAGMENTED:
802 // only copy if frag is true, since the
803 // first time through, receive == inputBuf
804 if( frag ) {
805 SocketZero::AppendFragment(receive, *inputBuf);
807 frag = true;
808 break;
810 case SB_COMMAND_DB_DONE:
811 // no copy needed, already in receive
812 done = true;
813 break;
815 default: {
816 std::ostringstream oss;
817 oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command;
818 eout(oss.str());
819 throw Error(oss.str());
821 break;
824 else {
825 blankCount++;
826 //std::cerr << "Blank! " << blankCount << std::endl;
827 if( blankCount == 10 ) {
828 // only ask for more data on stalled sockets
829 // for so long
830 throw Error(_("Socket: 10 blank packets received"));
834 if( !done ) {
835 // not done yet, ask for another read, and
836 // create new buffer for fragmented reads
837 if( frag && !inFrag.get() ) {
838 inFrag.reset( new Data );
839 inputBuf = inFrag.get();
841 Receive(*inputBuf);
846 void SocketBase::Packet(Barry::Packet &packet, int timeout)
848 Packet(packet.m_send, *packet.m_receive, timeout);
851 void SocketBase::Packet(Barry::JLPacket &packet, int timeout)
853 if( packet.HasData() ) {
854 SyncSend(packet.m_cmd);
855 PacketData(packet.m_data, *packet.m_receive, false, timeout);
857 else {
858 PacketData(packet.m_cmd, *packet.m_receive, false, timeout);
862 void SocketBase::Packet(Barry::JVMPacket &packet, int timeout)
864 PacketJVM(packet.m_cmd, *packet.m_receive, timeout);
867 // sends the send packet down to the device
868 // Blocks until response received or timed out in Usb::Device
870 // This function is used to send packet to JVM
871 void SocketBase::PacketJVM(Data &send, Data &receive, int timeout)
873 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
874 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
875 // we don't do that around here
876 throw std::logic_error(_("Socket: unknown send data in PacketJVM()"));
879 Data &inFrag = receive;
880 receive.Zap();
882 // send non-fragmented
883 RawSend(send, timeout);
884 Receive(inFrag, timeout);
886 bool done = false;
887 int blankCount = 0;
889 while( !done ) {
890 // check the packet's validity
891 if( inFrag.GetSize() > 6 ) {
892 MAKE_PACKET(rpack, inFrag);
894 blankCount = 0;
896 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
898 switch( rpack->command )
900 case SB_COMMAND_SEQUENCE_HANDSHAKE:
901 CheckSequence(inFrag);
902 break;
904 default: {
905 std::ostringstream oss;
906 oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command;
907 eout(oss.str());
908 throw Error(oss.str());
910 break;
913 else if( inFrag.GetSize() == 6 ) {
914 done = true;
916 else {
917 blankCount++;
919 //std::cerr << "Blank! " << blankCount << std::endl;
920 if( blankCount == 10 ) {
921 // only ask for more data on stalled sockets
922 // for so long
923 throw Error(_("Socket: 10 blank packets received"));
927 if( !done ) {
928 // not done yet, ask for another read
929 Receive(inFrag, timeout);
934 // sends the send packet down to the device
935 // Blocks until response received or timed out in Usb::Device
936 void SocketBase::PacketData(Data &send,
937 Data &receive,
938 bool done_on_sequence,
939 int timeout)
941 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
942 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
943 // we don't do that around here
944 throw std::logic_error(_("Socket: unknown send data in PacketData()"));
947 Data &inFrag = receive;
948 receive.Zap();
950 // send non-fragmented
951 SyncSend(send, timeout);
952 Receive(inFrag, timeout);
954 bool done = false;
955 int blankCount = 0;
957 while( !done ) {
958 // check the packet's validity
959 if( inFrag.GetSize() > 0 ) {
960 MAKE_PACKET(rpack, inFrag);
962 blankCount = 0;
964 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
966 switch( rpack->command )
968 case SB_COMMAND_SEQUENCE_HANDSHAKE:
969 // CheckSequence(inFrag);
970 if( done_on_sequence )
971 done = true;
972 break;
974 case SB_COMMAND_JL_READY:
975 case SB_COMMAND_JL_ACK:
976 case SB_COMMAND_JL_HELLO_ACK:
977 case SB_COMMAND_JL_RESET_REQUIRED:
978 done = true;
979 break;
981 case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream
982 done = true;
983 break;
985 case SB_DATA_JL_INVALID:
986 throw BadPacket(rpack->command, _("file is not a valid Java code file"));
987 break;
989 case SB_COMMAND_JL_NOT_SUPPORTED:
990 throw BadPacket(rpack->command, _("device does not support requested command"));
991 break;
993 default:
994 // unknown packet, pass it up to the
995 // next higher code layer
996 done = true;
997 break;
1000 else {
1001 blankCount++;
1002 //std::cerr << "Blank! " << blankCount << std::endl;
1003 if( blankCount == 10 ) {
1004 // only ask for more data on stalled sockets
1005 // for so long
1006 throw Error(_("Socket: 10 blank packets received"));
1010 if( !done ) {
1011 // not done yet, ask for another read
1012 Receive(inFrag);
1017 void SocketBase::NextRecord(Data &receive)
1019 Barry::Protocol::Packet packet;
1020 packet.size = htobs(7);
1021 packet.command = SB_COMMAND_DB_DONE;
1022 packet.u.db.tableCmd = 0;
1023 packet.u.db.u.command.operation = 0;
1025 Data command(&packet, 7);
1026 Packet(command, receive);
1031 //////////////////////////////////////////////////////////////////////////////
1032 // Socket class
1034 Socket::Socket( SocketZero &zero,
1035 uint16_t socket,
1036 uint8_t closeFlag)
1037 : m_zero(&zero)
1038 , m_socket(socket)
1039 , m_closeFlag(closeFlag)
1040 , m_registered(false)
1041 , m_sequence(new Data)
1045 Socket::~Socket()
1047 // trap exceptions in the destructor
1048 try {
1049 // a non-default socket has been opened, close it
1050 LocalClose();
1052 catch( std::runtime_error &DEBUG_ONLY(re) ) {
1053 // do nothing... log it?
1054 dout("Exception caught in ~Socket: " << re.what());
1059 ////////////////////////////////////
1060 // Socket protected API
1062 void Socket::ForceClosed()
1064 m_socket = 0;
1065 m_closeFlag = 0;
1068 void Socket::LocalClose()
1070 LocalUnregisterInterest();
1071 m_zero->Close(*this);
1074 void Socket::LocalUnregisterInterest()
1076 if( m_registered ) {
1077 if( m_zero->m_queue )
1078 m_zero->m_queue->UnregisterInterest(m_socket);
1079 m_registered = false;
1085 // Send
1087 /// Sends 'send' data to device, no receive.
1089 /// \returns void
1091 /// \exception Usb::Error on underlying bus errors.
1093 void Socket::RawSend(Data &send, int timeout)
1095 // force the socket number to this socket
1096 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
1097 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
1098 spack->socket = htobs(m_socket);
1100 m_zero->RawSend(send, timeout);
1103 void Socket::SyncSend(Data &send, int timeout)
1105 RawSend(send, timeout);
1106 Receive(*m_sequence, timeout);
1107 if( !Protocol::IsSequencePacket(*m_sequence) )
1108 throw Barry::Error(_("Non-sequence packet in Socket::SyncSend()"));
1109 CheckSequence(*m_sequence);
1112 void Socket::Receive(Data &receive, int timeout)
1114 if( m_registered ) {
1115 if( m_zero->m_queue ) {
1116 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
1117 throw Timeout(_("Socket::Receive: queue SocketRead returned false (likely a timeout)"));
1119 else {
1120 throw std::logic_error(_("NULL queue pointer in a registered socket read."));
1122 ddout("Socket::Receive: Endpoint "
1123 << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp)
1124 << "\nReceived:\n" << receive);
1126 else {
1127 m_zero->RawReceive(receive, timeout);
1132 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
1134 if( !m_zero->m_queue )
1135 throw std::logic_error(_("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()"));
1137 if( m_registered ) {
1138 throw std::logic_error(string_vprintf(_("Socket (%u) already registered in Socket::RegisterInterest()!"), (unsigned int)m_socket));
1141 m_zero->m_queue->RegisterInterest(m_socket, handler);
1142 m_registered = true;
1145 void Socket::Opening(Barry::SocketRoutingQueue::SocketDataHandlerPtr handler)
1147 // if we are running with a routing queue, register the
1148 // socket's interest in its own data packets. By default, this
1149 // data will be queued without a callback handler.
1150 // If other application code needs to intercept this with
1151 // its own handler, it must call UnregisterInterest() and
1152 // re-register its own handler
1154 // As opening requires sequence packets to still come in on
1155 // the default queue, only register for data until the socket
1156 // is opened.
1157 if( m_zero->m_queue ) {
1158 m_zero->m_queue->RegisterInterestAndType(m_socket,
1159 handler, SocketRoutingQueue::DataPackets);
1160 m_registered = true;
1164 void Socket::Opened()
1166 if( m_zero->m_queue ) {
1167 if( !m_registered ) {
1168 std::ostringstream oss;
1169 oss << "Socket (" << m_socket << ") not previously registered in Socket::Opened()!";
1170 throw std::logic_error(oss.str());
1172 // Need to complete registration and register for
1173 // sequence packets in addition to data packets.
1174 m_zero->m_queue->ChangeInterest(m_socket,
1175 SocketRoutingQueue::SequenceAndDataPackets);
1180 } // namespace Barry