Fixed trailing whitespace
[barry.git] / src / m_raw_channel.cc
blobe36333ff2df8cea4c6d9f25dcdf8b047621599c4
1 ///
2 /// \file m_raw_channel.cc
3 /// Mode class for a raw channel
4 ///
6 /*
7 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
8 Portions Copyright (C) 2010 RealVNC Ltd.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "m_raw_channel.h"
24 #include "semaphore.h"
25 #include "data.h"
26 #include "protocol.h"
27 #include "protostructs.h"
28 #include "packet.h"
29 #include "endian.h"
30 #include "error.h"
31 #include "usbwrap.h"
32 #include "controller.h"
33 #include <stdexcept>
34 #include <sstream>
35 #include <cstring>
36 #include <string>
37 #include "protostructs.h"
39 #include "debug.h"
41 namespace Barry { namespace Mode {
43 ///////////////////////////////////////////////////////////////////////////////
44 // RawChannel SocketDataHandler callback class for data socket
45 class RawChannelSocketHandler: public SocketRoutingQueue::SocketDataHandler
47 RawChannel &m_raw_channel;
48 public:
49 RawChannelSocketHandler(RawChannel &raw_channel)
50 : m_raw_channel(raw_channel)
52 virtual void DataReceived(Data &data)
54 m_raw_channel.HandleReceivedData(data);
56 virtual void Error(Barry::Error &error)
58 SocketDataHandler::Error(error);
59 m_raw_channel.HandleError(error);
61 virtual ~RawChannelSocketHandler()
65 ///////////////////////////////////////////////////////////////////////////////
66 // RawChannel SocketDataHandler callback class for zero socket
67 class RawChannelZeroSocketHandler: public SocketRoutingQueue::SocketDataHandler
69 RawChannel &m_raw_channel;
70 public:
71 RawChannelZeroSocketHandler(RawChannel &raw_channel)
72 : m_raw_channel(raw_channel)
74 virtual void DataReceived(Data &data)
76 m_raw_channel.HandleReceivedZeroPacket(data);
78 virtual void Error(Barry::Error &error)
80 SocketDataHandler::Error(error);
81 m_raw_channel.HandleError(error);
83 virtual ~RawChannelZeroSocketHandler()
87 ///////////////////////////////////////////////////////////////////////////////
88 // RawChannel Mode class
90 RawChannel::RawChannel(Controller &con, RawChannelDataCallback &callback)
91 : Mode(con, Controller::RawChannel)
92 , m_mutex_valid(false)
93 , m_cv_valid(false)
94 , m_semaphore(NULL)
95 , m_callback(&callback)
96 , m_send_buffer(NULL)
97 , m_zero_registered(false)
98 , m_pending_error(NULL)
100 CheckQueueAvailable();
101 InitBuffer();
102 InitSemaphore();
105 RawChannel::RawChannel(Controller &con)
106 : Mode(con, Controller::RawChannel)
107 , m_mutex_valid(false)
108 , m_cv_valid(false)
109 , m_semaphore(NULL)
110 , m_callback(NULL)
111 , m_send_buffer(NULL)
112 , m_zero_registered(false)
113 , m_pending_error(NULL)
115 CheckQueueAvailable();
116 InitBuffer();
117 InitSemaphore();
120 void RawChannel::CheckQueueAvailable()
122 if( !m_con.m_queue ) {
123 throw Barry::Error("RawChannel: No routing queue set in controller");
127 void RawChannel::InitBuffer()
129 m_send_buffer = new unsigned char[SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE];
132 void RawChannel::InitSemaphore()
134 // Create the thread synchronization objects
135 if( pthread_mutex_init(&m_mutex, NULL) ) {
136 throw Barry::Error("Failed to create mutex");
138 m_mutex_valid = true;
139 if( pthread_cond_init(&m_cv, NULL) ) {
140 throw Barry::Error("Failed to create condvar");
142 m_cv_valid = true;
143 m_semaphore = new semaphore(m_mutex, m_cv);
146 RawChannel::~RawChannel()
148 UnregisterZeroSocketInterest();
150 delete[] m_send_buffer;
152 if( m_mutex_valid ) {
153 pthread_mutex_destroy(&m_mutex);
155 if( m_cv_valid ) {
156 pthread_cond_destroy(&m_cv);
158 delete m_semaphore;
159 delete m_pending_error;
162 void RawChannel::OnOpen()
164 // Enable sequence packets so that DataSendAck callback and close can be
165 // implemented
166 m_zero_registered = true;
167 m_socket->HideSequencePacket(false);
168 SocketRoutingQueue::SocketDataHandlerPtr zeroCallback;
169 zeroCallback.reset(new RawChannelZeroSocketHandler(*this));
170 m_con.m_queue->RegisterInterest(0, zeroCallback);
171 // Get socket data packets routed to this class as well if a
172 // callback was provided, otherside just get the data packets
173 // placed into a queue for the socket.
174 if( m_callback ) {
175 SocketRoutingQueue::SocketDataHandlerPtr callback;
176 callback.reset(new RawChannelSocketHandler(*this));
177 m_socket->RegisterInterest(callback);
179 else {
180 SocketRoutingQueue::SocketDataHandlerPtr nullCallback;
181 m_socket->RegisterInterest(nullCallback);
186 void RawChannel::HandleReceivedZeroPacket(Data &data)
188 Protocol::CheckSize(data, SB_PACKET_HEADER_SIZE);
189 MAKE_PACKETPTR_BUF(packet, data.GetData());
191 if( packet->socket != 0 ) {
192 UnregisterZeroSocketInterest();
193 SetPendingError("RawChannel: Got packet not for socket-zero");
194 m_semaphore->Signal();
197 switch( btohs(packet->command) )
199 case SB_COMMAND_SEQUENCE_HANDSHAKE:
200 m_semaphore->Signal();
201 break;
202 case SB_COMMAND_CLOSE_SOCKET:
203 case SB_COMMAND_REMOTE_CLOSE_SOCKET:
204 // Stop listening to socket 0 messages
205 // so that socket close work.
206 UnregisterZeroSocketInterest();
207 if( m_callback ) {
208 m_callback->ChannelClose();
211 m_semaphore->Signal();
212 break;
213 default:
214 UnregisterZeroSocketInterest();
215 if( m_callback ) {
216 m_callback->ChannelError("RawChannel: Got unexpected socket zero packet");
218 else {
219 SetPendingError("RawChannel: Got unexpected socket zero packet");
221 m_semaphore->Signal();
222 break;
227 void RawChannel::HandleReceivedData(Data &data)
229 // Only ever called in callback mode
230 ValidateDataPacket(data);
231 MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData());
233 // Should be a socket packet for us, so remove packet headers
234 Data partial(packet->u.data, data.GetSize() - SB_CHANNELPACKET_HEADER_SIZE);
235 if( m_callback ) {
236 m_callback->DataReceived(partial);
238 else {
239 SetPendingError("RawChannel: Received data to handle when in non-callback mode");
243 void RawChannel::HandleError(Barry::Error &error)
245 std::ostringstream errorOss;
246 errorOss << "RawChannel: Socket error received, what: " << error.what();
248 if( m_callback ) {
249 m_callback->ChannelError(errorOss.str().c_str());
251 else {
252 SetPendingError(errorOss.str().c_str());
254 m_semaphore->Signal();
257 void RawChannel::UnregisterZeroSocketInterest()
259 if( m_zero_registered ) {
260 m_con.m_queue->UnregisterInterest(0);
261 m_socket->HideSequencePacket(true);
262 m_zero_registered = false;
266 void RawChannel::SetPendingError(const char *msg)
268 if( !m_pending_error ) {
269 m_pending_error = new std::string(msg);
273 ///////////////////////////////////////////////////////////////////////////////
274 // public API
276 void RawChannel::Send(Data &data, int timeout)
278 size_t packetSize = SB_CHANNELPACKET_HEADER_SIZE + data.GetSize();
280 if( packetSize > SB_CHANNELPACKET_HEADER_SIZE + SB_CHANNELPACKET_MAX_DATA_SIZE ) {
281 throw Barry::Error("RawChannel: send data size larger than MaximumPacketSize");
284 // setup header and copy data in
285 MAKE_CHANNELPACKETPTR_BUF(packet, m_send_buffer);
286 packet->socket = htobs(m_socket->GetSocket());
287 packet->size = htobs(packetSize);
288 std::memcpy(packet->u.data, data.GetData(), data.GetSize());
290 Data toSend(m_send_buffer, packetSize);
291 m_socket->Send(toSend, timeout);
292 m_semaphore->WaitForSignal();
293 if( m_pending_error ) {
294 throw Barry::Error(*m_pending_error);
298 void RawChannel::Receive(Data &data,int timeout)
300 if( m_callback ) {
301 throw std::logic_error("RawChannel: Receive called when channel was created with a callback");
303 // Receive into a buffer
304 m_socket->Receive(m_receive_data, timeout);
305 // Then transfer across, skipping the header
306 ValidateDataPacket(m_receive_data);
307 MAKE_CHANNELPACKETPTR_BUF(packet, m_receive_data.GetData());
309 size_t len = packet->size - SB_CHANNELPACKET_HEADER_SIZE;
310 memcpy(data.GetBuffer(), packet->u.data, len);
311 data.ReleaseBuffer(len);
315 void RawChannel::ValidateDataPacket(Data &data)
317 Protocol::CheckSize(data, SB_CHANNELPACKET_HEADER_SIZE);
318 MAKE_CHANNELPACKETPTR_BUF(packet, data.GetData());
319 if( packet->size != data.GetSize() ) {
321 throw std::logic_error("RawChannel: Data size doesn't match packet size");
325 size_t RawChannel::MaximumSendSize()
327 return SB_CHANNELPACKET_MAX_DATA_SIZE;
330 }} // namespace Barry::Mode