/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #ifndef CPPCMS_CGI_ACCEPTOR_H #define CPPCMS_CGI_ACCEPTOR_H #include "cgi_api.h" #include #include "service_impl.h" #include #include #include #include #ifndef CPPCMS_WIN32 #include #endif namespace io = booster::aio; namespace cppcms { namespace impl { namespace cgi { template struct server_api_factory { API *operator()(cppcms::service &srv) const { return new API(srv); } }; template > class socket_acceptor : public acceptor { public: socket_acceptor(cppcms::service &srv,std::string ip,int port,int backlog) : srv_(srv), acceptor_(srv_.get_io_service()), stopped_(false), tcp_(true), sndbuf_(-1), rcvbuf_(-1) { io::endpoint ep(ip,port); acceptor_.open(ep.family()); #ifndef CPPCMS_WIN32 acceptor_.set_option(io::basic_socket::reuse_address,true); #endif acceptor_.bind(ep); acceptor_.listen(backlog); } void factory(Factory const &f) { factory_ = f; } #if !defined(CPPCMS_WIN32) socket_acceptor(cppcms::service &srv,int backlog) : srv_(srv), acceptor_(srv_.get_io_service()), stopped_(false), tcp_(false) { acceptor_.attach(0); acceptor_.listen(backlog); } socket_acceptor(cppcms::service &srv,std::string path,int backlog) : srv_(srv), acceptor_(srv_.get_io_service()), stopped_(false), tcp_(false) { io::endpoint ep(path); acceptor_.open(io::pf_unix); acceptor_.set_option(io::basic_socket::reuse_address,true); ::unlink(path.c_str()); acceptor_.bind(ep); acceptor_.listen(backlog); } #endif struct accept_binder { socket_acceptor *self; accept_binder(socket_acceptor *s=0) : self(s) {} void operator()(booster::system::error_code const &e) { self->on_accept(e); } }; #ifndef CPPCMS_WIN32 virtual booster::shared_ptr< ::cppcms::http::context> accept(int fd) { booster::shared_ptr api; try { api.reset(factory_(srv_)); api->socket_.assign(fd); fd=-1; } catch(...) { ::close(fd); throw; } if(tcp_) api->socket_.set_option(io::basic_socket::tcp_no_delay,true); booster::shared_ptr< ::cppcms::http::context> cnt(new ::cppcms::http::context(api)); return cnt; } #endif virtual booster::aio::acceptor &socket() { return acceptor_; } virtual void async_accept() { if(stopped_) return; booster::shared_ptr api(factory_(srv_)); api_=api; asio_socket_ = &api->socket_; acceptor_.async_accept(*asio_socket_,accept_binder(this)); } virtual void stop() { stopped_=true; acceptor_.cancel(); } void sndbuf(int v) { sndbuf_ = v; } void rcvbuf(int v) { rcvbuf_ = v; } private: void on_accept(booster::system::error_code const &e) { if(!e) { if(tcp_) asio_socket_->set_option(io::basic_socket::tcp_no_delay,true); if(sndbuf_!=-1) asio_socket_->set_option(io::basic_socket::send_buffer_size,sndbuf_); if(rcvbuf_!=-1) asio_socket_->set_option(io::basic_socket::receive_buffer_size,rcvbuf_); booster::shared_ptr< ::cppcms::http::context> cnt(new ::cppcms::http::context(api_)); api_.reset(); cnt->run(); } async_accept(); } cppcms::service &srv_; booster::shared_ptr api_; booster::aio::stream_socket *asio_socket_; booster::aio::acceptor acceptor_; bool stopped_; bool tcp_; int sndbuf_,rcvbuf_; Factory factory_; }; } // cgi } // impl } // cppcms #endif