lib: removed needless data copy in Socket::Packet()
[barry.git] / src / socket.cc
blob6169b9e596f824f3ddcb2a61f029fa649868bd59
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2010, 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_hideSequencePacket(true),
56 m_resetOnClose(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_hideSequencePacket(true),
73 m_resetOnClose(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 } catch( Usb::Error & ) {
218 eeout(send, receive);
219 throw;
222 // check sequence ID
223 Protocol::CheckSize(receive, SB_PACKET_HEADER_SIZE);
224 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
225 CheckSequence(0, receive);
227 // still need our ACK
228 RawReceive(receive);
231 // receive now holds the Open response
234 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
235 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
237 unsigned char pwdigest[SHA_DIGEST_LENGTH];
238 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
240 // first, hash the password by itself
241 SHA1((unsigned char *) password, strlen(password), pwdigest);
243 // prefix the resulting hash with the provided seed
244 uint32_t seed = htobl(m_challengeSeed);
245 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
246 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
248 // hash again
249 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
252 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
254 // build open command
255 Barry::Protocol::Packet packet;
256 packet.socket = 0;
257 packet.size = htobs(size);
258 packet.command = SB_COMMAND_PASSWORD;
259 packet.u.socket.socket = htobs(socket);
260 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
261 packet.u.socket.u.password.remaining_tries = 0;
262 packet.u.socket.u.password.unknown = 0;
263 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
264 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
265 sizeof(packet.u.socket.u.password.u.hash));
267 // blank password hashes as we don't need these anymore
268 memset(pwdigest, 0, sizeof(pwdigest));
269 memset(prefixedhash, 0, sizeof(prefixedhash));
271 Data send(&packet, size);
272 RawSend(send);
273 RawReceive(receive);
275 // blank password hash as we don't need this anymore either
276 memset(packet.u.socket.u.password.u.hash, 0,
277 sizeof(packet.u.socket.u.password.u.hash));
278 send.Zap();
280 // check sequence ID
281 Protocol::CheckSize(receive, SB_PACKET_HEADER_SIZE);
282 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
283 CheckSequence(0, receive);
285 // still need our ACK
286 RawReceive(receive);
289 // receive now holds the Password response
292 void SocketZero::RawSend(Data &send, int timeout)
294 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
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 do {
318 if( m_queue ) {
319 if( !m_queue->DefaultRead(receive, timeout) )
320 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
322 else {
323 m_dev->BulkRead(m_readEp, receive, timeout);
325 ddout("SocketZero::RawReceive: Endpoint "
326 << (m_queue ? m_queue->GetReadEp() : m_readEp)
327 << "\nReceived:\n" << receive);
328 } while( SequencePacket(receive) );
332 // SequencePacket
334 /// Returns true if this is a sequence packet that should be ignored.
335 /// This function is used in SocketZero::RawReceive() in order
336 /// to determine whether to keep reading or not. By default,
337 /// this function checks whether the packet is a sequence packet
338 /// or not, and returns true if so. Also, if it is a sequence
339 /// packet, it checks the validity of the sequence number.
341 /// If sequence packets become important in the future, this
342 /// function could be changed to call a user-defined callback,
343 /// in order to handle these things out of band.
345 bool SocketZero::SequencePacket(const Data &data)
347 // Begin -- Test quiet durty :(
348 if (m_hideSequencePacket == false) {
349 return false;
351 // End -- Test quiet durty :(
353 if( data.GetSize() >= MIN_PACKET_SIZE ) {
354 MAKE_PACKET(rpack, data);
355 if( rpack->socket == 0 &&
356 rpack->command == SB_COMMAND_SEQUENCE_HANDSHAKE )
358 CheckSequence(0, data);
359 return true;
362 return false; // not a sequence packet
366 ///////////////////////////////////////
367 // SocketZero public API
369 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
371 // replace the current queue pointer
372 m_queue = &queue;
375 void SocketZero::UnlinkRoutingQueue()
377 m_queue = 0;
380 void SocketZero::Send(Data &send, int timeout)
382 // force the socket number to 0
383 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
384 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
385 spack->socket = 0;
388 // This is a socket 0 packet, so force the send packet data's
389 // socket 0 sequence number to something correct.
390 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
391 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
392 spack->u.socket.sequence = m_zeroSocketSequence;
393 m_zeroSocketSequence++;
396 RawSend(send, timeout);
399 void SocketZero::Send(Data &send, Data &receive, int timeout)
401 Send(send, timeout);
402 RawReceive(receive, timeout);
405 void SocketZero::Send(Barry::Packet &packet, int timeout)
407 Send(packet.m_send, packet.m_receive, timeout);
410 void SocketZero::Receive(Data &receive, int timeout)
412 RawReceive(receive, timeout);
417 // Open
419 /// Open a logical socket on the device.
421 /// Both the socket number and the flag are based on the response to the
422 /// SELECT_MODE command. See Controller::SelectMode() for more info
423 /// on this.
425 /// The packet sequence is normal for most socket operations.
427 /// - Down: command packet with OPEN_SOCKET
428 /// - Up: optional sequence handshake packet
429 /// - Up: command response, which repeats the socket and flag data
430 /// as confirmation
432 /// \exception Barry::Error
433 /// Thrown on protocol error.
435 /// \exception Barry::BadPassword
436 /// Thrown on invalid password, or not enough retries left
437 /// on device.
439 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
441 // Things get a little funky here, as we may be left in an
442 // intermediate state in the case of a failed password.
443 // This function should support being called as many times
444 // as needed to handle the password
446 Data send, receive;
447 ZeroPacket packet(send, receive);
449 // save sequence for later close
450 uint8_t closeFlag = GetZeroSocketSequence();
452 if( !m_halfOpen ) {
453 // starting fresh
454 m_remainingTries = 0;
456 SendOpen(socket, receive);
458 // check for password challenge, or success
459 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
460 m_halfOpen = true;
461 m_challengeSeed = packet.ChallengeSeed();
462 m_remainingTries = packet.RemainingTries();
465 // fall through to challenge code...
468 if( m_halfOpen ) {
469 // half open, device is expecting a password hash... do we
470 // have a password?
471 if( !password ) {
472 throw BadPassword("No password specified.", m_remainingTries, false);
475 // only allow password attempts if there are
476 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
477 // we want to give the user at least some chance on a
478 // Windows machine before the device commits suicide.
479 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
480 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.",
481 m_remainingTries,
482 true);
485 // save sequence for later close (again after SendOpen())
486 closeFlag = GetZeroSocketSequence();
488 SendPasswordHash(socket, password, receive);
490 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
491 m_halfOpen = true;
492 m_challengeSeed = packet.ChallengeSeed();
493 m_remainingTries = packet.RemainingTries();
494 throw BadPassword("Password rejected by device.", m_remainingTries, false);
497 // if we get this far, we are no longer in half-open password
498 // mode, so we can reset our flags
499 m_halfOpen = false;
501 // fall through to success check...
504 // If the device thinks that the socket was already open then
505 // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
507 // This happens most commonly when using raw channels which
508 // haven't been cleanly closed (such as by killing the process
509 // running Barry) and so the device still thinks the socket
510 // is open.
512 // Retrying the open will usually succeed, but relies on the
513 // device software re-creating the channel after it's closed
514 // so return an error here instead of automatically retrying.
515 if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
517 throw Error("Socket: Device closed socket when trying to open");
520 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
521 packet.SocketResponse() != socket ||
522 packet.SocketSequence() != closeFlag )
524 eout("Packet:\n" << receive);
525 throw Error("Socket: Bad OPENED packet in Open");
528 // success! save the socket
529 return SocketHandle(new Socket(*this, socket, closeFlag));
533 // Close
535 /// Closes a non-default socket (i.e. non-zero socket number)
537 /// The packet sequence is just like Open(), except the command is
538 /// CLOSE_SOCKET.
540 /// \exception Barry::Error
542 void SocketZero::Close(Socket &socket)
544 if( socket.GetSocket() == 0 )
545 return; // nothing to do
547 // build close command
548 Barry::Protocol::Packet packet;
549 packet.socket = 0;
550 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
551 packet.command = SB_COMMAND_CLOSE_SOCKET;
552 packet.u.socket.socket = htobs(socket.GetSocket());
553 packet.u.socket.sequence = socket.GetCloseFlag();
555 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
556 Data response;
557 try {
558 Send(command, response);
560 catch( Usb::Error & ) {
561 // reset so this won't be called again
562 socket.ForceClosed();
564 eeout(command, response);
565 throw;
568 // starting fresh, reset sequence ID
569 Protocol::CheckSize(response, SB_PACKET_HEADER_SIZE);
570 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
571 CheckSequence(0, response);
573 // still need our ACK
574 RawReceive(response);
577 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
578 MAKE_PACKET(rpack, response);
579 // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
580 // has closed the socket in response to our request.
582 // It's also possible for the reply to be
583 // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
584 // close the socket at the same time, such as if the channel
585 // API is being used by the device.
586 if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
587 rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
588 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
589 rpack->u.socket.sequence != socket.GetCloseFlag() )
591 // reset so this won't be called again
592 socket.ForceClosed();
594 eout("Packet:\n" << response);
595 throw BadPacket(rpack->command, "Socket: Bad CLOSED packet in Close");
598 if( m_resetOnClose ) {
599 Data send, receive;
600 ZeroPacket reset_packet(send, receive);
601 reset_packet.Reset();
603 Send(reset_packet);
604 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
605 throw BadPacket(reset_packet.CommandResponse(),
606 "Socket: Missing RESET_REPLY in Close");
610 // // and finally, there always seems to be an extra read of
611 // // an empty packet at the end... just throw it away
612 // try {
613 // RawReceive(response, 1);
614 // }
615 // catch( Usb::Timeout & ) {
616 // }
618 // reset socket and flag
619 socket.ForceClosed();
623 // ClearHalt
625 /// Clears the USB Halt bit on both the read and write endpoints
627 void SocketZero::ClearHalt()
629 // clear the read endpoint
630 if( m_queue ) {
631 m_dev->ClearHalt(m_queue->GetReadEp());
633 else {
634 m_dev->ClearHalt(m_readEp);
637 // clear the write endpoint
638 m_dev->ClearHalt(m_writeEp);
646 //////////////////////////////////////////////////////////////////////////////
647 // Socket class
649 Socket::Socket( SocketZero &zero,
650 uint16_t socket,
651 uint8_t closeFlag)
652 : m_zero(&zero)
653 , m_socket(socket)
654 , m_closeFlag(closeFlag)
655 , m_registered(false)
659 Socket::~Socket()
661 // trap exceptions in the destructor
662 try {
663 // a non-default socket has been opened, close it
664 Close();
666 catch( std::runtime_error &re ) {
667 // do nothing... log it?
668 dout("Exception caught in ~Socket: " << re.what());
673 ////////////////////////////////////
674 // Socket protected API
676 void Socket::CheckSequence(const Data &seq)
678 m_zero->CheckSequence(m_socket, seq);
681 void Socket::ForceClosed()
683 m_socket = 0;
684 m_closeFlag = 0;
688 ////////////////////////////////////
689 // Socket public API
691 void Socket::Close()
693 UnregisterInterest();
694 m_zero->Close(*this);
699 // Send
701 /// Sends 'send' data to device, no receive.
703 /// \returns void
705 /// \exception Usb::Error on underlying bus errors.
707 void Socket::Send(Data &send, int timeout)
709 // force the socket number to this socket
710 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
711 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
712 spack->socket = htobs(m_socket);
714 m_zero->RawSend(send, timeout);
718 // Send
720 /// Sends 'send' data to device, and waits for response.
722 /// \returns void
724 /// \exception Usb::Error on underlying bus errors.
726 void Socket::Send(Data &send, Data &receive, int timeout)
728 Send(send, timeout);
729 Receive(receive, timeout);
732 void Socket::Send(Barry::Packet &packet, int timeout)
734 Send(packet.m_send, packet.m_receive, timeout);
737 void Socket::Receive(Data &receive, int timeout)
739 if( m_registered ) {
740 if( m_zero->m_queue ) {
741 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
742 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
744 else {
745 throw std::logic_error("NULL queue pointer in a registered socket read.");
748 else {
749 m_zero->RawReceive(receive, timeout);
754 // FIXME - find a better way to do this?
755 void Socket::ReceiveData(Data &receive, int timeout)
757 HideSequencePacket(false);
758 Receive(receive);
759 HideSequencePacket(true);
762 void Socket::ClearHalt()
764 m_zero->ClearHalt();
768 // FIXME - find a better way to do this?
769 void Socket::InitSequence(int timeout)
771 Data receive;
772 receive.Zap();
774 HideSequencePacket(false);
775 Receive(receive);
776 HideSequencePacket(true);
778 Protocol::CheckSize(receive, SB_PACKET_HEADER_SIZE);
779 CheckSequence(receive);
783 // sends the send packet down to the device
784 // Blocks until response received or timed out in Usb::Device
786 // This function is used to send packet to JVM
787 void Socket::PacketJVM(Data &send, Data &receive, int timeout)
789 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
790 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
791 // we don't do that around here
792 throw std::logic_error("Socket: unknown send data in PacketJVM()");
795 Data &inFrag = receive;
796 receive.Zap();
798 // send non-fragmented
799 Send(send, inFrag, timeout);
801 bool done = false;
802 int blankCount = 0;
804 while( !done ) {
805 // check the packet's validity
806 if( inFrag.GetSize() > 6 ) {
807 MAKE_PACKET(rpack, inFrag);
809 blankCount = 0;
811 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
813 switch( rpack->command )
815 case SB_COMMAND_SEQUENCE_HANDSHAKE:
816 CheckSequence(inFrag);
817 break;
819 default: {
820 std::ostringstream oss;
821 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
822 eout(oss.str());
823 throw Error(oss.str());
825 break;
828 else if( inFrag.GetSize() == 6 ) {
829 done = true;
831 else {
832 blankCount++;
834 //std::cerr << "Blank! " << blankCount << std::endl;
835 if( blankCount == 10 ) {
836 // only ask for more data on stalled sockets
837 // for so long
838 throw Error("Socket: 10 blank packets received");
842 if( !done ) {
843 // not done yet, ask for another read
844 Receive(inFrag);
849 // sends the send packet down to the device
850 // Blocks until response received or timed out in Usb::Device
851 void Socket::PacketData(Data &send, Data &receive, int timeout)
853 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
854 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
855 // we don't do that around here
856 throw std::logic_error("Socket: unknown send data in PacketData()");
859 Data &inFrag = receive;
860 receive.Zap();
862 // send non-fragmented
863 Send(send, inFrag, timeout);
865 bool done = false;
866 int blankCount = 0;
868 while( !done ) {
869 // check the packet's validity
870 if( inFrag.GetSize() > 0 ) {
871 MAKE_PACKET(rpack, inFrag);
873 blankCount = 0;
875 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
877 switch( rpack->command )
879 case SB_COMMAND_SEQUENCE_HANDSHAKE:
880 CheckSequence(inFrag);
881 if (!m_zero->IsSequencePacketHidden())
882 done = true;
883 break;
885 case SB_COMMAND_JL_READY:
886 case SB_COMMAND_JL_ACK:
887 case SB_COMMAND_JL_HELLO_ACK:
888 case SB_COMMAND_JL_RESET_REQUIRED:
889 done = true;
890 break;
892 case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream
893 done = true;
894 break;
896 case SB_DATA_JL_INVALID:
897 throw BadPacket(rpack->command, "file is not a valid Java code file");
898 break;
900 case SB_COMMAND_JL_NOT_SUPPORTED:
901 throw BadPacket(rpack->command, "device does not support requested command");
902 break;
904 default:
905 // unknown packet, pass it up to the
906 // next higher code layer
907 done = true;
908 break;
911 else {
912 blankCount++;
913 //std::cerr << "Blank! " << blankCount << std::endl;
914 if( blankCount == 10 ) {
915 // only ask for more data on stalled sockets
916 // for so long
917 throw Error("Socket: 10 blank packets received");
921 if( !done ) {
922 // not done yet, ask for another read
923 Receive(inFrag);
928 // sends the send packet down to the device, fragmenting if
929 // necessary, and returns the response in receive, defragmenting
930 // if needed
931 // Blocks until response received or timed out in Usb::Device
933 // This is primarily for Desktop Database packets... Javaloader
934 // packets use PacketData().
936 void Socket::Packet(Data &send, Data &receive, int timeout)
938 MAKE_PACKET(spack, send);
939 if( send.GetSize() < MIN_PACKET_SIZE ||
940 (spack->command != SB_COMMAND_DB_DATA &&
941 spack->command != SB_COMMAND_DB_DONE) )
943 // we don't do that around here
944 eout("unknown send data in Packet(): " << send);
945 throw std::logic_error("Socket: unknown send data in Packet()");
948 // assume the common case of no fragmentation,
949 // and use the receive buffer for input... allocate a frag buffer
950 // later if necessary
951 Data *inputBuf = &receive;
952 receive.Zap();
954 if( send.GetSize() <= MAX_PACKET_SIZE ) {
955 // send non-fragmented
956 Send(send, *inputBuf, timeout);
958 else {
959 // send fragmented
960 unsigned int offset = 0;
961 Data outFrag;
963 // You haven't to sequence packet while the whole packet isn't sent
964 // a) No sequence received packet
965 // b) 1°) Sent framgment 1/N
966 // 2°) Sent framgment 2/N
967 // ...
968 // N°) Before sent fragment N/N, I enable the sequence packet process.
969 // Sent framgment N/N
970 HideSequencePacket(false);
972 do {
973 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
975 // Is last packet ?
976 MAKE_PACKET(spack, outFrag);
978 if (spack->command != SB_COMMAND_DB_FRAGMENTED)
979 HideSequencePacket(true);
981 Send(outFrag, *inputBuf, timeout);
983 // only process sequence handshakes... once we
984 // get to the last fragment, we fall through to normal
985 // processing below
986 if (spack->command != SB_COMMAND_DB_FRAGMENTED) {
987 MAKE_PACKET(rpack, *inputBuf);
989 if( offset && inputBuf->GetSize() > 0 ) {
990 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
992 switch( rpack->command )
994 case SB_COMMAND_SEQUENCE_HANDSHAKE:
995 CheckSequence(*inputBuf);
996 break;
998 default: {
999 std::ostringstream oss;
1000 oss << "Socket: (send) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
1001 eout(oss.str());
1002 throw Error(oss.str());
1004 break;
1009 } while( offset > 0 );
1011 // To be sure that it's clean...
1012 HideSequencePacket(true);
1015 std::auto_ptr<Data> inFrag;
1016 bool done = false, frag = false;
1017 int blankCount = 0;
1018 while( !done ) {
1019 MAKE_PACKET(rpack, *inputBuf);
1021 // check the packet's validity
1022 if( inputBuf->GetSize() > 0 ) {
1023 blankCount = 0;
1025 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
1027 switch( rpack->command )
1029 case SB_COMMAND_SEQUENCE_HANDSHAKE:
1030 CheckSequence(*inputBuf);
1031 break;
1033 case SB_COMMAND_DB_DATA:
1034 if( frag ) {
1035 SocketZero::AppendFragment(receive, *inputBuf);
1037 else {
1038 // no copy needed, already in receive,
1039 // since inputBuf starts out that way
1041 done = true;
1042 break;
1044 case SB_COMMAND_DB_FRAGMENTED:
1045 // only copy if frag is true, since the
1046 // first time through, receive == inputBuf
1047 if( frag ) {
1048 SocketZero::AppendFragment(receive, *inputBuf);
1050 frag = true;
1051 break;
1053 case SB_COMMAND_DB_DONE:
1054 // no copy needed, already in receive
1055 done = true;
1056 break;
1058 default: {
1059 std::ostringstream oss;
1060 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
1061 eout(oss.str());
1062 throw Error(oss.str());
1064 break;
1067 else {
1068 blankCount++;
1069 //std::cerr << "Blank! " << blankCount << std::endl;
1070 if( blankCount == 10 ) {
1071 // only ask for more data on stalled sockets
1072 // for so long
1073 throw Error("Socket: 10 blank packets received");
1077 if( !done ) {
1078 // not done yet, ask for another read, and
1079 // create new buffer for fragmented reads
1080 if( !inFrag.get() ) {
1081 inFrag.reset( new Data );
1082 inputBuf = inFrag.get();
1084 Receive(*inputBuf);
1089 void Socket::Packet(Barry::Packet &packet, int timeout)
1091 Packet(packet.m_send, packet.m_receive, timeout);
1094 void Socket::Packet(Barry::JLPacket &packet, int timeout)
1096 if( packet.HasData() ) {
1097 HideSequencePacket(false);
1098 PacketData(packet.m_cmd, packet.m_receive, timeout);
1099 HideSequencePacket(true);
1100 PacketData(packet.m_data, packet.m_receive, timeout);
1102 else {
1103 PacketData(packet.m_cmd, packet.m_receive, timeout);
1107 void Socket::Packet(Barry::JVMPacket &packet, int timeout)
1109 HideSequencePacket(false);
1110 PacketJVM(packet.m_cmd, packet.m_receive, timeout);
1111 HideSequencePacket(true);
1114 void Socket::NextRecord(Data &receive)
1116 Barry::Protocol::Packet packet;
1117 packet.socket = htobs(GetSocket());
1118 packet.size = htobs(7);
1119 packet.command = SB_COMMAND_DB_DONE;
1120 packet.u.db.tableCmd = 0;
1121 packet.u.db.u.command.operation = 0;
1123 Data command(&packet, 7);
1124 Packet(command, receive);
1127 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
1129 if( !m_zero->m_queue )
1130 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
1132 if( m_registered )
1133 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
1135 m_zero->m_queue->RegisterInterest(m_socket, handler);
1136 m_registered = true;
1139 void Socket::UnregisterInterest()
1141 if( m_registered ) {
1142 if( m_zero->m_queue )
1143 m_zero->m_queue->UnregisterInterest(m_socket);
1144 m_registered = false;
1149 } // namespace Barry