Minor whitespace and usage text fix in upldif.cc
[barry/pauldeden.git] / src / socket.cc
blob7fad709f0c2d6d946564dcc622dc74f1c74402fa
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>
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)
58 SocketZero::SocketZero( Device &dev,
59 int writeEndpoint, int readEndpoint,
60 uint8_t zeroSocketSequenceStart)
61 : m_dev(&dev),
62 m_queue(0),
63 m_writeEp(writeEndpoint),
64 m_readEp(readEndpoint),
65 m_zeroSocketSequence(zeroSocketSequenceStart),
66 m_sequenceId(0),
67 m_halfOpen(false),
68 m_challengeSeed(0),
69 m_remainingTries(0)
73 SocketZero::~SocketZero()
75 // nothing to close for socket zero
79 ///////////////////////////////////////
80 // Socket Zero static calls
82 // appends fragment to whole... if whole is empty, simply copies, and
83 // sets command to DATA instead of FRAGMENTED. Always updates the
84 // packet size of whole, to reflect the total size
85 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
87 if( whole.GetSize() == 0 ) {
88 // empty, so just copy
89 whole = fragment;
91 else {
92 // has some data already, so just append
93 int size = whole.GetSize();
94 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
95 MAKE_PACKET(fpack, fragment);
96 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
98 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
99 whole.ReleaseBuffer(size + fragsize);
102 // update whole's size and command type for future sanity
103 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
104 wpack->size = htobs((uint16_t) whole.GetSize());
105 wpack->command = SB_COMMAND_DB_DATA;
106 // don't need to call ReleaseBuffer here, since we're not changing
107 // the real data size, and ReleaseBuffer was called above during copy
110 // If offset is 0, starts fresh, taking the first fragment packet size chunk
111 // out of whole and creating a sendable packet in fragment. Returns the
112 // next offset if there is still more data, or 0 if finished.
113 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
115 // sanity check
116 if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
117 eout("Whole packet too short to fragment: " << whole.GetSize());
118 throw Error("Socket: Whole packet too short to fragment");
121 // calculate size
122 unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
123 unsigned int nextOffset = 0;
124 if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
125 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
126 nextOffset = offset + todo;
129 // create fragment header
130 unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
131 memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
133 // copy over a fragment size of data
134 memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
136 // update fragment's size and command type
137 Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
138 wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
139 if( nextOffset )
140 wpack->command = SB_COMMAND_DB_FRAGMENTED;
141 else
142 wpack->command = SB_COMMAND_DB_DATA;
144 // adjust the new fragment size
145 fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
147 // return next round
148 return nextOffset;
152 ///////////////////////////////////////
153 // SocketZero private API
156 // FIXME - not sure yet whether sequence ID's are per socket or not... if
157 // they are per socket, then this global sequence behaviour will not work,
158 // and we need to track m_sequenceId on a Socket level.
160 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
162 MAKE_PACKET(spack, seq);
163 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
164 eout("Short sequence packet:\n" << seq);
165 throw Error("Socket: invalid sequence packet");
168 // we'll cheat here... if the packet's sequence is 0, we'll
169 // silently restart, otherwise, fail
170 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
171 if( sequenceId == 0 ) {
172 // silently restart (will advance below)
173 m_sequenceId = 0;
175 else {
176 if( sequenceId != m_sequenceId ) {
177 if( socket != 0 ) {
178 std::ostringstream oss;
179 oss << "Socket 0x" << std::hex << (unsigned int)socket
180 << ": out of sequence. "
181 << "(Global sequence: " << m_sequenceId
182 << ". Packet sequence: " << sequenceId
183 << ")";
184 eout(oss.str());
185 throw Error(oss.str());
187 else {
188 dout("Bad sequence on socket 0: expected: "
189 << msequenceId
190 << ". Packet sequence: " << sequenceId);
195 // advance!
196 m_sequenceId++;
199 void SocketZero::SendOpen(uint16_t socket, Data &receive)
201 // build open command
202 Barry::Protocol::Packet packet;
203 packet.socket = 0;
204 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
205 packet.command = SB_COMMAND_OPEN_SOCKET;
206 packet.u.socket.socket = htobs(socket);
207 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
209 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
210 try {
211 RawSend(send);
212 RawReceive(receive);
213 } catch( Usb::Error & ) {
214 eeout(send, receive);
215 throw;
218 // check sequence ID
219 Protocol::CheckSize(receive);
220 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
221 CheckSequence(0, receive);
223 // still need our ACK
224 RawReceive(receive);
227 // receive now holds the Open response
230 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
231 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
233 unsigned char pwdigest[SHA_DIGEST_LENGTH];
234 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
236 // first, hash the password by itself
237 SHA1((unsigned char *) password, strlen(password), pwdigest);
239 // prefix the resulting hash with the provided seed
240 uint32_t seed = htobl(m_challengeSeed);
241 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
242 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
244 // hash again
245 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
248 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
250 // build open command
251 Barry::Protocol::Packet packet;
252 packet.socket = 0;
253 packet.size = htobs(size);
254 packet.command = SB_COMMAND_PASSWORD;
255 packet.u.socket.socket = htobs(socket);
256 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
257 packet.u.socket.u.password.remaining_tries = 0;
258 packet.u.socket.u.password.unknown = 0;
259 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
260 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
261 sizeof(packet.u.socket.u.password.u.hash));
263 // blank password hashes as we don't need these anymore
264 memset(pwdigest, 0, sizeof(pwdigest));
265 memset(prefixedhash, 0, sizeof(prefixedhash));
267 Data send(&packet, size);
268 RawSend(send);
269 RawReceive(receive);
271 // blank password hash as we don't need this anymore either
272 memset(packet.u.socket.u.password.u.hash, 0,
273 sizeof(packet.u.socket.u.password.u.hash));
274 send.Zap();
276 // check sequence ID
277 Protocol::CheckSize(receive);
278 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
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;
292 // Special case: it seems that sending packets with a size that's an
293 // exact multiple of 0x40 causes the device to get confused.
295 // To get around that, it is observed in the captures that the size
296 // is sent in a special 3 byte packet before the real packet.
297 // Check for this case here.
299 if( (send.GetSize() % 0x40) == 0 ) {
300 Protocol::SizePacket packet;
301 packet.size = htobs(send.GetSize());
302 packet.buffer[2] = 0; // zero the top byte
303 Data sizeCommand(&packet, 3);
305 dev->BulkWrite(m_writeEp, sizeCommand);
308 dev->BulkWrite(m_writeEp, send);
311 void SocketZero::RawReceive(Data &receive, int timeout)
313 do {
314 if( m_queue ) {
315 if( !m_queue->DefaultRead(receive, timeout) )
316 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
318 else {
319 m_dev->BulkRead(m_readEp, receive, timeout);
321 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
322 << "\nReceived:\n" << receive);
323 } while( SequencePacket(receive) );
327 // SequencePacket
329 /// Returns true if this is a sequence packet that should be ignored.
330 /// This function is used in SocketZero::RawReceive() in order
331 /// to determine whether to keep reading or not. By default,
332 /// this function checks whether the packet is a sequence packet
333 /// or not, and returns true if so. Also, if it is a sequence
334 /// packet, it checks the validity of the sequence number.
336 /// If sequence packets become important in the future, this
337 /// function could be changed to call a user-defined callback,
338 /// in order to handle these things out of band.
340 bool SocketZero::SequencePacket(const Data &data)
342 if( data.GetSize() >= MIN_PACKET_SIZE ) {
343 if( IS_COMMAND(data, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
344 CheckSequence(0, data);
345 return true;
348 return false; // not a sequence packet
352 ///////////////////////////////////////
353 // SocketZero public API
355 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
357 // replace the current queue pointer
358 m_queue = &queue;
361 void SocketZero::UnlinkRoutingQueue()
363 m_queue = 0;
366 void SocketZero::Send(Data &send, int timeout)
368 // force the socket number to 0
369 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
370 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
371 spack->socket = 0;
374 // This is a socket 0 packet, so force the send packet data's
375 // socket 0 sequence number to something correct.
376 if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
377 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
378 spack->u.socket.sequence = m_zeroSocketSequence;
379 m_zeroSocketSequence++;
382 RawSend(send, timeout);
385 void SocketZero::Send(Data &send, Data &receive, int timeout)
387 Send(send, timeout);
388 RawReceive(receive, timeout);
391 void SocketZero::Send(Barry::Packet &packet, int timeout)
393 Send(packet.m_send, packet.m_receive, timeout);
398 // Open
400 /// Open a logical socket on the device.
402 /// Both the socket number and the flag are based on the response to the
403 /// SELECT_MODE command. See Controller::SelectMode() for more info
404 /// on this.
406 /// The packet sequence is normal for most socket operations.
408 /// - Down: command packet with OPEN_SOCKET
409 /// - Up: optional sequence handshake packet
410 /// - Up: command response, which repeats the socket and flag data
411 /// as confirmation
413 /// \exception Barry::Error
414 /// Thrown on protocol error.
416 /// \exception Barry::BadPassword
417 /// Thrown on invalid password, or not enough retries left
418 /// on device.
420 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
422 // Things get a little funky here, as we may be left in an
423 // intermediate state in the case of a failed password.
424 // This function should support being called as many times
425 // as needed to handle the password
427 Data send, receive;
428 ZeroPacket packet(send, receive);
430 // save sequence for later close
431 uint8_t closeFlag = GetZeroSocketSequence();
433 if( !m_halfOpen ) {
434 // starting fresh
435 m_remainingTries = 0;
437 SendOpen(socket, receive);
439 // check for password challenge, or success
440 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
441 m_halfOpen = true;
442 m_challengeSeed = packet.ChallengeSeed();
443 m_remainingTries = packet.RemainingTries();
446 // fall through to challenge code...
449 if( m_halfOpen ) {
450 // half open, device is expecting a password hash... do we
451 // have a password?
452 if( !password ) {
453 throw BadPassword("No password specified.", m_remainingTries, false);
456 // only allow password attempts if there are 6 or more
457 // tries remaining... we want to give the user at least
458 // 5 chances on a Windows machine before the device
459 // commits suicide.
460 if( m_remainingTries < 6 ) {
461 throw BadPassword("Fewer than 6 password tries "
462 "remaining in device. Refusing to proceed, "
463 "to avoid device zapping itself. Use a "
464 "Windows client, or re-cradle the device.",
465 m_remainingTries,
466 true);
469 // save sequence for later close (again after SendOpen())
470 closeFlag = GetZeroSocketSequence();
472 SendPasswordHash(socket, password, receive);
474 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
475 m_halfOpen = true;
476 m_challengeSeed = packet.ChallengeSeed();
477 m_remainingTries = packet.RemainingTries();
478 throw BadPassword("Password rejected by device.", m_remainingTries, false);
481 // if we get this far, we are no longer in half-open password
482 // mode, so we can reset our flags
483 m_halfOpen = false;
485 // fall through to success check...
488 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
489 packet.SocketResponse() != socket ||
490 packet.SocketSequence() != closeFlag )
492 eout("Packet:\n" << receive);
493 throw Error("Socket: Bad OPENED packet in Open");
496 // success! save the socket
497 return SocketHandle(new Socket(*this, socket, closeFlag));
501 // Close
503 /// Closes a non-default socket (i.e. non-zero socket number)
505 /// The packet sequence is just like Open(), except the command is
506 /// CLOSE_SOCKET.
508 /// \exception Barry::Error
510 void SocketZero::Close(Socket &socket)
512 if( socket.GetSocket() == 0 )
513 return; // nothing to do
515 // build close command
516 Barry::Protocol::Packet packet;
517 packet.socket = 0;
518 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
519 packet.command = SB_COMMAND_CLOSE_SOCKET;
520 packet.u.socket.socket = htobs(socket.GetSocket());
521 packet.u.socket.sequence = socket.GetCloseFlag();
523 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
524 Data response;
525 try {
526 Send(command, response);
528 catch( Usb::Error & ) {
529 // reset so this won't be called again
530 socket.ForceClosed();
532 eeout(command, response);
533 throw;
536 // starting fresh, reset sequence ID
537 Protocol::CheckSize(response);
538 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
539 CheckSequence(0, response);
541 // still need our ACK
542 RawReceive(response);
545 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
546 MAKE_PACKET(rpack, response);
547 if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
548 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
549 rpack->u.socket.sequence != socket.GetCloseFlag() )
551 // reset so this won't be called again
552 socket.ForceClosed();
554 eout("Packet:\n" << response);
555 throw Error("Socket: Bad CLOSED packet in Close");
558 // // and finally, there always seems to be an extra read of
559 // // an empty packet at the end... just throw it away
560 // try {
561 // RawReceive(response, 1);
562 // }
563 // catch( Usb::Timeout & ) {
564 // }
566 // reset socket and flag
567 socket.ForceClosed();
575 //////////////////////////////////////////////////////////////////////////////
576 // Socket class
578 Socket::Socket( SocketZero &zero,
579 uint16_t socket,
580 uint8_t closeFlag)
581 : m_zero(&zero)
582 , m_socket(socket)
583 , m_closeFlag(closeFlag)
584 , m_registered(false)
588 Socket::~Socket()
590 // trap exceptions in the destructor
591 try {
592 // a non-default socket has been opened, close it
593 Close();
595 catch( std::runtime_error &re ) {
596 // do nothing... log it?
597 dout("Exception caught in ~Socket: " << re.what());
602 ////////////////////////////////////
603 // Socket protected API
605 void Socket::CheckSequence(const Data &seq)
607 m_zero->CheckSequence(m_socket, seq);
610 void Socket::ForceClosed()
612 m_socket = 0;
613 m_closeFlag = 0;
617 ////////////////////////////////////
618 // Socket public API
620 void Socket::Close()
622 UnregisterInterest();
623 m_zero->Close(*this);
628 // Send
630 /// Sends 'send' data to device, no receive.
632 /// \returns void
634 /// \exception Usb::Error on underlying bus errors.
636 void Socket::Send(Data &send, int timeout)
638 // force the socket number to this socket
639 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
640 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
641 spack->socket = htobs(m_socket);
643 m_zero->RawSend(send, timeout);
647 // Send
649 /// Sends 'send' data to device, and waits for response.
651 /// \returns void
653 /// \exception Usb::Error on underlying bus errors.
655 void Socket::Send(Data &send, Data &receive, int timeout)
657 Send(send, timeout);
658 Receive(receive, timeout);
661 void Socket::Send(Barry::Packet &packet, int timeout)
663 Send(packet.m_send, packet.m_receive, timeout);
666 void Socket::Receive(Data &receive, int timeout)
668 if( m_registered ) {
669 if( m_zero->m_queue ) {
670 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
671 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
673 else {
674 throw std::logic_error("NULL queue pointer in a registered socket read.");
677 else {
678 m_zero->RawReceive(receive, timeout);
682 // sends the send packet down to the device, fragmenting if
683 // necessary, and returns the response in receive, defragmenting
684 // if needed
685 // Blocks until response received or timed out in Usb::Device
686 void Socket::Packet(Data &send, Data &receive, int timeout)
689 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
690 // function that forces the socket number to the correct current value,
691 // but putting it here means a copy on every packet.
693 // force socket to our socket
694 Data send = sendorig;
695 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
696 sspack->socket = htobs(GetSocket());
699 MAKE_PACKET(spack, send);
700 if( send.GetSize() < MIN_PACKET_SIZE ||
701 (spack->command != SB_COMMAND_DB_DATA &&
702 spack->command != SB_COMMAND_DB_DONE) )
704 // we don't do that around here
705 throw std::logic_error("Socket: unknown send data in Packet()");
708 Data inFrag;
709 receive.Zap();
711 if( send.GetSize() <= MAX_PACKET_SIZE ) {
712 // send non-fragmented
713 Send(send, inFrag, timeout);
715 else {
716 // send fragmented
717 unsigned int offset = 0;
718 Data outFrag;
720 do {
721 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
722 Send(outFrag, inFrag, timeout);
724 MAKE_PACKET(rpack, inFrag);
725 // only process sequence handshakes... once we
726 // get to the last fragment, we fall through to normal
727 // processing below
728 if( offset && inFrag.GetSize() > 0 ) {
730 Protocol::CheckSize(inFrag);
732 switch( rpack->command )
734 case SB_COMMAND_SEQUENCE_HANDSHAKE:
735 CheckSequence(inFrag);
736 break;
738 default: {
739 std::ostringstream oss;
740 oss << "Socket: unhandled packet in Packet() (send): 0x" << std::hex << (unsigned int)rpack->command;
741 eout(oss.str());
742 throw Error(oss.str());
744 break;
749 } while( offset > 0 );
752 bool done = false, frag = false;
753 int blankCount = 0;
754 while( !done ) {
755 MAKE_PACKET(rpack, inFrag);
757 // check the packet's validity
758 if( inFrag.GetSize() > 0 ) {
759 blankCount = 0;
761 Protocol::CheckSize(inFrag);
763 switch( rpack->command )
765 case SB_COMMAND_SEQUENCE_HANDSHAKE:
766 CheckSequence(inFrag);
767 break;
769 case SB_COMMAND_DB_DATA:
770 if( frag ) {
771 SocketZero::AppendFragment(receive, inFrag);
773 else {
774 receive = inFrag;
776 done = true;
777 break;
779 case SB_COMMAND_DB_FRAGMENTED:
780 SocketZero::AppendFragment(receive, inFrag);
781 frag = true;
782 break;
784 case SB_COMMAND_DB_DONE:
785 receive = inFrag;
786 done = true;
787 break;
789 default: {
790 std::ostringstream oss;
791 oss << "Socket: unhandled packet in Packet() (read): 0x" << std::hex << (unsigned int)rpack->command;
792 eout(oss.str());
793 throw Error(oss.str());
795 break;
798 else {
799 blankCount++;
800 //std::cerr << "Blank! " << blankCount << std::endl;
801 if( blankCount == 10 ) {
802 // only ask for more data on stalled sockets
803 // for so long
804 throw Error("Socket: 10 blank packets received");
808 if( !done ) {
809 // not done yet, ask for another read
810 Receive(inFrag);
815 void Socket::Packet(Barry::Packet &packet, int timeout)
817 Packet(packet.m_send, packet.m_receive, timeout);
820 void Socket::NextRecord(Data &receive)
822 Barry::Protocol::Packet packet;
823 packet.socket = htobs(GetSocket());
824 packet.size = htobs(7);
825 packet.command = SB_COMMAND_DB_DONE;
826 packet.u.db.tableCmd = 0;
827 packet.u.db.u.command.operation = 0;
829 Data command(&packet, 7);
830 Packet(command, receive);
833 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler,
834 void *context)
836 if( !m_zero->m_queue )
837 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
839 if( m_registered )
840 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
842 m_zero->m_queue->RegisterInterest(m_socket, handler, context);
843 m_registered = true;
846 void Socket::UnregisterInterest()
848 if( m_registered ) {
849 if( m_zero->m_queue )
850 m_zero->m_queue->UnregisterInterest(m_socket);
851 m_registered = false;
856 } // namespace Barry