i18n work in progress... desperately needs some housecleaning.
[barry.git] / src / socket.cc
blobc68f81ae46f94c51438561b67111e117287a8722
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 // if( m_socket == 0 ) {
162 // // don't do any sequence checking on socket 0
163 // return;
164 // }
166 MAKE_PACKET(spack, seq);
167 if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
168 eout("Short sequence packet:\n" << seq);
169 throw Error("Socket: invalid sequence packet");
172 // we'll cheat here... if the packet's sequence is 0, we'll
173 // silently restart, otherwise, fail
174 uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
175 if( sequenceId == 0 ) {
176 // silently restart (will advance below)
177 m_sequenceId = 0;
179 else {
180 if( sequenceId != m_sequenceId ) {
181 if( socket != 0 ) {
182 std::ostringstream oss;
183 oss << "Socket 0x" << std::hex << (unsigned int)socket
184 << ": out of sequence. "
185 << "(Global sequence: " << m_sequenceId
186 << ". Packet sequence: " << sequenceId
187 << ")";
188 eout(oss.str());
189 throw Error(oss.str());
191 else {
192 dout("Bad sequence on socket 0: expected: "
193 << msequenceId
194 << ". Packet sequence: " << sequenceId);
199 // advance!
200 m_sequenceId++;
203 void SocketZero::SendOpen(uint16_t socket, Data &receive)
205 // build open command
206 Barry::Protocol::Packet packet;
207 packet.socket = 0;
208 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
209 packet.command = SB_COMMAND_OPEN_SOCKET;
210 packet.u.socket.socket = htobs(socket);
211 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
213 Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
214 try {
215 RawSend(send);
216 RawReceive(receive);
217 } catch( Usb::Error & ) {
218 eeout(send, receive);
219 throw;
222 // check sequence ID
223 Protocol::CheckSize(receive);
224 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
225 CheckSequence(0, receive);
227 // still need our ACK
228 RawReceive(receive);
231 // receive now holds the Open response
234 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
235 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
237 unsigned char pwdigest[SHA_DIGEST_LENGTH];
238 unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
240 // first, hash the password by itself
241 SHA1((unsigned char *) password, strlen(password), pwdigest);
243 // prefix the resulting hash with the provided seed
244 uint32_t seed = htobl(m_challengeSeed);
245 memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
246 memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
248 // hash again
249 SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
252 size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
254 // build open command
255 Barry::Protocol::Packet packet;
256 packet.socket = 0;
257 packet.size = htobs(size);
258 packet.command = SB_COMMAND_PASSWORD;
259 packet.u.socket.socket = htobs(socket);
260 packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
261 packet.u.socket.u.password.remaining_tries = 0;
262 packet.u.socket.u.password.unknown = 0;
263 packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
264 memcpy(packet.u.socket.u.password.u.hash, pwdigest,
265 sizeof(packet.u.socket.u.password.u.hash));
267 // blank password hashes as we don't need these anymore
268 memset(pwdigest, 0, sizeof(pwdigest));
269 memset(prefixedhash, 0, sizeof(prefixedhash));
271 Data send(&packet, size);
272 RawSend(send);
273 RawReceive(receive);
275 // blank password hash as we don't need this anymore either
276 memset(packet.u.socket.u.password.u.hash, 0,
277 sizeof(packet.u.socket.u.password.u.hash));
278 send.Zap();
280 // check sequence ID
281 Protocol::CheckSize(receive);
282 if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
283 CheckSequence(0, receive);
285 // still need our ACK
286 RawReceive(receive);
289 // receive now holds the Password response
293 ///////////////////////////////////////
294 // SocketZero public API
296 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
298 // replace the current queue pointer
299 m_queue = &queue;
302 void SocketZero::UnlinkRoutingQueue()
304 m_queue = 0;
307 void SocketZero::RawSend(Data &send, int timeout)
309 Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
311 // Special case: it seems that sending packets with a size that's an
312 // exact multiple of 0x40 causes the device to get confused.
314 // To get around that, it is observed in the captures that the size
315 // is sent in a special 3 byte packet before the real packet.
316 // Check for this case here.
318 if( (send.GetSize() % 0x40) == 0 ) {
319 Protocol::SizePacket packet;
320 packet.size = htobs(send.GetSize());
321 packet.buffer[2] = 0; // zero the top byte
322 Data sizeCommand(&packet, 3);
324 dev->BulkWrite(m_writeEp, sizeCommand);
327 dev->BulkWrite(m_writeEp, send);
330 void SocketZero::RawReceive(Data &receive, int timeout)
332 if( m_queue ) {
333 if( !m_queue->DefaultRead(receive, timeout) )
334 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
336 else {
337 m_dev->BulkRead(m_readEp, receive, timeout);
339 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
340 << "\nReceived:\n" << receive);
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);
375 // Open
377 /// Open a logical socket on the device.
379 /// Both the socket number and the flag are based on the response to the
380 /// SELECT_MODE command. See Controller::SelectMode() for more info
381 /// on this.
383 /// The packet sequence is normal for most socket operations.
385 /// - Down: command packet with OPEN_SOCKET
386 /// - Up: optional sequence handshake packet
387 /// - Up: command response, which repeats the socket and flag data
388 /// as confirmation
390 /// \exception Barry::Error
391 /// Thrown on protocol error.
393 /// \exception Barry::BadPassword
394 /// Thrown on invalid password, or not enough retries left
395 /// on device.
397 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
399 // Things get a little funky here, as we may be left in an
400 // intermediate state in the case of a failed password.
401 // This function should support being called as many times
402 // as needed to handle the password
404 Data send, receive;
405 ZeroPacket packet(send, receive);
407 // save sequence for later close
408 uint8_t closeFlag = GetZeroSocketSequence();
410 if( !m_halfOpen ) {
411 // starting fresh
412 m_remainingTries = 0;
414 SendOpen(socket, receive);
416 // check for password challenge, or success
417 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
418 m_halfOpen = true;
419 m_challengeSeed = packet.ChallengeSeed();
420 m_remainingTries = packet.RemainingTries();
423 // fall through to challenge code...
426 if( m_halfOpen ) {
427 // half open, device is expecting a password hash... do we
428 // have a password?
429 if( !password ) {
430 throw BadPassword("No password specified.", m_remainingTries, false);
433 // only allow password attempts if there are 6 or more
434 // tries remaining... we want to give the user at least
435 // 5 chances on a Windows machine before the device
436 // commits suicide.
437 if( m_remainingTries < 6 ) {
438 throw BadPassword("Fewer than 6 password tries "
439 "remaining in device. Refusing to proceed, "
440 "to avoid device zapping itself. Use a "
441 "Windows client, or re-cradle the device.",
442 m_remainingTries,
443 true);
446 // save sequence for later close (again after SendOpen())
447 closeFlag = GetZeroSocketSequence();
449 SendPasswordHash(socket, password, receive);
451 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
452 m_halfOpen = true;
453 m_challengeSeed = packet.ChallengeSeed();
454 m_remainingTries = packet.RemainingTries();
455 throw BadPassword("Password rejected by device.", m_remainingTries, false);
458 // if we get this far, we are no longer in half-open password
459 // mode, so we can reset our flags
460 m_halfOpen = false;
462 // fall through to success check...
465 if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
466 packet.SocketResponse() != socket ||
467 packet.SocketSequence() != closeFlag )
469 eout("Packet:\n" << receive);
470 throw Error("Socket: Bad OPENED packet in Open");
473 // success! save the socket
474 return SocketHandle(new Socket(*this, socket, closeFlag));
478 // Close
480 /// Closes a non-default socket (i.e. non-zero socket number)
482 /// The packet sequence is just like Open(), except the command is
483 /// CLOSE_SOCKET.
485 /// \exception Barry::Error
487 void SocketZero::Close(Socket &socket)
489 if( socket.GetSocket() == 0 )
490 return; // nothing to do
492 // build close command
493 Barry::Protocol::Packet packet;
494 packet.socket = 0;
495 packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
496 packet.command = SB_COMMAND_CLOSE_SOCKET;
497 packet.u.socket.socket = htobs(socket.GetSocket());
498 packet.u.socket.sequence = socket.GetCloseFlag();
500 Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
501 Data response;
502 try {
503 Send(command, response);
505 catch( Usb::Error & ) {
506 // reset so this won't be called again
507 socket.ForceClosed();
509 eeout(command, response);
510 throw;
513 // starting fresh, reset sequence ID
514 Protocol::CheckSize(response);
515 if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
516 CheckSequence(0, response);
518 // still need our ACK
519 RawReceive(response);
522 Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
523 MAKE_PACKET(rpack, response);
524 if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
525 btohs(rpack->u.socket.socket) != socket.GetSocket() ||
526 rpack->u.socket.sequence != socket.GetCloseFlag() )
528 // reset so this won't be called again
529 socket.ForceClosed();
531 eout("Packet:\n" << response);
532 throw Error("Socket: Bad CLOSED packet in Close");
535 // // and finally, there always seems to be an extra read of
536 // // an empty packet at the end... just throw it away
537 // try {
538 // RawReceive(response, 1);
539 // }
540 // catch( Usb::Timeout & ) {
541 // }
543 // reset socket and flag
544 socket.ForceClosed();
552 //////////////////////////////////////////////////////////////////////////////
553 // Socket class
555 Socket::Socket( SocketZero &zero,
556 uint16_t socket,
557 uint8_t closeFlag)
558 : m_zero(&zero)
559 , m_socket(socket)
560 , m_closeFlag(closeFlag)
561 , m_registered(false)
565 Socket::~Socket()
567 // trap exceptions in the destructor
568 try {
569 // a non-default socket has been opened, close it
570 Close();
572 catch( std::runtime_error &re ) {
573 // do nothing... log it?
574 dout("Exception caught in ~Socket: " << re.what());
579 ////////////////////////////////////
580 // Socket protected API
582 void Socket::CheckSequence(const Data &seq)
584 m_zero->CheckSequence(m_socket, seq);
587 void Socket::ForceClosed()
589 m_socket = 0;
590 m_closeFlag = 0;
594 ////////////////////////////////////
595 // Socket public API
597 void Socket::Close()
599 UnregisterInterest();
600 m_zero->Close(*this);
605 // Send
607 /// Sends 'send' data to device, no receive.
609 /// \returns void
611 /// \exception Usb::Error on underlying bus errors.
613 void Socket::Send(Data &send, int timeout)
615 // force the socket number to this socket
616 if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
617 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
618 spack->socket = htobs(m_socket);
620 m_zero->RawSend(send, timeout);
624 // Send
626 /// Sends 'send' data to device, and waits for response.
628 /// \returns void
630 /// \exception Usb::Error on underlying bus errors.
632 void Socket::Send(Data &send, Data &receive, int timeout)
634 Send(send, timeout);
635 Receive(receive, timeout);
638 void Socket::Send(Barry::Packet &packet, int timeout)
640 Send(packet.m_send, packet.m_receive, timeout);
643 void Socket::Receive(Data &receive, int timeout)
645 if( m_registered ) {
646 if( m_zero->m_queue ) {
647 if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
648 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
650 else {
651 throw std::logic_error("NULL queue pointer in a registered socket read.");
654 else {
655 m_zero->RawReceive(receive, timeout);
659 // sends the send packet down to the device, fragmenting if
660 // necessary, and returns the response in receive, defragmenting
661 // if needed
662 // Blocks until response received or timed out in Usb::Device
663 void Socket::Packet(Data &send, Data &receive, int timeout)
666 // FIXME - this might be a good idea someday, or perhaps provide a wrapper
667 // function that forces the socket number to the correct current value,
668 // but putting it here means a copy on every packet.
670 // force socket to our socket
671 Data send = sendorig;
672 Barry::Protocol::Packet *sspack = (Barry::Protocol::Packet *)send.GetBuffer(2);
673 sspack->socket = htobs(GetSocket());
676 MAKE_PACKET(spack, send);
677 if( send.GetSize() < MIN_PACKET_SIZE ||
678 (spack->command != SB_COMMAND_DB_DATA &&
679 spack->command != SB_COMMAND_DB_DONE) )
681 // we don't do that around here
682 throw std::logic_error("Socket: unknown send data in Packet()");
685 Data inFrag;
686 receive.Zap();
688 if( send.GetSize() <= MAX_PACKET_SIZE ) {
689 // send non-fragmented
690 Send(send, inFrag, timeout);
692 else {
693 // send fragmented
694 unsigned int offset = 0;
695 Data outFrag;
697 do {
698 offset = SocketZero::MakeNextFragment(send, outFrag, offset);
699 Send(outFrag, inFrag, timeout);
701 MAKE_PACKET(rpack, inFrag);
702 // only process sequence handshakes... once we
703 // get to the last fragment, we fall through to normal
704 // processing below
705 if( offset && inFrag.GetSize() > 0 ) {
707 Protocol::CheckSize(inFrag);
709 switch( rpack->command )
711 case SB_COMMAND_SEQUENCE_HANDSHAKE:
712 CheckSequence(inFrag);
713 break;
715 default: {
716 std::ostringstream oss;
717 oss << "Socket: unhandled packet in Packet() (send): 0x" << std::hex << (unsigned int)rpack->command;
718 eout(oss.str());
719 throw Error(oss.str());
721 break;
726 } while( offset > 0 );
729 bool done = false, frag = false;
730 int blankCount = 0;
731 while( !done ) {
732 MAKE_PACKET(rpack, inFrag);
734 // check the packet's validity
735 if( inFrag.GetSize() > 0 ) {
736 blankCount = 0;
738 Protocol::CheckSize(inFrag);
740 switch( rpack->command )
742 case SB_COMMAND_SEQUENCE_HANDSHAKE:
743 CheckSequence(inFrag);
744 break;
746 case SB_COMMAND_DB_DATA:
747 if( frag ) {
748 SocketZero::AppendFragment(receive, inFrag);
750 else {
751 receive = inFrag;
753 done = true;
754 break;
756 case SB_COMMAND_DB_FRAGMENTED:
757 SocketZero::AppendFragment(receive, inFrag);
758 frag = true;
759 break;
761 case SB_COMMAND_DB_DONE:
762 receive = inFrag;
763 done = true;
764 break;
766 default: {
767 std::ostringstream oss;
768 oss << "Socket: unhandled packet in Packet() (read): 0x" << std::hex << (unsigned int)rpack->command;
769 eout(oss.str());
770 throw Error(oss.str());
772 break;
775 else {
776 blankCount++;
777 //std::cerr << "Blank! " << blankCount << std::endl;
778 if( blankCount == 10 ) {
779 // only ask for more data on stalled sockets
780 // for so long
781 throw Error("Socket: 10 blank packets received");
785 if( !done ) {
786 // not done yet, ask for another read
787 Receive(inFrag);
792 void Socket::Packet(Barry::Packet &packet, int timeout)
794 Packet(packet.m_send, packet.m_receive, timeout);
797 void Socket::NextRecord(Data &receive)
799 Barry::Protocol::Packet packet;
800 packet.socket = htobs(GetSocket());
801 packet.size = htobs(7);
802 packet.command = SB_COMMAND_DB_DONE;
803 packet.u.db.tableCmd = 0;
804 packet.u.db.u.command.operation = 0;
806 Data command(&packet, 7);
807 Packet(command, receive);
810 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler,
811 void *context)
813 if( !m_zero->m_queue )
814 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
816 if( m_registered )
817 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
819 m_zero->m_queue->RegisterInterest(m_socket, handler, context);
820 m_registered = true;
823 void Socket::UnregisterInterest()
825 if( m_registered ) {
826 if( m_zero->m_queue )
827 m_zero->m_queue->UnregisterInterest(m_socket);
828 m_registered = false;
833 } // namespace Barry