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-2012, 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_modeSequencePacketSeen(false)
00056         , m_pushback(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_modeSequencePacketSeen(false)
00073         , m_pushback(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                 if( Protocol::IsSequencePacket(receive) ) {
00218                         m_modeSequencePacketSeen = true;
00219                         // during open, we could get a sequence packet in
00220                         // the middle, from the SelectMode operation
00221                         RawReceive(receive);
00222                 }
00223         } catch( Usb::Error & ) {
00224                 eeout(send, receive);
00225                 throw;
00226         }
00227 
00228         // receive now holds the Open response
00229 }
00230 
00231 // SHA1 hashing logic based on Rick Scott's XmBlackBerry's send_password()
00232 void SocketZero::SendPasswordHash(uint16_t socket, const char *password, Data &receive)
00233 {
00234         unsigned char pwdigest[SHA_DIGEST_LENGTH];
00235         unsigned char prefixedhash[SHA_DIGEST_LENGTH + 4];
00236 
00237         // first, hash the password by itself
00238         SHA1((unsigned char *) password, strlen(password), pwdigest);
00239 
00240         // prefix the resulting hash with the provided seed
00241         uint32_t seed = htobl(m_challengeSeed);
00242         memcpy(&prefixedhash[0], &seed, sizeof(uint32_t));
00243         memcpy(&prefixedhash[4], pwdigest, SHA_DIGEST_LENGTH);
00244 
00245         // hash again
00246         SHA1((unsigned char *) prefixedhash, SHA_DIGEST_LENGTH + 4, pwdigest);
00247 
00248 
00249         size_t size = SB_SOCKET_PACKET_HEADER_SIZE + PASSWORD_CHALLENGE_SIZE;
00250 
00251         // build open command
00252         Barry::Protocol::Packet packet;
00253         packet.socket = 0;
00254         packet.size = htobs(size);
00255         packet.command = SB_COMMAND_PASSWORD;
00256         packet.u.socket.socket = htobs(socket);
00257         packet.u.socket.sequence = m_zeroSocketSequence;// overwritten by Send()
00258         packet.u.socket.u.password.remaining_tries = 0;
00259         packet.u.socket.u.password.unknown = 0;
00260         packet.u.socket.u.password.param = htobs(0x14); // FIXME - what does this mean?
00261         memcpy(packet.u.socket.u.password.u.hash, pwdigest,
00262                 sizeof(packet.u.socket.u.password.u.hash));
00263 
00264         // blank password hashes as we don't need these anymore
00265         memset(pwdigest, 0, sizeof(pwdigest));
00266         memset(prefixedhash, 0, sizeof(prefixedhash));
00267 
00268         Data send(&packet, size);
00269         RawSend(send);
00270         RawReceive(receive);
00271 
00272         // blank password hash as we don't need this anymore either
00273         memset(packet.u.socket.u.password.u.hash, 0,
00274                 sizeof(packet.u.socket.u.password.u.hash));
00275         send.Zap();
00276 
00277         // check sequence ID
00278         if( Protocol::IsSequencePacket(receive) ) {
00279                 m_modeSequencePacketSeen = true;
00280 
00281                 CheckSequence(0, receive);
00282 
00283                 // still need our ACK
00284                 RawReceive(receive);
00285         }
00286 
00287         // receive now holds the Password response
00288 }
00289 
00290 void SocketZero::RawSend(Data &send, int timeout)
00291 {
00292         Usb::Device *dev = m_queue ? m_queue->GetUsbDevice() : m_dev;
00293         if( !dev )
00294                 throw Error("SocketZero: No device available for RawSend");
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, timeout);
00310         }
00311 
00312         dev->BulkWrite(m_writeEp, send, timeout);
00313 }
00314 
00315 void SocketZero::RawReceive(Data &receive, int timeout)
00316 {
00317         if( m_pushback ) {
00318                 receive = m_pushback_buffer;
00319                 m_pushback = false;
00320                 return;
00321         }
00322 
00323         if( m_queue ) {
00324                 if( !m_queue->DefaultRead(receive, timeout) )
00325                         throw Timeout("SocketZero::RawReceive: queue DefaultRead returned false (likely a timeout)");
00326         }
00327         else {
00328                 m_dev->BulkRead(m_readEp, receive, timeout);
00329         }
00330 
00331         ddout("SocketZero::RawReceive: Endpoint "
00332                 << (m_queue ? m_queue->GetReadEp() : m_readEp)
00333                 << "\nReceived:\n" << receive);
00334 }
00335 
00336 void SocketZero::Pushback(const Data &buf)
00337 {
00338         if( m_pushback )
00339                 throw Error("Multiple pushbacks");
00340 
00341         m_pushback = true;
00342         m_pushback_buffer = buf;
00343 }
00344 
00345 
00346 ///////////////////////////////////////
00347 // SocketZero public API
00348 
00349 void SocketZero::SetRoutingQueue(SocketRoutingQueue &queue)
00350 {
00351         // replace the current queue pointer
00352         m_queue = &queue;
00353 }
00354 
00355 void SocketZero::UnlinkRoutingQueue()
00356 {
00357         m_queue = 0;
00358 }
00359 
00360 void SocketZero::Send(Data &send, int timeout)
00361 {
00362         // force the socket number to 0
00363         if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
00364                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
00365                 spack->socket = 0;
00366         }
00367 
00368         // This is a socket 0 packet, so force the send packet data's
00369         // socket 0 sequence number to something correct.
00370         if( send.GetSize() >= SB_SOCKET_PACKET_HEADER_SIZE ) {
00371                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
00372                 spack->u.socket.sequence = m_zeroSocketSequence;
00373                 m_zeroSocketSequence++;
00374         }
00375 
00376         RawSend(send, timeout);
00377 }
00378 
00379 void SocketZero::Send(Data &send, Data &receive, int timeout)
00380 {
00381         Send(send, timeout);
00382         RawReceive(receive, timeout);
00383 }
00384 
00385 void SocketZero::Send(Barry::Packet &packet, int timeout)
00386 {
00387         Send(packet.m_send, *packet.m_receive, timeout);
00388 }
00389 
00390 void SocketZero::Receive(Data &receive, int timeout)
00391 {
00392         RawReceive(receive, timeout);
00393 }
00394 
00395 
00396 //
00397 // Open
00398 //
00399 /// Open a logical socket on the device.
00400 ///
00401 /// Both the socket number and the flag are based on the response to the
00402 /// SELECT_MODE command.  See Controller::SelectMode() for more info
00403 /// on this.
00404 ///
00405 /// The packet sequence is normal for most socket operations.
00406 ///
00407 ///     - Down: command packet with OPEN_SOCKET
00408 ///     - Up: optional sequence handshake packet
00409 ///     - Up: command response, which repeats the socket and flag data
00410 ///             as confirmation
00411 ///
00412 /// \exception  Barry::Error
00413 ///             Thrown on protocol error.
00414 ///
00415 /// \exception  Barry::BadPassword
00416 ///             Thrown on invalid password, or not enough retries left
00417 ///             on device.
00418 ///
00419 SocketHandle SocketZero::Open(uint16_t socket, const char *password)
00420 {
00421         // Things get a little funky here, as we may be left in an
00422         // intermediate state in the case of a failed password.
00423         // This function should support being called as many times
00424         // as needed to handle the password
00425 
00426         Data send, receive;
00427         ZeroPacket packet(send, receive);
00428 
00429         // save sequence for later close
00430         uint8_t closeFlag = GetZeroSocketSequence();
00431 
00432         if( !m_halfOpen ) {
00433                 // starting fresh
00434                 m_remainingTries = 0;
00435 
00436                 // this gets set to true if we see a starting sequence packet
00437                 // during any of our open and password commands... After
00438                 // a mode command (like "RIM Desktop", etc.) a starting
00439                 // sequence packet is sent, and may arrive before or after
00440                 // the socket open handshake.
00441                 m_modeSequencePacketSeen = false;
00442 
00443                 // go for it!
00444                 SendOpen(socket, receive);
00445 
00446                 // check for password challenge, or success
00447                 if( packet.Command() == SB_COMMAND_PASSWORD_CHALLENGE ) {
00448                         m_halfOpen = true;
00449                         m_challengeSeed = packet.ChallengeSeed();
00450                         m_remainingTries = packet.RemainingTries();
00451                 }
00452 
00453                 // fall through to challenge code...
00454         }
00455 
00456         if( m_halfOpen ) {
00457                 // half open, device is expecting a password hash... do we
00458                 // have a password?
00459                 if( !password ) {
00460                         throw BadPassword("No password specified.", m_remainingTries, false);
00461                 }
00462 
00463                 // only allow password attempts if there are
00464                 // BARRY_MIN_PASSWORD_TRIES or more tries remaining...
00465                 // we want to give the user at least some chance on a
00466                 // Windows machine before the device commits suicide.
00467                 if( m_remainingTries < BARRY_MIN_PASSWORD_TRIES ) {
00468                         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.",
00469                                 m_remainingTries,
00470                                 true);
00471                 }
00472 
00473                 // save sequence for later close (again after SendOpen())
00474                 closeFlag = GetZeroSocketSequence();
00475 
00476                 SendPasswordHash(socket, password, receive);
00477 
00478                 if( packet.Command() == SB_COMMAND_PASSWORD_FAILED ) {
00479                         m_halfOpen = true;
00480                         m_challengeSeed = packet.ChallengeSeed();
00481                         m_remainingTries = packet.RemainingTries();
00482                         throw BadPassword("Password rejected by device.", m_remainingTries, false);
00483                 }
00484 
00485                 // if we get this far, we are no longer in half-open password
00486                 // mode, so we can reset our flags
00487                 m_halfOpen = false;
00488 
00489                 // fall through to success check...
00490         }
00491 
00492         // If the device thinks that the socket was already open then
00493         // it will tell us by sending an SB_COMMAND_CLOSE_SOCKET.
00494         //
00495         // This happens most commonly when using raw channels which
00496         // haven't been cleanly closed (such as by killing the process
00497         // running Barry) and so the device still thinks the socket
00498         // is open.
00499         //
00500         // Retrying the open will usually succeed, but relies on the
00501         // device software re-creating the channel after it's closed
00502         // so return an error here instead of automatically retrying.
00503         if( packet.Command() == SB_COMMAND_CLOSE_SOCKET )
00504         {
00505                 throw SocketCloseOnOpen("Socket: Device closed socket when trying to open (can be caused by the wrong password, or if the device thinks the socket is already open... please try again)");
00506         }
00507 
00508         if( packet.Command() != SB_COMMAND_OPENED_SOCKET ||
00509             packet.SocketResponse() != socket ||
00510             packet.SocketSequence() != closeFlag )
00511         {
00512                 eout("Packet:\n" << receive);
00513                 throw Error("Socket: Bad OPENED packet in Open");
00514         }
00515 
00516         // if no sequence packet has yet arrived, wait for it here
00517         if( !m_modeSequencePacketSeen ) {
00518                 Data sequence;
00519                 RawReceive(sequence);
00520                 if( !Protocol::IsSequencePacket(sequence) ) {
00521                         // if this is not the sequence packet, then it might
00522                         // just be out of order (some devices do this when
00523                         // opening the JavaLoader mode), so as a last
00524                         // ditch effort, do one more read with a short
00525                         // timeout, and check that as well
00526                         Data late_sequence;
00527                         RawReceive(late_sequence, 500);
00528                         if( !Protocol::IsSequencePacket(late_sequence) ) {
00529                                 throw Error("Could not find mode's starting sequence packet");
00530                         }
00531 
00532                         // ok, so our ditch effort worked, but now we have
00533                         // a leftover packet on our hands... do a temporary
00534                         // pushback
00535                         Pushback(sequence);
00536                 }
00537         }
00538 
00539         // success!  save the socket
00540         Socket *sock = new Socket(*this, socket, closeFlag);
00541         SocketHandle sh(sock);
00542 
00543         // if we are running with a routing queue, register the
00544         // socket's interest in all its own data.  By default, this
00545         // data will be queued without a callback handler.
00546         // If other application code needs to intercept this with
00547         // its own handler, it must call UnregisterInterest() and
00548         // re-register its own handler.
00549         if( m_queue ) {
00550                 sock->RegisterInterest();
00551         }
00552 
00553         return sh;
00554 }
00555 
00556 //
00557 // Close
00558 //
00559 /// Closes a non-default socket (i.e. non-zero socket number)
00560 ///
00561 /// The packet sequence is just like Open(), except the command is
00562 /// CLOSE_SOCKET.
00563 ///
00564 /// \exception  Barry::Error
00565 ///
00566 void SocketZero::Close(Socket &socket)
00567 {
00568         if( socket.GetSocket() == 0 )
00569                 return;         // nothing to do
00570 
00571         // build close command
00572         Barry::Protocol::Packet packet;
00573         packet.socket = 0;
00574         packet.size = htobs(SB_SOCKET_PACKET_HEADER_SIZE);
00575         packet.command = SB_COMMAND_CLOSE_SOCKET;
00576         packet.u.socket.socket = htobs(socket.GetSocket());
00577         packet.u.socket.sequence = socket.GetCloseFlag();
00578 
00579         Data command(&packet, SB_SOCKET_PACKET_HEADER_SIZE);
00580         Data response;
00581         try {
00582                 Send(command, response);
00583         }
00584         catch( Usb::Error & ) {
00585                 // reset so this won't be called again
00586                 socket.ForceClosed();
00587 
00588                 eeout(command, response);
00589                 throw;
00590         }
00591 
00592         // starting fresh, reset sequence ID
00593         if( Protocol::IsSequencePacket(response) ) {
00594                 CheckSequence(0, response);
00595 
00596                 // still need our ACK
00597                 RawReceive(response);
00598         }
00599 
00600         Protocol::CheckSize(response, SB_SOCKET_PACKET_HEADER_SIZE);
00601         MAKE_PACKET(rpack, response);
00602         // The reply will be SB_COMMAND_CLOSED_SOCKET if the device
00603         // has closed the socket in response to our request.
00604         //
00605         // It's also possible for the reply to be
00606         // SB_COMMAND_REMOTE_CLOSE_SOCKET if the device wanted to
00607         // close the socket at the same time, such as if the channel
00608         // API is being used by the device.
00609         if( ( rpack->command != SB_COMMAND_CLOSED_SOCKET &&
00610               rpack->command != SB_COMMAND_REMOTE_CLOSE_SOCKET ) ||
00611             btohs(rpack->u.socket.socket) != socket.GetSocket() ||
00612             rpack->u.socket.sequence != socket.GetCloseFlag() )
00613         {
00614                 // reset so this won't be called again
00615                 socket.ForceClosed();
00616 
00617                 eout("Packet:\n" << response);
00618                 throw BadPacket(rpack->command, "Socket: Bad CLOSED packet in Close");
00619         }
00620 
00621         if( socket.IsResetOnClose() ) {
00622                 Data send, receive;
00623                 ZeroPacket reset_packet(send, receive);
00624                 reset_packet.Reset();
00625 
00626                 Send(reset_packet);
00627                 if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
00628                         throw BadPacket(reset_packet.CommandResponse(),
00629                                 "Socket: Missing RESET_REPLY in Close");
00630                 }
00631         }
00632 
00633 //      // and finally, there always seems to be an extra read of
00634 //      // an empty packet at the end... just throw it away
00635 //      try {
00636 //              RawReceive(response, 1);
00637 //      }
00638 //      catch( Usb::Timeout & ) {
00639 //      }
00640 
00641         // reset socket and flag
00642         socket.ForceClosed();
00643 }
00644 
00645 
00646 
00647 
00648 
00649 //////////////////////////////////////////////////////////////////////////////
00650 // SocketBase class
00651 
00652 SocketBase::~SocketBase()
00653 {
00654 }
00655 
00656 void SocketBase::CheckSequence(const Data &seq)
00657 {
00658         // FIXME - needs implementation
00659 }
00660 
00661 //
00662 // DBFragSend
00663 //
00664 /// Sends a fragmented Desktop / Database command packet.
00665 /// Assumes that 'send' contains a valid packet, which may or may not
00666 /// need fragmentation.  If it does, fragmentation will be done
00667 /// automatically.
00668 ///
00669 void SocketBase::DBFragSend(Data &send, int timeout)
00670 {
00671         MAKE_PACKET(spack, send);
00672         if( send.GetSize() < MIN_PACKET_SIZE ||
00673             (spack->command != SB_COMMAND_DB_DATA &&
00674              spack->command != SB_COMMAND_DB_DONE) )
00675         {
00676                 // we don't do that around here
00677                 eout("unknown send data in DBFragSend(): " << send);
00678                 throw std::logic_error("Socket: unknown send data in DBFragSend()");
00679         }
00680 
00681         if( send.GetSize() <= MAX_PACKET_SIZE ) {
00682                 // send non-fragmented
00683                 SyncSend(send, timeout);
00684         }
00685         else {
00686                 // send fragmented
00687                 unsigned int offset = 0;
00688                 Data outFrag;
00689 
00690                 do {
00691                         offset = SocketZero::MakeNextFragment(send, outFrag, offset);
00692                         SyncSend(outFrag, timeout);
00693                 } while( offset > 0 );
00694         }
00695 
00696 }
00697 
00698 //
00699 // Send
00700 //
00701 /// SyncSends 'send' data to device, and waits for response.
00702 ///
00703 /// \returns    void
00704 ///
00705 /// \exception  Usb::Error on underlying bus errors.
00706 ///
00707 void SocketBase::Send(Data &send, Data &receive, int timeout)
00708 {
00709         SyncSend(send, timeout);
00710         Receive(receive, timeout);
00711 }
00712 
00713 void SocketBase::Send(Barry::Packet &packet, int timeout)
00714 {
00715         Send(packet.m_send, *packet.m_receive, timeout);
00716 }
00717 
00718 // sends the send packet down to the device, fragmenting if
00719 // necessary, and returns the response in receive, defragmenting
00720 // if needed
00721 // Blocks until response received or timed out in Usb::Device
00722 //
00723 // This is primarily for Desktop Database packets... Javaloader
00724 // packets use PacketData().
00725 //
00726 void SocketBase::Packet(Data &send, Data &receive, int timeout)
00727 {
00728         // assume the common case of no fragmentation,
00729         // and use the receive buffer for input... allocate a frag buffer
00730         // later if necessary
00731         Data *inputBuf = &receive;
00732         receive.Zap();
00733 
00734         DBFragSend(send, timeout);
00735         Receive(*inputBuf, timeout);
00736 
00737         std::auto_ptr<Data> inFrag;
00738         bool done = false, frag = false;
00739         int blankCount = 0;
00740         while( !done ) {
00741                 MAKE_PACKET(rpack, *inputBuf);
00742 
00743                 // check the packet's validity
00744                 if( inputBuf->GetSize() > 0 ) {
00745                         blankCount = 0;
00746 
00747                         Protocol::CheckSize(*inputBuf, SB_PACKET_HEADER_SIZE);
00748 
00749                         switch( rpack->command )
00750                         {
00751                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00752                                 CheckSequence(*inputBuf);
00753                                 break;
00754 
00755                         case SB_COMMAND_DB_DATA:
00756                                 if( frag ) {
00757                                         SocketZero::AppendFragment(receive, *inputBuf);
00758                                 }
00759                                 else {
00760                                         // no copy needed, already in receive,
00761                                         // since inputBuf starts out that way
00762                                 }
00763                                 done = true;
00764                                 break;
00765 
00766                         case SB_COMMAND_DB_FRAGMENTED:
00767                                 // only copy if frag is true, since the
00768                                 // first time through, receive == inputBuf
00769                                 if( frag ) {
00770                                         SocketZero::AppendFragment(receive, *inputBuf);
00771                                 }
00772                                 frag = true;
00773                                 break;
00774 
00775                         case SB_COMMAND_DB_DONE:
00776                                 // no copy needed, already in receive
00777                                 done = true;
00778                                 break;
00779 
00780                         default: {
00781                                 std::ostringstream oss;
00782                                 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
00783                                 eout(oss.str());
00784                                 throw Error(oss.str());
00785                                 }
00786                                 break;
00787                         }
00788                 }
00789                 else {
00790                         blankCount++;
00791                         //std::cerr << "Blank! " << blankCount << std::endl;
00792                         if( blankCount == 10 ) {
00793                                 // only ask for more data on stalled sockets
00794                                 // for so long
00795                                 throw Error("Socket: 10 blank packets received");
00796                         }
00797                 }
00798 
00799                 if( !done ) {
00800                         // not done yet, ask for another read, and
00801                         // create new buffer for fragmented reads
00802                         if( frag && !inFrag.get() ) {
00803                                 inFrag.reset( new Data );
00804                                 inputBuf = inFrag.get();
00805                         }
00806                         Receive(*inputBuf);
00807                 }
00808         }
00809 }
00810 
00811 void SocketBase::Packet(Barry::Packet &packet, int timeout)
00812 {
00813         Packet(packet.m_send, *packet.m_receive, timeout);
00814 }
00815 
00816 void SocketBase::Packet(Barry::JLPacket &packet, int timeout)
00817 {
00818         if( packet.HasData() ) {
00819                 SyncSend(packet.m_cmd);
00820                 PacketData(packet.m_data, *packet.m_receive, false, timeout);
00821         }
00822         else {
00823                 PacketData(packet.m_cmd, *packet.m_receive, false, timeout);
00824         }
00825 }
00826 
00827 void SocketBase::Packet(Barry::JVMPacket &packet, int timeout)
00828 {
00829         PacketJVM(packet.m_cmd, *packet.m_receive, timeout);
00830 }
00831 
00832 // sends the send packet down to the device
00833 // Blocks until response received or timed out in Usb::Device
00834 //
00835 // This function is used to send packet to JVM
00836 void SocketBase::PacketJVM(Data &send, Data &receive, int timeout)
00837 {
00838         if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
00839                 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
00840                 // we don't do that around here
00841                 throw std::logic_error("Socket: unknown send data in PacketJVM()");
00842         }
00843 
00844         Data &inFrag = receive;
00845         receive.Zap();
00846 
00847         // send non-fragmented
00848         RawSend(send, timeout);
00849         Receive(inFrag, timeout);
00850 
00851         bool done = false;
00852         int blankCount = 0;
00853 
00854         while( !done ) {
00855                 // check the packet's validity
00856                 if( inFrag.GetSize() > 6 ) {
00857                         MAKE_PACKET(rpack, inFrag);
00858 
00859                         blankCount = 0;
00860 
00861                         Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
00862 
00863                         switch( rpack->command )
00864                         {
00865                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00866                                 CheckSequence(inFrag);
00867                                 break;
00868 
00869                         default: {
00870                                 std::ostringstream oss;
00871                                 oss << "Socket: (read) unhandled packet in Packet(): 0x" << std::hex << (unsigned int)rpack->command;
00872                                 eout(oss.str());
00873                                 throw Error(oss.str());
00874                                 }
00875                                 break;
00876                         }
00877                 }
00878                 else if( inFrag.GetSize() == 6 ) {
00879                         done = true;
00880                 }
00881                 else {
00882                         blankCount++;
00883 
00884                         //std::cerr << "Blank! " << blankCount << std::endl;
00885                         if( blankCount == 10 ) {
00886                                 // only ask for more data on stalled sockets
00887                                 // for so long
00888                                 throw Error("Socket: 10 blank packets received");
00889                         }
00890                 }
00891 
00892                 if( !done ) {
00893                         // not done yet, ask for another read
00894                         Receive(inFrag, timeout);
00895                 }
00896         }
00897 }
00898 
00899 // sends the send packet down to the device
00900 // Blocks until response received or timed out in Usb::Device
00901 void SocketBase::PacketData(Data &send,
00902                                 Data &receive,
00903                                 bool done_on_sequence,
00904                                 int timeout)
00905 {
00906         if( ( send.GetSize() < MIN_PACKET_DATA_SIZE ) ||
00907                 ( send.GetSize() > MAX_PACKET_DATA_SIZE ) ) {
00908                 // we don't do that around here
00909                 throw std::logic_error("Socket: unknown send data in PacketData()");
00910         }
00911 
00912         Data &inFrag = receive;
00913         receive.Zap();
00914 
00915         // send non-fragmented
00916         SyncSend(send, timeout);
00917         Receive(inFrag, timeout);
00918 
00919         bool done = false;
00920         int blankCount = 0;
00921 
00922         while( !done ) {
00923                 // check the packet's validity
00924                 if( inFrag.GetSize() > 0 ) {
00925                         MAKE_PACKET(rpack, inFrag);
00926 
00927                         blankCount = 0;
00928 
00929                         Protocol::CheckSize(inFrag, SB_PACKET_HEADER_SIZE);
00930 
00931                         switch( rpack->command )
00932                         {
00933                         case SB_COMMAND_SEQUENCE_HANDSHAKE:
00934 //                              CheckSequence(inFrag);
00935                                 if( done_on_sequence )
00936                                         done = true;
00937                                 break;
00938 
00939                         case SB_COMMAND_JL_READY:
00940                         case SB_COMMAND_JL_ACK:
00941                         case SB_COMMAND_JL_HELLO_ACK:
00942                         case SB_COMMAND_JL_RESET_REQUIRED:
00943                                 done = true;
00944                                 break;
00945 
00946                         case SB_COMMAND_JL_GET_DATA_ENTRY:      // This response means that the next packet is the stream
00947                                 done = true;
00948                                 break;
00949 
00950                         case SB_DATA_JL_INVALID:
00951                                 throw BadPacket(rpack->command, "file is not a valid Java code file");
00952                                 break;
00953 
00954                         case SB_COMMAND_JL_NOT_SUPPORTED:
00955                                 throw BadPacket(rpack->command, "device does not support requested command");
00956                                 break;
00957 
00958                         default:
00959                                 // unknown packet, pass it up to the
00960                                 // next higher code layer
00961                                 done = true;
00962                                 break;
00963                         }
00964                 }
00965                 else {
00966                         blankCount++;
00967                         //std::cerr << "Blank! " << blankCount << std::endl;
00968                         if( blankCount == 10 ) {
00969                                 // only ask for more data on stalled sockets
00970                                 // for so long
00971                                 throw Error("Socket: 10 blank packets received");
00972                         }
00973                 }
00974 
00975                 if( !done ) {
00976                         // not done yet, ask for another read
00977                         Receive(inFrag);
00978                 }
00979         }
00980 }
00981 
00982 void SocketBase::NextRecord(Data &receive)
00983 {
00984         Barry::Protocol::Packet packet;
00985         packet.size = htobs(7);
00986         packet.command = SB_COMMAND_DB_DONE;
00987         packet.u.db.tableCmd = 0;
00988         packet.u.db.u.command.operation = 0;
00989 
00990         Data command(&packet, 7);
00991         Packet(command, receive);
00992 }
00993 
00994 
00995 
00996 //////////////////////////////////////////////////////////////////////////////
00997 // Socket class
00998 
00999 Socket::Socket( SocketZero &zero,
01000                 uint16_t socket,
01001                 uint8_t closeFlag)
01002         : m_zero(&zero)
01003         , m_socket(socket)
01004         , m_closeFlag(closeFlag)
01005         , m_registered(false)
01006         , m_sequence(new Data)
01007 {
01008 }
01009 
01010 Socket::~Socket()
01011 {
01012         // trap exceptions in the destructor
01013         try {
01014                 // a non-default socket has been opened, close it
01015                 LocalClose();
01016         }
01017         catch( std::runtime_error &re ) {
01018                 // do nothing... log it?
01019                 dout("Exception caught in ~Socket: " << re.what());
01020         }
01021 }
01022 
01023 
01024 ////////////////////////////////////
01025 // Socket protected API
01026 
01027 void Socket::ForceClosed()
01028 {
01029         m_socket = 0;
01030         m_closeFlag = 0;
01031 }
01032 
01033 void Socket::LocalClose()
01034 {
01035         LocalUnregisterInterest();
01036         m_zero->Close(*this);
01037 }
01038 
01039 void Socket::LocalUnregisterInterest()
01040 {
01041         if( m_registered ) {
01042                 if( m_zero->m_queue )
01043                         m_zero->m_queue->UnregisterInterest(m_socket);
01044                 m_registered = false;
01045         }
01046 }
01047 
01048 
01049 //
01050 // Send
01051 //
01052 /// Sends 'send' data to device, no receive.
01053 ///
01054 /// \returns    void
01055 ///
01056 /// \exception  Usb::Error on underlying bus errors.
01057 ///
01058 void Socket::RawSend(Data &send, int timeout)
01059 {
01060         // force the socket number to this socket
01061         if( send.GetSize() >= SB_PACKET_HEADER_SIZE ) {
01062                 MAKE_PACKETPTR_BUF(spack, send.GetBuffer());
01063                 spack->socket = htobs(m_socket);
01064         }
01065         m_zero->RawSend(send, timeout);
01066 }
01067 
01068 void Socket::SyncSend(Data &send, int timeout)
01069 {
01070         RawSend(send, timeout);
01071         Receive(*m_sequence, timeout);
01072         if( !Protocol::IsSequencePacket(*m_sequence) )
01073                 throw Barry::Error("Non-sequence packet in Socket::SyncSend()");
01074         CheckSequence(*m_sequence);
01075 }
01076 
01077 void Socket::Receive(Data &receive, int timeout)
01078 {
01079         if( m_registered ) {
01080                 if( m_zero->m_queue ) {
01081                         if( !m_zero->m_queue->SocketRead(m_socket, receive, timeout) )
01082                                 throw Timeout("Socket::Receive: queue SocketRead returned false (likely a timeout)");
01083                 }
01084                 else {
01085                         throw std::logic_error("NULL queue pointer in a registered socket read.");
01086                 }
01087                 ddout("Socket::Receive: Endpoint "
01088                         << (m_zero->m_queue ? m_zero->m_queue->GetReadEp() : m_zero->m_readEp)
01089                         << "\nReceived:\n" << receive);
01090         }
01091         else {
01092                 m_zero->RawReceive(receive, timeout);
01093         }
01094 }
01095 
01096 
01097 void Socket::RegisterInterest(SocketRoutingQueue::SocketDataHandlerPtr handler)
01098 {
01099         if( !m_zero->m_queue )
01100                 throw std::logic_error("SocketRoutingQueue required in SocketZero in order to call Socket::RegisterInterest()");
01101 
01102         if( m_registered ) {
01103                 std::ostringstream oss;
01104                 oss << "Socket (" << m_socket << ") already registered in Socket::RegisterInterest()!";
01105                 throw std::logic_error(oss.str());
01106         }
01107 
01108         m_zero->m_queue->RegisterInterest(m_socket, handler);
01109         m_registered = true;
01110 }
01111 
01112 
01113 } // namespace Barry
01114