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 #if defined _MSC_VER
00020 #if defined _DEBUG
00021 #pragma comment(lib, "ssleay32d")
00022 #pragma comment(lib, "libeay32d")
00023 #else
00024 #pragma comment(lib, "ssleay32")
00025 #pragma comment(lib, "libeay32")
00026 #endif
00027 #endif
00028 #endif
00029
00030 #include <boost/noncopyable.hpp>
00031 #include <boost/shared_ptr.hpp>
00032 #include <boost/lexical_cast.hpp>
00033 #include <boost/enable_shared_from_this.hpp>
00034 #include <boost/asio.hpp>
00035 #include <boost/array.hpp>
00036 #include <boost/function.hpp>
00037 #include <boost/function/function1.hpp>
00038 #include <pion/PionConfig.hpp>
00039 #include <string>
00040
00041
00042 namespace pion {
00043 namespace net {
00044
00048 class TCPConnection :
00049 public boost::enable_shared_from_this<TCPConnection>,
00050 private boost::noncopyable
00051 {
00052 public:
00053
00055 enum LifecycleType {
00056 LIFECYCLE_CLOSE, LIFECYCLE_KEEPALIVE, LIFECYCLE_PIPELINED
00057 };
00058
00060 enum { READ_BUFFER_SIZE = 8192 };
00061
00063 typedef boost::function1<void, boost::shared_ptr<TCPConnection> > ConnectionHandler;
00064
00066 typedef boost::array<char, READ_BUFFER_SIZE> ReadBuffer;
00067
00069 typedef boost::asio::ip::tcp::socket Socket;
00070
00071 #ifdef PION_HAVE_SSL
00073 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket;
00074
00076 typedef boost::asio::ssl::context SSLContext;
00077 #else
00078 typedef Socket SSLSocket;
00079 typedef int SSLContext;
00080 #endif
00081
00082
00092 static inline boost::shared_ptr<TCPConnection> create(boost::asio::io_service& io_service,
00093 SSLContext& ssl_context,
00094 const bool ssl_flag,
00095 ConnectionHandler finished_handler)
00096 {
00097 return boost::shared_ptr<TCPConnection>(new TCPConnection(io_service, ssl_context,
00098 ssl_flag, finished_handler));
00099 }
00100
00107 explicit TCPConnection(boost::asio::io_service& io_service, const bool ssl_flag = false)
00108 : m_tcp_socket(io_service),
00109 #ifdef PION_HAVE_SSL
00110 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00111 m_ssl_socket(io_service, m_ssl_context),
00112 m_ssl_flag(ssl_flag),
00113 #else
00114 m_ssl_context(0),
00115 m_ssl_socket(io_service),
00116 m_ssl_flag(false),
00117 #endif
00118 m_lifecycle(LIFECYCLE_CLOSE)
00119 {
00120 saveReadPosition(NULL, NULL);
00121 }
00122
00129 TCPConnection(boost::asio::io_service& io_service, SSLContext& ssl_context)
00130 : m_tcp_socket(io_service),
00131 #ifdef PION_HAVE_SSL
00132 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00133 m_ssl_socket(io_service, ssl_context), m_ssl_flag(true),
00134 #else
00135 m_ssl_context(0),
00136 m_ssl_socket(io_service), m_ssl_flag(false),
00137 #endif
00138 m_lifecycle(LIFECYCLE_CLOSE)
00139 {
00140 saveReadPosition(NULL, NULL);
00141 }
00142
00144 inline bool is_open(void) const {
00145 #ifdef PION_HAVE_SSL
00146 if (getSSLFlag())
00147 return const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().is_open();
00148 else
00149 #endif
00150 return m_tcp_socket.is_open();
00151 }
00152
00154 inline void close(void) {
00155 #ifdef PION_HAVE_SSL
00156 if (getSSLFlag()) {
00157 if (m_ssl_socket.lowest_layer().is_open())
00158 m_ssl_socket.lowest_layer().close();
00159 } else
00160 #endif
00161 {
00162 if (m_tcp_socket.is_open())
00163 m_tcp_socket.close();
00164 }
00165 }
00166
00167
00168
00169
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00182 virtual ~TCPConnection() { close(); }
00183
00192 template <typename AcceptHandler>
00193 inline void async_accept(boost::asio::ip::tcp::acceptor& tcp_acceptor,
00194 AcceptHandler handler)
00195 {
00196 #ifdef PION_HAVE_SSL
00197 if (getSSLFlag())
00198 tcp_acceptor.async_accept(m_ssl_socket.lowest_layer(), handler);
00199 else
00200 #endif
00201 tcp_acceptor.async_accept(m_tcp_socket, handler);
00202 }
00203
00212 inline boost::system::error_code accept(boost::asio::ip::tcp::acceptor& tcp_acceptor)
00213 {
00214 boost::system::error_code ec;
00215 #ifdef PION_HAVE_SSL
00216 if (getSSLFlag())
00217 tcp_acceptor.accept(m_ssl_socket.lowest_layer(), ec);
00218 else
00219 #endif
00220 tcp_acceptor.accept(m_tcp_socket, ec);
00221 return ec;
00222 }
00223
00232 template <typename ConnectHandler>
00233 inline void async_connect(boost::asio::ip::tcp::endpoint& tcp_endpoint,
00234 ConnectHandler handler)
00235 {
00236 #ifdef PION_HAVE_SSL
00237 if (getSSLFlag())
00238 m_ssl_socket.lowest_layer().async_connect(tcp_endpoint, handler);
00239 else
00240 #endif
00241 m_tcp_socket.async_connect(tcp_endpoint, handler);
00242 }
00243
00253 template <typename ConnectHandler>
00254 inline void async_connect(const boost::asio::ip::address& remote_addr,
00255 const unsigned int remote_port,
00256 ConnectHandler handler)
00257 {
00258 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port);
00259 async_connect(tcp_endpoint, handler);
00260 }
00261
00270 inline boost::system::error_code connect(boost::asio::ip::tcp::endpoint& tcp_endpoint)
00271 {
00272 boost::system::error_code ec;
00273 #ifdef PION_HAVE_SSL
00274 if (getSSLFlag())
00275 m_ssl_socket.lowest_layer().connect(tcp_endpoint, ec);
00276 else
00277 #endif
00278 m_tcp_socket.connect(tcp_endpoint, ec);
00279 return ec;
00280 }
00281
00291 inline boost::system::error_code connect(const boost::asio::ip::address& remote_addr,
00292 const unsigned int remote_port)
00293 {
00294 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port);
00295 return connect(tcp_endpoint);
00296 }
00297
00307 inline boost::system::error_code connect(const std::string& remote_server,
00308 const unsigned int remote_port)
00309 {
00310
00311 boost::system::error_code ec;
00312 boost::asio::ip::tcp::resolver resolver(m_tcp_socket.get_io_service());
00313 boost::asio::ip::tcp::resolver::query query(remote_server,
00314 boost::lexical_cast<std::string>(remote_port),
00315 boost::asio::ip::tcp::resolver::query::numeric_service);
00316 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, ec);
00317 if (ec)
00318 return ec;
00319
00320
00321 ec = boost::asio::error::host_not_found;
00322 boost::asio::ip::tcp::resolver::iterator end;
00323 while (ec && endpoint_iterator != end) {
00324 boost::asio::ip::tcp::endpoint ep(endpoint_iterator->endpoint());
00325 ++endpoint_iterator;
00326 ec = connect(ep);
00327 if (ec)
00328 close();
00329 }
00330
00331 return ec;
00332 }
00333
00341 template <typename SSLHandshakeHandler>
00342 inline void async_handshake_client(SSLHandshakeHandler handler) {
00343 #ifdef PION_HAVE_SSL
00344 if (getSSLFlag())
00345 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::client, handler);
00346 #endif
00347 }
00348
00356 template <typename SSLHandshakeHandler>
00357 inline void async_handshake_server(SSLHandshakeHandler handler) {
00358 #ifdef PION_HAVE_SSL
00359 if (getSSLFlag())
00360 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::server, handler);
00361 #endif
00362 }
00363
00371 inline boost::system::error_code handshake_client(void) {
00372 boost::system::error_code ec;
00373 #ifdef PION_HAVE_SSL
00374 if (getSSLFlag())
00375 m_ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec);
00376 #endif
00377 return ec;
00378 }
00379
00387 inline boost::system::error_code handshake_server(void) {
00388 boost::system::error_code ec;
00389 #ifdef PION_HAVE_SSL
00390 if (getSSLFlag())
00391 m_ssl_socket.handshake(boost::asio::ssl::stream_base::server, ec);
00392 #endif
00393 return ec;
00394 }
00395
00403 template <typename ReadHandler>
00404 inline void async_read_some(ReadHandler handler) {
00405 #ifdef PION_HAVE_SSL
00406 if (getSSLFlag())
00407 m_ssl_socket.async_read_some(boost::asio::buffer(m_read_buffer),
00408 handler);
00409 else
00410 #endif
00411 m_tcp_socket.async_read_some(boost::asio::buffer(m_read_buffer),
00412 handler);
00413 }
00414
00423 template <typename ReadBufferType, typename ReadHandler>
00424 inline void async_read_some(ReadBufferType read_buffer,
00425 ReadHandler handler) {
00426 #ifdef PION_HAVE_SSL
00427 if (getSSLFlag())
00428 m_ssl_socket.async_read_some(read_buffer, handler);
00429 else
00430 #endif
00431 m_tcp_socket.async_read_some(read_buffer, handler);
00432 }
00433
00442 inline std::size_t read_some(boost::system::error_code& ec) {
00443 #ifdef PION_HAVE_SSL
00444 if (getSSLFlag())
00445 return m_ssl_socket.read_some(boost::asio::buffer(m_read_buffer), ec);
00446 else
00447 #endif
00448 return m_tcp_socket.read_some(boost::asio::buffer(m_read_buffer), ec);
00449 }
00450
00460 template <typename ReadBufferType>
00461 inline std::size_t read_some(ReadBufferType read_buffer,
00462 boost::system::error_code& ec)
00463 {
00464 #ifdef PION_HAVE_SSL
00465 if (getSSLFlag())
00466 return m_ssl_socket.read_some(read_buffer, ec);
00467 else
00468 #endif
00469 return m_tcp_socket.read_some(read_buffer, ec);
00470 }
00471
00481 template <typename CompletionCondition, typename ReadHandler>
00482 inline void async_read(CompletionCondition completion_condition,
00483 ReadHandler handler)
00484 {
00485 #ifdef PION_HAVE_SSL
00486 if (getSSLFlag())
00487 boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer),
00488 completion_condition, handler);
00489 else
00490 #endif
00491 boost::asio::async_read(m_tcp_socket, boost::asio::buffer(m_read_buffer),
00492 completion_condition, handler);
00493 }
00494
00505 template <typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler>
00506 inline void async_read(const MutableBufferSequence& buffers,
00507 CompletionCondition completion_condition,
00508 ReadHandler handler)
00509 {
00510 #ifdef PION_HAVE_SSL
00511 if (getSSLFlag())
00512 boost::asio::async_read(m_ssl_socket, buffers,
00513 completion_condition, handler);
00514 else
00515 #endif
00516 boost::asio::async_read(m_tcp_socket, buffers,
00517 completion_condition, handler);
00518 }
00519
00530 template <typename CompletionCondition>
00531 inline std::size_t read(CompletionCondition completion_condition,
00532 boost::system::error_code& ec)
00533 {
00534 #ifdef PION_HAVE_SSL
00535 if (getSSLFlag())
00536 return boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer),
00537 completion_condition, ec);
00538 else
00539 #endif
00540 return boost::asio::async_read(m_tcp_socket, boost::asio::buffer(m_read_buffer),
00541 completion_condition, ec);
00542 }
00543
00555 template <typename MutableBufferSequence, typename CompletionCondition>
00556 inline std::size_t read(const MutableBufferSequence& buffers,
00557 CompletionCondition completion_condition,
00558 boost::system::error_code& ec)
00559 {
00560 #ifdef PION_HAVE_SSL
00561 if (getSSLFlag())
00562 return boost::asio::read(m_ssl_socket, buffers,
00563 completion_condition, ec);
00564 else
00565 #endif
00566 return boost::asio::read(m_tcp_socket, buffers,
00567 completion_condition, ec);
00568 }
00569
00578 template <typename ConstBufferSequence, typename WriteHandler>
00579 inline void async_write(const ConstBufferSequence& buffers, WriteHandler handler) {
00580 #ifdef PION_HAVE_SSL
00581 if (getSSLFlag())
00582 boost::asio::async_write(m_ssl_socket, buffers, handler);
00583 else
00584 #endif
00585 boost::asio::async_write(m_tcp_socket, buffers, handler);
00586 }
00587
00597 template <typename ConstBufferSequence>
00598 inline std::size_t write(const ConstBufferSequence& buffers,
00599 boost::system::error_code ec)
00600 {
00601 #ifdef PION_HAVE_SSL
00602 if (getSSLFlag())
00603 return boost::asio::write(m_ssl_socket, buffers,
00604 boost::asio::transfer_all(), ec);
00605 else
00606 #endif
00607 return boost::asio::write(m_tcp_socket, buffers,
00608 boost::asio::transfer_all(), ec);
00609 }
00610
00611
00614 inline void finish(void) { if (m_finished_handler) m_finished_handler(shared_from_this()); }
00615
00617 inline bool getSSLFlag(void) const { return m_ssl_flag; }
00618
00620 inline void setLifecycle(LifecycleType t) { m_lifecycle = t; }
00621
00623 inline LifecycleType getLifecycle(void) const { return m_lifecycle; }
00624
00626 inline bool getKeepAlive(void) const { return m_lifecycle != LIFECYCLE_CLOSE; }
00627
00629 inline bool getPipelined(void) const { return m_lifecycle == LIFECYCLE_PIPELINED; }
00630
00632 inline ReadBuffer& getReadBuffer(void) { return m_read_buffer; }
00633
00640 inline void saveReadPosition(const char *read_ptr, const char *read_end_ptr) {
00641 m_read_position.first = read_ptr;
00642 m_read_position.second = read_end_ptr;
00643 }
00644
00651 inline void loadReadPosition(const char *&read_ptr, const char *&read_end_ptr) const {
00652 read_ptr = m_read_position.first;
00653 read_end_ptr = m_read_position.second;
00654 }
00655
00657 inline boost::asio::ip::tcp::endpoint getRemoteEndpoint(void) const {
00658 boost::asio::ip::tcp::endpoint remote_endpoint;
00659 try {
00660 #ifdef PION_HAVE_SSL
00661 if (getSSLFlag())
00662
00663 remote_endpoint = const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().remote_endpoint();
00664 else
00665 #endif
00666 remote_endpoint = m_tcp_socket.remote_endpoint();
00667 } catch (boost::system::system_error& ) {
00668
00669 }
00670 return remote_endpoint;
00671 }
00672
00674 inline boost::asio::ip::address getRemoteIp(void) const {
00675 return getRemoteEndpoint().address();
00676 }
00677
00679 inline unsigned short getRemotePort(void) const {
00680 return getRemoteEndpoint().port();
00681 }
00682
00683
00684 protected:
00685
00695 TCPConnection(boost::asio::io_service& io_service,
00696 SSLContext& ssl_context,
00697 const bool ssl_flag,
00698 ConnectionHandler finished_handler)
00699 : m_tcp_socket(io_service),
00700 #ifdef PION_HAVE_SSL
00701 m_ssl_context(io_service, boost::asio::ssl::context::sslv23),
00702 m_ssl_socket(io_service, ssl_context), m_ssl_flag(ssl_flag),
00703 #else
00704 m_ssl_context(0),
00705 m_ssl_socket(io_service), m_ssl_flag(false),
00706 #endif
00707 m_lifecycle(LIFECYCLE_CLOSE),
00708 m_finished_handler(finished_handler)
00709 {
00710 saveReadPosition(NULL, NULL);
00711 }
00712
00713
00714 private:
00715
00717 typedef std::pair<const char*, const char*> ReadPosition;
00718
00719
00721 Socket m_tcp_socket;
00722
00724 SSLContext m_ssl_context;
00725
00727 SSLSocket m_ssl_socket;
00728
00730 const bool m_ssl_flag;
00731
00733 ReadBuffer m_read_buffer;
00734
00736 ReadPosition m_read_position;
00737
00739 LifecycleType m_lifecycle;
00740
00742 ConnectionHandler m_finished_handler;
00743 };
00744
00745
00747 typedef boost::shared_ptr<TCPConnection> TCPConnectionPtr;
00748
00749
00750 }
00751 }
00752
00753 #endif