00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef __PION_TCPCONNECTION_HEADER__
00011 #define __PION_TCPCONNECTION_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/PionConfig.hpp>
00030 #include <string>
00031
00032
00033 namespace pion {
00034 namespace net {
00035
00039 class TCPConnection :
00040 public boost::enable_shared_from_this<TCPConnection>,
00041 private boost::noncopyable
00042 {
00043 public:
00044
00046 enum LifecycleType {
00047 LIFECYCLE_CLOSE, LIFECYCLE_KEEPALIVE, LIFECYCLE_PIPELINED
00048 };
00049
00051 enum { READ_BUFFER_SIZE = 8192 };
00052
00054 typedef boost::function1<void, boost::shared_ptr<TCPConnection> > ConnectionHandler;
00055
00057 typedef boost::array<char, READ_BUFFER_SIZE> ReadBuffer;
00058
00060 typedef boost::asio::ip::tcp::socket Socket;
00061
00062 #ifdef PION_HAVE_SSL
00064 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket;
00065
00067 typedef boost::asio::ssl::context SSLContext;
00068 #else
00069 typedef Socket SSLSocket;
00070 typedef int SSLContext;
00071 #endif
00072
00073
00083 static inline boost::shared_ptr<TCPConnection> create(boost::asio::io_service& io_service,
00084 SSLContext& ssl_context,
00085 const bool ssl_flag,
00086 ConnectionHandler finished_handler)
00087 {
00088 return boost::shared_ptr<TCPConnection>(new TCPConnection(io_service, ssl_context,
00089 ssl_flag, finished_handler));
00090 }
00091
00098 explicit TCPConnection(boost::asio::io_service& io_service, const bool ssl_flag = false)
00099 : m_tcp_socket(io_service),
00100 #ifdef PION_HAVE_SSL
00101 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00102 m_ssl_socket(io_service, m_ssl_context),
00103 m_ssl_flag(ssl_flag),
00104 #else
00105 m_ssl_context(0),
00106 m_ssl_socket(io_service),
00107 m_ssl_flag(false),
00108 #endif
00109 m_lifecycle(LIFECYCLE_CLOSE)
00110 {
00111 saveReadPosition(NULL, NULL);
00112 }
00113
00120 TCPConnection(boost::asio::io_service& io_service, SSLContext& ssl_context)
00121 : m_tcp_socket(io_service),
00122 #ifdef PION_HAVE_SSL
00123 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00124 m_ssl_socket(io_service, ssl_context), m_ssl_flag(true),
00125 #else
00126 m_ssl_context(0),
00127 m_ssl_socket(io_service), m_ssl_flag(false),
00128 #endif
00129 m_lifecycle(LIFECYCLE_CLOSE)
00130 {
00131 saveReadPosition(NULL, NULL);
00132 }
00133
00135 inline bool is_open(void) const {
00136 #ifdef PION_HAVE_SSL
00137 if (getSSLFlag())
00138 return const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().is_open();
00139 else
00140 #endif
00141 return m_tcp_socket.is_open();
00142 }
00143
00145 inline void close(void) {
00146 #ifdef PION_HAVE_SSL
00147 if (getSSLFlag()) {
00148 if (m_ssl_socket.lowest_layer().is_open())
00149 m_ssl_socket.lowest_layer().close();
00150 } else
00151 #endif
00152 {
00153 if (m_tcp_socket.is_open())
00154 m_tcp_socket.close();
00155 }
00156 }
00157
00158
00159
00160
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00173 virtual ~TCPConnection() { close(); }
00174
00183 template <typename AcceptHandler>
00184 inline void async_accept(boost::asio::ip::tcp::acceptor& tcp_acceptor,
00185 AcceptHandler handler)
00186 {
00187 #ifdef PION_HAVE_SSL
00188 if (getSSLFlag())
00189 tcp_acceptor.async_accept(m_ssl_socket.lowest_layer(), handler);
00190 else
00191 #endif
00192 tcp_acceptor.async_accept(m_tcp_socket, handler);
00193 }
00194
00203 inline boost::system::error_code accept(boost::asio::ip::tcp::acceptor& tcp_acceptor)
00204 {
00205 boost::system::error_code ec;
00206 #ifdef PION_HAVE_SSL
00207 if (getSSLFlag())
00208 tcp_acceptor.accept(m_ssl_socket.lowest_layer(), ec);
00209 else
00210 #endif
00211 tcp_acceptor.accept(m_tcp_socket, ec);
00212 return ec;
00213 }
00214
00223 template <typename ConnectHandler>
00224 inline void async_connect(boost::asio::ip::tcp::endpoint& tcp_endpoint,
00225 ConnectHandler handler)
00226 {
00227 #ifdef PION_HAVE_SSL
00228 if (getSSLFlag())
00229 m_ssl_socket.lowest_layer().async_connect(tcp_endpoint, handler);
00230 else
00231 #endif
00232 m_tcp_socket.async_connect(tcp_endpoint, handler);
00233 }
00234
00244 template <typename ConnectHandler>
00245 inline void async_connect(const boost::asio::ip::address& remote_addr,
00246 const unsigned int remote_port,
00247 ConnectHandler handler)
00248 {
00249 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port);
00250 async_connect(tcp_endpoint, handler);
00251 }
00252
00261 inline boost::system::error_code connect(boost::asio::ip::tcp::endpoint& tcp_endpoint)
00262 {
00263 boost::system::error_code ec;
00264 #ifdef PION_HAVE_SSL
00265 if (getSSLFlag())
00266 m_ssl_socket.lowest_layer().connect(tcp_endpoint, ec);
00267 else
00268 #endif
00269 m_tcp_socket.connect(tcp_endpoint, ec);
00270 return ec;
00271 }
00272
00282 inline boost::system::error_code connect(const boost::asio::ip::address& remote_addr,
00283 const unsigned int remote_port)
00284 {
00285 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port);
00286 return connect(tcp_endpoint);
00287 }
00288
00298 inline boost::system::error_code connect(const std::string& remote_server,
00299 const unsigned int remote_port)
00300 {
00301
00302 boost::system::error_code ec;
00303 boost::asio::ip::tcp::resolver resolver(m_tcp_socket.get_io_service());
00304 boost::asio::ip::tcp::resolver::query query(remote_server,
00305 boost::lexical_cast<std::string>(remote_port),
00306 boost::asio::ip::tcp::resolver::query::numeric_service);
00307 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, ec);
00308 if (ec)
00309 return ec;
00310
00311
00312 ec = boost::asio::error::host_not_found;
00313 boost::asio::ip::tcp::resolver::iterator end;
00314 while (ec && endpoint_iterator != end) {
00315 boost::asio::ip::tcp::endpoint ep(endpoint_iterator->endpoint());
00316 ++endpoint_iterator;
00317 ec = connect(ep);
00318 if (ec)
00319 close();
00320 }
00321
00322 return ec;
00323 }
00324
00332 template <typename SSLHandshakeHandler>
00333 inline void async_handshake_client(SSLHandshakeHandler handler) {
00334 #ifdef PION_HAVE_SSL
00335 if (getSSLFlag())
00336 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::client, handler);
00337 #endif
00338 }
00339
00347 template <typename SSLHandshakeHandler>
00348 inline void async_handshake_server(SSLHandshakeHandler handler) {
00349 #ifdef PION_HAVE_SSL
00350 if (getSSLFlag())
00351 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::server, handler);
00352 #endif
00353 }
00354
00362 inline boost::system::error_code handshake_client(void) {
00363 boost::system::error_code ec;
00364 #ifdef PION_HAVE_SSL
00365 if (getSSLFlag())
00366 m_ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec);
00367 #endif
00368 return ec;
00369 }
00370
00378 inline boost::system::error_code handshake_server(void) {
00379 boost::system::error_code ec;
00380 #ifdef PION_HAVE_SSL
00381 if (getSSLFlag())
00382 m_ssl_socket.handshake(boost::asio::ssl::stream_base::server, ec);
00383 #endif
00384 return ec;
00385 }
00386
00394 template <typename ReadHandler>
00395 inline void async_read_some(ReadHandler handler) {
00396 #ifdef PION_HAVE_SSL
00397 if (getSSLFlag())
00398 m_ssl_socket.async_read_some(boost::asio::buffer(m_read_buffer),
00399 handler);
00400 else
00401 #endif
00402 m_tcp_socket.async_read_some(boost::asio::buffer(m_read_buffer),
00403 handler);
00404 }
00405
00414 template <typename ReadBufferType, typename ReadHandler>
00415 inline void async_read_some(ReadBufferType read_buffer,
00416 ReadHandler handler) {
00417 #ifdef PION_HAVE_SSL
00418 if (getSSLFlag())
00419 m_ssl_socket.async_read_some(read_buffer, handler);
00420 else
00421 #endif
00422 m_tcp_socket.async_read_some(read_buffer, handler);
00423 }
00424
00433 inline std::size_t read_some(boost::system::error_code& ec) {
00434 #ifdef PION_HAVE_SSL
00435 if (getSSLFlag())
00436 return m_ssl_socket.read_some(boost::asio::buffer(m_read_buffer), ec);
00437 else
00438 #endif
00439 return m_tcp_socket.read_some(boost::asio::buffer(m_read_buffer), ec);
00440 }
00441
00451 template <typename ReadBufferType>
00452 inline std::size_t read_some(ReadBufferType read_buffer,
00453 boost::system::error_code& ec)
00454 {
00455 #ifdef PION_HAVE_SSL
00456 if (getSSLFlag())
00457 return m_ssl_socket.read_some(read_buffer, ec);
00458 else
00459 #endif
00460 return m_tcp_socket.read_some(read_buffer, ec);
00461 }
00462
00472 template <typename CompletionCondition, typename ReadHandler>
00473 inline void async_read(CompletionCondition completion_condition,
00474 ReadHandler handler)
00475 {
00476 #ifdef PION_HAVE_SSL
00477 if (getSSLFlag())
00478 boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer),
00479 completion_condition, handler);
00480 else
00481 #endif
00482 boost::asio::async_read(m_tcp_socket, boost::asio::buffer(m_read_buffer),
00483 completion_condition, handler);
00484 }
00485
00496 template <typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler>
00497 inline void async_read(const MutableBufferSequence& buffers,
00498 CompletionCondition completion_condition,
00499 ReadHandler handler)
00500 {
00501 #ifdef PION_HAVE_SSL
00502 if (getSSLFlag())
00503 boost::asio::async_read(m_ssl_socket, buffers,
00504 completion_condition, handler);
00505 else
00506 #endif
00507 boost::asio::async_read(m_tcp_socket, buffers,
00508 completion_condition, handler);
00509 }
00510
00521 template <typename CompletionCondition>
00522 inline std::size_t read(CompletionCondition completion_condition,
00523 boost::system::error_code& ec)
00524 {
00525 #ifdef PION_HAVE_SSL
00526 if (getSSLFlag())
00527 return boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer),
00528 completion_condition, ec);
00529 else
00530 #endif
00531 return boost::asio::async_read(m_tcp_socket, boost::asio::buffer(m_read_buffer),
00532 completion_condition, ec);
00533 }
00534
00546 template <typename MutableBufferSequence, typename CompletionCondition>
00547 inline std::size_t read(const MutableBufferSequence& buffers,
00548 CompletionCondition completion_condition,
00549 boost::system::error_code& ec)
00550 {
00551 #ifdef PION_HAVE_SSL
00552 if (getSSLFlag())
00553 return boost::asio::read(m_ssl_socket, buffers,
00554 completion_condition, ec);
00555 else
00556 #endif
00557 return boost::asio::read(m_tcp_socket, buffers,
00558 completion_condition, ec);
00559 }
00560
00569 template <typename ConstBufferSequence, typename WriteHandler>
00570 inline void async_write(const ConstBufferSequence& buffers, WriteHandler handler) {
00571 #ifdef PION_HAVE_SSL
00572 if (getSSLFlag())
00573 boost::asio::async_write(m_ssl_socket, buffers, handler);
00574 else
00575 #endif
00576 boost::asio::async_write(m_tcp_socket, buffers, handler);
00577 }
00578
00588 template <typename ConstBufferSequence>
00589 inline std::size_t write(const ConstBufferSequence& buffers,
00590 boost::system::error_code& ec)
00591 {
00592 #ifdef PION_HAVE_SSL
00593 if (getSSLFlag())
00594 return boost::asio::write(m_ssl_socket, buffers,
00595 boost::asio::transfer_all(), ec);
00596 else
00597 #endif
00598 return boost::asio::write(m_tcp_socket, buffers,
00599 boost::asio::transfer_all(), ec);
00600 }
00601
00602
00605 inline void finish(void) { if (m_finished_handler) m_finished_handler(shared_from_this()); }
00606
00608 inline bool getSSLFlag(void) const { return m_ssl_flag; }
00609
00611 inline void setLifecycle(LifecycleType t) { m_lifecycle = t; }
00612
00614 inline LifecycleType getLifecycle(void) const { return m_lifecycle; }
00615
00617 inline bool getKeepAlive(void) const { return m_lifecycle != LIFECYCLE_CLOSE; }
00618
00620 inline bool getPipelined(void) const { return m_lifecycle == LIFECYCLE_PIPELINED; }
00621
00623 inline ReadBuffer& getReadBuffer(void) { return m_read_buffer; }
00624
00631 inline void saveReadPosition(const char *read_ptr, const char *read_end_ptr) {
00632 m_read_position.first = read_ptr;
00633 m_read_position.second = read_end_ptr;
00634 }
00635
00642 inline void loadReadPosition(const char *&read_ptr, const char *&read_end_ptr) const {
00643 read_ptr = m_read_position.first;
00644 read_end_ptr = m_read_position.second;
00645 }
00646
00648 inline boost::asio::ip::tcp::endpoint getRemoteEndpoint(void) const {
00649 boost::asio::ip::tcp::endpoint remote_endpoint;
00650 try {
00651 #ifdef PION_HAVE_SSL
00652 if (getSSLFlag())
00653
00654 remote_endpoint = const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().remote_endpoint();
00655 else
00656 #endif
00657 remote_endpoint = m_tcp_socket.remote_endpoint();
00658 } catch (boost::system::system_error& ) {
00659
00660 }
00661 return remote_endpoint;
00662 }
00663
00665 inline boost::asio::ip::address getRemoteIp(void) const {
00666 return getRemoteEndpoint().address();
00667 }
00668
00670 inline unsigned short getRemotePort(void) const {
00671 return getRemoteEndpoint().port();
00672 }
00673
00675 inline boost::asio::io_service& getIOService(void) {
00676 return m_tcp_socket.io_service();
00677 }
00678
00680 inline Socket& getSocket(void) { return m_tcp_socket; }
00681
00683 inline SSLSocket& getSSLSocket(void) { return m_ssl_socket; }
00684
00686 inline const Socket& getSocket(void) const { return m_tcp_socket; }
00687
00689 inline const SSLSocket& getSSLSocket(void) const { return m_ssl_socket; }
00690
00691
00692 protected:
00693
00703 TCPConnection(boost::asio::io_service& io_service,
00704 SSLContext& ssl_context,
00705 const bool ssl_flag,
00706 ConnectionHandler finished_handler)
00707 : m_tcp_socket(io_service),
00708 #ifdef PION_HAVE_SSL
00709 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00710 m_ssl_socket(io_service, ssl_context), m_ssl_flag(ssl_flag),
00711 #else
00712 m_ssl_context(0),
00713 m_ssl_socket(io_service), m_ssl_flag(false),
00714 #endif
00715 m_lifecycle(LIFECYCLE_CLOSE),
00716 m_finished_handler(finished_handler)
00717 {
00718 saveReadPosition(NULL, NULL);
00719 }
00720
00721
00722 private:
00723
00725 typedef std::pair<const char*, const char*> ReadPosition;
00726
00727
00729 Socket m_tcp_socket;
00730
00732 SSLContext m_ssl_context;
00733
00735 SSLSocket m_ssl_socket;
00736
00738 const bool m_ssl_flag;
00739
00741 ReadBuffer m_read_buffer;
00742
00744 ReadPosition m_read_position;
00745
00747 LifecycleType m_lifecycle;
00748
00750 ConnectionHandler m_finished_handler;
00751 };
00752
00753
00755 typedef boost::shared_ptr<TCPConnection> TCPConnectionPtr;
00756
00757
00758 }
00759 }
00760
00761 #endif