diff options
author | Jiří Pinkava <j-pi@seznam.cz> | 2014-12-04 16:36:11 +0100 |
---|---|---|
committer | Jiří Pinkava <j-pi@seznam.cz> | 2016-06-29 09:08:08 +0200 |
commit | 950310a0cc632723358e1301ab76c4a58d545162 (patch) | |
tree | b830e057a8d79abaed438daf575a366308b1f5bf | |
parent | d659dbee3904b436fa835afc2f82566f1f66f4be (diff) |
tcp_server_sink: implementation
-rw-r--r-- | gr-blocks/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-blocks/lib/tcp_server_sink_impl.cc | 161 | ||||
-rw-r--r-- | gr-blocks/lib/tcp_server_sink_impl.h | 73 |
3 files changed, 235 insertions, 0 deletions
diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index 643190c2ee..1d69f27a1d 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -199,6 +199,7 @@ list(APPEND gr_blocks_sources throttle_impl.cc transcendental_impl.cc tcp_connection.cc + tcp_server_sink_impl.cc tuntap_pdu_impl.cc tag_gate_impl.cc tagged_stream_align_impl.cc diff --git a/gr-blocks/lib/tcp_server_sink_impl.cc b/gr-blocks/lib/tcp_server_sink_impl.cc new file mode 100644 index 0000000000..329e798ca8 --- /dev/null +++ b/gr-blocks/lib/tcp_server_sink_impl.cc @@ -0,0 +1,161 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007-2010,2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tcp_server_sink_impl.h" +#include <gnuradio/io_signature.h> +#include <algorithm> +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <boost/format.hpp> +#include <gnuradio/thread/thread.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> + +namespace gr { + namespace blocks { + + tcp_server_sink::sptr + tcp_server_sink::make(size_t itemsize, + const std::string &host, int port, + bool noblock) + { + return gnuradio::get_initial_sptr + (new tcp_server_sink_impl(itemsize, host, port, noblock)); + } + + tcp_server_sink_impl::tcp_server_sink_impl(size_t itemsize, + const std::string &host, int port, + bool noblock) + : sync_block("tcp_server_sink", + io_signature::make(1, 1, itemsize), + io_signature::make(0, 0, 0)), + d_itemsize(itemsize), + d_acceptor(d_io_service), + d_buf(new uint8_t[BUF_SIZE]), + d_writing(0) + { + std::string s_port = (boost::format("%d") % port).str(); + std::string s_host = host.empty() ? std::string("localhost") : host; + boost::asio::ip::tcp::resolver resolver(d_io_service); + boost::asio::ip::tcp::resolver::query query(s_host, s_port, + boost::asio::ip::resolver_query_base::passive); + d_endpoint = *resolver.resolve(query); + + d_acceptor.open(d_endpoint.protocol()); + d_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + d_acceptor.bind(d_endpoint); + d_acceptor.listen(); + + if (!noblock) { + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.accept(*d_socket, d_endpoint); + d_sockets.insert(d_socket.release()); + } + + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.async_accept(*d_socket, boost::bind(&tcp_server_sink_impl::do_accept, + this, boost::asio::placeholders::error)); + d_io_serv_thread = boost::thread( + boost::bind(&boost::asio::io_service::run, &d_io_service)); + } + + void + tcp_server_sink_impl::do_accept(const boost::system::error_code& error) + { + if (!error) { + gr::thread::scoped_lock guard(d_writing_mut); + d_sockets.insert(d_socket.release()); + d_socket.reset(new boost::asio::ip::tcp::socket(d_io_service)); + d_acceptor.async_accept(*d_socket, boost::bind(&tcp_server_sink_impl::do_accept, + this, boost::asio::placeholders::error)); + } + } + + void + tcp_server_sink_impl::do_write(const boost::system::error_code& error, + size_t len, std::set<boost::asio::ip::tcp::socket *>::iterator i) + { + { + gr::thread::scoped_lock guard(d_writing_mut); + --d_writing; + if (error) { + delete *i; + d_sockets.erase(i); + } + } + d_writing_cond.notify_one(); + } + + tcp_server_sink_impl::~tcp_server_sink_impl() + { + gr::thread::scoped_lock guard(d_writing_mut); + while (d_writing) { + d_writing_cond.wait(guard); + } + + for (std::set<boost::asio::ip::tcp::socket *>::iterator i = d_sockets.begin(); + i != d_sockets.end(); ++i ) { + delete *i; + } + d_sockets.clear(); + + d_io_service.reset(); + d_io_service.stop(); + d_io_serv_thread.join(); + } + + int + tcp_server_sink_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const char *in = (const char *) input_items[0]; + + gr::thread::scoped_lock guard(d_writing_mut); + while (d_writing) { + d_writing_cond.wait(guard); + } + + size_t data_len = std::min(size_t(BUF_SIZE), noutput_items * d_itemsize); + data_len -= data_len % d_itemsize; + memcpy(d_buf.get(), in, data_len); + for (std::set<boost::asio::ip::tcp::socket *>::iterator i = d_sockets.begin(); + i != d_sockets.end(); ++i ) { + boost::asio::async_write(**i, boost::asio::buffer(d_buf.get(), data_len), + boost::bind(&tcp_server_sink_impl::do_write, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + i)); + } + d_writing = d_sockets.size(); + + return data_len / d_itemsize; + } + + } /* namespace blocks */ +} /* namespace gr */ + diff --git a/gr-blocks/lib/tcp_server_sink_impl.h b/gr-blocks/lib/tcp_server_sink_impl.h new file mode 100644 index 0000000000..d10f3b95b8 --- /dev/null +++ b/gr-blocks/lib/tcp_server_sink_impl.h @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2014 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_TCP_SERVER_SINK_IMPL_H +#define INCLUDED_GR_TCP_SERVER_SINK_IMPL_H + +#include <gnuradio/blocks/tcp_server_sink.h> +#include <boost/asio.hpp> +#include <set> +#include <boost/ptr_container/ptr_vector.hpp> + +namespace gr { + namespace blocks { + + class tcp_server_sink_impl : public tcp_server_sink + { + private: + size_t d_itemsize; + + boost::asio::io_service d_io_service; + gr::thread::thread d_io_serv_thread; + boost::asio::ip::tcp::endpoint d_endpoint; + std::auto_ptr<boost::asio::ip::tcp::socket> d_socket; + std::set<boost::asio::ip::tcp::socket *> d_sockets; + boost::asio::ip::tcp::acceptor d_acceptor; + + boost::shared_ptr<uint8_t> d_buf; + enum { + BUF_SIZE = 256 * 1024, + }; + + int d_writing; + boost::condition_variable d_writing_cond; + boost::mutex d_writing_mut; + + void do_accept(const boost::system::error_code& error); + void do_write(const boost::system::error_code& error, std::size_t len, + std::set<boost::asio::ip::tcp::socket *>::iterator); + + public: + tcp_server_sink_impl(size_t itemsize, + const std::string &host, int port, + bool noblock); + ~tcp_server_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_TCP_SERVER_SINK_IMPL_H */ |