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