// // Copyright 2010 Ettus Research LLC // // This program 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 of the License, or // (at your option) any later version. // // This program 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 this program. If not, see . // #include #include #include #include #include #include using namespace uhd::transport; /*********************************************************************** * Smart buffer implementation for udp zerocopy none * * This smart buffer implemention houses a const buffer. * When the smart buffer is deleted, the buffer is freed. * The memory in the const buffer is allocated with new [], * and so the destructor frees the buffer with delete []. **********************************************************************/ class smart_buffer_impl : public smart_buffer{ public: smart_buffer_impl(const boost::asio::const_buffer &buff){ _buff = buff; } ~smart_buffer_impl(void){ delete [] boost::asio::buffer_cast(_buff); } const boost::asio::const_buffer &get(void) const{ return _buff; } private: boost::asio::const_buffer _buff; }; /*********************************************************************** * UDP zero copy implementation class * * This is the portable zero copy implementation for systems * where a faster, platform specific solution is not available. * * It uses boost asio udp sockets and the standard recv() class, * and in-fact, is not actually doing a zero-copy implementation. **********************************************************************/ class udp_zero_copy_impl : public udp_zero_copy{ public: //structors udp_zero_copy_impl(const std::string &addr, const std::string &port); ~udp_zero_copy_impl(void); //send/recv size_t send(const boost::asio::const_buffer &buff); smart_buffer::sptr recv(void); private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; size_t get_recv_buff_size(void); void set_recv_buff_size(size_t); }; udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; // resolve the address boost::asio::ip::udp::resolver resolver(_io_service); boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); // Create, open, and connect the socket _socket = new boost::asio::ip::udp::socket(_io_service); _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); // set the rx socket buffer size: // pick a huge size, and deal with whatever we get set_recv_buff_size(size_t(54321e3)); //some big number! size_t current_buff_size = get_recv_buff_size(); std::cout << boost::format( "Current rx socket buffer size: %d\n" ) % current_buff_size; if (current_buff_size < size_t(.1e6)) std::cout << boost::format( "Adjust max rx socket buffer size (linux only):\n" " sysctl -w net.core.rmem_max=VALUE\n" ); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ delete _socket; } size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ return _socket->send(boost::asio::buffer(buff)); } smart_buffer::sptr udp_zero_copy_impl::recv(void){ size_t available = 0; //implement timeout through polling and sleeping boost::asio::deadline_timer timer(_socket->get_io_service()); timer.expires_from_now(boost::posix_time::milliseconds(100)); while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } //allocate memory and create buffer boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; boost::asio::mutable_buffer buff(buff_mem, available); //receive only if data is available if (available){ _socket->receive(boost::asio::buffer(buff)); } //create a new smart buffer to house the data return smart_buffer::sptr(new smart_buffer_impl(buff)); } size_t udp_zero_copy_impl::get_recv_buff_size(void){ boost::asio::socket_base::receive_buffer_size option; _socket->get_option(option); return option.value(); } void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){ boost::asio::socket_base::receive_buffer_size option(new_size); _socket->set_option(option); } /*********************************************************************** * UDP zero copy make function **********************************************************************/ udp_zero_copy::sptr udp_zero_copy::make( const std::string &addr, const std::string &port ){ return sptr(new udp_zero_copy_impl(addr, port)); }