Minor change to buildgen.sh for personal ctags use
[barry/progweb.git] / src / socket.cc
blob11ff1848c1095ca4324954425978e50e98f562de
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2011, 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)
59 SocketZero::SocketZero( Device &dev,
60 int writeEndpoint, int readEndpoint,
61 uint8_t zeroSocketSequenceStart)
62 : m_dev(&dev)
63 , m_queue(0)
64 , m_writeEp(writeEndpoint)
65 , m_readEp(readEndpoint)
66 , m_zeroSocketSequence(zeroSocketSequenceStart)
67 , m_sequenceId(0)
68 , m_halfOpen(false)
69 , m_challengeSeed(0)
70 , m_remainingTries(0)
71 , m_modeSequencePacketSeen(false)
75 SocketZero::~SocketZero()
77 // nothing to close for socket zero
81 ///////////////////////////////////////
82 // Socket Zero static calls
84 // appends fragment to whole... if whole is empty, simply copies, and
85 // sets command to DATA instead of FRAGMENTED. Always updates the
86 // packet size of whole, to reflect the total size
87 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
89 if( whole.GetSize() == 0 ) {
90 // empty, so just copy
91 whole = fragment;
93 else {
94 // has some data already, so just append
95 int size = whole.GetSize();
96 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
97 MAKE_PACKET(fpack, fragment);
98 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
100 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
101 whole.ReleaseBuffer(size + fragsize);
104 // update whole's size and command type for future sanity
105 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
106 wpack->size = htobs((uint16_t) whole.GetSize());
107 wpack->command = SB_COMMAND_DB_DATA;
108 // don't need to call ReleaseBuffer here, since we're not changing
109 // the real data size, and ReleaseBuffer was called above during copy
112 // If offset is 0, starts fresh, taking the first fragment packet size chunk
113 // out of whole and creating a sendable packet in fragment. Returns the
114 // next offset if there is still more data, or 0 if finished.
115 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
117 // sanity check
118 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
119 eout("Whole packet too short to fragment: " << whole.GetSize());
120 throw Error("Socket: Whole packet too short to fragment");
123 // calculate size
124 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
125 unsigned int nextOffset = 0;
126 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
127 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
128 nextOffset = offset + todo;
131 // create fragment header
132 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
133 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
135 // copy over a fragment size of data
136 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
138 // update fragment's size and command type
139 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
140 wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
141 if( nextOffset )
142 wpack->command = SB_COMMAND_DB_FRAGMENTED;
143 else
144 wpack->command = SB_COMMAND_DB_DATA;
146 // adjust the new fragment size
147 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
149 // return next round
150 return nextOffset;
154 ///////////////////////////////////////
155 // SocketZero private API
158 // FIXME - not sure yet whether sequence ID's are per socket or not... if
159 // they are per socket, then this global sequence behaviour will not work,
160 // and we need to track m_sequenceId on a Socket level.
162 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
164 MAKE_PACKET(spack, seq);
165 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
166 eout("Short sequence packet:\n" << seq);
167 throw Error("Socket: invalid sequence packet");
170 // we'll cheat here... if the packet's sequence is 0, we'll
171 // silently restart, otherwise, fail
172 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
173 if( sequenceId == 0 ) {
174 // silently restart (will advance below)
175 m_sequenceId = 0;
177 else {
178 if( sequenceId != m_sequenceId ) {
179 if( socket != 0 ) {
180 std::ostringstream oss;
181 oss << "Socket 0x" << std::hex << (unsigned int)socket
182 << ": out of sequence. "
183 << "(Global sequence: " << m_sequenceId
184 << ". Packet sequence: " << sequenceId
185 << ")";
186 eout(oss.str());
187 throw Error(oss.str());
189 else {
190 dout("Bad sequence on socket 0: expected: "
191 << m_sequenceId
192 << ". Packet sequence: " << sequenceId);
197 // advance!
198 m_sequenceId++;
201 void SocketZero::SendOpen(uint16_t socket, Data &receive)
203 // build open command
204 Barry::Protocol::Packet packet;
205 packet.socket = 0;
206 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
207 packet.command = SB_COMMAND_OPEN_SOCKET;
208 packet.u.socket.socket = htobs(socket);
209 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
211 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
212 try {
213 RawSend(send);
214 RawReceive(receive);
215 if( Protocol::IsSequencePacket(receive) ) {
216 m_modeSequencePacketSeen = true;
217 // during open, we could get a sequence packet in
218 // the middle, from the SelectMode operation
219 RawReceive(receive);
221 } catch( Usb::Error & ) {
222 eeout(send, receive);
223 throw;
226 // receive now holds the Open response
229 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
230 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
232 unsigned char pwdigest[SHA_DIGEST_LENGTH];
233 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
235 // first, hash the password by itself
236 SHA1((unsigned char *) password, strlen(password), pwdigest);
238 // prefix the resulting hash with the provided seed
239 uint32_t seed = htobl(m_challengeSeed);
240 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
241 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
243 // hash again
244 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
247 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
249 // build open command
250 Barry::Protocol::Packet packet;
251 packet.socket = 0;
252 packet.size = htobs(size);
253 packet.command = SB_COMMAND_PASSWORD;
254 packet.u.socket.socket = htobs(socket);
255 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
256 packet.u.socket.u.password.remaining_tries = 0;
257 packet.u.socket.u.password.unknown = 0;
258 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
259 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
260 sizeof(packet.u.socket.u.password.u.hash));
262 // blank password hashes as we don't need these anymore
263 memset(pwdigest, 0, sizeof(pwdigest));
264 memset(prefixedhash, 0, sizeof(prefixedhash));
266 Data send(&packet, size);
267 RawSend(send);
268 RawReceive(receive);
270 // blank password hash as we don't need this anymore either
271 memset(packet.u.socket.u.password.u.hash, 0,
272 sizeof(packet.u.socket.u.password.u.hash));
273 send.Zap();
275 // check sequence ID
276 if( Protocol::IsSequencePacket(receive) ) {
277 m_modeSequencePacketSeen = true;
279 CheckSequence(0, receive);
281 // still need our ACK
282 RawReceive(receive);
285 // receive now holds the Password response
288 void SocketZero::RawSend(Data &send, int timeout)
290 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
291 if( !dev )
292 throw Error("SocketZero: No device available for RawSend");
294 // Special case: it seems that sending packets with a size that's an
295 // exact multiple of 0x40 causes the device to get confused.
297 // To get around that, it is observed in the captures that the size
298 // is sent in a special 3 byte packet before the real packet.
299 // Check for this case here.
301 if( (send.GetSize() % 0x40) == 0 ) {
302 Protocol::SizePacket packet;
303 packet.size = htobs(send.GetSize());
304 packet.buffer[2] = 0; // zero the top byte
305 Data sizeCommand(&packet, 3);
307 dev->BulkWrite(m_writeEp, sizeCommand, timeout);
310 dev->BulkWrite(m_writeEp, send, timeout);
313 void SocketZero::RawReceive(Data &receive, int timeout)
315 if( m_queue ) {
316 if( !m_queue->DefaultRead(receive, timeout) )
317 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
319 else {
320 m_dev->BulkRead(m_readEp, receive, timeout);
323 ddout("SocketZero::RawReceive: Endpoint "
324 << (m_queue ? m_queue->GetReadEp() : m_readEp)
325 << "\nReceived:\n" << receive);
329 ///////////////////////////////////////
330 // SocketZero public API
332 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
334 // replace the current queue pointer
335 m_queue = &queue;
338 void SocketZero::UnlinkRoutingQueue()
340 m_queue = 0;
343 void SocketZero::Send(Data &send, int timeout)
345 // force the socket number to 0
346 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
347 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
348 spack->socket = 0;
351 // This is a socket 0 packet, so force the send packet data's
352 // socket 0 sequence number to something correct.
353 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
354 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
355 spack->u.socket.sequence = m_zeroSocketSequence;
356 m_zeroSocketSequence++;
359 RawSend(send, timeout);
362 void SocketZero::Send(Data &send, Data &receive, int timeout)
364 Send(send, timeout);
365 RawReceive(receive, timeout);
368 void SocketZero::Send(Barry::Packet &packet, int timeout)
370 Send(packet.m_send, *packet.m_receive, timeout);
373 void SocketZero::Receive(Data &receive, int timeout)
375 RawReceive(receive, timeout);
380 // Open
382 /// Open a logical socket on the device.
384 /// Both the socket number and the flag are based on the response to the
385 /// SELECT_MODE command. See Controller::SelectMode() for more info
386 /// on this.
388 /// The packet sequence is normal for most socket operations.
390 /// - Down: command packet with OPEN_SOCKET
391 /// - Up: optional sequence handshake packet
392 /// - Up: command response, which repeats the socket and flag data
393 /// as confirmation
395 /// \exception Barry::Error
396 /// Thrown on protocol error.
398 /// \exception Barry::BadPassword
399 /// Thrown on invalid password, or not enough retries left
400 /// on device.
402 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
404 // Things get a little funky here, as we may be left in an
405 // intermediate state in the case of a failed password.
406 // This function should support being called as many times
407 // as needed to handle the password
409 Data send, receive;
410 ZeroPacket packet(send, receive);
412 // save sequence for later close
413 uint8_t closeFlag = GetZeroSocketSequence();
415 if( !m_halfOpen ) {
416 // starting fresh
417 m_remainingTries = 0;
419 // this gets set to true if we see a starting sequence packet
420 // during any of our open and password commands... After
421 // a mode command (like "RIM Desktop", etc.) a starting
422 // sequence packet is sent, and may arrive before or after
423 // the socket open handshake.
424 m_modeSequencePacketSeen = false;
426 // go for it!
427 SendOpen(socket, receive);
429 // check for password challenge, or success
430 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
431 m_halfOpen = true;
432 m_challengeSeed = packet.ChallengeSeed();
433 m_remainingTries = packet.RemainingTries();
436 // fall through to challenge code...
439 if( m_halfOpen ) {
440 // half open, device is expecting a password hash... do we
441 // have a password?
442 if( !password ) {
443 throw BadPassword("No password specified.", m_remainingTries, false);
446 // only allow password attempts if there are
447 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
448 // we want to give the user at least some chance on a
449 // Windows machine before the device commits suicide.
450 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
451 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.",
452 m_remainingTries,
453 true);
456 // save sequence for later close (again after SendOpen())
457 closeFlag = GetZeroSocketSequence();
459 SendPasswordHash(socket, password, receive);
461 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
462 m_halfOpen = true;
463 m_challengeSeed = packet.ChallengeSeed();
464 m_remainingTries = packet.RemainingTries();
465 throw BadPassword("Password rejected by device.", m_remainingTries, false);
468 // if we get this far, we are no longer in half-open password
469 // mode, so we can reset our flags
470 m_halfOpen = false;
472 // fall through to success check...
475 // If the device thinks that the socket was already open then
476 // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
478 // This happens most commonly when using raw channels which
479 // haven't been cleanly closed (such as by killing the process
480 // running Barry) and so the device still thinks the socket
481 // is open.
483 // Retrying the open will usually succeed, but relies on the
484 // device software re-creating the channel after it's closed
485 // so return an error here instead of automatically retrying.
486 if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
488 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)");
491 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
492 packet.SocketResponse() != socket ||
493 packet.SocketSequence() != closeFlag )
495 eout("Packet:\n" << receive);
496 throw Error("Socket: Bad OPENED packet in Open");
499 // if no sequence packet has yet arrived, wait for it here
500 if( !m_modeSequencePacketSeen ) {
501 Data sequence;
502 RawReceive(sequence);
503 if( !Protocol::IsSequencePacket(sequence) )
504 throw Error("Could not find mode's starting sequence packet");
507 // success! save the socket
508 Socket *sock = new Socket(*this, socket, closeFlag);
509 SocketHandle sh(sock);
511 // if we are running with a routing queue, register the
512 // socket's interest in all its own data. By default, this
513 // data will be queued without a callback handler.
514 // If other application code needs to intercept this with
515 // its own handler, it must call UnregisterInterest() and
516 // re-register its own handler.
517 if( m_queue ) {
518 sock->RegisterInterest();
521 return sh;
525 // Close
527 /// Closes a non-default socket (i.e. non-zero socket number)
529 /// The packet sequence is just like Open(), except the command is
530 /// CLOSE_SOCKET.
532 /// \exception Barry::Error
534 void SocketZero::Close(Socket &socket)
536 if( socket.GetSocket() == 0 )
537 return; // nothing to do
539 // build close command
540 Barry::Protocol::Packet packet;
541 packet.socket = 0;
542 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
543 packet.command = SB_COMMAND_CLOSE_SOCKET;
544 packet.u.socket.socket = htobs(socket.GetSocket());
545 packet.u.socket.sequence = socket.GetCloseFlag();
547 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
548 Data response;
549 try {
550 Send(command, response);
552 catch( Usb::Error & ) {
553 // reset so this won't be called again
554 socket.ForceClosed();
556 eeout(command, response);
557 throw;
560 // starting fresh, reset sequence ID
561 if( Protocol::IsSequencePacket(response) ) {
562 CheckSequence(0, response);
564 // still need our ACK
565 RawReceive(response);
568 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
569 MAKE_PACKET(rpack, response);
570 // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
571 // has closed the socket in response to our request.
573 // It's also possible for the reply to be
574 // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
575 // close the socket at the same time, such as if the channel
576 // API is being used by the device.
577 if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
578 rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
579 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
580 rpack->u.socket.sequence != socket.GetCloseFlag() )
582 // reset so this won't be called again
583 socket.ForceClosed();
585 eout("Packet:\n" << response);
586 throw BadPacket(rpack->command, "Socket: Bad CLOSED packet in Close");
589 if( socket.IsResetOnClose() ) {
590 Data send, receive;
591 ZeroPacket reset_packet(send, receive);
592 reset_packet.Reset();
594 Send(reset_packet);
595 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
596 throw BadPacket(reset_packet.CommandResponse(),
597 "Socket: Missing RESET_REPLY in Close");
601 // // and finally, there always seems to be an extra read of
602 // // an empty packet at the end... just throw it away
603 // try {
604 // RawReceive(response, 1);
605 // }
606 // catch( Usb::Timeout & ) {
607 // }
609 // reset socket and flag
610 socket.ForceClosed();
617 //////////////////////////////////////////////////////////////////////////////
618 // SocketBase class
620 SocketBase::~SocketBase()
624 void SocketBase::CheckSequence(const Data &seq)
626 // FIXME - needs implementation
630 // DBFragSend
632 /// Sends a fragmented Desktop / Database command packet.
633 /// Assumes that 'send' contains a valid packet, which may or may not
634 /// need fragmentation. If it does, fragmentation will be done
635 /// automatically.
637 void SocketBase::DBFragSend(Data &send, int timeout)
639 MAKE_PACKET(spack, send);
640 if( send.GetSize() < MIN_PACKET_SIZE ||
641 (spack->command != SB_COMMAND_DB_DATA &&
642 spack->command != SB_COMMAND_DB_DONE) )
644 // we don't do that around here
645 eout("unknown send data in DBFragSend(): " << send);
646 throw std::logic_error("Socket: unknown send data in DBFragSend()");
649 if( send.GetSize() <= MAX_PACKET_SIZE ) {
650 // send non-fragmented
651 SyncSend(send, timeout);
653 else {
654 // send fragmented
655 unsigned int offset = 0;
656 Data outFrag;
658 do {
659 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
660 SyncSend(outFrag, timeout);
661 } while( offset > 0 );
667 // Send
669 /// SyncSends 'send' data to device, and waits for response.
671 /// \returns void
673 /// \exception Usb::Error on underlying bus errors.
675 void SocketBase::Send(Data &send, Data &receive, int timeout)
677 SyncSend(send, timeout);
678 Receive(receive, timeout);
681 void SocketBase::Send(Barry::Packet &packet, int timeout)
683 Send(packet.m_send, *packet.m_receive, timeout);
686 // sends the send packet down to the device, fragmenting if
687 // necessary, and returns the response in receive, defragmenting
688 // if needed
689 // Blocks until response received or timed out in Usb::Device
691 // This is primarily for Desktop Database packets... Javaloader
692 // packets use PacketData().
694 void SocketBase::Packet(Data &send, Data &receive, int timeout)
696 // assume the common case of no fragmentation,
697 // and use the receive buffer for input... allocate a frag buffer
698 // later if necessary
699 Data *inputBuf = &receive;
700 receive.Zap();
702 DBFragSend(send, timeout);
703 Receive(*inputBuf, timeout);
705 std::auto_ptr<Data> inFrag;
706 bool done = false, frag = false;
707 int blankCount = 0;
708 while( !done ) {
709 MAKE_PACKET(rpack, *inputBuf);
711 // check the packet's validity
712 if( inputBuf->GetSize() > 0 ) {
713 blankCount = 0;
715 Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
717 switch( rpack->command )
719 case SB_COMMAND_SEQUENCE_HANDSHAKE:
720 CheckSequence(*inputBuf);
721 break;
723 case SB_COMMAND_DB_DATA:
724 if( frag ) {
725 SocketZero::AppendFragment(receive, *inputBuf);
727 else {
728 // no copy needed, already in receive,
729 // since inputBuf starts out that way
731 done = true;
732 break;
734 case SB_COMMAND_DB_FRAGMENTED:
735 // only copy if frag is true, since the
736 // first time through, receive == inputBuf
737 if( frag ) {
738 SocketZero::AppendFragment(receive, *inputBuf);
740 frag = true;
741 break;
743 case SB_COMMAND_DB_DONE:
744 // no copy needed, already in receive
745 done = true;
746 break;
748 default: {
749 std::ostringstream oss;
750 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
751 eout(oss.str());
752 throw Error(oss.str());
754 break;
757 else {
758 blankCount++;
759 //std::cerr << "Blank! " << blankCount << std::endl;
760 if( blankCount == 10 ) {
761 // only ask for more data on stalled sockets
762 // for so long
763 throw Error("Socket: 10 blank packets received");
767 if( !done ) {
768 // not done yet, ask for another read, and
769 // create new buffer for fragmented reads
770 if( frag && !inFrag.get() ) {
771 inFrag.reset( new Data );
772 inputBuf = inFrag.get();
774 Receive(*inputBuf);
779 void SocketBase::Packet(Barry::Packet &packet, int timeout)
781 Packet(packet.m_send, *packet.m_receive, timeout);
784 void SocketBase::Packet(Barry::JLPacket &packet, int timeout)
786 if( packet.HasData() ) {
787 SyncSend(packet.m_cmd);
788 PacketData(packet.m_data, *packet.m_receive, false, timeout);
790 else {
791 PacketData(packet.m_cmd, *packet.m_receive, false, timeout);
795 void SocketBase::Packet(Barry::JVMPacket &packet, int timeout)
797 PacketJVM(packet.m_cmd, *packet.m_receive, timeout);
800 // sends the send packet down to the device
801 // Blocks until response received or timed out in Usb::Device
803 // This function is used to send packet to JVM
804 void SocketBase::PacketJVM(Data &send, Data &receive, int timeout)
806 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
807 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
808 // we don't do that around here
809 throw std::logic_error("Socket: unknown send data in PacketJVM()");
812 Data &inFrag = receive;
813 receive.Zap();
815 // send non-fragmented
816 RawSend(send, timeout);
817 Receive(inFrag, timeout);
819 bool done = false;
820 int blankCount = 0;
822 while( !done ) {
823 // check the packet's validity
824 if( inFrag.GetSize() > 6 ) {
825 MAKE_PACKET(rpack, inFrag);
827 blankCount = 0;
829 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
831 switch( rpack->command )
833 case SB_COMMAND_SEQUENCE_HANDSHAKE:
834 CheckSequence(inFrag);
835 break;
837 default: {
838 std::ostringstream oss;
839 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
840 eout(oss.str());
841 throw Error(oss.str());
843 break;
846 else if( inFrag.GetSize() == 6 ) {
847 done = true;
849 else {
850 blankCount++;
852 //std::cerr << "Blank! " << blankCount << std::endl;
853 if( blankCount == 10 ) {
854 // only ask for more data on stalled sockets
855 // for so long
856 throw Error("Socket: 10 blank packets received");
860 if( !done ) {
861 // not done yet, ask for another read
862 Receive(inFrag, timeout);
867 // sends the send packet down to the device
868 // Blocks until response received or timed out in Usb::Device
869 void SocketBase::PacketData(Data &send,
870 Data &receive,
871 bool done_on_sequence,
872 int timeout)
874 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
875 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
876 // we don't do that around here
877 throw std::logic_error("Socket: unknown send data in PacketData()");
880 Data &inFrag = receive;
881 receive.Zap();
883 // send non-fragmented
884 SyncSend(send, timeout);
885 Receive(inFrag, timeout);
887 bool done = false;
888 int blankCount = 0;
890 while( !done ) {
891 // check the packet's validity
892 if( inFrag.GetSize() > 0 ) {
893 MAKE_PACKET(rpack, inFrag);
895 blankCount = 0;
897 Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
899 switch( rpack->command )
901 case SB_COMMAND_SEQUENCE_HANDSHAKE:
902 // CheckSequence(inFrag);
903 if( done_on_sequence )
904 done = true;
905 break;
907 case SB_COMMAND_JL_READY:
908 case SB_COMMAND_JL_ACK:
909 case SB_COMMAND_JL_HELLO_ACK:
910 case SB_COMMAND_JL_RESET_REQUIRED:
911 done = true;
912 break;
914 case SB_COMMAND_JL_GET_DATA_ENTRY: // This response means that the next packet is the stream
915 done = true;
916 break;
918 case SB_DATA_JL_INVALID:
919 throw BadPacket(rpack->command, "file is not a valid Java code file");
920 break;
922 case SB_COMMAND_JL_NOT_SUPPORTED:
923 throw BadPacket(rpack->command, "device does not support requested command");
924 break;
926 default:
927 // unknown packet, pass it up to the
928 // next higher code layer
929 done = true;
930 break;
933 else {
934 blankCount++;
935 //std::cerr << "Blank! " << blankCount << std::endl;
936 if( blankCount == 10 ) {
937 // only ask for more data on stalled sockets
938 // for so long
939 throw Error("Socket: 10 blank packets received");
943 if( !done ) {
944 // not done yet, ask for another read
945 Receive(inFrag);
950 void SocketBase::NextRecord(Data &receive)
952 Barry::Protocol::Packet packet;
953 packet.size = htobs(7);
954 packet.command = SB_COMMAND_DB_DONE;
955 packet.u.db.tableCmd = 0;
956 packet.u.db.u.command.operation = 0;
958 Data command(&packet, 7);
959 Packet(command, receive);
964 //////////////////////////////////////////////////////////////////////////////
965 // Socket class
967 Socket::Socket( SocketZero &zero,
968 uint16_t socket,
969 uint8_t closeFlag)
970 : m_zero(&zero)
971 , m_socket(socket)
972 , m_closeFlag(closeFlag)
973 , m_registered(false)
974 , m_sequence(new Data)
978 Socket::~Socket()
980 // trap exceptions in the destructor
981 try {
982 // a non-default socket has been opened, close it
983 LocalClose();
985 catch( std::runtime_error &re ) {
986 // do nothing... log it?
987 dout("Exception caught in ~Socket: " << re.what());
992 ////////////////////////////////////
993 // Socket protected API
995 void Socket::ForceClosed()
997 m_socket = 0;
998 m_closeFlag = 0;
1001 void Socket::LocalClose()
1003 LocalUnregisterInterest();
1004 m_zero->Close(*this);
1007 void Socket::LocalUnregisterInterest()
1009 if( m_registered ) {
1010 if( m_zero->m_queue )
1011 m_zero->m_queue->UnregisterInterest(m_socket);
1012 m_registered = false;
1018 // Send
1020 /// Sends 'send' data to device, no receive.
1022 /// \returns void
1024 /// \exception Usb::Error on underlying bus errors.
1026 void Socket::RawSend(Data &send, int timeout)
1028 // force the socket number to this socket
1029 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
1030 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
1031 spack->socket = htobs(m_socket);
1033 m_zero->RawSend(send, timeout);
1036 void Socket::SyncSend(Data &send, int timeout)
1038 RawSend(send, timeout);
1039 Receive(*m_sequence, timeout);
1040 if( !Protocol::IsSequencePacket(*m_sequence) )
1041 throw Barry::Error("Non-sequence packet in Socket::SyncSend()");
1042 CheckSequence(*m_sequence);
1045 void Socket::Receive(Data &receive, int timeout)
1047 if( m_registered ) {
1048 if( m_zero->m_queue ) {
1049 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
1050 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
1052 else {
1053 throw std::logic_error("NULL queue pointer in a registered socket read.");
1055 ddout("Socket::Receive: Endpoint "
1056 << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp)
1057 << "\nReceived:\n" << receive);
1059 else {
1060 m_zero->RawReceive(receive, timeout);
1065 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
1067 if( !m_zero->m_queue )
1068 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
1070 if( m_registered ) {
1071 std::ostringstream oss;
1072 oss << "Socket (" << m_socket << ") already registered in Socket::RegisterInterest()!";
1073 throw std::logic_error(oss.str());
1076 m_zero->m_queue->RegisterInterest(m_socket, handler);
1077 m_registered = true;
1081 } // namespace Barry