pion
5.0.6
|
00001 // --------------------------------------------------------------------- 00002 // pion: a Boost C++ framework for building lightweight HTTP interfaces 00003 // --------------------------------------------------------------------- 00004 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 00005 // 00006 // Distributed under the Boost Software License, Version 1.0. 00007 // See http://www.boost.org/LICENSE_1_0.txt 00008 // 00009 00010 #ifndef __PION_TCP_CONNECTION_HEADER__ 00011 #define __PION_TCP_CONNECTION_HEADER__ 00012 00013 #ifdef PION_HAVE_SSL 00014 #ifdef PION_XCODE 00015 // ignore openssl warnings if building with XCode 00016 #pragma GCC system_header 00017 #endif 00018 #include <boost/asio/ssl.hpp> 00019 #endif 00020 00021 #include <boost/noncopyable.hpp> 00022 #include <boost/shared_ptr.hpp> 00023 #include <boost/lexical_cast.hpp> 00024 #include <boost/enable_shared_from_this.hpp> 00025 #include <boost/asio.hpp> 00026 #include <boost/array.hpp> 00027 #include <boost/function.hpp> 00028 #include <boost/function/function1.hpp> 00029 #include <pion/config.hpp> 00030 #include <string> 00031 00032 00033 namespace pion { // begin namespace pion 00034 namespace tcp { // begin namespace tcp 00035 00036 00040 class connection : 00041 public boost::enable_shared_from_this<connection>, 00042 private boost::noncopyable 00043 { 00044 public: 00045 00047 enum lifecycle_type { 00048 LIFECYCLE_CLOSE, LIFECYCLE_KEEPALIVE, LIFECYCLE_PIPELINED 00049 }; 00050 00052 enum { READ_BUFFER_SIZE = 8192 }; 00053 00055 typedef boost::function1<void, boost::shared_ptr<connection> > connection_handler; 00056 00058 typedef boost::array<char, READ_BUFFER_SIZE> read_buffer_type; 00059 00061 typedef boost::asio::ip::tcp::socket socket_type; 00062 00063 #ifdef PION_HAVE_SSL 00064 00065 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket_type; 00066 00068 typedef boost::asio::ssl::context ssl_context_type; 00069 #else 00070 class ssl_socket_type { 00071 public: 00072 ssl_socket_type(boost::asio::io_service& io_service) : m_socket(io_service) {} 00073 inline socket_type& next_layer(void) { return m_socket; } 00074 inline const socket_type& next_layer(void) const { return m_socket; } 00075 inline socket_type::lowest_layer_type& lowest_layer(void) { return m_socket.lowest_layer(); } 00076 inline const socket_type::lowest_layer_type& lowest_layer(void) const { return m_socket.lowest_layer(); } 00077 inline void shutdown(void) {} 00078 private: 00079 socket_type m_socket; 00080 }; 00081 typedef int ssl_context_type; 00082 #endif 00083 00084 00094 static inline boost::shared_ptr<connection> create(boost::asio::io_service& io_service, 00095 ssl_context_type& ssl_context, 00096 const bool ssl_flag, 00097 connection_handler finished_handler) 00098 { 00099 return boost::shared_ptr<connection>(new connection(io_service, ssl_context, 00100 ssl_flag, finished_handler)); 00101 } 00102 00109 explicit connection(boost::asio::io_service& io_service, const bool ssl_flag = false) 00110 : 00111 #ifdef PION_HAVE_SSL 00112 m_ssl_context(io_service, boost::asio::ssl::context::sslv23), 00113 m_ssl_socket(io_service, m_ssl_context), 00114 m_ssl_flag(ssl_flag), 00115 #else 00116 m_ssl_context(0), 00117 m_ssl_socket(io_service), 00118 m_ssl_flag(false), 00119 #endif 00120 m_lifecycle(LIFECYCLE_CLOSE) 00121 { 00122 save_read_pos(NULL, NULL); 00123 } 00124 00131 connection(boost::asio::io_service& io_service, ssl_context_type& ssl_context) 00132 : 00133 #ifdef PION_HAVE_SSL 00134 m_ssl_context(io_service, boost::asio::ssl::context::sslv23), 00135 m_ssl_socket(io_service, ssl_context), m_ssl_flag(true), 00136 #else 00137 m_ssl_context(0), 00138 m_ssl_socket(io_service), m_ssl_flag(false), 00139 #endif 00140 m_lifecycle(LIFECYCLE_CLOSE) 00141 { 00142 save_read_pos(NULL, NULL); 00143 } 00144 00146 inline bool is_open(void) const { 00147 return const_cast<ssl_socket_type&>(m_ssl_socket).lowest_layer().is_open(); 00148 } 00149 00151 inline void close(void) { 00152 if (is_open()) { 00153 try { 00154 00155 // shutting down SSL will wait forever for a response from the remote end, 00156 // which causes it to hang indefinitely if the other end died unexpectedly 00157 // if (get_ssl_flag()) m_ssl_socket.shutdown(); 00158 00159 // windows seems to require this otherwise it doesn't 00160 // recognize that connections have been closed 00161 m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both); 00162 00163 } catch (...) {} // ignore exceptions 00164 00165 // close the underlying socket (ignore errors) 00166 boost::system::error_code ec; 00167 m_ssl_socket.next_layer().close(ec); 00168 } 00169 } 00170 00176 inline void cancel(void) { 00177 #if !defined(_MSC_VER) || (_WIN32_WINNT >= 0x0600) 00178 boost::system::error_code ec; 00179 m_ssl_socket.next_layer().cancel(ec); 00180 #endif 00181 } 00182 00184 virtual ~connection() { close(); } 00185 00194 template <typename AcceptHandler> 00195 inline void async_accept(boost::asio::ip::tcp::acceptor& tcp_acceptor, 00196 AcceptHandler handler) 00197 { 00198 tcp_acceptor.async_accept(m_ssl_socket.lowest_layer(), handler); 00199 } 00200 00209 inline boost::system::error_code accept(boost::asio::ip::tcp::acceptor& tcp_acceptor) 00210 { 00211 boost::system::error_code ec; 00212 tcp_acceptor.accept(m_ssl_socket.lowest_layer(), ec); 00213 return ec; 00214 } 00215 00224 template <typename ConnectHandler> 00225 inline void async_connect(const boost::asio::ip::tcp::endpoint& tcp_endpoint, 00226 ConnectHandler handler) 00227 { 00228 m_ssl_socket.lowest_layer().async_connect(tcp_endpoint, handler); 00229 } 00230 00240 template <typename ConnectHandler> 00241 inline void async_connect(const boost::asio::ip::address& remote_addr, 00242 const unsigned int remote_port, 00243 ConnectHandler handler) 00244 { 00245 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port); 00246 async_connect(tcp_endpoint, handler); 00247 } 00248 00257 inline boost::system::error_code connect(boost::asio::ip::tcp::endpoint& tcp_endpoint) 00258 { 00259 boost::system::error_code ec; 00260 m_ssl_socket.lowest_layer().connect(tcp_endpoint, ec); 00261 return ec; 00262 } 00263 00273 inline boost::system::error_code connect(const boost::asio::ip::address& remote_addr, 00274 const unsigned int remote_port) 00275 { 00276 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port); 00277 return connect(tcp_endpoint); 00278 } 00279 00289 inline boost::system::error_code connect(const std::string& remote_server, 00290 const unsigned int remote_port) 00291 { 00292 // query a list of matching endpoints 00293 boost::system::error_code ec; 00294 boost::asio::ip::tcp::resolver resolver(m_ssl_socket.lowest_layer().get_io_service()); 00295 boost::asio::ip::tcp::resolver::query query(remote_server, 00296 boost::lexical_cast<std::string>(remote_port), 00297 boost::asio::ip::tcp::resolver::query::numeric_service); 00298 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, ec); 00299 if (ec) 00300 return ec; 00301 00302 // try each one until we are successful 00303 ec = boost::asio::error::host_not_found; 00304 boost::asio::ip::tcp::resolver::iterator end; 00305 while (ec && endpoint_iterator != end) { 00306 boost::asio::ip::tcp::endpoint ep(endpoint_iterator->endpoint()); 00307 ++endpoint_iterator; 00308 ec = connect(ep); 00309 if (ec) 00310 close(); 00311 } 00312 00313 return ec; 00314 } 00315 00323 template <typename SSLHandshakeHandler> 00324 inline void async_handshake_client(SSLHandshakeHandler handler) { 00325 #ifdef PION_HAVE_SSL 00326 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::client, handler); 00327 m_ssl_flag = true; 00328 #endif 00329 } 00330 00338 template <typename SSLHandshakeHandler> 00339 inline void async_handshake_server(SSLHandshakeHandler handler) { 00340 #ifdef PION_HAVE_SSL 00341 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::server, handler); 00342 m_ssl_flag = true; 00343 #endif 00344 } 00345 00353 inline boost::system::error_code handshake_client(void) { 00354 boost::system::error_code ec; 00355 #ifdef PION_HAVE_SSL 00356 m_ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec); 00357 m_ssl_flag = true; 00358 #endif 00359 return ec; 00360 } 00361 00369 inline boost::system::error_code handshake_server(void) { 00370 boost::system::error_code ec; 00371 #ifdef PION_HAVE_SSL 00372 m_ssl_socket.handshake(boost::asio::ssl::stream_base::server, ec); 00373 m_ssl_flag = true; 00374 #endif 00375 return ec; 00376 } 00377 00385 template <typename ReadHandler> 00386 inline void async_read_some(ReadHandler handler) { 00387 #ifdef PION_HAVE_SSL 00388 if (get_ssl_flag()) 00389 m_ssl_socket.async_read_some(boost::asio::buffer(m_read_buffer), 00390 handler); 00391 else 00392 #endif 00393 m_ssl_socket.next_layer().async_read_some(boost::asio::buffer(m_read_buffer), 00394 handler); 00395 } 00396 00405 template <typename ReadBufferType, typename ReadHandler> 00406 inline void async_read_some(ReadBufferType read_buffer, 00407 ReadHandler handler) { 00408 #ifdef PION_HAVE_SSL 00409 if (get_ssl_flag()) 00410 m_ssl_socket.async_read_some(read_buffer, handler); 00411 else 00412 #endif 00413 m_ssl_socket.next_layer().async_read_some(read_buffer, handler); 00414 } 00415 00424 inline std::size_t read_some(boost::system::error_code& ec) { 00425 #ifdef PION_HAVE_SSL 00426 if (get_ssl_flag()) 00427 return m_ssl_socket.read_some(boost::asio::buffer(m_read_buffer), ec); 00428 else 00429 #endif 00430 return m_ssl_socket.next_layer().read_some(boost::asio::buffer(m_read_buffer), ec); 00431 } 00432 00442 template <typename ReadBufferType> 00443 inline std::size_t read_some(ReadBufferType read_buffer, 00444 boost::system::error_code& ec) 00445 { 00446 #ifdef PION_HAVE_SSL 00447 if (get_ssl_flag()) 00448 return m_ssl_socket.read_some(read_buffer, ec); 00449 else 00450 #endif 00451 return m_ssl_socket.next_layer().read_some(read_buffer, ec); 00452 } 00453 00463 template <typename CompletionCondition, typename ReadHandler> 00464 inline void async_read(CompletionCondition completion_condition, 00465 ReadHandler handler) 00466 { 00467 #ifdef PION_HAVE_SSL 00468 if (get_ssl_flag()) 00469 boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer), 00470 completion_condition, handler); 00471 else 00472 #endif 00473 boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(m_read_buffer), 00474 completion_condition, handler); 00475 } 00476 00487 template <typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> 00488 inline void async_read(const MutableBufferSequence& buffers, 00489 CompletionCondition completion_condition, 00490 ReadHandler handler) 00491 { 00492 #ifdef PION_HAVE_SSL 00493 if (get_ssl_flag()) 00494 boost::asio::async_read(m_ssl_socket, buffers, 00495 completion_condition, handler); 00496 else 00497 #endif 00498 boost::asio::async_read(m_ssl_socket.next_layer(), buffers, 00499 completion_condition, handler); 00500 } 00501 00512 template <typename CompletionCondition> 00513 inline std::size_t read(CompletionCondition completion_condition, 00514 boost::system::error_code& ec) 00515 { 00516 #ifdef PION_HAVE_SSL 00517 if (get_ssl_flag()) 00518 return boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer), 00519 completion_condition, ec); 00520 else 00521 #endif 00522 return boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(m_read_buffer), 00523 completion_condition, ec); 00524 } 00525 00537 template <typename MutableBufferSequence, typename CompletionCondition> 00538 inline std::size_t read(const MutableBufferSequence& buffers, 00539 CompletionCondition completion_condition, 00540 boost::system::error_code& ec) 00541 { 00542 #ifdef PION_HAVE_SSL 00543 if (get_ssl_flag()) 00544 return boost::asio::read(m_ssl_socket, buffers, 00545 completion_condition, ec); 00546 else 00547 #endif 00548 return boost::asio::read(m_ssl_socket.next_layer(), buffers, 00549 completion_condition, ec); 00550 } 00551 00560 template <typename ConstBufferSequence, typename write_handler_t> 00561 inline void async_write(const ConstBufferSequence& buffers, write_handler_t handler) { 00562 #ifdef PION_HAVE_SSL 00563 if (get_ssl_flag()) 00564 boost::asio::async_write(m_ssl_socket, buffers, handler); 00565 else 00566 #endif 00567 boost::asio::async_write(m_ssl_socket.next_layer(), buffers, handler); 00568 } 00569 00579 template <typename ConstBufferSequence> 00580 inline std::size_t write(const ConstBufferSequence& buffers, 00581 boost::system::error_code& ec) 00582 { 00583 #ifdef PION_HAVE_SSL 00584 if (get_ssl_flag()) 00585 return boost::asio::write(m_ssl_socket, buffers, 00586 boost::asio::transfer_all(), ec); 00587 else 00588 #endif 00589 return boost::asio::write(m_ssl_socket.next_layer(), buffers, 00590 boost::asio::transfer_all(), ec); 00591 } 00592 00593 00596 inline void finish(void) { if (m_finished_handler) m_finished_handler(shared_from_this()); } 00597 00599 inline bool get_ssl_flag(void) const { return m_ssl_flag; } 00600 00602 inline void set_lifecycle(lifecycle_type t) { m_lifecycle = t; } 00603 00605 inline lifecycle_type get_lifecycle(void) const { return m_lifecycle; } 00606 00608 inline bool get_keep_alive(void) const { return m_lifecycle != LIFECYCLE_CLOSE; } 00609 00611 inline bool get_pipelined(void) const { return m_lifecycle == LIFECYCLE_PIPELINED; } 00612 00614 inline read_buffer_type& get_read_buffer(void) { return m_read_buffer; } 00615 00622 inline void save_read_pos(const char *read_ptr, const char *read_end_ptr) { 00623 m_read_position.first = read_ptr; 00624 m_read_position.second = read_end_ptr; 00625 } 00626 00633 inline void load_read_pos(const char *&read_ptr, const char *&read_end_ptr) const { 00634 read_ptr = m_read_position.first; 00635 read_end_ptr = m_read_position.second; 00636 } 00637 00639 inline boost::asio::ip::tcp::endpoint get_remote_endpoint(void) const { 00640 boost::asio::ip::tcp::endpoint remote_endpoint; 00641 try { 00642 // const_cast is required since lowest_layer() is only defined non-const in asio 00643 remote_endpoint = const_cast<ssl_socket_type&>(m_ssl_socket).lowest_layer().remote_endpoint(); 00644 } catch (boost::system::system_error& /* e */) { 00645 // do nothing 00646 } 00647 return remote_endpoint; 00648 } 00649 00651 inline boost::asio::ip::address get_remote_ip(void) const { 00652 return get_remote_endpoint().address(); 00653 } 00654 00656 inline unsigned short get_remote_port(void) const { 00657 return get_remote_endpoint().port(); 00658 } 00659 00661 inline boost::asio::io_service& get_io_service(void) { 00662 return m_ssl_socket.lowest_layer().get_io_service(); 00663 } 00664 00666 inline socket_type& get_socket(void) { return m_ssl_socket.next_layer(); } 00667 00669 inline ssl_socket_type& get_ssl_socket(void) { return m_ssl_socket; } 00670 00672 inline const socket_type& get_socket(void) const { return const_cast<ssl_socket_type&>(m_ssl_socket).next_layer(); } 00673 00675 inline const ssl_socket_type& get_ssl_socket(void) const { return m_ssl_socket; } 00676 00677 00678 protected: 00679 00689 connection(boost::asio::io_service& io_service, 00690 ssl_context_type& ssl_context, 00691 const bool ssl_flag, 00692 connection_handler finished_handler) 00693 : 00694 #ifdef PION_HAVE_SSL 00695 m_ssl_context(io_service, boost::asio::ssl::context::sslv23), 00696 m_ssl_socket(io_service, ssl_context), m_ssl_flag(ssl_flag), 00697 #else 00698 m_ssl_context(0), 00699 m_ssl_socket(io_service), m_ssl_flag(false), 00700 #endif 00701 m_lifecycle(LIFECYCLE_CLOSE), 00702 m_finished_handler(finished_handler) 00703 { 00704 save_read_pos(NULL, NULL); 00705 } 00706 00707 00708 private: 00709 00711 typedef std::pair<const char*, const char*> read_pos_type; 00712 00713 00715 ssl_context_type m_ssl_context; 00716 00718 ssl_socket_type m_ssl_socket; 00719 00721 bool m_ssl_flag; 00722 00724 read_buffer_type m_read_buffer; 00725 00727 read_pos_type m_read_position; 00728 00730 lifecycle_type m_lifecycle; 00731 00733 connection_handler m_finished_handler; 00734 }; 00735 00736 00738 typedef boost::shared_ptr<connection> connection_ptr; 00739 00740 00741 } // end namespace tcp 00742 } // end namespace pion 00743 00744 #endif