Added eout() data dump to socket::Packet() unknown send error
[barry.git] / src / socket.cc
blob1d3cf014d61a43c76b804b4d5cb0683e5f437fd7
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2009, 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_sequencePacket(true)
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_sequencePacket(true)
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 << msequenceId
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 } catch( Usb::Error & ) {
216 eeout(send, receive);
217 throw;
220 // check sequence ID
221 Protocol::CheckSize(receive);
222 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
223 CheckSequence(0, receive);
225 // still need our ACK
226 RawReceive(receive);
229 // receive now holds the Open response
232 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
233 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
235 unsigned char pwdigest[SHA_DIGEST_LENGTH];
236 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
238 // first, hash the password by itself
239 SHA1((unsigned char *) password, strlen(password), pwdigest);
241 // prefix the resulting hash with the provided seed
242 uint32_t seed = htobl(m_challengeSeed);
243 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
244 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
246 // hash again
247 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
250 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
252 // build open command
253 Barry::Protocol::Packet packet;
254 packet.socket = 0;
255 packet.size = htobs(size);
256 packet.command = SB_COMMAND_PASSWORD;
257 packet.u.socket.socket = htobs(socket);
258 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
259 packet.u.socket.u.password.remaining_tries = 0;
260 packet.u.socket.u.password.unknown = 0;
261 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
262 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
263 sizeof(packet.u.socket.u.password.u.hash));
265 // blank password hashes as we don't need these anymore
266 memset(pwdigest, 0, sizeof(pwdigest));
267 memset(prefixedhash, 0, sizeof(prefixedhash));
269 Data send(&packet, size);
270 RawSend(send);
271 RawReceive(receive);
273 // blank password hash as we don't need this anymore either
274 memset(packet.u.socket.u.password.u.hash, 0,
275 sizeof(packet.u.socket.u.password.u.hash));
276 send.Zap();
278 // check sequence ID
279 Protocol::CheckSize(receive);
280 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
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;
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);
310 dev->BulkWrite(m_writeEp, send);
313 void SocketZero::RawReceive(Data &receive, int timeout)
315 do {
316 if( m_queue ) {
317 if( !m_queue->DefaultRead(receive, timeout) )
318 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
320 else {
321 m_dev->BulkRead(m_readEp, receive, timeout);
323 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
324 << "\nReceived:\n" << receive);
325 } while( SequencePacket(receive) );
329 // SequencePacket
331 /// Returns true if this is a sequence packet that should be ignored.
332 /// This function is used in SocketZero::RawReceive() in order
333 /// to determine whether to keep reading or not. By default,
334 /// this function checks whether the packet is a sequence packet
335 /// or not, and returns true if so. Also, if it is a sequence
336 /// packet, it checks the validity of the sequence number.
338 /// If sequence packets become important in the future, this
339 /// function could be changed to call a user-defined callback,
340 /// in order to handle these things out of band.
342 bool SocketZero::SequencePacket(const Data &data)
344 // Begin -- Test quiet durty :(
345 if (m_sequencePacket == false) {
346 return false;
348 // End -- Test quiet durty :(
350 if( data.GetSize() >= MIN_PACKET_SIZE ) {
351 if( IS_COMMAND(data, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
352 CheckSequence(0, data);
353 return true;
356 return false; // not a sequence packet
360 ///////////////////////////////////////
361 // SocketZero public API
363 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
365 // replace the current queue pointer
366 m_queue = &queue;
369 void SocketZero::UnlinkRoutingQueue()
371 m_queue = 0;
374 void SocketZero::Send(Data &send, int timeout)
376 // force the socket number to 0
377 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
378 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
379 spack->socket = 0;
382 // This is a socket 0 packet, so force the send packet data's
383 // socket 0 sequence number to something correct.
384 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
385 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
386 spack->u.socket.sequence = m_zeroSocketSequence;
387 m_zeroSocketSequence++;
390 RawSend(send, timeout);
393 void SocketZero::Send(Data &send, Data &receive, int timeout)
395 Send(send, timeout);
396 RawReceive(receive, timeout);
399 void SocketZero::Send(Barry::Packet &packet, int timeout)
401 Send(packet.m_send, packet.m_receive, timeout);
406 // Open
408 /// Open a logical socket on the device.
410 /// Both the socket number and the flag are based on the response to the
411 /// SELECT_MODE command. See Controller::SelectMode() for more info
412 /// on this.
414 /// The packet sequence is normal for most socket operations.
416 /// - Down: command packet with OPEN_SOCKET
417 /// - Up: optional sequence handshake packet
418 /// - Up: command response, which repeats the socket and flag data
419 /// as confirmation
421 /// \exception Barry::Error
422 /// Thrown on protocol error.
424 /// \exception Barry::BadPassword
425 /// Thrown on invalid password, or not enough retries left
426 /// on device.
428 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
430 // Things get a little funky here, as we may be left in an
431 // intermediate state in the case of a failed password.
432 // This function should support being called as many times
433 // as needed to handle the password
435 Data send, receive;
436 ZeroPacket packet(send, receive);
438 // save sequence for later close
439 uint8_t closeFlag = GetZeroSocketSequence();
441 if( !m_halfOpen ) {
442 // starting fresh
443 m_remainingTries = 0;
445 SendOpen(socket, receive);
447 // check for password challenge, or success
448 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
449 m_halfOpen = true;
450 m_challengeSeed = packet.ChallengeSeed();
451 m_remainingTries = packet.RemainingTries();
454 // fall through to challenge code...
457 if( m_halfOpen ) {
458 // half open, device is expecting a password hash... do we
459 // have a password?
460 if( !password ) {
461 throw BadPassword("No password specified.", m_remainingTries, false);
464 // only allow password attempts if there are
465 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
466 // we want to give the user at least some chance on a
467 // Windows machine before the device commits suicide.
468 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
469 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.",
470 m_remainingTries,
471 true);
474 // save sequence for later close (again after SendOpen())
475 closeFlag = GetZeroSocketSequence();
477 SendPasswordHash(socket, password, receive);
479 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
480 m_halfOpen = true;
481 m_challengeSeed = packet.ChallengeSeed();
482 m_remainingTries = packet.RemainingTries();
483 throw BadPassword("Password rejected by device.", m_remainingTries, false);
486 // if we get this far, we are no longer in half-open password
487 // mode, so we can reset our flags
488 m_halfOpen = false;
490 // fall through to success check...
493 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
494 packet.SocketResponse() != socket ||
495 packet.SocketSequence() != closeFlag )
497 eout("Packet:\n" << receive);
498 throw Error("Socket: Bad OPENED packet in Open");
501 // success! save the socket
502 return SocketHandle(new Socket(*this, socket, closeFlag));
506 // Close
508 /// Closes a non-default socket (i.e. non-zero socket number)
510 /// The packet sequence is just like Open(), except the command is
511 /// CLOSE_SOCKET.
513 /// \exception Barry::Error
515 void SocketZero::Close(Socket &socket)
517 if( socket.GetSocket() == 0 )
518 return; // nothing to do
520 // build close command
521 Barry::Protocol::Packet packet;
522 packet.socket = 0;
523 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
524 packet.command = SB_COMMAND_CLOSE_SOCKET;
525 packet.u.socket.socket = htobs(socket.GetSocket());
526 packet.u.socket.sequence = socket.GetCloseFlag();
528 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
529 Data response;
530 try {
531 Send(command, response);
533 catch( Usb::Error & ) {
534 // reset so this won't be called again
535 socket.ForceClosed();
537 eeout(command, response);
538 throw;
541 // starting fresh, reset sequence ID
542 Protocol::CheckSize(response);
543 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
544 CheckSequence(0, response);
546 // still need our ACK
547 RawReceive(response);
550 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
551 MAKE_PACKET(rpack, response);
552 if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
553 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
554 rpack->u.socket.sequence != socket.GetCloseFlag() )
556 // reset so this won't be called again
557 socket.ForceClosed();
559 eout("Packet:\n" << response);
560 throw Error("Socket: Bad CLOSED packet in Close");
563 // // and finally, there always seems to be an extra read of
564 // // an empty packet at the end... just throw it away
565 // try {
566 // RawReceive(response, 1);
567 // }
568 // catch( Usb::Timeout & ) {
569 // }
571 // reset socket and flag
572 socket.ForceClosed();
580 //////////////////////////////////////////////////////////////////////////////
581 // Socket class
583 Socket::Socket( SocketZero &zero,
584 uint16_t socket,
585 uint8_t closeFlag)
586 : m_zero(&zero)
587 , m_socket(socket)
588 , m_closeFlag(closeFlag)
589 , m_registered(false)
593 Socket::~Socket()
595 // trap exceptions in the destructor
596 try {
597 // a non-default socket has been opened, close it
598 Close();
600 catch( std::runtime_error &re ) {
601 // do nothing... log it?
602 dout("Exception caught in ~Socket: " << re.what());
607 ////////////////////////////////////
608 // Socket protected API
610 void Socket::CheckSequence(const Data &seq)
612 m_zero->CheckSequence(m_socket, seq);
615 void Socket::ForceClosed()
617 m_socket = 0;
618 m_closeFlag = 0;
622 ////////////////////////////////////
623 // Socket public API
625 void Socket::Close()
627 UnregisterInterest();
628 m_zero->Close(*this);
633 // Send
635 /// Sends 'send' data to device, no receive.
637 /// \returns void
639 /// \exception Usb::Error on underlying bus errors.
641 void Socket::Send(Data &send, int timeout)
643 // force the socket number to this socket
644 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
645 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
646 spack->socket = htobs(m_socket);
648 m_zero->RawSend(send, timeout);
652 // Send
654 /// Sends 'send' data to device, and waits for response.
656 /// \returns void
658 /// \exception Usb::Error on underlying bus errors.
660 void Socket::Send(Data &send, Data &receive, int timeout)
662 Send(send, timeout);
663 Receive(receive, timeout);
666 void Socket::Send(Barry::Packet &packet, int timeout)
668 Send(packet.m_send, packet.m_receive, timeout);
671 void Socket::Receive(Data &receive, int timeout)
673 if( m_registered ) {
674 if( m_zero->m_queue ) {
675 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
676 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
678 else {
679 throw std::logic_error("NULL queue pointer in a registered socket read.");
682 else {
683 m_zero->RawReceive(receive, timeout);
688 // sends the send packet down to the device
689 // Blocks until response received or timed out in Usb::Device
690 // This function sends only Data (and not a command)
691 // 04 00 FC 07 DE CO FF FF 00 00 00
692 // ^^^^^............... data
693 // ^^^^^ size
694 // ^^^^^ socket
695 void Socket::PacketData(Data &send, Data &receive, int timeout)
697 if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
698 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
699 // we don't do that around here
700 throw std::logic_error("Socket: unknown send data in PacketData()");
703 Data inFrag;
704 receive.Zap();
706 // send non-fragmented
707 Send(send, inFrag, timeout);
709 bool done = false;
710 int blankCount = 0;
711 while( !done ) {
712 MAKE_PACKET(rpack, inFrag);
714 // check the packet's validity
715 if( inFrag.GetSize() > 0 ) {
716 blankCount = 0;
718 Protocol::CheckSize(inFrag);
720 switch( rpack->command )
722 case 0x1: // To wait a friendly name :)
723 case 0x64: // To wait a friendly name :)
724 case 0x65: // To wait a friendly name :)
725 done = true;
726 break;
728 default: {
729 std::ostringstream oss;
730 oss << "Socket: (b) unhandled packet in PacketData() (read): 0x" << std::hex << (unsigned int)rpack->command;
731 eout(oss.str());
732 throw Error(oss.str());
734 break;
737 else {
738 blankCount++;
739 //std::cerr << "Blank! " << blankCount << std::endl;
740 if( blankCount == 10 ) {
741 // only ask for more data on stalled sockets
742 // for so long
743 throw Error("Socket: 10 blank packets received");
747 if( !done ) {
748 // not done yet, ask for another read
749 Receive(inFrag);
754 // sends the send packet down to the device, fragmenting if
755 // necessary, and returns the response in receive, defragmenting
756 // if needed
757 // Blocks until response received or timed out in Usb::Device
758 void Socket::Packet(Data &send, Data &receive, int timeout)
761 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
762 // function that forces the socket number to the correct current value,
763 // but putting it here means a copy on every packet.
765 // force socket to our socket
766 Data send = sendorig;
767 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
768 sspack->socket = htobs(GetSocket());
771 MAKE_PACKET(spack, send);
772 // Begin -- I comment the code. Indeed, for JavaLoader we have new unknown command...
773 if( send.GetSize() < MIN_PACKET_SIZE ||
774 (spack->command != SB_COMMAND_DB_DATA &&
775 spack->command != SB_COMMAND_DB_DONE &&
776 spack->command != SB_COMMAND_JL_UNKOWN1 &&
777 spack->command != SB_COMMAND_JL_UNKOWN2 &&
778 spack->command != SB_COMMAND_JL_UNKOWN3 &&
779 spack->command != SB_COMMAND_JL_UNKOWN4 &&
780 spack->command != SB_COMMAND_JL_UNKOWN5 &&
781 spack->command != SB_COMMAND_JL_UNKOWN6 &&
782 spack->command != SB_COMMAND_JL_UNKOWN7))
784 // we don't do that around here
785 eout("unknown send data in Packet(): " << send);
786 throw std::logic_error("Socket: unknown send data in Packet()");
788 // End -- I comment the code. Indeed, for JavaLoader we have new unknown command...
790 Data inFrag;
791 receive.Zap();
793 if( send.GetSize() <= MAX_PACKET_SIZE ) {
794 // send non-fragmented
795 Send(send, inFrag, timeout);
797 else {
798 // send fragmented
799 unsigned int offset = 0;
800 Data outFrag;
802 do {
803 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
804 Send(outFrag, inFrag, timeout);
806 MAKE_PACKET(rpack, inFrag);
807 // only process sequence handshakes... once we
808 // get to the last fragment, we fall through to normal
809 // processing below
810 if( offset && inFrag.GetSize() > 0 ) {
812 Protocol::CheckSize(inFrag);
814 switch( rpack->command )
816 case 0x1: // To wait a friendly name :)
817 break;
819 case SB_COMMAND_SEQUENCE_HANDSHAKE:
820 CheckSequence(inFrag);
821 break;
823 default: {
824 std::ostringstream oss;
825 oss << "Socket: (send) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
826 eout(oss.str());
827 throw Error(oss.str());
829 break;
834 } while( offset > 0 );
837 bool done = false, frag = false;
838 int blankCount = 0;
839 while( !done ) {
840 MAKE_PACKET(rpack, inFrag);
842 // check the packet's validity
843 if( inFrag.GetSize() > 0 ) {
844 blankCount = 0;
846 Protocol::CheckSize(inFrag);
848 switch( rpack->command )
850 case SB_COMMAND_SEQUENCE_HANDSHAKE:
851 CheckSequence(inFrag);
852 if (m_zero->GetSequencePacket() == false)
853 done = true;
854 break;
856 case SB_COMMAND_DB_DATA:
857 if( frag ) {
858 SocketZero::AppendFragment(receive, inFrag);
860 else {
861 receive = inFrag;
863 done = true;
864 break;
866 case SB_COMMAND_DB_FRAGMENTED:
867 SocketZero::AppendFragment(receive, inFrag);
868 frag = true;
869 break;
871 case SB_COMMAND_DB_DONE:
872 receive = inFrag;
873 done = true;
874 break;
876 case 0x1: // To wait a friendly name :)
877 case 0x64: // To wait a friendly name :)
878 case 0x65: // To wait a friendly name :)
879 done = true;
880 break;
882 default: {
883 std::ostringstream oss;
884 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
885 eout(oss.str());
886 throw Error(oss.str());
888 break;
891 else {
892 blankCount++;
893 //std::cerr << "Blank! " << blankCount << std::endl;
894 if( blankCount == 10 ) {
895 // only ask for more data on stalled sockets
896 // for so long
897 throw Error("Socket: 10 blank packets received");
901 if( !done ) {
902 // not done yet, ask for another read
903 Receive(inFrag);
908 void Socket::Packet(Barry::Packet &packet, int timeout)
910 Packet(packet.m_send, packet.m_receive, timeout);
913 void Socket::NextRecord(Data &receive)
915 Barry::Protocol::Packet packet;
916 packet.socket = htobs(GetSocket());
917 packet.size = htobs(7);
918 packet.command = SB_COMMAND_DB_DONE;
919 packet.u.db.tableCmd = 0;
920 packet.u.db.u.command.operation = 0;
922 Data command(&packet, 7);
923 Packet(command, receive);
926 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler,
927 void *context)
929 if( !m_zero->m_queue )
930 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
932 if( m_registered )
933 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
935 m_zero->m_queue->RegisterInterest(m_socket, handler, context);
936 m_registered = true;
939 void Socket::UnregisterInterest()
941 if( m_registered ) {
942 if( m_zero->m_queue )
943 m_zero->m_queue->UnregisterInterest(m_socket);
944 m_registered = false;
949 } // namespace Barry