c++ - Boost asio async operation bad file descriptor -
i'm usig boost asio irc bot, , 1 of async operation results in bad file descriptor. tried put socket in shared_ptr, still got "bad file descriptor" error. don't know whats wrong in it.
here files, omitted of functions cpp file. want read full file, it's here on github.
the error happends in _read function.
thanks!
irc.hpp
#ifndef h_irc #define h_irc #include <vector> #include <boost/asio.hpp> #include <boost/tokenizer.hpp> #include <boost/shared_ptr.hpp> class irc { public: irc(const std::string &server, const std::string &port, const std::function<void()> onconnect); void connect(); void close(); void user(const std::string &username); void user(const std::string &username, const std::string &hostname, const std::string &server, const std::string &realname); void nick(std::string &nickname); void join(const std::string &chan); void part(const std::string &chan); void privmsg(const std::string &to, const std::string &msg); void command(const std::string &cmd, const std::string &msg); void command(const std::string &cmd, const std::string &to, const std::string &msg); void run(); private: void _read(const boost::system::error_code &error); void _send(std::string &message); void _readhandler(const boost::tokenizer<boost::char_separator<char> > &tokenizer); void _connecthandler(const boost::system::error_code &error); void _pong(const std::string &ping); std::string _server; std::string _port; std::string _chan; std::vector<std::function<void (const boost::tokenizer<boost::char_separator<char> >&)>> _readhandlers; std::function<void()> _onconnect; boost::asio::streambuf _buffer; boost::asio::io_service _ios; boost::shared_ptr<boost::asio::ip::tcp::socket> _socket; }; #endif irc.cpp
#include "irc.hpp" #include <iostream> #include <boost/bind.hpp> #include <boost/make_shared.hpp> irc::irc(const std::string &server, const std::string &port, const std::function<void()> onconnect) : _server(server), _port(port), _onconnect(onconnect), _socket(boost::make_shared<boost::asio::ip::tcp::socket>(boost::ref(_ios))) { // ping handler _readhandlers.push_back([this](const boost::tokenizer<boost::char_separator<char> > &tokenizer) { std::vector<std::string> tokens(begin(tokenizer), end(tokenizer)); if(tokens[0].compare("ping") == 0) _pong(tokens[1]); }); } void irc::connect() { boost::asio::ip::tcp::resolver resolver(_ios); boost::asio::ip::tcp::resolver::query query(_server, _port); boost::asio::ip::tcp::resolver::iterator = resolver.resolve(query); boost::asio::ip::tcp::resolver::iterator end; boost::system::error_code error = boost::asio::error::host_not_found; while(it != end) { if(!error) break; std::cout << "connecting " << _server << " " << _port << std::endl; boost::asio::async_connect(*_socket, it, boost::bind(&irc::_connecthandler, this, error) ); it++; if(error) std::cout << "error : " << error.message() << std::endl; } if(error) std::cout << "error connectinf " << _server << " " << error.message() << std::endl; else std::cout << "connection success" << std::endl; } void irc::close() { _socket->close(); _ios.stop(); } void irc::run() { boost::asio::async_read_until(*_socket, _buffer, "\r\n", boost::bind(&irc::_read, this, boost::asio::placeholders::error ) ); _ios.run(); } /* * private */ void irc::_read(const boost::system::error_code &error) { if(error) { std::cerr << "error in read : " << error.message() << std::endl; } else { std::string data(buffers_begin(_buffer.data()), buffers_begin(_buffer.data()) + _buffer.size()); std::cout << data << std::endl; boost::char_separator<char> sep("!@:; "); boost::tokenizer<boost::char_separator<char> > tokenizer(data, sep); _readhandler(tokenizer); boost::asio::async_read_until(*_socket, _buffer, "\r\n", boost::bind(&irc::_read, this, boost::asio::placeholders::error ) ); } } inline void irc::_send(std::string &message) { boost::asio::write(*_socket, boost::asio::buffer(message + "\r\n")); } void irc::_readhandler(const boost::tokenizer<boost::char_separator<char> > &tokenizer) { for(auto : _readhandlers) it(tokenizer); } void irc::_connecthandler(const boost::system::error_code &error) { if(!error) { _onconnect(); } }
connectnever called.
this causes "bad file handle" error
further notes
- suddenly,
_senduses synchronousasio::write. why? - error handling should added there, (catch or pass
error_code&argument). there's 1 socket never gets re-initialized or assigned. embedding shared pointer isn't changing anything¹.
this strange:
std::cout << "connecting " << _server << " " << _port << std::endl; boost::asio::async_connect(*_socket, it, boost::bind(&irc::_connecthandler, this, error) );this potentially many asynchronous connect operations on same socket simultaneously. data race , therefore undefined behaviour, see: documentation.
so need fix use several sockets or sequential. turns out, simple: you're using free function version of
async_connect:this function attempts connect socket 1 of sequence of endpoints. it repeated calls socket's
async_connectmember function, once each endpoint in sequence, until connection established.so fix call once.
your bind doesn't use placeholder, instead uses hardcoded error!
boost::system::error_code error = boost::asio::error::host_not_found; boost::asio::async_connect(_socket, it, boost::bind(&irc::_connecthandler, this, error));needs more like
boost::asio::async_connect(_socket, it, boost::bind(&irc::_connecthandler, this, boost::asio::placeholders::error()));after handling incoming traffic, need consume buffer contents, or infinitely repeat same:
_readhandler(tokenizer); _buffer.consume(_buffer.size());
pull request
adds:
869c225 use shared_ptr 9042c6d add function level trace 50dee1b revert shared_ptr , rename _onconnect(ed) 20475b9 fixing async_connect debacle c6d8a2e fixed channel handling , consistency join/part 6fd9242 initiate `connect()` instead of read `run()` 06a6c06 **not** assume contiguous buffer storage (ub) 090fe8c consume handled input 68e5e8a comment all above changed, have connected irc channel , receiving mesages.
¹ (especially not unless make sure hangs on instance of shared_ptr)

Comments
Post a Comment