pion-net
4.0.9
|
00001 // ------------------------------------------------------------------ 00002 // pion-net: a C++ framework for building lightweight HTTP interfaces 00003 // ------------------------------------------------------------------ 00004 // Copyright (C) 2007-2008 Atomic Labs, Inc. (http://www.atomiclabs.com) 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_TCPCONNECTION_HEADER__ 00011 #define __PION_TCPCONNECTION_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/PionConfig.hpp> 00030 #include <string> 00031 00032 00033 namespace pion { // begin namespace pion 00034 namespace net { // begin namespace net (Pion Network Library) 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 00063 00064 typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket; 00065 00067 typedef boost::asio::ssl::context SSLContext; 00068 #else 00069 class SSLSocket { 00070 public: 00071 SSLSocket(boost::asio::io_service& io_service) : m_socket(io_service) {} 00072 inline Socket& next_layer(void) { return m_socket; } 00073 inline const Socket& next_layer(void) const { return m_socket; } 00074 inline Socket& lowest_layer(void) { return m_socket.lowest_layer(); } 00075 inline const Socket& lowest_layer(void) const { return m_socket.lowest_layer(); } 00076 private: 00077 Socket m_socket; 00078 }; 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 : 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 : 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 return const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().is_open(); 00146 } 00147 00149 inline void close(void) { 00150 if (m_ssl_socket.lowest_layer().is_open()) 00151 m_ssl_socket.lowest_layer().close(); 00152 } 00153 00154 /* 00155 Use close instead; basic_socket::cancel is deprecated for Windows XP. 00156 00158 inline void cancel(void) { 00159 m_ssl_socket.lowest_layer().cancel(); 00160 } 00161 */ 00162 00164 virtual ~TCPConnection() { close(); } 00165 00174 template <typename AcceptHandler> 00175 inline void async_accept(boost::asio::ip::tcp::acceptor& tcp_acceptor, 00176 AcceptHandler handler) 00177 { 00178 tcp_acceptor.async_accept(m_ssl_socket.lowest_layer(), handler); 00179 } 00180 00189 inline boost::system::error_code accept(boost::asio::ip::tcp::acceptor& tcp_acceptor) 00190 { 00191 boost::system::error_code ec; 00192 tcp_acceptor.accept(m_ssl_socket.lowest_layer(), ec); 00193 return ec; 00194 } 00195 00204 template <typename ConnectHandler> 00205 inline void async_connect(boost::asio::ip::tcp::endpoint& tcp_endpoint, 00206 ConnectHandler handler) 00207 { 00208 m_ssl_socket.lowest_layer().async_connect(tcp_endpoint, handler); 00209 } 00210 00220 template <typename ConnectHandler> 00221 inline void async_connect(const boost::asio::ip::address& remote_addr, 00222 const unsigned int remote_port, 00223 ConnectHandler handler) 00224 { 00225 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port); 00226 async_connect(tcp_endpoint, handler); 00227 } 00228 00237 inline boost::system::error_code connect(boost::asio::ip::tcp::endpoint& tcp_endpoint) 00238 { 00239 boost::system::error_code ec; 00240 m_ssl_socket.lowest_layer().connect(tcp_endpoint, ec); 00241 return ec; 00242 } 00243 00253 inline boost::system::error_code connect(const boost::asio::ip::address& remote_addr, 00254 const unsigned int remote_port) 00255 { 00256 boost::asio::ip::tcp::endpoint tcp_endpoint(remote_addr, remote_port); 00257 return connect(tcp_endpoint); 00258 } 00259 00269 inline boost::system::error_code connect(const std::string& remote_server, 00270 const unsigned int remote_port) 00271 { 00272 // query a list of matching endpoints 00273 boost::system::error_code ec; 00274 boost::asio::ip::tcp::resolver resolver(m_ssl_socket.lowest_layer().get_io_service()); 00275 boost::asio::ip::tcp::resolver::query query(remote_server, 00276 boost::lexical_cast<std::string>(remote_port), 00277 boost::asio::ip::tcp::resolver::query::numeric_service); 00278 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, ec); 00279 if (ec) 00280 return ec; 00281 00282 // try each one until we are successful 00283 ec = boost::asio::error::host_not_found; 00284 boost::asio::ip::tcp::resolver::iterator end; 00285 while (ec && endpoint_iterator != end) { 00286 boost::asio::ip::tcp::endpoint ep(endpoint_iterator->endpoint()); 00287 ++endpoint_iterator; 00288 ec = connect(ep); 00289 if (ec) 00290 close(); 00291 } 00292 00293 return ec; 00294 } 00295 00303 template <typename SSLHandshakeHandler> 00304 inline void async_handshake_client(SSLHandshakeHandler handler) { 00305 #ifdef PION_HAVE_SSL 00306 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::client, handler); 00307 m_ssl_flag = true; 00308 #endif 00309 } 00310 00318 template <typename SSLHandshakeHandler> 00319 inline void async_handshake_server(SSLHandshakeHandler handler) { 00320 #ifdef PION_HAVE_SSL 00321 m_ssl_socket.async_handshake(boost::asio::ssl::stream_base::server, handler); 00322 m_ssl_flag = true; 00323 #endif 00324 } 00325 00333 inline boost::system::error_code handshake_client(void) { 00334 boost::system::error_code ec; 00335 #ifdef PION_HAVE_SSL 00336 m_ssl_socket.handshake(boost::asio::ssl::stream_base::client, ec); 00337 m_ssl_flag = true; 00338 #endif 00339 return ec; 00340 } 00341 00349 inline boost::system::error_code handshake_server(void) { 00350 boost::system::error_code ec; 00351 #ifdef PION_HAVE_SSL 00352 m_ssl_socket.handshake(boost::asio::ssl::stream_base::server, ec); 00353 m_ssl_flag = true; 00354 #endif 00355 return ec; 00356 } 00357 00365 template <typename ReadHandler> 00366 inline void async_read_some(ReadHandler handler) { 00367 #ifdef PION_HAVE_SSL 00368 if (getSSLFlag()) 00369 m_ssl_socket.async_read_some(boost::asio::buffer(m_read_buffer), 00370 handler); 00371 else 00372 #endif 00373 m_ssl_socket.next_layer().async_read_some(boost::asio::buffer(m_read_buffer), 00374 handler); 00375 } 00376 00385 template <typename ReadBufferType, typename ReadHandler> 00386 inline void async_read_some(ReadBufferType read_buffer, 00387 ReadHandler handler) { 00388 #ifdef PION_HAVE_SSL 00389 if (getSSLFlag()) 00390 m_ssl_socket.async_read_some(read_buffer, handler); 00391 else 00392 #endif 00393 m_ssl_socket.next_layer().async_read_some(read_buffer, handler); 00394 } 00395 00404 inline std::size_t read_some(boost::system::error_code& ec) { 00405 #ifdef PION_HAVE_SSL 00406 if (getSSLFlag()) 00407 return m_ssl_socket.read_some(boost::asio::buffer(m_read_buffer), ec); 00408 else 00409 #endif 00410 return m_ssl_socket.next_layer().read_some(boost::asio::buffer(m_read_buffer), ec); 00411 } 00412 00422 template <typename ReadBufferType> 00423 inline std::size_t read_some(ReadBufferType read_buffer, 00424 boost::system::error_code& ec) 00425 { 00426 #ifdef PION_HAVE_SSL 00427 if (getSSLFlag()) 00428 return m_ssl_socket.read_some(read_buffer, ec); 00429 else 00430 #endif 00431 return m_ssl_socket.next_layer().read_some(read_buffer, ec); 00432 } 00433 00443 template <typename CompletionCondition, typename ReadHandler> 00444 inline void async_read(CompletionCondition completion_condition, 00445 ReadHandler handler) 00446 { 00447 #ifdef PION_HAVE_SSL 00448 if (getSSLFlag()) 00449 boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer), 00450 completion_condition, handler); 00451 else 00452 #endif 00453 boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(m_read_buffer), 00454 completion_condition, handler); 00455 } 00456 00467 template <typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> 00468 inline void async_read(const MutableBufferSequence& buffers, 00469 CompletionCondition completion_condition, 00470 ReadHandler handler) 00471 { 00472 #ifdef PION_HAVE_SSL 00473 if (getSSLFlag()) 00474 boost::asio::async_read(m_ssl_socket, buffers, 00475 completion_condition, handler); 00476 else 00477 #endif 00478 boost::asio::async_read(m_ssl_socket.next_layer(), buffers, 00479 completion_condition, handler); 00480 } 00481 00492 template <typename CompletionCondition> 00493 inline std::size_t read(CompletionCondition completion_condition, 00494 boost::system::error_code& ec) 00495 { 00496 #ifdef PION_HAVE_SSL 00497 if (getSSLFlag()) 00498 return boost::asio::async_read(m_ssl_socket, boost::asio::buffer(m_read_buffer), 00499 completion_condition, ec); 00500 else 00501 #endif 00502 return boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(m_read_buffer), 00503 completion_condition, ec); 00504 } 00505 00517 template <typename MutableBufferSequence, typename CompletionCondition> 00518 inline std::size_t read(const MutableBufferSequence& buffers, 00519 CompletionCondition completion_condition, 00520 boost::system::error_code& ec) 00521 { 00522 #ifdef PION_HAVE_SSL 00523 if (getSSLFlag()) 00524 return boost::asio::read(m_ssl_socket, buffers, 00525 completion_condition, ec); 00526 else 00527 #endif 00528 return boost::asio::read(m_ssl_socket.next_layer(), buffers, 00529 completion_condition, ec); 00530 } 00531 00540 template <typename ConstBufferSequence, typename WriteHandler> 00541 inline void async_write(const ConstBufferSequence& buffers, WriteHandler handler) { 00542 #ifdef PION_HAVE_SSL 00543 if (getSSLFlag()) 00544 boost::asio::async_write(m_ssl_socket, buffers, handler); 00545 else 00546 #endif 00547 boost::asio::async_write(m_ssl_socket.next_layer(), buffers, handler); 00548 } 00549 00559 template <typename ConstBufferSequence> 00560 inline std::size_t write(const ConstBufferSequence& buffers, 00561 boost::system::error_code& ec) 00562 { 00563 #ifdef PION_HAVE_SSL 00564 if (getSSLFlag()) 00565 return boost::asio::write(m_ssl_socket, buffers, 00566 boost::asio::transfer_all(), ec); 00567 else 00568 #endif 00569 return boost::asio::write(m_ssl_socket.next_layer(), buffers, 00570 boost::asio::transfer_all(), ec); 00571 } 00572 00573 00576 inline void finish(void) { if (m_finished_handler) m_finished_handler(shared_from_this()); } 00577 00579 inline bool getSSLFlag(void) const { return m_ssl_flag; } 00580 00582 inline void setLifecycle(LifecycleType t) { m_lifecycle = t; } 00583 00585 inline LifecycleType getLifecycle(void) const { return m_lifecycle; } 00586 00588 inline bool getKeepAlive(void) const { return m_lifecycle != LIFECYCLE_CLOSE; } 00589 00591 inline bool getPipelined(void) const { return m_lifecycle == LIFECYCLE_PIPELINED; } 00592 00594 inline ReadBuffer& getReadBuffer(void) { return m_read_buffer; } 00595 00602 inline void saveReadPosition(const char *read_ptr, const char *read_end_ptr) { 00603 m_read_position.first = read_ptr; 00604 m_read_position.second = read_end_ptr; 00605 } 00606 00613 inline void loadReadPosition(const char *&read_ptr, const char *&read_end_ptr) const { 00614 read_ptr = m_read_position.first; 00615 read_end_ptr = m_read_position.second; 00616 } 00617 00619 inline boost::asio::ip::tcp::endpoint getRemoteEndpoint(void) const { 00620 boost::asio::ip::tcp::endpoint remote_endpoint; 00621 try { 00622 // const_cast is required since lowest_layer() is only defined non-const in asio 00623 remote_endpoint = const_cast<SSLSocket&>(m_ssl_socket).lowest_layer().remote_endpoint(); 00624 } catch (boost::system::system_error& /* e */) { 00625 // do nothing 00626 } 00627 return remote_endpoint; 00628 } 00629 00631 inline boost::asio::ip::address getRemoteIp(void) const { 00632 return getRemoteEndpoint().address(); 00633 } 00634 00636 inline unsigned short getRemotePort(void) const { 00637 return getRemoteEndpoint().port(); 00638 } 00639 00641 inline boost::asio::io_service& getIOService(void) { 00642 return m_ssl_socket.lowest_layer().get_io_service(); 00643 } 00644 00646 inline Socket& getSocket(void) { return m_ssl_socket.next_layer(); } 00647 00649 inline SSLSocket& getSSLSocket(void) { return m_ssl_socket; } 00650 00652 inline const Socket& getSocket(void) const { return const_cast<SSLSocket&>(m_ssl_socket).next_layer(); } 00653 00655 inline const SSLSocket& getSSLSocket(void) const { return m_ssl_socket; } 00656 00657 00658 protected: 00659 00669 TCPConnection(boost::asio::io_service& io_service, 00670 SSLContext& ssl_context, 00671 const bool ssl_flag, 00672 ConnectionHandler finished_handler) 00673 : 00674 #ifdef PION_HAVE_SSL 00675 m_ssl_context(io_service, boost::asio::ssl::context::sslv23), 00676 m_ssl_socket(io_service, ssl_context), m_ssl_flag(ssl_flag), 00677 #else 00678 m_ssl_context(0), 00679 m_ssl_socket(io_service), m_ssl_flag(false), 00680 #endif 00681 m_lifecycle(LIFECYCLE_CLOSE), 00682 m_finished_handler(finished_handler) 00683 { 00684 saveReadPosition(NULL, NULL); 00685 } 00686 00687 00688 private: 00689 00691 typedef std::pair<const char*, const char*> ReadPosition; 00692 00693 00695 SSLContext m_ssl_context; 00696 00698 SSLSocket m_ssl_socket; 00699 00701 bool m_ssl_flag; 00702 00704 ReadBuffer m_read_buffer; 00705 00707 ReadPosition m_read_position; 00708 00710 LifecycleType m_lifecycle; 00711 00713 ConnectionHandler m_finished_handler; 00714 }; 00715 00716 00718 typedef boost::shared_ptr<TCPConnection> TCPConnectionPtr; 00719 00720 00721 } // end namespace net 00722 } // end namespace pion 00723 00724 #endif