src/socket.cc: Source code reorganization
[barry/pauldeden.git] / src / socket.cc
blobff185ae3888802af925ddebdea828422858dd45a
1 ///
2 /// \file socket.cc
3 /// Class wrapper to encapsulate the Blackberry USB logical socket
4 ///
6 /*
7 Copyright (C) 2005-2008, 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 <openssl/sha.h>
31 #include <sstream>
33 using namespace Usb;
36 namespace Barry {
39 //////////////////////////////////////////////////////////////////////////////
40 // SocketZero class
42 SocketZero::SocketZero( SocketRoutingQueue &queue,
43 int writeEndpoint,
44 uint8_t zeroSocketSequenceStart)
45 : m_dev(0),
46 m_queue(&queue),
47 m_writeEp(writeEndpoint),
48 m_readEp(0),
49 m_zeroSocketSequence(zeroSocketSequenceStart),
50 m_sequenceId(0),
51 m_halfOpen(false),
52 m_challengeSeed(0),
53 m_remainingTries(0)
57 SocketZero::SocketZero( Device &dev,
58 int writeEndpoint, int readEndpoint,
59 uint8_t zeroSocketSequenceStart)
60 : m_dev(&dev),
61 m_queue(0),
62 m_writeEp(writeEndpoint),
63 m_readEp(readEndpoint),
64 m_zeroSocketSequence(zeroSocketSequenceStart),
65 m_sequenceId(0),
66 m_halfOpen(false),
67 m_challengeSeed(0),
68 m_remainingTries(0)
72 SocketZero::~SocketZero()
74 // nothing to close for socket zero
78 ///////////////////////////////////////
79 // Socket Zero static calls
81 // appends fragment to whole... if whole is empty, simply copies, and
82 // sets command to DATA instead of FRAGMENTED. Always updates the
83 // packet size of whole, to reflect the total size
84 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
86 if( whole.GetSize() == 0 ) {
87 // empty, so just copy
88 whole = fragment;
90 else {
91 // has some data already, so just append
92 int size = whole.GetSize();
93 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
94 MAKE_PACKET(fpack, fragment);
95 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
97 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
98 whole.ReleaseBuffer(size + fragsize);
101 // update whole's size and command type for future sanity
102 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
103 wpack->size = htobs((uint16_t) whole.GetSize());
104 wpack->command = SB_COMMAND_DB_DATA;
105 // don't need to call ReleaseBuffer here, since we're not changing
106 // the real data size, and ReleaseBuffer was called above during copy
109 // If offset is 0, starts fresh, taking the first fragment packet size chunk
110 // out of whole and creating a sendable packet in fragment. Returns the
111 // next offset if there is still more data, or 0 if finished.
112 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
114 // sanity check
115 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
116 eout("Whole packet too short to fragment: " << whole.GetSize());
117 throw Error("Socket: Whole packet too short to fragment");
120 // calculate size
121 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
122 unsigned int nextOffset = 0;
123 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
124 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
125 nextOffset = offset + todo;
128 // create fragment header
129 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
130 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
132 // copy over a fragment size of data
133 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
135 // update fragment's size and command type
136 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
137 wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
138 if( nextOffset )
139 wpack->command = SB_COMMAND_DB_FRAGMENTED;
140 else
141 wpack->command = SB_COMMAND_DB_DATA;
143 // adjust the new fragment size
144 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
146 // return next round
147 return nextOffset;
151 ///////////////////////////////////////
152 // SocketZero private API
155 // FIXME - not sure yet whether sequence ID's are per socket or not... if
156 // they are per socket, then this global sequence behaviour will not work,
157 // and we need to track m_sequenceId on a Socket level.
159 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
161 MAKE_PACKET(spack, seq);
162 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
163 eout("Short sequence packet:\n" << seq);
164 throw Error("Socket: invalid sequence packet");
167 // we'll cheat here... if the packet's sequence is 0, we'll
168 // silently restart, otherwise, fail
169 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
170 if( sequenceId == 0 ) {
171 // silently restart (will advance below)
172 m_sequenceId = 0;
174 else {
175 if( sequenceId != m_sequenceId ) {
176 if( socket != 0 ) {
177 std::ostringstream oss;
178 oss << "Socket 0x" << std::hex << (unsigned int)socket
179 << ": out of sequence. "
180 << "(Global sequence: " << m_sequenceId
181 << ". Packet sequence: " << sequenceId
182 << ")";
183 eout(oss.str());
184 throw Error(oss.str());
186 else {
187 dout("Bad sequence on socket 0: expected: "
188 << msequenceId
189 << ". Packet sequence: " << sequenceId);
194 // advance!
195 m_sequenceId++;
198 void SocketZero::SendOpen(uint16_t socket, Data &receive)
200 // build open command
201 Barry::Protocol::Packet packet;
202 packet.socket = 0;
203 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
204 packet.command = SB_COMMAND_OPEN_SOCKET;
205 packet.u.socket.socket = htobs(socket);
206 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
208 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
209 try {
210 RawSend(send);
211 RawReceive(receive);
212 } catch( Usb::Error & ) {
213 eeout(send, receive);
214 throw;
217 // check sequence ID
218 Protocol::CheckSize(receive);
219 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
220 CheckSequence(0, receive);
222 // still need our ACK
223 RawReceive(receive);
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 Protocol::CheckSize(receive);
277 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
278 CheckSequence(0, receive);
280 // still need our ACK
281 RawReceive(receive);
284 // receive now holds the Password response
287 void SocketZero::RawSend(Data &send, int timeout)
289 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
291 // Special case: it seems that sending packets with a size that's an
292 // exact multiple of 0x40 causes the device to get confused.
294 // To get around that, it is observed in the captures that the size
295 // is sent in a special 3 byte packet before the real packet.
296 // Check for this case here.
298 if( (send.GetSize() % 0x40) == 0 ) {
299 Protocol::SizePacket packet;
300 packet.size = htobs(send.GetSize());
301 packet.buffer[2] = 0; // zero the top byte
302 Data sizeCommand(&packet, 3);
304 dev->BulkWrite(m_writeEp, sizeCommand);
307 dev->BulkWrite(m_writeEp, send);
310 void SocketZero::RawReceive(Data &receive, int timeout)
312 do {
313 if( m_queue ) {
314 if( !m_queue->DefaultRead(receive, timeout) )
315 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
317 else {
318 m_dev->BulkRead(m_readEp, receive, timeout);
320 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
321 << "\nReceived:\n" << receive);
322 } while( SequencePacket(receive) );
326 // SequencePacket
328 /// Returns true if this is a sequence packet that should be ignored.
329 /// This function is used in SocketZero::RawReceive() in order
330 /// to determine whether to keep reading or not. By default,
331 /// this function checks whether the packet is a sequence packet
332 /// or not, and returns true if so. Also, if it is a sequence
333 /// packet, it checks the validity of the sequence number.
335 /// If sequence packets become important in the future, this
336 /// function could be changed to call a user-defined callback,
337 /// in order to handle these things out of band.
339 bool SocketZero::SequencePacket(const Data &data)
341 if( data.GetSize() >= MIN_PACKET_SIZE ) {
342 if( IS_COMMAND(data, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
343 CheckSequence(0, data);
344 return true;
347 return false; // not a sequence packet
351 ///////////////////////////////////////
352 // SocketZero public API
354 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
356 // replace the current queue pointer
357 m_queue = &queue;
360 void SocketZero::UnlinkRoutingQueue()
362 m_queue = 0;
365 void SocketZero::Send(Data &send, int timeout)
367 // force the socket number to 0
368 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
369 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
370 spack->socket = 0;
373 // This is a socket 0 packet, so force the send packet data's
374 // socket 0 sequence number to something correct.
375 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
376 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
377 spack->u.socket.sequence = m_zeroSocketSequence;
378 m_zeroSocketSequence++;
381 RawSend(send, timeout);
384 void SocketZero::Send(Data &send, Data &receive, int timeout)
386 Send(send, timeout);
387 RawReceive(receive, timeout);
390 void SocketZero::Send(Barry::Packet &packet, int timeout)
392 Send(packet.m_send, packet.m_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 SendOpen(socket, receive);
438 // check for password challenge, or success
439 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
440 m_halfOpen = true;
441 m_challengeSeed = packet.ChallengeSeed();
442 m_remainingTries = packet.RemainingTries();
445 // fall through to challenge code...
448 if( m_halfOpen ) {
449 // half open, device is expecting a password hash... do we
450 // have a password?
451 if( !password ) {
452 throw BadPassword("No password specified.", m_remainingTries, false);
455 // only allow password attempts if there are 6 or more
456 // tries remaining... we want to give the user at least
457 // 5 chances on a Windows machine before the device
458 // commits suicide.
459 if( m_remainingTries < 6 ) {
460 throw BadPassword("Fewer than 6 password tries "
461 "remaining in device. Refusing to proceed, "
462 "to avoid device zapping itself. Use a "
463 "Windows client, or re-cradle the device.",
464 m_remainingTries,
465 true);
468 // save sequence for later close (again after SendOpen())
469 closeFlag = GetZeroSocketSequence();
471 SendPasswordHash(socket, password, receive);
473 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
474 m_halfOpen = true;
475 m_challengeSeed = packet.ChallengeSeed();
476 m_remainingTries = packet.RemainingTries();
477 throw BadPassword("Password rejected by device.", m_remainingTries, false);
480 // if we get this far, we are no longer in half-open password
481 // mode, so we can reset our flags
482 m_halfOpen = false;
484 // fall through to success check...
487 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
488 packet.SocketResponse() != socket ||
489 packet.SocketSequence() != closeFlag )
491 eout("Packet:\n" << receive);
492 throw Error("Socket: Bad OPENED packet in Open");
495 // success! save the socket
496 return SocketHandle(new Socket(*this, socket, closeFlag));
500 // Close
502 /// Closes a non-default socket (i.e. non-zero socket number)
504 /// The packet sequence is just like Open(), except the command is
505 /// CLOSE_SOCKET.
507 /// \exception Barry::Error
509 void SocketZero::Close(Socket &socket)
511 if( socket.GetSocket() == 0 )
512 return; // nothing to do
514 // build close command
515 Barry::Protocol::Packet packet;
516 packet.socket = 0;
517 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
518 packet.command = SB_COMMAND_CLOSE_SOCKET;
519 packet.u.socket.socket = htobs(socket.GetSocket());
520 packet.u.socket.sequence = socket.GetCloseFlag();
522 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
523 Data response;
524 try {
525 Send(command, response);
527 catch( Usb::Error & ) {
528 // reset so this won't be called again
529 socket.ForceClosed();
531 eeout(command, response);
532 throw;
535 // starting fresh, reset sequence ID
536 Protocol::CheckSize(response);
537 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
538 CheckSequence(0, response);
540 // still need our ACK
541 RawReceive(response);
544 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
545 MAKE_PACKET(rpack, response);
546 if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
547 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
548 rpack->u.socket.sequence != socket.GetCloseFlag() )
550 // reset so this won't be called again
551 socket.ForceClosed();
553 eout("Packet:\n" << response);
554 throw Error("Socket: Bad CLOSED packet in Close");
557 // // and finally, there always seems to be an extra read of
558 // // an empty packet at the end... just throw it away
559 // try {
560 // RawReceive(response, 1);
561 // }
562 // catch( Usb::Timeout & ) {
563 // }
565 // reset socket and flag
566 socket.ForceClosed();
574 //////////////////////////////////////////////////////////////////////////////
575 // Socket class
577 Socket::Socket( SocketZero &zero,
578 uint16_t socket,
579 uint8_t closeFlag)
580 : m_zero(&zero)
581 , m_socket(socket)
582 , m_closeFlag(closeFlag)
583 , m_registered(false)
587 Socket::~Socket()
589 // trap exceptions in the destructor
590 try {
591 // a non-default socket has been opened, close it
592 Close();
594 catch( std::runtime_error &re ) {
595 // do nothing... log it?
596 dout("Exception caught in ~Socket: " << re.what());
601 ////////////////////////////////////
602 // Socket protected API
604 void Socket::CheckSequence(const Data &seq)
606 m_zero->CheckSequence(m_socket, seq);
609 void Socket::ForceClosed()
611 m_socket = 0;
612 m_closeFlag = 0;
616 ////////////////////////////////////
617 // Socket public API
619 void Socket::Close()
621 UnregisterInterest();
622 m_zero->Close(*this);
627 // Send
629 /// Sends 'send' data to device, no receive.
631 /// \returns void
633 /// \exception Usb::Error on underlying bus errors.
635 void Socket::Send(Data &send, int timeout)
637 // force the socket number to this socket
638 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
639 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
640 spack->socket = htobs(m_socket);
642 m_zero->RawSend(send, timeout);
646 // Send
648 /// Sends 'send' data to device, and waits for response.
650 /// \returns void
652 /// \exception Usb::Error on underlying bus errors.
654 void Socket::Send(Data &send, Data &receive, int timeout)
656 Send(send, timeout);
657 Receive(receive, timeout);
660 void Socket::Send(Barry::Packet &packet, int timeout)
662 Send(packet.m_send, packet.m_receive, timeout);
665 void Socket::Receive(Data &receive, int timeout)
667 if( m_registered ) {
668 if( m_zero->m_queue ) {
669 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
670 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
672 else {
673 throw std::logic_error("NULL queue pointer in a registered socket read.");
676 else {
677 m_zero->RawReceive(receive, timeout);
681 // sends the send packet down to the device, fragmenting if
682 // necessary, and returns the response in receive, defragmenting
683 // if needed
684 // Blocks until response received or timed out in Usb::Device
685 void Socket::Packet(Data &send, Data &receive, int timeout)
688 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
689 // function that forces the socket number to the correct current value,
690 // but putting it here means a copy on every packet.
692 // force socket to our socket
693 Data send = sendorig;
694 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
695 sspack->socket = htobs(GetSocket());
698 MAKE_PACKET(spack, send);
699 if( send.GetSize() < MIN_PACKET_SIZE ||
700 (spack->command != SB_COMMAND_DB_DATA &&
701 spack->command != SB_COMMAND_DB_DONE) )
703 // we don't do that around here
704 throw std::logic_error("Socket: unknown send data in Packet()");
707 Data inFrag;
708 receive.Zap();
710 if( send.GetSize() <= MAX_PACKET_SIZE ) {
711 // send non-fragmented
712 Send(send, inFrag, timeout);
714 else {
715 // send fragmented
716 unsigned int offset = 0;
717 Data outFrag;
719 do {
720 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
721 Send(outFrag, inFrag, timeout);
723 MAKE_PACKET(rpack, inFrag);
724 // only process sequence handshakes... once we
725 // get to the last fragment, we fall through to normal
726 // processing below
727 if( offset && inFrag.GetSize() > 0 ) {
729 Protocol::CheckSize(inFrag);
731 switch( rpack->command )
733 case SB_COMMAND_SEQUENCE_HANDSHAKE:
734 CheckSequence(inFrag);
735 break;
737 default: {
738 std::ostringstream oss;
739 oss << "Socket: unhandled packet in Packet() (send): 0x" << std::hex << (unsigned int)rpack->command;
740 eout(oss.str());
741 throw Error(oss.str());
743 break;
748 } while( offset > 0 );
751 bool done = false, frag = false;
752 int blankCount = 0;
753 while( !done ) {
754 MAKE_PACKET(rpack, inFrag);
756 // check the packet's validity
757 if( inFrag.GetSize() > 0 ) {
758 blankCount = 0;
760 Protocol::CheckSize(inFrag);
762 switch( rpack->command )
764 case SB_COMMAND_SEQUENCE_HANDSHAKE:
765 CheckSequence(inFrag);
766 break;
768 case SB_COMMAND_DB_DATA:
769 if( frag ) {
770 SocketZero::AppendFragment(receive, inFrag);
772 else {
773 receive = inFrag;
775 done = true;
776 break;
778 case SB_COMMAND_DB_FRAGMENTED:
779 SocketZero::AppendFragment(receive, inFrag);
780 frag = true;
781 break;
783 case SB_COMMAND_DB_DONE:
784 receive = inFrag;
785 done = true;
786 break;
788 default: {
789 std::ostringstream oss;
790 oss << "Socket: unhandled packet in Packet() (read): 0x" << std::hex << (unsigned int)rpack->command;
791 eout(oss.str());
792 throw Error(oss.str());
794 break;
797 else {
798 blankCount++;
799 //std::cerr << "Blank! " << blankCount << std::endl;
800 if( blankCount == 10 ) {
801 // only ask for more data on stalled sockets
802 // for so long
803 throw Error("Socket: 10 blank packets received");
807 if( !done ) {
808 // not done yet, ask for another read
809 Receive(inFrag);
814 void Socket::Packet(Barry::Packet &packet, int timeout)
816 Packet(packet.m_send, packet.m_receive, timeout);
819 void Socket::NextRecord(Data &receive)
821 Barry::Protocol::Packet packet;
822 packet.socket = htobs(GetSocket());
823 packet.size = htobs(7);
824 packet.command = SB_COMMAND_DB_DONE;
825 packet.u.db.tableCmd = 0;
826 packet.u.db.u.command.operation = 0;
828 Data command(&packet, 7);
829 Packet(command, receive);
832 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler,
833 void *context)
835 if( !m_zero->m_queue )
836 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
838 if( m_registered )
839 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
841 m_zero->m_queue->RegisterInterest(m_socket, handler, context);
842 m_registered = true;
845 void Socket::UnregisterInterest()
847 if( m_registered ) {
848 if( m_zero->m_queue )
849 m_zero->m_queue->UnregisterInterest(m_socket);
850 m_registered = false;
855 } // namespace Barry