00001
00002
00003
00004
00005
00006
00007
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
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 {
00034 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
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
00156
00157
00158
00159
00160
00161 m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
00162
00163 } catch (...) {}
00164
00165
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(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
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
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
00643 remote_endpoint = const_cast<ssl_socket_type&>(m_ssl_socket).lowest_layer().remote_endpoint();
00644 } catch (boost::system::system_error& ) {
00645
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 }
00742 }
00743
00744 #endif