TOBI Interface A  0.1
/home/breidi/Dropbox/libtia/src/tia/network/tcp_data_server.cpp
Go to the documentation of this file.
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
 All Data Structures Files Functions Variables Typedefs Enumerations