|
TOBI Interface A
0.1
|
00001 /* 00002 This file is part of the TOBI Interface A (TiA) library. 00003 00004 Commercial Usage 00005 Licensees holding valid Graz University of Technology Commercial 00006 licenses may use this file in accordance with the Graz University 00007 of Technology Commercial License Agreement provided with the 00008 Software or, alternatively, in accordance with the terms contained in 00009 a written agreement between you and Graz University of Technology. 00010 00011 -------------------------------------------------- 00012 00013 GNU Lesser General Public License Usage 00014 Alternatively, this file may be used under the terms of the GNU Lesser 00015 General Public License version 3.0 as published by the Free Software 00016 Foundation and appearing in the file lgpl.txt included in the 00017 packaging of this file. Please review the following information to 00018 ensure the GNU General Public License version 3.0 requirements will be 00019 met: http://www.gnu.org/copyleft/lgpl.html. 00020 00021 In case of GNU Lesser General Public License Usage ,the TiA library 00022 is distributed in the hope that it will be useful, 00023 but WITHOUT ANY WARRANTY; without even the implied warranty of 00024 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00025 GNU General Public License for more details. 00026 00027 You should have received a copy of the GNU Lesser General Public License 00028 along with the TiA library. If not, see <http://www.gnu.org/licenses/>. 00029 00030 Copyright 2010 Graz University of Technology 00031 Contact: TiA@tobi-project.org 00032 */ 00033 00039 // Boost 00040 #include <boost/thread.hpp> 00041 #include <boost/bind.hpp> 00042 #include <boost/iostreams/stream.hpp> 00043 00044 // local 00045 #include "tia/constants.h" 00046 00047 #include "tia-private/config/control_message_decoder.h" 00048 #include "tia-private/config/control_message_encoder.h" 00049 00050 #include "tia-private/network/control_connection.h" 00051 #include "tia-private/network/control_connection_server.h" 00052 #include "tia-private/network/tcp_data_server.h" 00053 #include "tia-private/network/udp_data_server.h" 00054 00055 namespace tia 00056 { 00057 using std::cout; 00058 using std::cerr; 00059 using std::endl; 00060 using std::istream; 00061 00062 using boost::uint16_t; 00063 using boost::uint32_t; 00064 00065 //----------------------------------------------------------------------------- 00066 00067 ControlConnection::ControlConnection(boost::asio::io_service& io_service, 00068 const ConnectionID& id, 00069 ControlConnectionServer& ctl_conn_server, 00070 const TCPConnection::pointer& tcp_conn) 00071 : io_service_(io_service), 00072 connection_id_(id), 00073 ctl_conn_server_(ctl_conn_server), 00074 tcp_connection_(tcp_conn), 00075 msg_encoder_(0), 00076 msg_decoder_(0), 00077 state_(State_Connected), 00078 connection_type_(GetDataConnectionMsg::Tcp) 00079 { 00080 input_buffer_ = new boost::asio::streambuf; 00081 output_buffer_ = new boost::asio::streambuf; 00082 00083 msg_encoder_ = new ControlMsgEncoderXML; 00084 msg_decoder_ = new ControlMsgDecoderXML; 00085 00086 config_msg_ = boost::shared_ptr<ConfigMsg>(new ConfigMsg); 00087 ctl_conn_server.getConfig(*config_msg_); 00088 } 00089 00090 //----------------------------------------------------------------------------- 00091 00092 ControlConnection::~ControlConnection() 00093 { 00094 delete input_buffer_; 00095 delete output_buffer_; 00096 delete msg_encoder_; 00097 delete msg_decoder_; 00098 } 00099 00100 //----------------------------------------------------------------------------- 00101 00102 void ControlConnection::start() 00103 { 00104 tcp_connection_->socket().async_read_some(input_buffer_->prepare(MAX_DATA_SIZE), 00105 boost::bind(&ControlConnection::handle_read, shared_from_this(), 00106 boost::asio::placeholders::error, 00107 boost::asio::placeholders::bytes_transferred)); 00108 } 00109 00110 //----------------------------------------------------------------------------- 00111 00112 void ControlConnection::handle_read(const boost::system::error_code& error, 00113 std::size_t bytes_transferred) 00114 { 00115 if (error) 00116 { 00117 if (error != boost::asio::error::eof) 00118 { 00119 cerr << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00120 << "closing connection -- Error: " 00121 << "--> " << error.message() << endl; 00122 } 00123 00124 close(); 00125 return; 00126 } 00127 00128 input_buffer_->commit(bytes_transferred); 00129 00130 istream instream(input_buffer_); 00131 00132 msg_decoder_->setInputStream(&instream); 00133 00134 boost::shared_ptr<ControlMsg> msg(msg_decoder_->decodeMsg()); 00135 00136 if (msg != 0) 00137 { 00138 switch (msg->msgType()) 00139 { 00140 case ControlMsg::KeepAlive: 00141 { 00142 // TODO: 00143 break; 00144 } 00145 00146 case ControlMsg::GetConfig: 00147 { 00148 cout << "Client @" << connection_id_.second 00149 << " requests config" << endl; 00150 00151 sendMsg(*config_msg_); 00152 00153 break; 00154 } 00155 00156 case ControlMsg::GetDataConnection: 00157 { 00158 #ifdef DEBUG 00159 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00160 << "Got Request 'GetDataConnection'" << endl; 00161 #endif 00162 00163 if (state_ == State_TransmissionStarted) 00164 { 00165 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00166 << "request 'GetDataConnection' failed - " 00167 "not allowed while transmission is running" << endl; 00168 sendMsg(ReplyMsg::error()); 00169 break; 00170 } 00171 00172 if (connection_type_ == GetDataConnectionMsg::Tcp && 00173 (state_ == State_AllocatedDataConnection || 00174 state_ == State_TransmissionStopped )) 00175 { 00176 ctl_conn_server_.tcpDataServer()->removeConnection(tcp_data_server_local_endpoint_); 00177 } 00178 00179 boost::shared_ptr<GetDataConnectionMsg> get_data_conn_msg = 00180 boost::static_pointer_cast<GetDataConnectionMsg>(msg); 00181 00182 connection_type_ = get_data_conn_msg->connectionType(); 00183 00184 DataConnectionMsg data_conn_msg; 00185 00186 switch (connection_type_) 00187 { 00188 case GetDataConnectionMsg::Udp: 00189 { 00190 boost::asio::ip::udp::endpoint endpoint = 00191 ctl_conn_server_.udpDataServer()->destination(); 00192 00193 data_conn_msg.setPort(endpoint.port()); 00194 00195 cout << "Client @" << connection_id_.second 00196 << " requests UDP data broadcast - allocating port " 00197 << endpoint.port() << endl; 00198 break; 00199 } 00200 case GetDataConnectionMsg::Tcp: 00201 { 00202 tcp_data_server_local_endpoint_ = ctl_conn_server_.tcpDataServer()->addConnection(); 00203 00204 data_conn_msg.setPort(tcp_data_server_local_endpoint_.port()); 00205 00206 cout << "Client @" << connection_id_.second 00207 << " requests TCP data connection - allocating port " 00208 << tcp_data_server_local_endpoint_.port() << endl; 00209 00210 break; 00211 } 00212 } 00213 00214 if (state_ == State_Connected) 00215 { 00216 state_ = State_AllocatedDataConnection; 00217 } 00218 00219 sendMsg(data_conn_msg); 00220 00221 break; 00222 } 00223 00224 case ControlMsg::StartTransmission: 00225 { 00226 cout << "Client @" << connection_id_.second 00227 << " requests data transmission start." << endl; 00228 00229 if (state_ == State_Connected) 00230 { 00231 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00232 << "request 'StartTransmission' failed - cannot start transmission before " 00233 << "data connection has been requested." << endl; 00234 00235 sendMsg(ReplyMsg::error()); 00236 break; 00237 } 00238 00239 if (state_ == State_TransmissionStarted) 00240 { 00241 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00242 << "request 'StartTransmission' failed - transmission is already running." << endl; 00243 00244 sendMsg(ReplyMsg::error()); 00245 break; 00246 } 00247 00248 switch (connection_type_) 00249 { 00250 case GetDataConnectionMsg::Udp: 00251 { 00252 ctl_conn_server_.udpDataServer()->incClientCount(); 00253 break; 00254 } 00255 case GetDataConnectionMsg::Tcp: 00256 { 00257 ctl_conn_server_.tcpDataServer()->enableTransmission( 00258 tcp_data_server_local_endpoint_, true); 00259 break; 00260 } 00261 } 00262 00263 sendMsg(ReplyMsg::ok()); 00264 00265 state_ = State_TransmissionStarted; 00266 00267 break; 00268 } 00269 00270 case ControlMsg::StopTransmission: 00271 { 00272 cout << "Client @" << connection_id_.second 00273 << " requests data transmission stop." << endl; 00274 00275 if (state_ == State_Connected) 00276 { 00277 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00278 << "request 'StopTransmission' failed - cannot stop transmission if " 00279 << "data connection has never been requested." << endl; 00280 00281 sendMsg(ReplyMsg::error()); 00282 break; 00283 } 00284 00285 if (state_ == State_TransmissionStopped) 00286 { 00287 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00288 << "request 'StopTransmission' failed - transmission is not running." 00289 << endl; 00290 sendMsg(ReplyMsg::error()); 00291 break; 00292 } 00293 00294 switch (connection_type_) 00295 { 00296 case GetDataConnectionMsg::Udp: 00297 { 00298 ctl_conn_server_.udpDataServer()->decClientCount(); 00299 break; 00300 } 00301 case GetDataConnectionMsg::Tcp: 00302 { 00303 ctl_conn_server_.tcpDataServer()->enableTransmission( 00304 tcp_data_server_local_endpoint_, false); 00305 break; 00306 } 00307 } 00308 00309 sendMsg(ReplyMsg::ok()); 00310 00311 state_ = State_TransmissionStopped; 00312 00313 break; 00314 } 00315 00316 default: 00317 { 00318 cout << "ControlConnection::handle_read [Client @" << connection_id_.second << "]: " 00319 << "unsupported request type (" << msg->msgType() << ") - ignoring request." 00320 << endl; 00321 break; 00322 } 00323 } 00324 00325 // Read next message 00326 tcp_connection_->socket().async_read_some(input_buffer_->prepare(MAX_DATA_SIZE), 00327 boost::bind(&ControlConnection::handle_read, shared_from_this(), 00328 boost::asio::placeholders::error, 00329 boost::asio::placeholders::bytes_transferred)); 00330 } 00331 else 00332 close (); 00333 } 00334 00335 //----------------------------------------------------------------------------- 00336 00337 void ControlConnection::sendMsg(const ControlMsg& msg) 00338 { 00339 #ifdef DEBUG 00340 cout << "ControlConnection::sendMsg [Client @" << connection_id_.second << "]" << endl; 00341 #endif 00342 00343 std::ostream ostream(output_buffer_); 00344 msg.writeMsg(*msg_encoder_, ostream); 00345 00346 #ifdef DEBUG 00347 { 00348 cout << "ControlConnection::sendMsg [Client @" << connection_id_.second << "]" << endl; 00349 cout << "-----------" << endl; 00350 00351 std::stringstream sstream; 00352 msg.writeMsg(*msg_encoder_, sstream); 00353 00354 cout << sstream.str() << endl; 00355 00356 cout << "-----------" << endl; 00357 } 00358 #endif 00359 00360 boost::asio::async_write(tcp_connection_->socket(), output_buffer_->data(), 00361 boost::bind(&ControlConnection::handle_write, shared_from_this(), 00362 boost::asio::placeholders::error, output_buffer_->size())); 00363 } 00364 00365 //----------------------------------------------------------------------------- 00366 00367 void ControlConnection::close() 00368 { 00369 00370 #ifdef DEBUG 00371 cout << "ControlConnection::close [Client @" << connection_id_.second << "]" << endl; 00372 #endif 00373 00374 // Initiate graceful connection closure. 00375 boost::system::error_code ignored_ec; 00376 tcp_connection_->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); 00377 00378 tcp_connection_->socket().close(); 00379 00380 switch (connection_type_) 00381 { 00382 case GetDataConnectionMsg::Udp: 00383 { 00384 if (state_ == State_TransmissionStarted) ctl_conn_server_.udpDataServer()->decClientCount(); 00385 break; 00386 } 00387 case GetDataConnectionMsg::Tcp: 00388 { 00389 if (state_ == State_AllocatedDataConnection || 00390 state_ == State_TransmissionStarted || 00391 state_ == State_TransmissionStopped) 00392 { 00393 ctl_conn_server_.tcpDataServer()->removeConnection(tcp_data_server_local_endpoint_); 00394 } 00395 00396 break; 00397 } 00398 } 00399 00400 state_ = State_ConnectionClosed; 00401 00402 ctl_conn_server_.clientHasDisconnected(connection_id_); 00403 } 00404 00405 //----------------------------------------------------------------------------- 00406 00407 void ControlConnection::handle_write(const boost::system::error_code& error, 00408 std::size_t bytes_transferred) 00409 { 00410 #ifdef DEBUG 00411 cout << "ControlConnection::handle_write [Client @" << connection_id_.second << "]" << endl; 00412 #endif 00413 00414 if (error) 00415 { 00416 cerr << "ControlConnection::handle_write [Client@" << connection_id_.second << "]: " 00417 << "error during write - closing connection." 00418 << "--> " << error.message() << endl; 00419 close(); 00420 00421 // No new asynchronous operations are started. This means that all shared_ptr 00422 // references to the connection object will disappear and the object will be 00423 // destroyed automatically after this handler returns. The connection class's 00424 // destructor closes the socket. 00425 return; 00426 } 00427 00428 // Consume whole input sequence 00429 output_buffer_->consume(bytes_transferred); 00430 } 00431 00432 //----------------------------------------------------------------------------- 00433 00434 } // Namespace tobiss 00435 00436 // End Of File