PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/boost/cgi/scgi/request_acceptor_service.hpp

http://github.com/darrengarvey/cgi
C++ Header | 333 lines | 263 code | 44 blank | 26 comment | 8 complexity | bb33f43fc752d218e8c23b91b9275a3d MD5 | raw file
  1. // -- scgi/scgi_request_acceptor_service.hpp --
  2. //
  3. // Copyright (c) Darren Garvey 2010.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. ////////////////////////////////////////////////////////////////
  9. #ifndef CGI_SCGI_REQUEST_ACCEPTOR_SERVICE_HPP_INCLUDED__
  10. #define CGI_SCGI_REQUEST_ACCEPTOR_SERVICE_HPP_INCLUDED__
  11. #include "boost/cgi/detail/push_options.hpp"
  12. #include <boost/ref.hpp>
  13. #include <boost/bind.hpp>
  14. #include <boost/asio.hpp>
  15. #include <boost/thread.hpp>
  16. #include <boost/function.hpp>
  17. #include <boost/shared_ptr.hpp>
  18. #include <boost/static_assert.hpp>
  19. #include <boost/version.hpp>
  20. #include <boost/utility/enable_if.hpp>
  21. #include <boost/system/error_code.hpp>
  22. ///////////////////////////////////////////////////////////
  23. #include "boost/cgi/common/protocol_traits.hpp"
  24. #include "boost/cgi/scgi/request.hpp"
  25. #include "boost/cgi/scgi/error.hpp"
  26. #include "boost/cgi/import/io_service.hpp"
  27. #include "boost/cgi/detail/throw_error.hpp"
  28. #include "boost/cgi/detail/service_base.hpp"
  29. #include "boost/cgi/fwd/basic_protocol_service_fwd.hpp"
  30. BOOST_CGI_NAMESPACE_BEGIN
  31. //namespace scgi {
  32. /// The service_impl class for FCGI basic_request_acceptor<>s
  33. template<typename Protocol = common::tags::scgi>
  34. class scgi_request_acceptor_service
  35. : public detail::service_base<
  36. ::BOOST_CGI_NAMESPACE::scgi_request_acceptor_service<Protocol>
  37. >
  38. {
  39. public:
  40. typedef scgi_request_acceptor_service<Protocol> self_type;
  41. typedef Protocol protocol_type;
  42. typedef common::protocol_traits<Protocol> traits;
  43. typedef typename traits::protocol_service_type protocol_service_type;
  44. typedef typename traits::native_protocol_type native_protocol_type;
  45. typedef typename traits::native_type native_type;
  46. typedef typename traits::request_type request_type;
  47. typedef typename traits::acceptor_service_type acceptor_service_type;
  48. typedef typename traits::acceptor_impl_type acceptor_impl_type;
  49. typedef typename traits::endpoint_type endpoint_type;
  50. typedef boost::shared_ptr<request_type> request_ptr;
  51. typedef std::pair<
  52. typename std::set<request_ptr>::iterator, bool> request_iter;
  53. typedef boost::function<int (request_type&)> accept_handler_type;
  54. struct implementation_type
  55. {
  56. typedef Protocol protocol_type;
  57. typedef common::protocol_traits<Protocol> traits;
  58. typedef typename traits::protocol_service_type protocol_service_type;
  59. typedef typename traits::native_protocol_type native_protocol_type;
  60. typedef typename traits::request_type request_type;
  61. typedef typename traits::acceptor_service_type acceptor_service_type;
  62. typedef typename traits::endpoint_type endpoint_type;
  63. acceptor_impl_type acceptor_;
  64. protocol_service_type* protocol_service_;
  65. endpoint_type endpoint_;
  66. };
  67. explicit scgi_request_acceptor_service(::BOOST_CGI_NAMESPACE::common::io_service& ios)
  68. : detail::service_base< ::BOOST_CGI_NAMESPACE::scgi_request_acceptor_service<Protocol> >(ios)
  69. , acceptor_service_(boost::asio::use_service<acceptor_service_type>(ios))
  70. , strand_(ios)
  71. {
  72. }
  73. protocol_service_type&
  74. service(implementation_type const& impl) const
  75. {
  76. return *impl.protocol_service_;
  77. }
  78. void set_protocol_service(implementation_type& impl
  79. , protocol_service_type& ps)
  80. {
  81. impl.protocol_service_ = &ps;
  82. }
  83. protocol_service_type&
  84. get_protocol_service(implementation_type& impl)
  85. {
  86. BOOST_ASSERT(impl.protocol_service_ != NULL);
  87. return *impl.protocol_service_;
  88. }
  89. void construct(implementation_type& impl)
  90. {
  91. acceptor_service_.construct(impl.acceptor_);
  92. }
  93. void destroy(implementation_type& impl)
  94. {
  95. // close/reject all the waiting requests
  96. acceptor_service_.destroy(impl.acceptor_);
  97. }
  98. #if BOOST_VERSION >= 104700
  99. void shutdown_service()
  100. {
  101. #if BOOST_VERSION < 104900
  102. acceptor_service_.shutdown_service();
  103. #endif
  104. }
  105. #endif
  106. boost::system::error_code
  107. default_init(implementation_type& impl, boost::system::error_code& ec)
  108. {
  109. #if BOOST_VERSION < 104400
  110. ec = boost::system::error_code(829, boost::system::system_category);
  111. #else
  112. ec = boost::system::error_code(829, boost::system::system_category());
  113. #endif
  114. return ec;
  115. }
  116. /// Check if the given implementation is open.
  117. bool is_open(implementation_type& impl)
  118. {
  119. return acceptor_service_.is_open(impl.acceptor_);
  120. }
  121. /// Open a new *socket* acceptor implementation.
  122. boost::system::error_code
  123. open(implementation_type& impl, const native_protocol_type& protocol
  124. , boost::system::error_code& ec)
  125. {
  126. return acceptor_service_.open(impl.acceptor_, protocol, ec);
  127. }
  128. template<typename Endpoint>
  129. boost::system::error_code
  130. bind(implementation_type& impl, const Endpoint& endpoint
  131. , boost::system::error_code& ec)
  132. {
  133. return acceptor_service_.bind(impl.acceptor_, endpoint, ec);
  134. }
  135. /// Assign an existing native acceptor to a *socket* acceptor.
  136. boost::system::error_code
  137. assign(implementation_type& impl, const native_protocol_type& protocol
  138. , const native_type& native_acceptor
  139. , boost::system::error_code& ec)
  140. {
  141. return acceptor_service_.assign(impl.acceptor_, protocol
  142. , native_acceptor, ec);
  143. }
  144. boost::system::error_code
  145. listen(implementation_type& impl, int backlog, boost::system::error_code& ec)
  146. {
  147. return acceptor_service_.listen(impl.acceptor_, backlog, ec);
  148. }
  149. template<typename SettableSocketOption>
  150. boost::system::error_code
  151. set_option(implementation_type& impl, const SettableSocketOption& option
  152. , boost::system::error_code& ec)
  153. {
  154. return acceptor_service_.set_option(impl.acceptor_, option, ec);
  155. }
  156. void do_accept(implementation_type& impl
  157. , accept_handler_type handler)
  158. {
  159. request_ptr new_request;
  160. new_request = request_type::create(*impl.protocol_service_);
  161. if (!new_request->is_open())
  162. {
  163. acceptor_service_.async_accept(impl.acceptor_,
  164. new_request->client().connection()->next_layer(), 0,
  165. strand_.wrap(
  166. boost::bind(&self_type::handle_accept
  167. , this, boost::ref(impl), new_request, handler, _1
  168. )
  169. )
  170. );
  171. }
  172. else
  173. {
  174. impl.protocol_service_->post(
  175. strand_.wrap(
  176. boost::bind(&self_type::handle_accept
  177. , this, boost::ref(impl), new_request, handler, boost::system::error_code()
  178. )
  179. )
  180. );
  181. }
  182. }
  183. void handle_accept(
  184. implementation_type& impl, request_ptr new_request,
  185. accept_handler_type handler, const boost::system::error_code& ec
  186. )
  187. {
  188. new_request->status(common::accepted);
  189. int status = handler(*new_request);
  190. if (new_request->is_open()) {
  191. new_request->close(http::ok, status);
  192. }
  193. new_request->clear();
  194. }
  195. /// Accepts a request and runs the passed handler.
  196. void async_accept(implementation_type& impl
  197. , accept_handler_type handler)
  198. {
  199. strand_.post(
  200. boost::bind(&self_type::do_accept,
  201. this, boost::ref(impl), handler)
  202. );
  203. }
  204. int accept(implementation_type& impl, accept_handler_type handler
  205. , endpoint_type* endpoint, boost::system::error_code& ec)
  206. {
  207. request_ptr new_request;
  208. // Accepting on new request.
  209. new_request = request_type::create(*impl.protocol_service_);
  210. // The waiting request may be open if it is a multiplexed request.
  211. if (!new_request->is_open())
  212. {
  213. ec = acceptor_service_.accept(impl.acceptor_,
  214. new_request->client().connection()->next_layer(), endpoint, ec);
  215. }
  216. new_request->status(common::accepted);
  217. int status = handler(*new_request);
  218. if (new_request->is_open()) {
  219. new_request->close(common::http::ok, status);
  220. }
  221. new_request->clear();
  222. return status;
  223. }
  224. /// Accepts one request.
  225. template<typename CommonGatewayRequest>
  226. boost::system::error_code
  227. accept(implementation_type& impl, CommonGatewayRequest& request
  228. , endpoint_type* endpoint, boost::system::error_code& ec)
  229. {
  230. BOOST_ASSERT
  231. ( ! request.is_open()
  232. && "Error: Calling accept on open request (close it first?)."
  233. );
  234. // If the client is open, make sure the request is clean.
  235. // ie. don't leak data from one request to another!
  236. if (request.client().is_open())
  237. {
  238. request.clear();
  239. }
  240. // ...otherwise accept a new connection.
  241. ec = acceptor_service_.accept(impl.acceptor_,
  242. request.client().connection()->next_layer(), endpoint, ec);
  243. if (!ec)
  244. request.status(common::accepted);
  245. return ec;
  246. }
  247. /// Asynchronously accepts one request.
  248. template<typename Handler>
  249. void async_accept(implementation_type& impl
  250. , typename implementation_type::request_type& request
  251. , Handler handler)
  252. {
  253. acceptor_service_.async_accept(impl.acceptor_,
  254. request.client().connection()->next_layer(), handler);
  255. }
  256. /// Close the acceptor (not implemented yet).
  257. boost::system::error_code
  258. close(implementation_type& impl, boost::system::error_code& ec)
  259. {
  260. #if BOOST_VERSION < 104400
  261. return boost::system::error_code(348, boost::system::system_category);
  262. #else
  263. return boost::system::error_code(348, boost::system::system_category());
  264. #endif
  265. }
  266. typename implementation_type::endpoint_type
  267. local_endpoint(implementation_type& impl, boost::system::error_code& ec)
  268. {
  269. return acceptor_service_.local_endpoint(impl.acceptor_, ec);
  270. }
  271. native_type
  272. native(implementation_type& impl)
  273. {
  274. return acceptor_service_.native(impl.acceptor_);
  275. }
  276. bool
  277. is_cgi(implementation_type& impl)
  278. {
  279. return false;
  280. }
  281. public:
  282. /// The underlying socket acceptor service.
  283. acceptor_service_type& acceptor_service_;
  284. boost::asio::io_service::strand strand_;
  285. };
  286. //} // namespace scgi
  287. BOOST_CGI_NAMESPACE_END
  288. #include "boost/cgi/detail/pop_options.hpp"
  289. #endif // CGI_SCGI_REQUEST_ACCEPTOR_SERVICE_HPP_INCLUDED__