23 #include <boost/bind.hpp>
24 #include <boost/enable_shared_from_this.hpp>
36 const size_t BUF_SIZE = 32768;
44 class Connection :
public boost::enable_shared_from_this<Connection> {
65 const boost::shared_ptr<UnixDomainSocket>& socket,
66 ConnectionPool& connection_pool,
68 : socket_(socket), timeout_timer_(*io_service), timeout_(timeout),
69 buf_(), response_(), connection_pool_(connection_pool), feed_(),
70 response_in_progress_(false), watch_socket_(new util::WatchSocket()) {
73 .arg(socket_->getNative());
91 timeout_timer_.cancel();
95 void scheduleTimer() {
96 timeout_timer_.setup(boost::bind(&Connection::timeoutHandler,
this),
107 if (!response_in_progress_) {
109 .arg(socket_->getNative());
115 std::string watch_error;
116 if (!watch_socket_->closeSocket(watch_error)) {
122 timeout_timer_.cancel();
138 socket_->asyncReceive(&buf_[0],
sizeof(buf_),
139 boost::bind(&Connection::receiveHandler,
140 shared_from_this(), _1, _2));
151 size_t chunk_size = (response_.size() < BUF_SIZE) ? response_.size() : BUF_SIZE;
152 socket_->asyncSend(&response_[0], chunk_size,
153 boost::bind(&Connection::sendHandler, shared_from_this(), _1, _2));
159 watch_socket_->markReady();
161 }
catch (
const std::exception& ex) {
179 void receiveHandler(
const boost::system::error_code& ec,
180 size_t bytes_transferred);
191 void sendHandler(
const boost::system::error_code& ec,
192 size_t bytes_transferred);
198 void timeoutHandler();
203 boost::shared_ptr<UnixDomainSocket> socket_;
212 std::array<char, BUF_SIZE> buf_;
215 std::string response_;
218 ConnectionPool& connection_pool_;
226 bool response_in_progress_;
234 typedef boost::shared_ptr<Connection> ConnectionPtr;
237 class ConnectionPool {
243 void start(
const ConnectionPtr& connection) {
244 connection->doReceive();
245 connections_.insert(connection);
251 void stop(
const ConnectionPtr& connection) {
254 connections_.erase(connection);
255 }
catch (
const std::exception& ex) {
263 for (
auto conn = connections_.begin(); conn != connections_.end();
267 connections_.clear();
273 std::set<ConnectionPtr> connections_;
278 Connection::terminate() {
282 }
catch (
const std::exception& ex) {
289 Connection::receiveHandler(
const boost::system::error_code& ec,
290 size_t bytes_transferred) {
292 if (ec.value() == boost::asio::error::eof) {
293 std::stringstream os;
294 if (feed_.getProcessedText().empty()) {
295 os <<
"no input data to discard";
298 os <<
"discarding partial command of "
299 << feed_.getProcessedText().size() <<
" bytes";
305 .arg(socket_->getNative()).arg(os.str());
306 }
else if (ec.value() != boost::asio::error::operation_aborted) {
308 .arg(ec.value()).arg(socket_->getNative());
311 connection_pool_.stop(shared_from_this());
314 }
else if (bytes_transferred == 0) {
316 connection_pool_.stop(shared_from_this());
321 .arg(bytes_transferred).arg(socket_->getNative());
331 feed_.postBuffer(&buf_[0], bytes_transferred);
334 if (feed_.needData()) {
340 if (feed_.feedOk()) {
342 response_in_progress_ =
true;
346 timeout_timer_.cancel();
349 rsp = CommandMgr::instance().processCommand(cmd);
351 response_in_progress_ =
false;
369 "internal server error: no response generated");
379 response_ = rsp->str();
386 connection_pool_.stop(shared_from_this());
390 Connection::sendHandler(
const boost::system::error_code& ec,
391 size_t bytes_transferred) {
395 watch_socket_->clearReady();
397 }
catch (
const std::exception& ex) {
404 if (ec.value() != boost::asio::error::operation_aborted) {
406 .arg(socket_->getNative()).arg(ec.message());
417 response_.erase(0, bytes_transferred);
420 .arg(bytes_transferred).arg(response_.size())
421 .arg(socket_->getNative());
424 if (!response_.empty()) {
435 connection_pool_.stop(shared_from_this());
439 Connection::timeoutHandler() {
441 .arg(socket_->getNative());
446 }
catch (
const std::exception& ex) {
448 .arg(socket_->getNative())
452 std::stringstream os;
453 os <<
"Connection over control channel timed out";
454 if (!feed_.getProcessedText().empty()) {
455 os <<
", discarded partial command of "
456 << feed_.getProcessedText().size() <<
" bytes";
460 response_ = rsp->str();
476 : io_service_(), acceptor_(), socket_(), socket_name_(),
514 socket_name_.clear();
526 if (type->stringValue() !=
"unix") {
528 << type->stringValue());
538 if (name->getType() != Element::string) {
542 socket_name_ = name->stringValue();
551 acceptor_->open(endpoint);
552 acceptor_->bind(endpoint);
560 }
catch (
const std::exception& ex) {
566 CommandMgrImpl::doAccept() {
569 acceptor_->asyncAccept(*socket_, [
this](
const boost::system::error_code& ec) {
572 ConnectionPtr connection(
new Connection(io_service_, socket_,
575 connection_pool_.start(connection);
577 }
else if (ec.value() != boost::asio::error::operation_aborted) {
579 .arg(acceptor_->getNative()).arg(ec.message());
583 if (ec.value() != boost::asio::error::operation_aborted) {
589 CommandMgr::CommandMgr()
595 impl_->openCommandSocket(socket_info);
600 if (impl_->acceptor_ && impl_->acceptor_->isOpen()) {
602 impl_->acceptor_->close();
603 static_cast<void>(::remove(impl_->socket_name_.c_str()));
610 impl_->connection_pool_.stopAll();
615 return (impl_->acceptor_ ? impl_->acceptor_->getNative() : -1);
627 impl_->io_service_ = io_service;
632 impl_->timeout_ = timeout;