socket.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       socket.cc
00003 ///             Class wrapper to encapsulate the Blackberry USB logical socket
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "socket.h"
00023 #include "usbwrap.h"
00024 #include "data.h"
00025 #include "protocol.h"
00026 #include "protostructs.h"
00027 #include "endian.h"
00028 #include "debug.h"
00029 #include "packet.h"
00030 #include "sha1.h"
00031 #include <sstream>
00032 #include <string.h>
00033 
00034 using namespace Usb;
00035 
00036 
00037 namespace Barry {
00038 
00039 
00040 //////////////////////////////////////////////////////////////////////////////
00041 // SocketZero class
00042 
00043 SocketZero::SocketZero( SocketRoutingQueue &queue,
00044                         int writeEndpoint,
00045                         uint8_t zeroSocketSequenceStart)
00046         : m_dev(0),
00047         m_queue(&queue),
00048         m_writeEp(writeEndpoint),
00049         m_readEp(0),
00050         m_zeroSocketSequence(zeroSocketSequenceStart),
00051         m_sequenceId(0),
00052         m_halfOpen(false),
00053         m_challengeSeed(0),
00054         m_remainingTries(0),
00055         m_hideSequencePacket(true),
00056         m_resetOnClose(false)
00057 {
00058 }
00059 
00060 SocketZero::SocketZero( Device &dev,
00061                         int writeEndpoint, int readEndpoint,
00062                         uint8_t zeroSocketSequenceStart)
00063         : m_dev(&dev),
00064         m_queue(0),
00065         m_writeEp(writeEndpoint),
00066         m_readEp(readEndpoint),
00067         m_zeroSocketSequence(zeroSocketSequenceStart),
00068         m_sequenceId(0),
00069         m_halfOpen(false),
00070         m_challengeSeed(0),
00071         m_remainingTries(0),
00072         m_hideSequencePacket(true),
00073         m_resetOnClose(false)
00074 {
00075 }
00076 
00077 SocketZero::~SocketZero()
00078 {
00079         // nothing to close for socket zero
00080 }
00081 
00082 
00083 ///////////////////////////////////////
00084 // Socket Zero static calls
00085 
00086 // appends fragment to whole... if whole is empty, simply copies, and
00087 // sets command to DATA instead of FRAGMENTED.  Always updates the
00088 // packet size of whole, to reflect the total size
00089 void SocketZero::AppendFragment(Data &whole, const Data &fragment)
00090 {
00091         if( whole.GetSize() == 0 ) {
00092                 // empty, so just copy
00093                 whole = fragment;
00094         }
00095         else {
00096                 // has some data already, so just append
00097                 int size = whole.GetSize();
00098                 unsigned char *buf = whole.GetBuffer(size + fragment.GetSize());
00099                 MAKE_PACKET(fpack, fragment);
00100                 int fragsize = fragment.GetSize() - SB_FRAG_HEADER_SIZE;
00101 
00102                 memcpy(buf+size, &fpack->u.db.u.fragment, fragsize);
00103                 whole.ReleaseBuffer(size + fragsize);
00104         }
00105 
00106         // update whole's size and command type for future sanity
00107         Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) whole.GetBuffer();
00108         wpack->size = htobs((uint16_t) whole.GetSize());
00109         wpack->command = SB_COMMAND_DB_DATA;
00110         // don't need to call ReleaseBuffer here, since we're not changing
00111         // the real data size, and ReleaseBuffer was called above during copy
00112 }
00113 
00114 // If offset is 0, starts fresh, taking the first fragment packet size chunk
00115 // out of whole and creating a sendable packet in fragment.  Returns the
00116 // next offset if there is still more data, or 0 if finished.
00117 unsigned int SocketZero::MakeNextFragment(const Data &whole, Data &fragment, unsigned int offset)
00118 {
00119         // sanity check
00120         if( whole.GetSize() < SB_FRAG_HEADER_SIZE ) {
00121                 eout("Whole packet too short to fragment: " << whole.GetSize());
00122                 throw Error("Socket: Whole packet too short to fragment");
00123         }
00124 
00125         // calculate size
00126         unsigned int todo = whole.GetSize() - SB_FRAG_HEADER_SIZE - offset;
00127         unsigned int nextOffset = 0;
00128         if( todo > (MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE) ) {
00129                 todo = MAX_PACKET_SIZE - SB_FRAG_HEADER_SIZE;
00130                 nextOffset = offset + todo;
00131         }
00132 
00133         // create fragment header
00134         unsigned char *buf = fragment.GetBuffer(SB_FRAG_HEADER_SIZE + todo);
00135         memcpy(buf, whole.GetData(), SB_FRAG_HEADER_SIZE);
00136 
00137         // copy over a fragment size of data
00138         memcpy(buf + SB_FRAG_HEADER_SIZE, whole.GetData() + SB_FRAG_HEADER_SIZE + offset, todo);
00139 
00140         // update fragment's size and command type
00141         Barry::Protocol::Packet *wpack = (Barry::Protocol::Packet *) buf;
00142         wpack->size = htobs((uint16_t) (todo + SB_FRAG_HEADER_SIZE));
00143         if( nextOffset )
00144                 wpack->command = SB_COMMAND_DB_FRAGMENTED;
00145         else
00146                 wpack->command = SB_COMMAND_DB_DATA;
00147 
00148         // adjust the new fragment size
00149         fragment.ReleaseBuffer(SB_FRAG_HEADER_SIZE + todo);
00150 
00151         // return next round
00152         return nextOffset;
00153 }
00154 
00155 
00156 ///////////////////////////////////////
00157 // SocketZero private API
00158 
00159 //
00160 // FIXME - not sure yet whether sequence ID's are per socket or not... if
00161 // they are per socket, then this global sequence behaviour will not work,
00162 // and we need to track m_sequenceId on a Socket level.
00163 //
00164 void SocketZero::CheckSequence(uint16_t socket, const Data &seq)
00165 {
00166         MAKE_PACKET(spack, seq);
00167         if( (unsigned int) seq.GetSize() < SB_SEQUENCE_PACKET_SIZE ) {
00168                 eout("Short sequence packet:\n" << seq);
00169                 throw Error("Socket: invalid sequence packet");
00170         }
00171 
00172         // we'll cheat here... if the packet's sequence is 0, we'll
00173         // silently restart, otherwise, fail
00174         uint32_t sequenceId = btohl(spack->u.sequence.sequenceId);
00175         if( sequenceId == 0 ) {
00176                 // silently restart (will advance below)
00177                 m_sequenceId = 0;
00178         }
00179         else {
00180                 if( sequenceId != m_sequenceId ) {
00181                         if( socket != 0 ) {
00182                                 std::ostringstream oss;
00183                                 oss << "Socket 0x" << std::hex << (unsigned int)socket
00184                                         << ": out of sequence. "
00185                                         << "(Global sequence: " << m_sequenceId
00186                                         << ". Packet sequence: " << sequenceId
00187                                         << ")";
00188                                 eout(oss.str());
00189                                 throw Error(oss.str());
00190                         }
00191                         else {
00192                                 dout("Bad sequence on socket 0: expected: "
00193                                         << m_sequenceId
00194                                         << ". Packet sequence: " << sequenceId);
00195                         }
00196                 }
00197         }
00198 
00199         // advance!
00200         m_sequenceId++;
00201 }
00202 
00203 void SocketZero::SendOpen(uint16_t socket, Data &receive)
00204 {
00205         // build open command
00206         Barry::Protocol::Packet packet;
00207         packet.socket = 0;
00208         packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
00209         packet.command = SB_COMMAND_OPEN_SOCKET;
00210         packet.u.socket.socket = htobs(socket);
00211         packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
00212 
00213         Data send(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
00214         try {
00215                 RawSend(send);
00216                 RawReceive(receive);
00217         } catch( Usb::Error & ) {
00218                 eeout(send, receive);
00219                 throw;
00220         }
00221 
00222         // check sequence ID
00223         Protocol::CheckSize(receive, SB_PACKET_HEADER_SIZE);
00224         if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
00225                 CheckSequence(0, receive);
00226 
00227                 // still need our ACK
00228                 RawReceive(receive);
00229         }
00230 
00231         // receive now holds the Open response
00232 }
00233 
00234 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
00235 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
00236 {
00237         unsigned char pwdigest[SHA_DIGEST_LENGTH];
00238         unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
00239 
00240         // first, hash the password by itself
00241         SHA1((unsigned char *) password, strlen(password), pwdigest);
00242 
00243         // prefix the resulting hash with the provided seed
00244         uint32_t seed = htobl(m_challengeSeed);
00245         memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
00246         memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
00247 
00248         // hash again
00249         SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
00250 
00251 
00252         size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
00253 
00254         // build open command
00255         Barry::Protocol::Packet packet;
00256         packet.socket = 0;
00257         packet.size = htobs(size);
00258         packet.command = SB_COMMAND_PASSWORD;
00259         packet.u.socket.socket = htobs(socket);
00260         packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
00261         packet.u.socket.u.password.remaining_tries = 0;
00262         packet.u.socket.u.password.unknown = 0;
00263         packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
00264         memcpy(packet.u.socket.u.password.u.hash, pwdigest,
00265                 sizeof(packet.u.socket.u.password.u.hash));
00266 
00267         // blank password hashes as we don't need these anymore
00268         memset(pwdigest, 0, sizeof(pwdigest));
00269         memset(prefixedhash, 0, sizeof(prefixedhash));
00270 
00271         Data send(&packet, size);
00272         RawSend(send);
00273         RawReceive(receive);
00274 
00275         // blank password hash as we don't need this anymore either
00276         memset(packet.u.socket.u.password.u.hash, 0,
00277                 sizeof(packet.u.socket.u.password.u.hash));
00278         send.Zap();
00279 
00280         // check sequence ID
00281         Protocol::CheckSize(receive, SB_PACKET_HEADER_SIZE);
00282         if( IS_COMMAND(receive, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
00283                 CheckSequence(0, receive);
00284 
00285                 // still need our ACK
00286                 RawReceive(receive);
00287         }
00288 
00289         // receive now holds the Password response
00290 }
00291 
00292 void SocketZero::RawSend(Data &send, int timeout)
00293 {
00294         Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
00295 
00296         // Special case: it seems that sending packets with a size that's an
00297         // exact multiple of 0x40 causes the device to get confused.
00298         //
00299         // To get around that, it is observed in the captures that the size
00300         // is sent in a special 3 byte packet before the real packet.
00301         // Check for this case here.
00302         //
00303         if( (send.GetSize() % 0x40) == 0 ) {
00304                 Protocol::SizePacket packet;
00305                 packet.size = htobs(send.GetSize());
00306                 packet.buffer[2] = 0;           // zero the top byte
00307                 Data sizeCommand(&packet, 3);
00308 
00309                 dev->BulkWrite(m_writeEp, sizeCommand);
00310         }
00311 
00312         dev->BulkWrite(m_writeEp, send);
00313 }
00314 
00315 void SocketZero::RawReceive(Data &receive, int timeout)
00316 {
00317         do {
00318                 if( m_queue ) {
00319                         if( !m_queue->DefaultRead(receive, timeout) )
00320                                 throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
00321                 }
00322                 else {
00323                         m_dev->BulkRead(m_readEp, receive, timeout);
00324                 }
00325                 ddout("SocketZero::RawReceive: Endpoint " << m_readEp
00326                         << "\nReceived:\n" << receive);
00327         } while( SequencePacket(receive) );
00328 }
00329 
00330 //
00331 // SequencePacket
00332 //
00333 /// Returns true if this is a sequence packet that should be ignored.
00334 /// This function is used in SocketZero::RawReceive() in order
00335 /// to determine whether to keep reading or not.  By default,
00336 /// this function checks whether the packet is a sequence packet
00337 /// or not, and returns true if so.  Also, if it is a sequence
00338 /// packet, it checks the validity of the sequence number.
00339 ///
00340 /// If sequence packets become important in the future, this
00341 /// function could be changed to call a user-defined callback,
00342 /// in order to handle these things out of band.
00343 ///
00344 bool SocketZero::SequencePacket(const Data &data)
00345 {
00346         // Begin -- Test quiet durty :(
00347         if (m_hideSequencePacket == false) {
00348                 return false;
00349         }
00350         // End -- Test quiet durty :(
00351 
00352         if( data.GetSize() >= MIN_PACKET_SIZE ) {
00353                 MAKE_PACKET(rpack, data);
00354                 if( rpack->socket == 0 &&
00355                     rpack->command == SB_COMMAND_SEQUENCE_HANDSHAKE )
00356                 {
00357                         CheckSequence(0, data);
00358                         return true;
00359                 }
00360         }
00361         return false;   // not a sequence packet
00362 }
00363 
00364 
00365 ///////////////////////////////////////
00366 // SocketZero public API
00367 
00368 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
00369 {
00370         // replace the current queue pointer
00371         m_queue = &queue;
00372 }
00373 
00374 void SocketZero::UnlinkRoutingQueue()
00375 {
00376         m_queue = 0;
00377 }
00378 
00379 void SocketZero::Send(Data &send, int timeout)
00380 {
00381         // force the socket number to 0
00382         if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
00383                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
00384                 spack->socket = 0;
00385         }
00386 
00387         // This is a socket 0 packet, so force the send packet data's
00388         // socket 0 sequence number to something correct.
00389         if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
00390                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
00391                 spack->u.socket.sequence = m_zeroSocketSequence;
00392                 m_zeroSocketSequence++;
00393         }
00394 
00395         RawSend(send, timeout);
00396 }
00397 
00398 void SocketZero::Send(Data &send, Data &receive, int timeout)
00399 {
00400         Send(send, timeout);
00401         RawReceive(receive, timeout);
00402 }
00403 
00404 void SocketZero::Send(Barry::Packet &packet, int timeout)
00405 {
00406         Send(packet.m_send, packet.m_receive, timeout);
00407 }
00408 
00409 void SocketZero::Receive(Data &receive, int timeout)
00410 {
00411         RawReceive(receive, timeout);
00412 }
00413 
00414 
00415 //
00416 // Open
00417 //
00418 /// Open a logical socket on the device.
00419 ///
00420 /// Both the socket number and the flag are based on the response to the
00421 /// SELECT_MODE command.  See Controller::SelectMode() for more info
00422 /// on this.
00423 ///
00424 /// The packet sequence is normal for most socket operations.
00425 ///
00426 ///     - Down: command packet with OPEN_SOCKET
00427 ///     - Up: optional sequence handshake packet
00428 ///     - Up: command response, which repeats the socket and flag data
00429 ///             as confirmation
00430 ///
00431 /// \exception  Barry::Error
00432 ///             Thrown on protocol error.
00433 ///
00434 /// \exception  Barry::BadPassword
00435 ///             Thrown on invalid password, or not enough retries left
00436 ///             on device.
00437 ///
00438 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
00439 {
00440         // Things get a little funky here, as we may be left in an
00441         // intermediate state in the case of a failed password.
00442         // This function should support being called as many times
00443         // as needed to handle the password
00444 
00445         Data send, receive;
00446         ZeroPacket packet(send, receive);
00447 
00448         // save sequence for later close
00449         uint8_t closeFlag = GetZeroSocketSequence();
00450 
00451         if( !m_halfOpen ) {
00452                 // starting fresh
00453                 m_remainingTries = 0;
00454 
00455                 SendOpen(socket, receive);
00456 
00457                 // check for password challenge, or success
00458                 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
00459                         m_halfOpen = true;
00460                         m_challengeSeed = packet.ChallengeSeed();
00461                         m_remainingTries = packet.RemainingTries();
00462                 }
00463 
00464                 // fall through to challenge code...
00465         }
00466 
00467         if( m_halfOpen ) {
00468                 // half open, device is expecting a password hash... do we
00469                 // have a password?
00470                 if( !password ) {
00471                         throw BadPassword("No password specified.", m_remainingTries, false);
00472                 }
00473 
00474                 // only allow password attempts if there are
00475                 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
00476                 // we want to give the user at least some chance on a
00477                 // Windows machine before the device commits suicide.
00478                 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
00479                         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.",
00480                                 m_remainingTries,
00481                                 true);
00482                 }
00483 
00484                 // save sequence for later close (again after SendOpen())
00485                 closeFlag = GetZeroSocketSequence();
00486 
00487                 SendPasswordHash(socket, password, receive);
00488 
00489                 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
00490                         m_halfOpen = true;
00491                         m_challengeSeed = packet.ChallengeSeed();
00492                         m_remainingTries = packet.RemainingTries();
00493                         throw BadPassword("Password rejected by device.", m_remainingTries, false);
00494                 }
00495 
00496                 // if we get this far, we are no longer in half-open password
00497                 // mode, so we can reset our flags
00498                 m_halfOpen = false;
00499 
00500                 // fall through to success check...
00501         }
00502 
00503         if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
00504             packet.SocketResponse() != socket ||
00505             packet.SocketSequence() != closeFlag )
00506         {
00507                 eout("Packet:\n" << receive);
00508                 throw Error("Socket: Bad OPENED packet in Open");
00509         }
00510 
00511         // success!  save the socket
00512         return SocketHandle(new Socket(*this, socket, closeFlag));
00513 }
00514 
00515 //
00516 // Close
00517 //
00518 /// Closes a non-default socket (i.e. non-zero socket number)
00519 ///
00520 /// The packet sequence is just like Open(), except the command is
00521 /// CLOSE_SOCKET.
00522 ///
00523 /// \exception  Barry::Error
00524 ///
00525 void SocketZero::Close(Socket &socket)
00526 {
00527         if( socket.GetSocket() == 0 )
00528                 return;         // nothing to do
00529 
00530         // build close command
00531         Barry::Protocol::Packet packet;
00532         packet.socket = 0;
00533         packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
00534         packet.command = SB_COMMAND_CLOSE_SOCKET;
00535         packet.u.socket.socket = htobs(socket.GetSocket());
00536         packet.u.socket.sequence = socket.GetCloseFlag();
00537 
00538         Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
00539         Data response;
00540         try {
00541                 Send(command, response);
00542         }
00543         catch( Usb::Error & ) {
00544                 // reset so this won't be called again
00545                 socket.ForceClosed();
00546 
00547                 eeout(command, response);
00548                 throw;
00549         }
00550 
00551         // starting fresh, reset sequence ID
00552         Protocol::CheckSize(response, SB_PACKET_HEADER_SIZE);
00553         if( IS_COMMAND(response, SB_COMMAND_SEQUENCE_HANDSHAKE) ) {
00554                 CheckSequence(0, response);
00555 
00556                 // still need our ACK
00557                 RawReceive(response);
00558         }
00559 
00560         Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
00561         MAKE_PACKET(rpack, response);
00562         if( rpack->command != SB_COMMAND_CLOSED_SOCKET ||
00563             btohs(rpack->u.socket.socket) != socket.GetSocket() ||
00564             rpack->u.socket.sequence != socket.GetCloseFlag() )
00565         {
00566                 // reset so this won't be called again
00567                 socket.ForceClosed();
00568 
00569                 eout("Packet:\n" << response);
00570                 throw BadPacket(rpack->command, "Socket: Bad CLOSED packet in Close");
00571         }
00572 
00573         if( m_resetOnClose ) {
00574                 Data send, receive;
00575                 ZeroPacket reset_packet(send, receive);
00576                 reset_packet.Reset();
00577 
00578                 Send(reset_packet);
00579                 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
00580                         throw BadPacket(reset_packet.CommandResponse(),
00581                                 "Socket: Missing RESET_REPLY in Close");
00582                 }
00583         }
00584 
00585 //      // and finally, there always seems to be an extra read of
00586 //      // an empty packet at the end... just throw it away
00587 //      try {
00588 //              RawReceive(response, 1);
00589 //      }
00590 //      catch( Usb::Timeout & ) {
00591 //      }
00592 
00593         // reset socket and flag
00594         socket.ForceClosed();
00595 }
00596 
00597 
00598 
00599 
00600 
00601 
00602 //////////////////////////////////////////////////////////////////////////////
00603 // Socket class
00604 
00605 Socket::Socket( SocketZero &zero,
00606                 uint16_t socket,
00607                 uint8_t closeFlag)
00608         : m_zero(&zero)
00609         , m_socket(socket)
00610         , m_closeFlag(closeFlag)
00611         , m_registered(false)
00612 {
00613 }
00614 
00615 Socket::~Socket()
00616 {
00617         // trap exceptions in the destructor
00618         try {
00619                 // a non-default socket has been opened, close it
00620                 Close();
00621         }
00622         catch( std::runtime_error &re ) {
00623                 // do nothing... log it?
00624                 dout("Exception caught in ~Socket: " << re.what());
00625         }
00626 }
00627 
00628 
00629 ////////////////////////////////////
00630 // Socket protected API
00631 
00632 void Socket::CheckSequence(const Data &seq)
00633 {
00634         m_zero->CheckSequence(m_socket, seq);
00635 }
00636 
00637 void Socket::ForceClosed()
00638 {
00639         m_socket = 0;
00640         m_closeFlag = 0;
00641 }
00642 
00643 
00644 ////////////////////////////////////
00645 // Socket public API
00646 
00647 void Socket::Close()
00648 {
00649         UnregisterInterest();
00650         m_zero->Close(*this);
00651 }
00652 
00653 
00654 //
00655 // Send
00656 //
00657 /// Sends 'send' data to device, no receive.
00658 ///
00659 /// \returns    void
00660 ///
00661 /// \exception  Usb::Error on underlying bus errors.
00662 ///
00663 void Socket::Send(Data &send, int timeout)
00664 {
00665         // force the socket number to this socket
00666         if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
00667                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
00668                 spack->socket = htobs(m_socket);
00669         }
00670         m_zero->RawSend(send, timeout);
00671 }
00672 
00673 //
00674 // Send
00675 //
00676 /// Sends 'send' data to device, and waits for response.
00677 ///
00678 /// \returns    void
00679 ///
00680 /// \exception  Usb::Error on underlying bus errors.
00681 ///
00682 void Socket::Send(Data &send, Data &receive, int timeout)
00683 {
00684         Send(send, timeout);
00685         Receive(receive, timeout);
00686 }
00687 
00688 void Socket::Send(Barry::Packet &packet, int timeout)
00689 {
00690         Send(packet.m_send, packet.m_receive, timeout);
00691 }
00692 
00693 void Socket::Receive(Data &receive, int timeout)
00694 {
00695         if( m_registered ) {
00696                 if( m_zero->m_queue ) {
00697                         if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
00698                                 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
00699                 }
00700                 else {
00701                         throw std::logic_error("NULL queue pointer in a registered socket read.");
00702                 }
00703         }
00704         else {
00705                 m_zero->RawReceive(receive, timeout);
00706         }
00707 }
00708 
00709 
00710 // sends the send packet down to the device
00711 // Blocks until response received or timed out in Usb::Device
00712 void Socket::PacketData(Data &send, Data &receive, int timeout)
00713 {
00714         if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
00715                 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
00716                 // we don't do that around here
00717                 throw std::logic_error("Socket: unknown send data in PacketData()");
00718         }
00719 
00720         Data &inFrag = receive;
00721         receive.Zap();
00722 
00723         // send non-fragmented
00724         Send(send, inFrag, timeout);
00725 
00726         bool done = false;
00727         int blankCount = 0;
00728 
00729         while( !done ) {
00730                 // check the packet's validity
00731                 if( inFrag.GetSize() > 0 ) {
00732                         MAKE_PACKET(rpack, inFrag);
00733 
00734                         blankCount = 0;
00735 
00736                         Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
00737 
00738                         switch( rpack->command )
00739                         {
00740                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00741                                 CheckSequence(inFrag);
00742                                 if (!m_zero->IsSequencePacketHidden())
00743                                         done = true;
00744                                 break;
00745 
00746                         case SB_COMMAND_JL_READY:
00747                         case SB_COMMAND_JL_ACK:
00748                         case SB_COMMAND_JL_HELLO_ACK:
00749                         case SB_COMMAND_JL_RESET_REQUIRED:
00750                                 done = true;
00751                                 break;
00752 
00753                         case SB_COMMAND_JL_GET_DATA_ENTRY:      // This response means that the next packet is the stream
00754                                 done = true;
00755                                 break;
00756 
00757                         case SB_DATA_JL_INVALID:
00758                                 throw BadPacket(rpack->command, "file is not a valid Java code file");
00759                                 break;
00760 
00761                         case SB_COMMAND_JL_NOT_SUPPORTED:
00762                                 throw BadPacket(rpack->command, "device does not support requested command");
00763                                 break;
00764 
00765                         default:
00766                                 // unknown packet, pass it up to the
00767                                 // next higher code layer
00768                                 done = true;
00769                                 break;
00770                         }
00771                 }
00772                 else {
00773                         blankCount++;
00774                         //std::cerr << "Blank! " << blankCount << std::endl;
00775                         if( blankCount == 10 ) {
00776                                 // only ask for more data on stalled sockets
00777                                 // for so long
00778                                 throw Error("Socket: 10 blank packets received");
00779                         }
00780                 }
00781 
00782                 if( !done ) {
00783                         // not done yet, ask for another read
00784                         Receive(inFrag);
00785                 }
00786         }
00787 }
00788 
00789 // sends the send packet down to the device, fragmenting if
00790 // necessary, and returns the response in receive, defragmenting
00791 // if needed
00792 // Blocks until response received or timed out in Usb::Device
00793 //
00794 // This is primarily for Desktop Database packets... Javaloader
00795 // packets use PacketData().
00796 //
00797 void Socket::Packet(Data &send, Data &receive, int timeout)
00798 {
00799         MAKE_PACKET(spack, send);
00800         if( send.GetSize() < MIN_PACKET_SIZE ||
00801             (spack->command != SB_COMMAND_DB_DATA &&
00802              spack->command != SB_COMMAND_DB_DONE) )
00803         {
00804                 // we don't do that around here
00805                 eout("unknown send data in Packet(): " << send);
00806                 throw std::logic_error("Socket: unknown send data in Packet()");
00807         }
00808 
00809         Data inFrag;
00810         receive.Zap();
00811 
00812         if( send.GetSize() <= MAX_PACKET_SIZE ) {
00813                 // send non-fragmented
00814                 Send(send, inFrag, timeout);
00815         }
00816         else {
00817                 // send fragmented
00818                 unsigned int offset = 0;
00819                 Data outFrag;
00820 
00821                 // You haven't to sequence packet while the whole packet isn't sent
00822                 //  a) No sequence received packet
00823                 //  b) 1°) Sent framgment 1/N
00824                 //     2°) Sent framgment 2/N
00825                 //         ...
00826                 //     N°) Before sent fragment N/N, I enable the sequence packet process.
00827                 //         Sent framgment N/N
00828                 HideSequencePacket(false);
00829 
00830                 do {
00831                         offset = SocketZero::MakeNextFragment(send, outFrag, offset);
00832 
00833                         // Is last packet ?
00834                         MAKE_PACKET(spack, outFrag);
00835 
00836                         if (spack->command != SB_COMMAND_DB_FRAGMENTED)
00837                                 HideSequencePacket(true);
00838 
00839                         Send(outFrag, inFrag, timeout);
00840 
00841                         // only process sequence handshakes... once we
00842                         // get to the last fragment, we fall through to normal
00843                         // processing below
00844                         if (spack->command != SB_COMMAND_DB_FRAGMENTED) {
00845                                 MAKE_PACKET(rpack, inFrag);
00846 
00847                                 if( offset && inFrag.GetSize() > 0 ) {
00848                                         Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
00849 
00850                                         switch( rpack->command )
00851                                         {
00852                                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00853                                                 CheckSequence(inFrag);
00854                                                 break;
00855 
00856                                         default: {
00857                                                 std::ostringstream oss;
00858                                                 oss << "Socket: (send) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
00859                                                 eout(oss.str());
00860                                                 throw Error(oss.str());
00861                                                 }
00862                                                 break;
00863                                         }
00864                                 }
00865                         }
00866 
00867                 } while( offset > 0 );
00868 
00869                 // To be sure that it's clean...
00870                 HideSequencePacket(true);
00871         }
00872 
00873         bool done = false, frag = false;
00874         int blankCount = 0;
00875         while( !done ) {
00876                 MAKE_PACKET(rpack, inFrag);
00877 
00878                 // check the packet's validity
00879                 if( inFrag.GetSize() > 0 ) {
00880                         blankCount = 0;
00881 
00882                         Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
00883 
00884                         switch( rpack->command )
00885                         {
00886                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00887                                 CheckSequence(inFrag);
00888                                 break;
00889 
00890                         case SB_COMMAND_DB_DATA:
00891                                 if( frag ) {
00892                                         SocketZero::AppendFragment(receive, inFrag);
00893                                 }
00894                                 else {
00895                                         receive = inFrag;
00896                                 }
00897                                 done = true;
00898                                 break;
00899 
00900                         case SB_COMMAND_DB_FRAGMENTED:
00901                                 SocketZero::AppendFragment(receive, inFrag);
00902                                 frag = true;
00903                                 break;
00904 
00905                         case SB_COMMAND_DB_DONE:
00906                                 receive = inFrag;
00907                                 done = true;
00908                                 break;
00909 
00910                         default: {
00911                                 std::ostringstream oss;
00912                                 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
00913                                 eout(oss.str());
00914                                 throw Error(oss.str());
00915                                 }
00916                                 break;
00917                         }
00918                 }
00919                 else {
00920                         blankCount++;
00921                         //std::cerr << "Blank! " << blankCount << std::endl;
00922                         if( blankCount == 10 ) {
00923                                 // only ask for more data on stalled sockets
00924                                 // for so long
00925                                 throw Error("Socket: 10 blank packets received");
00926                         }
00927                 }
00928 
00929                 if( !done ) {
00930                         // not done yet, ask for another read
00931                         Receive(inFrag);
00932                 }
00933         }
00934 }
00935 
00936 void Socket::Packet(Barry::Packet &packet, int timeout)
00937 {
00938         Packet(packet.m_send, packet.m_receive, timeout);
00939 }
00940 
00941 void Socket::Packet(Barry::JLPacket &packet, int timeout)
00942 {
00943         if( packet.HasData() ) {
00944                 HideSequencePacket(false);
00945                 PacketData(packet.m_cmd, packet.m_receive, timeout);
00946                 HideSequencePacket(true);
00947                 PacketData(packet.m_data, packet.m_receive, timeout);
00948         }
00949         else {
00950                 PacketData(packet.m_cmd, packet.m_receive, timeout);
00951         }
00952 }
00953 
00954 void Socket::NextRecord(Data &receive)
00955 {
00956         Barry::Protocol::Packet packet;
00957         packet.socket = htobs(GetSocket());
00958         packet.size = htobs(7);
00959         packet.command = SB_COMMAND_DB_DONE;
00960         packet.u.db.tableCmd = 0;
00961         packet.u.db.u.command.operation = 0;
00962 
00963         Data command(&packet, 7);
00964         Packet(command, receive);
00965 }
00966 
00967 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandler handler,
00968                                 void *context)
00969 {
00970         if( !m_zero->m_queue )
00971                 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
00972 
00973         if( m_registered )
00974                 throw std::logic_error("Socket already registered in Socket::RegisterInterest()!");
00975 
00976         m_zero->m_queue->RegisterInterest(m_socket, handler, context);
00977         m_registered = true;
00978 }
00979 
00980 void Socket::UnregisterInterest()
00981 {
00982         if( m_registered ) {
00983                 if( m_zero->m_queue )
00984                         m_zero->m_queue->UnregisterInterest(m_socket);
00985                 m_registered = false;
00986         }
00987 }
00988 
00989 
00990 } // namespace Barry
00991 

Generated on Tue Jun 30 16:08:14 2009 for Barry by  doxygen 1.5.8