debian: added Replaces/Breaks to barrybackup-gui
[barry.git] / src / socket.cc
blob546f7b7b10cce3f14809bc6586f0c66588e9a088
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2012, 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 // Things get a little funky here, as we may be left in an
421 // intermediate state in the case of a failed password.
422 // This function should support being called as many times
423 // as needed to handle the password
425 Data send, receive;
426 ZeroPacket packet(send, receive);
428 // save sequence for later close
429 uint8_t closeFlag = GetZeroSocketSequence();
431 if( !m_halfOpen ) {
432 // starting fresh
433 m_remainingTries = 0;
435 // this gets set to true if we see a starting sequence packet
436 // during any of our open and password commands... After
437 // a mode command (like "RIM Desktop", etc.) a starting
438 // sequence packet is sent, and may arrive before or after
439 // the socket open handshake.
440 m_modeSequencePacketSeen = false;
442 // go for it!
443 SendOpen(socket, receive);
445 // check for password challenge, or success
446 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
447 m_halfOpen = true;
448 m_challengeSeed = packet.ChallengeSeed();
449 m_remainingTries = packet.RemainingTries();
452 // fall through to challenge code...
455 if( m_halfOpen ) {
456 // half open, device is expecting a password hash... do we
457 // have a password?
458 if( !password ) {
459 throw BadPassword(_("No password specified."), m_remainingTries, false);
462 // only allow password attempts if there are
463 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
464 // we want to give the user at least some chance on a
465 // Windows machine before the device commits suicide.
466 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
467 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),
468 m_remainingTries,
469 true);
472 // save sequence for later close (again after SendOpen())
473 closeFlag = GetZeroSocketSequence();
475 SendPasswordHash(socket, password, receive);
477 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
478 m_halfOpen = true;
479 m_challengeSeed = packet.ChallengeSeed();
480 m_remainingTries = packet.RemainingTries();
481 throw BadPassword(_("Password rejected by device."), m_remainingTries, false);
484 // if we get this far, we are no longer in half-open password
485 // mode, so we can reset our flags
486 m_halfOpen = false;
488 // fall through to success check...
491 // If the device thinks that the socket was already open then
492 // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
494 // This happens most commonly when using raw channels which
495 // haven't been cleanly closed (such as by killing the process
496 // running Barry) and so the device still thinks the socket
497 // is open.
499 // Retrying the open will usually succeed, but relies on the
500 // device software re-creating the channel after it's closed
501 // so return an error here instead of automatically retrying.
502 if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
504 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)"));
507 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
508 packet.SocketResponse() != socket ||
509 packet.SocketSequence() != closeFlag )
511 eout("Packet:\n" << receive);
512 throw Error(_("Socket: Bad OPENED packet in Open"));
515 // if no sequence packet has yet arrived, wait for it here
516 if( !m_modeSequencePacketSeen ) {
517 Data sequence;
518 RawReceive(sequence);
519 if( !Protocol::IsSequencePacket(sequence) ) {
520 // if this is not the sequence packet, then it might
521 // just be out of order (some devices do this when
522 // opening the JavaLoader mode), so as a last
523 // ditch effort, do one more read with a short
524 // timeout, and check that as well
525 Data late_sequence;
526 RawReceive(late_sequence, 500);
527 if( !Protocol::IsSequencePacket(late_sequence) ) {
528 throw Error(_("Could not find mode's starting sequence packet"));
531 // ok, so our ditch effort worked, but now we have
532 // a leftover packet on our hands... do a temporary
533 // pushback
534 Pushback(sequence);
538 // success! save the socket
539 Socket *sock = new Socket(*this, socket, closeFlag);
540 SocketHandle sh(sock);
542 // if we are running with a routing queue, register the
543 // socket's interest in all its own data. By default, this
544 // data will be queued without a callback handler.
545 // If other application code needs to intercept this with
546 // its own handler, it must call UnregisterInterest() and
547 // re-register its own handler.
548 if( m_queue ) {
549 sock->RegisterInterest();
552 return sh;
556 // Close
558 /// Closes a non-default socket (i.e. non-zero socket number)
560 /// The packet sequence is just like Open(), except the command is
561 /// CLOSE_SOCKET.
563 /// \exception Barry::Error
565 void SocketZero::Close(Socket &socket)
567 if( socket.GetSocket() == 0 )
568 return; // nothing to do
570 // build close command
571 Barry::Protocol::Packet packet;
572 packet.socket = 0;
573 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
574 packet.command = SB_COMMAND_CLOSE_SOCKET;
575 packet.u.socket.socket = htobs(socket.GetSocket());
576 packet.u.socket.sequence = socket.GetCloseFlag();
578 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
579 Data response;
580 try {
581 Send(command, response);
583 catch( Usb::Error & ) {
584 // reset so this won't be called again
585 socket.ForceClosed();
587 eeout(command, response);
588 throw;
591 // starting fresh, reset sequence ID
592 if( Protocol::IsSequencePacket(response) ) {
593 CheckSequence(0, response);
595 // still need our ACK
596 RawReceive(response);
599 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
600 MAKE_PACKET(rpack, response);
601 // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
602 // has closed the socket in response to our request.
604 // It's also possible for the reply to be
605 // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
606 // close the socket at the same time, such as if the channel
607 // API is being used by the device.
608 if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
609 rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
610 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
611 rpack->u.socket.sequence != socket.GetCloseFlag() )
613 // reset so this won't be called again
614 socket.ForceClosed();
616 eout("Packet:\n" << response);
617 throw BadPacket(rpack->command, _("Socket: Bad CLOSED packet in Close"));
620 if( socket.IsResetOnClose() ) {
621 Data send, receive;
622 ZeroPacket reset_packet(send, receive);
623 reset_packet.Reset();
625 Send(reset_packet);
626 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
627 throw BadPacket(reset_packet.CommandResponse(),
628 _("Socket: Missing RESET_REPLY in Close"));
632 // // and finally, there always seems to be an extra read of
633 // // an empty packet at the end... just throw it away
634 // try {
635 // RawReceive(response, 1);
636 // }
637 // catch( Usb::Timeout & ) {
638 // }
640 // reset socket and flag
641 socket.ForceClosed();
648 //////////////////////////////////////////////////////////////////////////////
649 // SocketBase class
651 SocketBase::~SocketBase()
655 void SocketBase::CheckSequence(const Data &seq)
657 // FIXME - needs implementation
661 // DBFragSend
663 /// Sends a fragmented Desktop / Database command packet.
664 /// Assumes that 'send' contains a valid packet, which may or may not
665 /// need fragmentation. If it does, fragmentation will be done
666 /// automatically.
668 void SocketBase::DBFragSend(Data &send, int timeout)
670 MAKE_PACKET(spack, send);
671 if( send.GetSize() < MIN_PACKET_SIZE ||
672 (spack->command != SB_COMMAND_DB_DATA &&
673 spack->command != SB_COMMAND_DB_DONE) )
675 // we don't do that around here
676 eout("unknown send data in DBFragSend(): " << send);
677 throw std::logic_error(_("Socket: unknown send data in DBFragSend()"));
680 if( send.GetSize() <= MAX_PACKET_SIZE ) {
681 // send non-fragmented
682 SyncSend(send, timeout);
684 else {
685 // send fragmented
686 unsigned int offset = 0;
687 Data outFrag;
689 do {
690 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
691 SyncSend(outFrag, timeout);
692 } while( offset > 0 );
698 // Send
700 /// SyncSends 'send' data to device, and waits for response.
702 /// \returns void
704 /// \exception Usb::Error on underlying bus errors.
706 void SocketBase::Send(Data &send, Data &receive, int timeout)
708 SyncSend(send, timeout);
709 Receive(receive, timeout);
712 void SocketBase::Send(Barry::Packet &packet, int timeout)
714 Send(packet.m_send, *packet.m_receive, timeout);
717 // sends the send packet down to the device, fragmenting if
718 // necessary, and returns the response in receive, defragmenting
719 // if needed
720 // Blocks until response received or timed out in Usb::Device
722 // This is primarily for Desktop Database packets... Javaloader
723 // packets use PacketData().
725 void SocketBase::Packet(Data &send, Data &receive, int timeout)
727 // assume the common case of no fragmentation,
728 // and use the receive buffer for input... allocate a frag buffer
729 // later if necessary
730 Data *inputBuf = &receive;
731 receive.Zap();
733 DBFragSend(send, timeout);
734 Receive(*inputBuf, timeout);
736 std::auto_ptr<Data> inFrag;
737 bool done = false, frag = false;
738 int blankCount = 0;
739 while( !done ) {
740 MAKE_PACKET(rpack, *inputBuf);
742 // check the packet's validity
743 if( inputBuf->GetSize() > 0 ) {
744 blankCount = 0;
746 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
748 switch( rpack->command )
750 case SB_COMMAND_SEQUENCE_HANDSHAKE:
751 CheckSequence(*inputBuf);
752 break;
754 case SB_COMMAND_DB_DATA:
755 if( frag ) {
756 SocketZero::AppendFragment(receive, *inputBuf);
758 else {
759 // no copy needed, already in receive,
760 // since inputBuf starts out that way
762 done = true;
763 break;
765 case SB_COMMAND_DB_FRAGMENTED:
766 // only copy if frag is true, since the
767 // first time through, receive == inputBuf
768 if( frag ) {
769 SocketZero::AppendFragment(receive, *inputBuf);
771 frag = true;
772 break;
774 case SB_COMMAND_DB_DONE:
775 // no copy needed, already in receive
776 done = true;
777 break;
779 default: {
780 std::ostringstream oss;
781 oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command;
782 eout(oss.str());
783 throw Error(oss.str());
785 break;
788 else {
789 blankCount++;
790 //std::cerr << "Blank! " << blankCount << std::endl;
791 if( blankCount == 10 ) {
792 // only ask for more data on stalled sockets
793 // for so long
794 throw Error(_("Socket: 10 blank packets received"));
798 if( !done ) {
799 // not done yet, ask for another read, and
800 // create new buffer for fragmented reads
801 if( frag && !inFrag.get() ) {
802 inFrag.reset( new Data );
803 inputBuf = inFrag.get();
805 Receive(*inputBuf);
810 void SocketBase::Packet(Barry::Packet &packet, int timeout)
812 Packet(packet.m_send, *packet.m_receive, timeout);
815 void SocketBase::Packet(Barry::JLPacket &packet, int timeout)
817 if( packet.HasData() ) {
818 SyncSend(packet.m_cmd);
819 PacketData(packet.m_data, *packet.m_receive, false, timeout);
821 else {
822 PacketData(packet.m_cmd, *packet.m_receive, false, timeout);
826 void SocketBase::Packet(Barry::JVMPacket &packet, int timeout)
828 PacketJVM(packet.m_cmd, *packet.m_receive, timeout);
831 // sends the send packet down to the device
832 // Blocks until response received or timed out in Usb::Device
834 // This function is used to send packet to JVM
835 void SocketBase::PacketJVM(Data &send, Data &receive, int timeout)
837 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
838 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
839 // we don't do that around here
840 throw std::logic_error(_("Socket: unknown send data in PacketJVM()"));
843 Data &inFrag = receive;
844 receive.Zap();
846 // send non-fragmented
847 RawSend(send, timeout);
848 Receive(inFrag, timeout);
850 bool done = false;
851 int blankCount = 0;
853 while( !done ) {
854 // check the packet's validity
855 if( inFrag.GetSize() > 6 ) {
856 MAKE_PACKET(rpack, inFrag);
858 blankCount = 0;
860 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
862 switch( rpack->command )
864 case SB_COMMAND_SEQUENCE_HANDSHAKE:
865 CheckSequence(inFrag);
866 break;
868 default: {
869 std::ostringstream oss;
870 oss << _("Socket: (read) unhandled packet in Packet(): ") << "0x" << std::hex << (unsigned int)rpack->command;
871 eout(oss.str());
872 throw Error(oss.str());
874 break;
877 else if( inFrag.GetSize() == 6 ) {
878 done = true;
880 else {
881 blankCount++;
883 //std::cerr << "Blank! " << blankCount << std::endl;
884 if( blankCount == 10 ) {
885 // only ask for more data on stalled sockets
886 // for so long
887 throw Error(_("Socket: 10 blank packets received"));
891 if( !done ) {
892 // not done yet, ask for another read
893 Receive(inFrag, timeout);
898 // sends the send packet down to the device
899 // Blocks until response received or timed out in Usb::Device
900 void SocketBase::PacketData(Data &send,
901 Data &receive,
902 bool done_on_sequence,
903 int timeout)
905 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
906 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
907 // we don't do that around here
908 throw std::logic_error(_("Socket: unknown send data in PacketData()"));
911 Data &inFrag = receive;
912 receive.Zap();
914 // send non-fragmented
915 SyncSend(send, timeout);
916 Receive(inFrag, timeout);
918 bool done = false;
919 int blankCount = 0;
921 while( !done ) {
922 // check the packet's validity
923 if( inFrag.GetSize() > 0 ) {
924 MAKE_PACKET(rpack, inFrag);
926 blankCount = 0;
928 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
930 switch( rpack->command )
932 case SB_COMMAND_SEQUENCE_HANDSHAKE:
933 // CheckSequence(inFrag);
934 if( done_on_sequence )
935 done = true;
936 break;
938 case SB_COMMAND_JL_READY:
939 case SB_COMMAND_JL_ACK:
940 case SB_COMMAND_JL_HELLO_ACK:
941 case SB_COMMAND_JL_RESET_REQUIRED:
942 done = true;
943 break;
945 case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream
946 done = true;
947 break;
949 case SB_DATA_JL_INVALID:
950 throw BadPacket(rpack->command, _("file is not a valid Java code file"));
951 break;
953 case SB_COMMAND_JL_NOT_SUPPORTED:
954 throw BadPacket(rpack->command, _("device does not support requested command"));
955 break;
957 default:
958 // unknown packet, pass it up to the
959 // next higher code layer
960 done = true;
961 break;
964 else {
965 blankCount++;
966 //std::cerr << "Blank! " << blankCount << std::endl;
967 if( blankCount == 10 ) {
968 // only ask for more data on stalled sockets
969 // for so long
970 throw Error(_("Socket: 10 blank packets received"));
974 if( !done ) {
975 // not done yet, ask for another read
976 Receive(inFrag);
981 void SocketBase::NextRecord(Data &receive)
983 Barry::Protocol::Packet packet;
984 packet.size = htobs(7);
985 packet.command = SB_COMMAND_DB_DONE;
986 packet.u.db.tableCmd = 0;
987 packet.u.db.u.command.operation = 0;
989 Data command(&packet, 7);
990 Packet(command, receive);
995 //////////////////////////////////////////////////////////////////////////////
996 // Socket class
998 Socket::Socket( SocketZero &zero,
999 uint16_t socket,
1000 uint8_t closeFlag)
1001 : m_zero(&zero)
1002 , m_socket(socket)
1003 , m_closeFlag(closeFlag)
1004 , m_registered(false)
1005 , m_sequence(new Data)
1009 Socket::~Socket()
1011 // trap exceptions in the destructor
1012 try {
1013 // a non-default socket has been opened, close it
1014 LocalClose();
1016 catch( std::runtime_error &DEBUG_ONLY(re) ) {
1017 // do nothing... log it?
1018 dout("Exception caught in ~Socket: " << re.what());
1023 ////////////////////////////////////
1024 // Socket protected API
1026 void Socket::ForceClosed()
1028 m_socket = 0;
1029 m_closeFlag = 0;
1032 void Socket::LocalClose()
1034 LocalUnregisterInterest();
1035 m_zero->Close(*this);
1038 void Socket::LocalUnregisterInterest()
1040 if( m_registered ) {
1041 if( m_zero->m_queue )
1042 m_zero->m_queue->UnregisterInterest(m_socket);
1043 m_registered = false;
1049 // Send
1051 /// Sends 'send' data to device, no receive.
1053 /// \returns void
1055 /// \exception Usb::Error on underlying bus errors.
1057 void Socket::RawSend(Data &send, int timeout)
1059 // force the socket number to this socket
1060 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
1061 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
1062 spack->socket = htobs(m_socket);
1064 m_zero->RawSend(send, timeout);
1067 void Socket::SyncSend(Data &send, int timeout)
1069 RawSend(send, timeout);
1070 Receive(*m_sequence, timeout);
1071 if( !Protocol::IsSequencePacket(*m_sequence) )
1072 throw Barry::Error(_("Non-sequence packet in Socket::SyncSend()"));
1073 CheckSequence(*m_sequence);
1076 void Socket::Receive(Data &receive, int timeout)
1078 if( m_registered ) {
1079 if( m_zero->m_queue ) {
1080 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
1081 throw Timeout(_("Socket::Receive: queue SocketRead returned false (likely a timeout)"));
1083 else {
1084 throw std::logic_error(_("NULL queue pointer in a registered socket read."));
1086 ddout("Socket::Receive: Endpoint "
1087 << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp)
1088 << "\nReceived:\n" << receive);
1090 else {
1091 m_zero->RawReceive(receive, timeout);
1096 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
1098 if( !m_zero->m_queue )
1099 throw std::logic_error(_("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()"));
1101 if( m_registered ) {
1102 throw std::logic_error(string_vprintf(_("Socket (%u) already registered in Socket::RegisterInterest()!"), (unsigned int)m_socket));
1105 m_zero->m_queue->RegisterInterest(m_socket, handler);
1106 m_registered = true;
1110 } // namespace Barry