lib: Adding DEBUG_ONLY macro for parameters only used in debug builds.
[barry.git] / src / socket.cc
blob5955962e9305141b447ba0ca13750c7ffd53c91f
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 "socket.h"
23 #include "usbwrap.h"
24 #include "data.h"
25 #include "protocol.h"
26 #include "protostructs.h"
27 #include "endian.h"
28 #include "debug.h"
29 #include "packet.h"
30 #include "sha1.h"
31 #include <sstream>
32 #include <string.h>
34 using namespace Usb;
37 namespace Barry {
40 //////////////////////////////////////////////////////////////////////////////
41 // SocketZero class
43 SocketZero::SocketZero( SocketRoutingQueue &queue,
44 int writeEndpoint,
45 uint8_t zeroSocketSequenceStart)
46 : m_dev(0)
47 , m_queue(&queue)
48 , m_writeEp(writeEndpoint)
49 , m_readEp(0)
50 , m_zeroSocketSequence(zeroSocketSequenceStart)
51 , m_sequenceId(0)
52 , m_halfOpen(false)
53 , m_challengeSeed(0)
54 , m_remainingTries(0)
55 , m_modeSequencePacketSeen(false)
56 , m_pushback(false)
60 SocketZero::SocketZero( Device &dev,
61 int writeEndpoint, int readEndpoint,
62 uint8_t zeroSocketSequenceStart)
63 : m_dev(&dev)
64 , m_queue(0)
65 , m_writeEp(writeEndpoint)
66 , m_readEp(readEndpoint)
67 , m_zeroSocketSequence(zeroSocketSequenceStart)
68 , m_sequenceId(0)
69 , m_halfOpen(false)
70 , m_challengeSeed(0)
71 , m_remainingTries(0)
72 , m_modeSequencePacketSeen(false)
73 , m_pushback(false)
77 SocketZero::~SocketZero()
79 // nothing to close for socket zero
83 ///////////////////////////////////////
84 // Socket Zero static calls
86 // appends fragment to whole... if whole is empty, simply copies, and
87 // sets command to DATA instead of FRAGMENTED. Always updates the
88 // packet size of whole, to reflect the total size
89 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
91 if( whole.GetSize() == 0 ) {
92 // empty, so just copy
93 whole = fragment;
95 else {
96 // has some data already, so just append
97 int size = whole.GetSize();
98 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
99 MAKE_PACKET(fpack, fragment);
100 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
102 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
103 whole.ReleaseBuffer(size + fragsize);
106 // update whole's size and command type for future sanity
107 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
108 wpack->size = htobs((uint16_t) whole.GetSize());
109 wpack->command = SB_COMMAND_DB_DATA;
110 // don't need to call ReleaseBuffer here, since we're not changing
111 // the real data size, and ReleaseBuffer was called above during copy
114 // If offset is 0, starts fresh, taking the first fragment packet size chunk
115 // out of whole and creating a sendable packet in fragment. Returns the
116 // next offset if there is still more data, or 0 if finished.
117 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
119 // sanity check
120 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
121 eout("Whole packet too short to fragment: " << whole.GetSize());
122 throw Error("Socket: Whole packet too short to fragment");
125 // calculate size
126 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
127 unsigned int nextOffset = 0;
128 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
129 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
130 nextOffset = offset + todo;
133 // create fragment header
134 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
135 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
137 // copy over a fragment size of data
138 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
140 // update fragment's size and command type
141 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
142 wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
143 if( nextOffset )
144 wpack->command = SB_COMMAND_DB_FRAGMENTED;
145 else
146 wpack->command = SB_COMMAND_DB_DATA;
148 // adjust the new fragment size
149 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
151 // return next round
152 return nextOffset;
156 ///////////////////////////////////////
157 // SocketZero private API
160 // FIXME - not sure yet whether sequence ID's are per socket or not... if
161 // they are per socket, then this global sequence behaviour will not work,
162 // and we need to track m_sequenceId on a Socket level.
164 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
166 MAKE_PACKET(spack, seq);
167 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
168 eout("Short sequence packet:\n" << seq);
169 throw Error("Socket: invalid sequence packet");
172 // we'll cheat here... if the packet's sequence is 0, we'll
173 // silently restart, otherwise, fail
174 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
175 if( sequenceId == 0 ) {
176 // silently restart (will advance below)
177 m_sequenceId = 0;
179 else {
180 if( sequenceId != m_sequenceId ) {
181 if( socket != 0 ) {
182 std::ostringstream oss;
183 oss << "Socket 0x" << std::hex << (unsigned int)socket
184 << ": out of sequence. "
185 << "(Global sequence: " << m_sequenceId
186 << ". Packet sequence: " << sequenceId
187 << ")";
188 eout(oss.str());
189 throw Error(oss.str());
191 else {
192 dout("Bad sequence on socket 0: expected: "
193 << m_sequenceId
194 << ". Packet sequence: " << sequenceId);
199 // advance!
200 m_sequenceId++;
203 void SocketZero::SendOpen(uint16_t socket, Data &receive)
205 // build open command
206 Barry::Protocol::Packet packet;
207 packet.socket = 0;
208 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
209 packet.command = SB_COMMAND_OPEN_SOCKET;
210 packet.u.socket.socket = htobs(socket);
211 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
213 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
214 try {
215 RawSend(send);
216 RawReceive(receive);
217 if( Protocol::IsSequencePacket(receive) ) {
218 m_modeSequencePacketSeen = true;
219 // during open, we could get a sequence packet in
220 // the middle, from the SelectMode operation
221 RawReceive(receive);
223 } catch( Usb::Error & ) {
224 eeout(send, receive);
225 throw;
228 // receive now holds the Open response
231 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
232 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
234 unsigned char pwdigest[SHA_DIGEST_LENGTH];
235 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
237 // first, hash the password by itself
238 SHA1((unsigned char *) password, strlen(password), pwdigest);
240 // prefix the resulting hash with the provided seed
241 uint32_t seed = htobl(m_challengeSeed);
242 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
243 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
245 // hash again
246 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
249 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
251 // build open command
252 Barry::Protocol::Packet packet;
253 packet.socket = 0;
254 packet.size = htobs(size);
255 packet.command = SB_COMMAND_PASSWORD;
256 packet.u.socket.socket = htobs(socket);
257 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
258 packet.u.socket.u.password.remaining_tries = 0;
259 packet.u.socket.u.password.unknown = 0;
260 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
261 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
262 sizeof(packet.u.socket.u.password.u.hash));
264 // blank password hashes as we don't need these anymore
265 memset(pwdigest, 0, sizeof(pwdigest));
266 memset(prefixedhash, 0, sizeof(prefixedhash));
268 Data send(&packet, size);
269 RawSend(send);
270 RawReceive(receive);
272 // blank password hash as we don't need this anymore either
273 memset(packet.u.socket.u.password.u.hash, 0,
274 sizeof(packet.u.socket.u.password.u.hash));
275 send.Zap();
277 // check sequence ID
278 if( Protocol::IsSequencePacket(receive) ) {
279 m_modeSequencePacketSeen = true;
281 CheckSequence(0, receive);
283 // still need our ACK
284 RawReceive(receive);
287 // receive now holds the Password response
290 void SocketZero::RawSend(Data &send, int timeout)
292 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
293 if( !dev )
294 throw Error("SocketZero: No device available for RawSend");
296 // Special case: it seems that sending packets with a size that's an
297 // exact multiple of 0x40 causes the device to get confused.
299 // To get around that, it is observed in the captures that the size
300 // is sent in a special 3 byte packet before the real packet.
301 // Check for this case here.
303 if( (send.GetSize() % 0x40) == 0 ) {
304 Protocol::SizePacket packet;
305 packet.size = htobs(send.GetSize());
306 packet.buffer[2] = 0; // zero the top byte
307 Data sizeCommand(&packet, 3);
309 dev->BulkWrite(m_writeEp, sizeCommand, timeout);
312 dev->BulkWrite(m_writeEp, send, timeout);
315 void SocketZero::RawReceive(Data &receive, int timeout)
317 if( m_pushback ) {
318 receive = m_pushback_buffer;
319 m_pushback = false;
320 return;
323 if( m_queue ) {
324 if( !m_queue->DefaultRead(receive, timeout) )
325 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
327 else {
328 m_dev->BulkRead(m_readEp, receive, timeout);
331 ddout("SocketZero::RawReceive: Endpoint "
332 << (m_queue ? m_queue->GetReadEp() : m_readEp)
333 << "\nReceived:\n" << receive);
336 void SocketZero::Pushback(const Data &buf)
338 if( m_pushback )
339 throw Error("Multiple pushbacks");
341 m_pushback = true;
342 m_pushback_buffer = buf;
346 ///////////////////////////////////////
347 // SocketZero public API
349 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
351 // replace the current queue pointer
352 m_queue = &queue;
355 void SocketZero::UnlinkRoutingQueue()
357 m_queue = 0;
360 void SocketZero::Send(Data &send, int timeout)
362 // force the socket number to 0
363 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
364 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
365 spack->socket = 0;
368 // This is a socket 0 packet, so force the send packet data's
369 // socket 0 sequence number to something correct.
370 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
371 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
372 spack->u.socket.sequence = m_zeroSocketSequence;
373 m_zeroSocketSequence++;
376 RawSend(send, timeout);
379 void SocketZero::Send(Data &send, Data &receive, int timeout)
381 Send(send, timeout);
382 RawReceive(receive, timeout);
385 void SocketZero::Send(Barry::Packet &packet, int timeout)
387 Send(packet.m_send, *packet.m_receive, timeout);
390 void SocketZero::Receive(Data &receive, int timeout)
392 RawReceive(receive, timeout);
397 // Open
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
403 /// on this.
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
410 /// as confirmation
412 /// \exception Barry::Error
413 /// Thrown on protocol error.
415 /// \exception Barry::BadPassword
416 /// Thrown on invalid password, or not enough retries left
417 /// on device.
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
426 Data send, receive;
427 ZeroPacket packet(send, receive);
429 // save sequence for later close
430 uint8_t closeFlag = GetZeroSocketSequence();
432 if( !m_halfOpen ) {
433 // starting fresh
434 m_remainingTries = 0;
436 // this gets set to true if we see a starting sequence packet
437 // during any of our open and password commands... After
438 // a mode command (like "RIM Desktop", etc.) a starting
439 // sequence packet is sent, and may arrive before or after
440 // the socket open handshake.
441 m_modeSequencePacketSeen = false;
443 // go for it!
444 SendOpen(socket, receive);
446 // check for password challenge, or success
447 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
448 m_halfOpen = true;
449 m_challengeSeed = packet.ChallengeSeed();
450 m_remainingTries = packet.RemainingTries();
453 // fall through to challenge code...
456 if( m_halfOpen ) {
457 // half open, device is expecting a password hash... do we
458 // have a password?
459 if( !password ) {
460 throw BadPassword("No password specified.", m_remainingTries, false);
463 // only allow password attempts if there are
464 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
465 // we want to give the user at least some chance on a
466 // Windows machine before the device commits suicide.
467 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
468 throw BadPassword("Fewer than " BARRY_MIN_PASSWORD_TRIES_ASC " password tries remaining in device. Refusing to proceed, to avoid device zapping itself. Use a Windows client, or re-cradle the device.",
469 m_remainingTries,
470 true);
473 // save sequence for later close (again after SendOpen())
474 closeFlag = GetZeroSocketSequence();
476 SendPasswordHash(socket, password, receive);
478 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
479 m_halfOpen = true;
480 m_challengeSeed = packet.ChallengeSeed();
481 m_remainingTries = packet.RemainingTries();
482 throw BadPassword("Password rejected by device.", m_remainingTries, false);
485 // if we get this far, we are no longer in half-open password
486 // mode, so we can reset our flags
487 m_halfOpen = false;
489 // fall through to success check...
492 // If the device thinks that the socket was already open then
493 // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
495 // This happens most commonly when using raw channels which
496 // haven't been cleanly closed (such as by killing the process
497 // running Barry) and so the device still thinks the socket
498 // is open.
500 // Retrying the open will usually succeed, but relies on the
501 // device software re-creating the channel after it's closed
502 // so return an error here instead of automatically retrying.
503 if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
505 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)");
508 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
509 packet.SocketResponse() != socket ||
510 packet.SocketSequence() != closeFlag )
512 eout("Packet:\n" << receive);
513 throw Error("Socket: Bad OPENED packet in Open");
516 // if no sequence packet has yet arrived, wait for it here
517 if( !m_modeSequencePacketSeen ) {
518 Data sequence;
519 RawReceive(sequence);
520 if( !Protocol::IsSequencePacket(sequence) ) {
521 // if this is not the sequence packet, then it might
522 // just be out of order (some devices do this when
523 // opening the JavaLoader mode), so as a last
524 // ditch effort, do one more read with a short
525 // timeout, and check that as well
526 Data late_sequence;
527 RawReceive(late_sequence, 500);
528 if( !Protocol::IsSequencePacket(late_sequence) ) {
529 throw Error("Could not find mode's starting sequence packet");
532 // ok, so our ditch effort worked, but now we have
533 // a leftover packet on our hands... do a temporary
534 // pushback
535 Pushback(sequence);
539 // success! save the socket
540 Socket *sock = new Socket(*this, socket, closeFlag);
541 SocketHandle sh(sock);
543 // if we are running with a routing queue, register the
544 // socket's interest in all its own data. By default, this
545 // data will be queued without a callback handler.
546 // If other application code needs to intercept this with
547 // its own handler, it must call UnregisterInterest() and
548 // re-register its own handler.
549 if( m_queue ) {
550 sock->RegisterInterest();
553 return sh;
557 // Close
559 /// Closes a non-default socket (i.e. non-zero socket number)
561 /// The packet sequence is just like Open(), except the command is
562 /// CLOSE_SOCKET.
564 /// \exception Barry::Error
566 void SocketZero::Close(Socket &socket)
568 if( socket.GetSocket() == 0 )
569 return; // nothing to do
571 // build close command
572 Barry::Protocol::Packet packet;
573 packet.socket = 0;
574 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
575 packet.command = SB_COMMAND_CLOSE_SOCKET;
576 packet.u.socket.socket = htobs(socket.GetSocket());
577 packet.u.socket.sequence = socket.GetCloseFlag();
579 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
580 Data response;
581 try {
582 Send(command, response);
584 catch( Usb::Error & ) {
585 // reset so this won't be called again
586 socket.ForceClosed();
588 eeout(command, response);
589 throw;
592 // starting fresh, reset sequence ID
593 if( Protocol::IsSequencePacket(response) ) {
594 CheckSequence(0, response);
596 // still need our ACK
597 RawReceive(response);
600 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
601 MAKE_PACKET(rpack, response);
602 // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
603 // has closed the socket in response to our request.
605 // It's also possible for the reply to be
606 // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
607 // close the socket at the same time, such as if the channel
608 // API is being used by the device.
609 if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
610 rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
611 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
612 rpack->u.socket.sequence != socket.GetCloseFlag() )
614 // reset so this won't be called again
615 socket.ForceClosed();
617 eout("Packet:\n" << response);
618 throw BadPacket(rpack->command, "Socket: Bad CLOSED packet in Close");
621 if( socket.IsResetOnClose() ) {
622 Data send, receive;
623 ZeroPacket reset_packet(send, receive);
624 reset_packet.Reset();
626 Send(reset_packet);
627 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
628 throw BadPacket(reset_packet.CommandResponse(),
629 "Socket: Missing RESET_REPLY in Close");
633 // // and finally, there always seems to be an extra read of
634 // // an empty packet at the end... just throw it away
635 // try {
636 // RawReceive(response, 1);
637 // }
638 // catch( Usb::Timeout & ) {
639 // }
641 // reset socket and flag
642 socket.ForceClosed();
649 //////////////////////////////////////////////////////////////////////////////
650 // SocketBase class
652 SocketBase::~SocketBase()
656 void SocketBase::CheckSequence(const Data &seq)
658 // FIXME - needs implementation
662 // DBFragSend
664 /// Sends a fragmented Desktop / Database command packet.
665 /// Assumes that 'send' contains a valid packet, which may or may not
666 /// need fragmentation. If it does, fragmentation will be done
667 /// automatically.
669 void SocketBase::DBFragSend(Data &send, int timeout)
671 MAKE_PACKET(spack, send);
672 if( send.GetSize() < MIN_PACKET_SIZE ||
673 (spack->command != SB_COMMAND_DB_DATA &&
674 spack->command != SB_COMMAND_DB_DONE) )
676 // we don't do that around here
677 eout("unknown send data in DBFragSend(): " << send);
678 throw std::logic_error("Socket: unknown send data in DBFragSend()");
681 if( send.GetSize() <= MAX_PACKET_SIZE ) {
682 // send non-fragmented
683 SyncSend(send, timeout);
685 else {
686 // send fragmented
687 unsigned int offset = 0;
688 Data outFrag;
690 do {
691 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
692 SyncSend(outFrag, timeout);
693 } while( offset > 0 );
699 // Send
701 /// SyncSends 'send' data to device, and waits for response.
703 /// \returns void
705 /// \exception Usb::Error on underlying bus errors.
707 void SocketBase::Send(Data &send, Data &receive, int timeout)
709 SyncSend(send, timeout);
710 Receive(receive, timeout);
713 void SocketBase::Send(Barry::Packet &packet, int timeout)
715 Send(packet.m_send, *packet.m_receive, timeout);
718 // sends the send packet down to the device, fragmenting if
719 // necessary, and returns the response in receive, defragmenting
720 // if needed
721 // Blocks until response received or timed out in Usb::Device
723 // This is primarily for Desktop Database packets... Javaloader
724 // packets use PacketData().
726 void SocketBase::Packet(Data &send, Data &receive, int timeout)
728 // assume the common case of no fragmentation,
729 // and use the receive buffer for input... allocate a frag buffer
730 // later if necessary
731 Data *inputBuf = &receive;
732 receive.Zap();
734 DBFragSend(send, timeout);
735 Receive(*inputBuf, timeout);
737 std::auto_ptr<Data> inFrag;
738 bool done = false, frag = false;
739 int blankCount = 0;
740 while( !done ) {
741 MAKE_PACKET(rpack, *inputBuf);
743 // check the packet's validity
744 if( inputBuf->GetSize() > 0 ) {
745 blankCount = 0;
747 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
749 switch( rpack->command )
751 case SB_COMMAND_SEQUENCE_HANDSHAKE:
752 CheckSequence(*inputBuf);
753 break;
755 case SB_COMMAND_DB_DATA:
756 if( frag ) {
757 SocketZero::AppendFragment(receive, *inputBuf);
759 else {
760 // no copy needed, already in receive,
761 // since inputBuf starts out that way
763 done = true;
764 break;
766 case SB_COMMAND_DB_FRAGMENTED:
767 // only copy if frag is true, since the
768 // first time through, receive == inputBuf
769 if( frag ) {
770 SocketZero::AppendFragment(receive, *inputBuf);
772 frag = true;
773 break;
775 case SB_COMMAND_DB_DONE:
776 // no copy needed, already in receive
777 done = true;
778 break;
780 default: {
781 std::ostringstream oss;
782 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
783 eout(oss.str());
784 throw Error(oss.str());
786 break;
789 else {
790 blankCount++;
791 //std::cerr << "Blank! " << blankCount << std::endl;
792 if( blankCount == 10 ) {
793 // only ask for more data on stalled sockets
794 // for so long
795 throw Error("Socket: 10 blank packets received");
799 if( !done ) {
800 // not done yet, ask for another read, and
801 // create new buffer for fragmented reads
802 if( frag && !inFrag.get() ) {
803 inFrag.reset( new Data );
804 inputBuf = inFrag.get();
806 Receive(*inputBuf);
811 void SocketBase::Packet(Barry::Packet &packet, int timeout)
813 Packet(packet.m_send, *packet.m_receive, timeout);
816 void SocketBase::Packet(Barry::JLPacket &packet, int timeout)
818 if( packet.HasData() ) {
819 SyncSend(packet.m_cmd);
820 PacketData(packet.m_data, *packet.m_receive, false, timeout);
822 else {
823 PacketData(packet.m_cmd, *packet.m_receive, false, timeout);
827 void SocketBase::Packet(Barry::JVMPacket &packet, int timeout)
829 PacketJVM(packet.m_cmd, *packet.m_receive, timeout);
832 // sends the send packet down to the device
833 // Blocks until response received or timed out in Usb::Device
835 // This function is used to send packet to JVM
836 void SocketBase::PacketJVM(Data &send, Data &receive, int timeout)
838 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
839 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
840 // we don't do that around here
841 throw std::logic_error("Socket: unknown send data in PacketJVM()");
844 Data &inFrag = receive;
845 receive.Zap();
847 // send non-fragmented
848 RawSend(send, timeout);
849 Receive(inFrag, timeout);
851 bool done = false;
852 int blankCount = 0;
854 while( !done ) {
855 // check the packet's validity
856 if( inFrag.GetSize() > 6 ) {
857 MAKE_PACKET(rpack, inFrag);
859 blankCount = 0;
861 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
863 switch( rpack->command )
865 case SB_COMMAND_SEQUENCE_HANDSHAKE:
866 CheckSequence(inFrag);
867 break;
869 default: {
870 std::ostringstream oss;
871 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
872 eout(oss.str());
873 throw Error(oss.str());
875 break;
878 else if( inFrag.GetSize() == 6 ) {
879 done = true;
881 else {
882 blankCount++;
884 //std::cerr << "Blank! " << blankCount << std::endl;
885 if( blankCount == 10 ) {
886 // only ask for more data on stalled sockets
887 // for so long
888 throw Error("Socket: 10 blank packets received");
892 if( !done ) {
893 // not done yet, ask for another read
894 Receive(inFrag, timeout);
899 // sends the send packet down to the device
900 // Blocks until response received or timed out in Usb::Device
901 void SocketBase::PacketData(Data &send,
902 Data &receive,
903 bool done_on_sequence,
904 int timeout)
906 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
907 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
908 // we don't do that around here
909 throw std::logic_error("Socket: unknown send data in PacketData()");
912 Data &inFrag = receive;
913 receive.Zap();
915 // send non-fragmented
916 SyncSend(send, timeout);
917 Receive(inFrag, timeout);
919 bool done = false;
920 int blankCount = 0;
922 while( !done ) {
923 // check the packet's validity
924 if( inFrag.GetSize() > 0 ) {
925 MAKE_PACKET(rpack, inFrag);
927 blankCount = 0;
929 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
931 switch( rpack->command )
933 case SB_COMMAND_SEQUENCE_HANDSHAKE:
934 // CheckSequence(inFrag);
935 if( done_on_sequence )
936 done = true;
937 break;
939 case SB_COMMAND_JL_READY:
940 case SB_COMMAND_JL_ACK:
941 case SB_COMMAND_JL_HELLO_ACK:
942 case SB_COMMAND_JL_RESET_REQUIRED:
943 done = true;
944 break;
946 case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream
947 done = true;
948 break;
950 case SB_DATA_JL_INVALID:
951 throw BadPacket(rpack->command, "file is not a valid Java code file");
952 break;
954 case SB_COMMAND_JL_NOT_SUPPORTED:
955 throw BadPacket(rpack->command, "device does not support requested command");
956 break;
958 default:
959 // unknown packet, pass it up to the
960 // next higher code layer
961 done = true;
962 break;
965 else {
966 blankCount++;
967 //std::cerr << "Blank! " << blankCount << std::endl;
968 if( blankCount == 10 ) {
969 // only ask for more data on stalled sockets
970 // for so long
971 throw Error("Socket: 10 blank packets received");
975 if( !done ) {
976 // not done yet, ask for another read
977 Receive(inFrag);
982 void SocketBase::NextRecord(Data &receive)
984 Barry::Protocol::Packet packet;
985 packet.size = htobs(7);
986 packet.command = SB_COMMAND_DB_DONE;
987 packet.u.db.tableCmd = 0;
988 packet.u.db.u.command.operation = 0;
990 Data command(&packet, 7);
991 Packet(command, receive);
996 //////////////////////////////////////////////////////////////////////////////
997 // Socket class
999 Socket::Socket( SocketZero &zero,
1000 uint16_t socket,
1001 uint8_t closeFlag)
1002 : m_zero(&zero)
1003 , m_socket(socket)
1004 , m_closeFlag(closeFlag)
1005 , m_registered(false)
1006 , m_sequence(new Data)
1010 Socket::~Socket()
1012 // trap exceptions in the destructor
1013 try {
1014 // a non-default socket has been opened, close it
1015 LocalClose();
1017 catch( std::runtime_error &DEBUG_ONLY(re) ) {
1018 // do nothing... log it?
1019 dout("Exception caught in ~Socket: " << re.what());
1024 ////////////////////////////////////
1025 // Socket protected API
1027 void Socket::ForceClosed()
1029 m_socket = 0;
1030 m_closeFlag = 0;
1033 void Socket::LocalClose()
1035 LocalUnregisterInterest();
1036 m_zero->Close(*this);
1039 void Socket::LocalUnregisterInterest()
1041 if( m_registered ) {
1042 if( m_zero->m_queue )
1043 m_zero->m_queue->UnregisterInterest(m_socket);
1044 m_registered = false;
1050 // Send
1052 /// Sends 'send' data to device, no receive.
1054 /// \returns void
1056 /// \exception Usb::Error on underlying bus errors.
1058 void Socket::RawSend(Data &send, int timeout)
1060 // force the socket number to this socket
1061 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
1062 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
1063 spack->socket = htobs(m_socket);
1065 m_zero->RawSend(send, timeout);
1068 void Socket::SyncSend(Data &send, int timeout)
1070 RawSend(send, timeout);
1071 Receive(*m_sequence, timeout);
1072 if( !Protocol::IsSequencePacket(*m_sequence) )
1073 throw Barry::Error("Non-sequence packet in Socket::SyncSend()");
1074 CheckSequence(*m_sequence);
1077 void Socket::Receive(Data &receive, int timeout)
1079 if( m_registered ) {
1080 if( m_zero->m_queue ) {
1081 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
1082 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
1084 else {
1085 throw std::logic_error("NULL queue pointer in a registered socket read.");
1087 ddout("Socket::Receive: Endpoint "
1088 << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp)
1089 << "\nReceived:\n" << receive);
1091 else {
1092 m_zero->RawReceive(receive, timeout);
1097 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
1099 if( !m_zero->m_queue )
1100 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
1102 if( m_registered ) {
1103 std::ostringstream oss;
1104 oss << "Socket (" << m_socket << ") already registered in Socket::RegisterInterest()!";
1105 throw std::logic_error(oss.str());
1108 m_zero->m_queue->RegisterInterest(m_socket, handler);
1109 m_registered = true;
1113 } // namespace Barry