# m_raw_channel.cc

Go to the documentation of this file.

    00001 ///
    00002 /// \file       m_raw_channel.cc
    00003 ///             Mode class for a raw channel
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00008     Portions Copyright (C) 2010 RealVNC Ltd.
    00009
    00010     This program is free software; you can redistribute it and/or modify
    00011     it under the terms of the GNU General Public License as published by
    00012     the Free Software Foundation; either version 2 of the License, or
    00013     (at your option) any later version.
    00014
    00015     This program is distributed in the hope that it will be useful,
    00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00018
    00019     See the GNU General Public License in the COPYING file at the
    00020     root directory of this project for more details.
    00021 */
    00022
    00023 #include "m_raw_channel.h"
    00024 #include "semaphore.h"
    00025 #include "data.h"
    00026 #include "protocol.h"
    00027 #include "protostructs.h"
    00028 #include "packet.h"
    00029 #include "endian.h"
    00030 #include "error.h"
    00031 #include "usbwrap.h"
    00032 #include "controller.h"
    00033 #include <stdexcept>
    00034 #include <sstream>
    00035 #include <cstring>
    00036 #include <string>
    00037 #include "protostructs.h"
    00038
    00039 #include "debug.h"
    00040
    00041 namespace Barry { namespace Mode {
    00042
    00043 ///////////////////////////////////////////////////////////////////////////////
    00044 // RawChannel SocketDataHandler callback class for data socket
    00045 class RawChannelSocketHandler: public SocketRoutingQueue::SocketDataHandler
    00046 {
    00047         RawChannel &m_raw_channel;
    00048 public:
    00049         RawChannelSocketHandler(RawChannel &raw_channel)
    00050                 : m_raw_channel(raw_channel)
    00051         {}
    00052         virtual void DataReceived(Data &data)
    00053         {
    00054                 m_raw_channel.HandleReceivedData(data);
    00055         }
    00056         virtual void Error(Barry::Error &error)
    00057         {
    00058                 SocketDataHandler::Error(error);
    00059                 m_raw_channel.HandleError(error);
    00060         }
    00061         virtual ~RawChannelSocketHandler()
    00062         {}
    00063 };
    00064
    00065 ///////////////////////////////////////////////////////////////////////////////
    00066 // RawChannel SocketDataHandler callback class for zero socket
    00067 class RawChannelZeroSocketHandler: public SocketRoutingQueue::SocketDataHandler
    00068 {
    00069         RawChannel &m_raw_channel;
    00070 public:
    00071         RawChannelZeroSocketHandler(RawChannel &raw_channel)
    00072                 : m_raw_channel(raw_channel)
    00073         {}
    00074         virtual void DataReceived(Data &data)
    00075         {
    00076                 m_raw_channel.HandleReceivedZeroPacket(data);
    00077         }
    00078         virtual void Error(Barry::Error &error)
    00079         {
    00080                 SocketDataHandler::Error(error);
    00081                 m_raw_channel.HandleError(error);
    00082         }
    00083         virtual ~RawChannelZeroSocketHandler()
    00084         {}
    00085 };
    00086
    00087 ///////////////////////////////////////////////////////////////////////////////
    00088 // RawChannel Mode class
    00089
    00090 RawChannel::RawChannel(Controller &con, RawChannelDataCallback &callback)
    00091         : Mode(con, Controller::RawChannel)
    00092         , m_mutex_valid(false)
    00093         , m_cv_valid(false)
    00094         , m_semaphore(NULL)
    00095         , m_callback(&callback)
    00096         , m_send_buffer(NULL)
    00097         , m_zero_registered(false)
    00098         , m_pending_error(NULL)
    00099 {
    00100         CheckQueueAvailable();
    00101         InitBuffer();
    00102         InitSemaphore();
    00103 }
    00104
    00105 RawChannel::RawChannel(Controller &con)
    00106         : Mode(con, Controller::RawChannel)
    00107         , m_mutex_valid(false)
    00108         , m_cv_valid(false)
    00109         , m_semaphore(NULL)
    00110         , m_callback(NULL)
    00111         , m_send_buffer(NULL)
    00112         , m_zero_registered(false)
    00113         , m_pending_error(NULL)
    00114 {
    00115         CheckQueueAvailable();
    00116         InitBuffer();
    00117         InitSemaphore();
    00118 }
    00119
    00120 void RawChannel::CheckQueueAvailable()
    00121 {
    00122         if( !m_con.m_queue ) {
    00123                 throw Barry::Error("RawChannel: No routing queue set in controller");
    00124         }
    00125 }
    00126
    00127 void RawChannel::InitBuffer()
    00128 {
    00129         m_send_buffer = new unsigned char[SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE];
    00130 }
    00131
    00132 void RawChannel::InitSemaphore()
    00133 {
    00134         // Create the thread synchronization objects
    00135         if( pthread_mutex_init(&m_mutex, NULL) ) {
    00136                 throw Barry::Error("Failed to create mutex");
    00137         }
    00138         m_mutex_valid = true;
    00139         if( pthread_cond_init(&m_cv, NULL) ) {
    00140                 throw Barry::Error("Failed to create condvar");
    00141         }
    00142         m_cv_valid = true;
    00143         m_semaphore = new semaphore(m_mutex, m_cv);
    00144 }
    00145
    00146 RawChannel::~RawChannel()
    00147 {
    00148         UnregisterZeroSocketInterest();
    00149
    00150         delete[] m_send_buffer;
    00151
    00152         if( m_mutex_valid ) {
    00153                 pthread_mutex_destroy(&m_mutex);
    00154         }
    00155         if( m_cv_valid ) {
    00156                 pthread_cond_destroy(&m_cv);
    00157         }
    00158         delete m_semaphore;
    00159         delete m_pending_error;
    00160 }
    00161
    00162 void RawChannel::OnOpen()
    00163 {
    00164         // Enable sequence packets so that DataSendAck callback and close can be
    00165         // implemented
    00166         m_zero_registered = true;
    00167         m_socket->HideSequencePacket(false);
    00168         SocketRoutingQueue::SocketDataHandlerPtr zeroCallback;
    00169         zeroCallback.reset(new RawChannelZeroSocketHandler(*this));
    00170         m_con.m_queue->RegisterInterest(0, zeroCallback);
    00171         // Get socket data packets routed to this class as well if a
    00172         // callback was provided, otherside just get the data packets
    00173         // placed into a queue for the socket.
    00174         if( m_callback ) {
    00175                 SocketRoutingQueue::SocketDataHandlerPtr callback;
    00176                 callback.reset(new RawChannelSocketHandler(*this));
    00177                 m_socket->RegisterInterest(callback);
    00178         }
    00179         else {
    00180                 SocketRoutingQueue::SocketDataHandlerPtr nullCallback;
    00181                 m_socket->RegisterInterest(nullCallback);
    00182         }
    00183 }
    00184
    00185
    00186 void RawChannel::HandleReceivedZeroPacket(Data &data)
    00187 {
    00188         Protocol::CheckSize(data, SB_PACKET_HEADER_SIZE);
    00189         MAKE_PACKETPTR_BUF(packet, data.GetData());
    00190
    00191         if( packet->socket != 0 ) {
    00192                 UnregisterZeroSocketInterest();
    00193                 SetPendingError("RawChannel: Got packet not for socket-zero");
    00194                 m_semaphore->Signal();
    00195         }
    00196
    00197         switch( btohs(packet->command) )
    00198         {
    00199         case SB_COMMAND_SEQUENCE_HANDSHAKE:
    00200                 m_semaphore->Signal();
    00201                 break;
    00202         case SB_COMMAND_CLOSE_SOCKET:
    00203         case SB_COMMAND_REMOTE_CLOSE_SOCKET:
    00204                 // Stop listening to socket 0 messages
    00205                 // so that socket close work.
    00206                 UnregisterZeroSocketInterest();
    00207                 if( m_callback ) {
    00208                         m_callback->ChannelClose();
    00209                 }
    00210
    00211                 m_semaphore->Signal();
    00212                 break;
    00213         default:
    00214                 UnregisterZeroSocketInterest();
    00215                 if( m_callback ) {
    00216                         m_callback->ChannelError("RawChannel: Got unexpected socket zero packet");
    00217                 }
    00218                 else {
    00219                         SetPendingError("RawChannel: Got unexpected socket zero packet");
    00220                 }
    00221                 m_semaphore->Signal();
    00222                 break;
    00223         }
    00224
    00225 }
    00226
    00227 void RawChannel::HandleReceivedData(Data &data)
    00228 {
    00229         // Only ever called in callback mode
    00230         ValidateDataPacket(data);
    00231         MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData());
    00232
    00233         // Should be a socket packet for us, so remove packet headers
    00234         Data partial(packet->u.data, data.GetSize() - SB_CHANNELPACKET_HEADER_SIZE);
    00235         if( m_callback ) {
    00236                 m_callback->DataReceived(partial);
    00237         }
    00238         else {
    00239                 SetPendingError("RawChannel: Received data to handle when in non-callback mode");
    00240         }
    00241 }
    00242
    00243 void RawChannel::HandleError(Barry::Error &error)
    00244 {
    00245         std::ostringstream errorOss;
    00246         errorOss << "RawChannel: Socket error received, what: " << error.what();
    00247
    00248         if( m_callback ) {
    00249                 m_callback->ChannelError(errorOss.str().c_str());
    00250         }
    00251         else {
    00252                 SetPendingError(errorOss.str().c_str());
    00253         }
    00254         m_semaphore->Signal();
    00255 }
    00256
    00257 void RawChannel::UnregisterZeroSocketInterest()
    00258 {
    00259         if( m_zero_registered ) {
    00260                 m_con.m_queue->UnregisterInterest(0);
    00261                 m_socket->HideSequencePacket(true);
    00262                 m_zero_registered = false;
    00263         }
    00264 }
    00265
    00266 void RawChannel::SetPendingError(const char *msg)
    00267 {
    00268         if( !m_pending_error ) {
    00269                 m_pending_error = new std::string(msg);
    00270         }
    00271 }
    00272
    00273 ///////////////////////////////////////////////////////////////////////////////
    00274 // public API
    00275
    00276 void RawChannel::Send(Data &data, int timeout)
    00277 {
    00278         size_t packetSize = SB_CHANNELPACKET_HEADER_SIZE + data.GetSize();
    00279
    00280         if( packetSize > SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE ) {
    00281                 throw Barry::Error("RawChannel: send data size larger than MaximumPacketSize");
    00282         }
    00283
    00284         // setup header and copy data in
    00285         MAKE_CHANNELPACKETPTR_BUF(packet, m_send_buffer);
    00286         packet->socket = htobs(m_socket->GetSocket());
    00287         packet->size = htobs(packetSize);
    00288         std::memcpy(packet->u.data, data.GetData(), data.GetSize());
    00289
    00290         Data toSend(m_send_buffer, packetSize);
    00291         m_socket->Send(toSend, timeout);
    00292         m_semaphore->WaitForSignal();
    00293         if( m_pending_error ) {
    00294                 throw Barry::Error(*m_pending_error);
    00295         }
    00296 }
    00297
    00298 void RawChannel::Receive(Data &data,int timeout)
    00299 {
    00300         if( m_callback ) {
    00301                 throw std::logic_error("RawChannel: Receive called when channel was created with a callback");
    00302         }
    00303         // Receive into a buffer
    00304         m_socket->Receive(m_receive_data, timeout);
    00305         // Then transfer across, skipping the header
    00306         ValidateDataPacket(m_receive_data);
    00307         MAKE_CHANNELPACKETPTR_BUF(packet, m_receive_data.GetData());
    00308
    00309         size_t len = packet->size - SB_CHANNELPACKET_HEADER_SIZE;
    00310         memcpy(data.GetBuffer(), packet->u.data, len);
    00311         data.ReleaseBuffer(len);
    00312
    00313 }
    00314
    00315 void RawChannel::ValidateDataPacket(Data &data)
    00316 {
    00317         Protocol::CheckSize(data, SB_CHANNELPACKET_HEADER_SIZE);
    00318         MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData());
    00319         if( packet->size != data.GetSize() ) {
    00320
    00321                 throw std::logic_error("RawChannel: Data size doesn't match packet size");
    00322         }
    00323 }
    00324
    00325 size_t RawChannel::MaximumSendSize()
    00326 {
    00327         return SB_CHANNELPACKET_MAX_DATA_SIZE;
    00328 }
    00329
    00330 }} // namespace Barry::Mode