|
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 00041 // Standard 00042 #include <assert.h> 00043 #include <iostream> 00044 00045 // boost 00046 #include <boost/bind.hpp> 00047 00048 // local 00049 #include "tia-private/network/tcp_data_server.h" 00050 #include "tia/data_packet_interface.h" 00051 00052 namespace tia 00053 { 00054 using std::cout; 00055 using std::cerr; 00056 using std::endl; 00057 using std::make_pair; 00058 00059 using boost::uint32_t; 00060 00061 //----------------------------------------------------------------------------- 00062 00063 TCPDataConnection::TCPDataConnection(boost::asio::io_service& io_service) : 00064 TCPServer(io_service) 00065 {} 00066 00067 00068 //----------------------------------------------------------------------------- 00069 00070 void TCPDataConnection::handleWrite(const boost::system::error_code& ec, 00071 std::size_t /*bytes_transferred*/) 00072 { 00073 if (ec) 00074 { 00075 cerr << "TCPDataConnection::handleWrite: sending data packet to client @" 00076 << remote_endpoint_.address().to_string() << ":" << remote_endpoint_.port() 00077 << " failed - closing connection -- Error:" << endl 00078 << "--> " << ec.message() << endl; 00079 00080 boost::unique_lock<boost::mutex> lock(mutex_); 00081 00082 // Initiate graceful connection closure. 00083 boost::system::error_code ignored_ec; 00084 connection_->socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); 00085 connection_->socket().close(); 00086 } 00087 } 00088 00089 //----------------------------------------------------------------------------- 00090 00091 void TCPDataConnection::sendDataPacket(DataPacket& packet) 00092 { 00093 boost::unique_lock<boost::mutex> lock(mutex_); 00094 00095 if (!connection_ || !connection_->socket().is_open()) return; 00096 00097 void* data = packet.getRaw(); 00098 uint32_t size = packet.getRawMemorySize(); 00099 00100 assert(data != 0); 00101 assert(size != 0); 00102 00103 #ifdef DEBUG 00104 std::cout << "TCPDataConnection::sendDataPacket: sending data packet to " 00105 << remote_endpoint_.address().to_string() << ":" << remote_endpoint_.port() 00106 << std::endl; 00107 #endif 00108 00109 connection_->socket().async_send(boost::asio::buffer(data, size), 00110 boost::bind(&TCPDataConnection::handleWrite, 00111 shared_from_this(), 00112 boost::asio::placeholders::error, 00113 boost::asio::placeholders::bytes_transferred)); 00114 } 00115 00116 //----------------------------------------------------------------------------- 00117 00118 void TCPDataConnection::startAccept() 00119 { 00120 TCPConnection::pointer new_connection = TCPConnection::create(io_service_); 00121 00122 acceptor_.async_accept(new_connection->socket(), boost::bind( 00123 &TCPDataConnection::handleAccept, shared_from_this(), new_connection, 00124 boost::asio::placeholders::error)); 00125 } 00126 00127 //----------------------------------------------------------------------------- 00128 00129 void TCPDataConnection::handleAccept(const TCPConnection::pointer& new_connection, 00130 const boost::system::error_code& error) 00131 { 00132 if (error) 00133 { 00134 cerr << "TCPDataConnection::handleAccept: cannot accept connection on " 00135 << localEndpoint().address().to_string() << ":" << localEndpoint().port() 00136 << "-- Error:" << endl 00137 << error.message() << endl; 00138 00139 startAccept(); 00140 return; 00141 } 00142 00143 boost::unique_lock<boost::mutex> lock(mutex_); 00144 00145 connection_ = new_connection; 00146 remote_endpoint_ = connection_->socket().remote_endpoint(); 00147 boost::asio::socket_base::send_buffer_size buffer_option(BUFFER_SIZE); 00148 connection_->socket().set_option(buffer_option); 00149 00150 boost::asio::ip::tcp::no_delay delay_option(true); 00151 connection_->socket().set_option(delay_option); 00152 00153 boost::asio::socket_base::linger linger_option(false, 0); 00154 connection_->socket().set_option(linger_option); 00155 00156 #ifdef DEBUG 00157 cout << "TCPDataConnection::handleAccept: client @" 00158 << remote_endpoint_.address().to_string() << ":" << remote_endpoint_.port() 00159 << " connected on " 00160 << connection_->socket().local_endpoint().address().to_string() 00161 << connection_->socket().local_endpoint().port(); 00162 #endif 00163 } 00164 //----------------------------------------------------------------------------- 00165 00166 TCPDataServer::TCPDataServer(boost::asio::io_service& io_service) : 00167 io_service_(io_service) 00168 {} 00169 00170 //----------------------------------------------------------------------------- 00171 00172 bool TCPDataServer::connected(const boost::asio::ip::tcp::endpoint& endpoint) const 00173 { 00174 boost::unique_lock<boost::mutex> lock(mutex_); 00175 ClientConnectionMap::const_iterator it = connections_.find(endpoint); 00176 if (it != connections_.end()) 00177 { 00178 throw(std::invalid_argument("No connection with that local endpoint")); 00179 } 00180 00181 TCPDataConnection::pointer connection = (*it).second; 00182 return connection->connected(); 00183 } 00184 00185 //----------------------------------------------------------------------------- 00186 00187 boost::asio::ip::tcp::endpoint TCPDataServer::addConnection() 00188 { 00189 boost::unique_lock<boost::mutex> lock(mutex_); 00190 TCPDataConnection::pointer connection = TCPDataConnection::create(io_service_); 00191 00192 boost::asio::ip::tcp::endpoint local_endpoint; 00193 00194 try 00195 { 00196 connection->bind(0); 00197 local_endpoint = connection->localEndpoint(); 00198 } 00199 catch (boost::exception& e) 00200 { 00201 throw (std::runtime_error("Could not bind socket - adding new connection failed")); 00202 } 00203 00204 connection->listen(); 00205 00206 connections_.insert(make_pair(local_endpoint, connection)); 00207 00208 return local_endpoint; 00209 } 00210 00211 //----------------------------------------------------------------------------- 00212 00213 void TCPDataServer::removeConnection(const boost::asio::ip::tcp::endpoint& endpoint) 00214 { 00215 boost::unique_lock<boost::mutex> lock(mutex_); 00216 ClientConnectionMap::iterator it = connections_.find(endpoint); 00217 if (it == connections_.end()) 00218 { 00219 throw(std::invalid_argument("No connection with that local endpoint")); 00220 } 00221 00222 connections_.erase(it); 00223 00224 connections_transmission_enabled_.erase(endpoint); 00225 } 00226 00227 //----------------------------------------------------------------------------- 00228 00229 void TCPDataServer::enableTransmission(const boost::asio::ip::tcp::endpoint& endpoint, 00230 bool enable) 00231 { 00232 boost::unique_lock<boost::mutex> lock(mutex_); 00233 00234 ClientConnectionMap::iterator it = connections_.find(endpoint); 00235 if (it == connections_.end()) 00236 { 00237 throw(std::invalid_argument("No connection with that local endpoint")); 00238 } 00239 00240 if (enable) 00241 { 00242 connections_transmission_enabled_[(*it).first] = (*it).second; 00243 } 00244 else 00245 { 00246 connections_transmission_enabled_.erase((*it).first); 00247 } 00248 } 00249 00250 //----------------------------------------------------------------------------- 00251 00252 void TCPDataServer::sendDataPacket(DataPacket& packet) 00253 { 00254 // lock the connection list 00255 boost::unique_lock<boost::mutex> lock(mutex_); 00256 00257 ClientConnectionMap::iterator it = connections_transmission_enabled_.begin(); 00258 ClientConnectionMap::iterator end = connections_transmission_enabled_.end(); 00259 00260 for (; it != end; ++it) 00261 { 00262 TCPDataConnection::pointer connection = (*it).second; 00263 connection->sendDataPacket(packet); 00264 } 00265 } 00266 00267 //----------------------------------------------------------------------------- 00268 00269 } // Namespace tobiss