2 * @brief TCPService class header. This class represents a TCP client.
6 * @copyright Intra2net AG
10 #include "tcp_service.hpp"
12 typedef boost::shared_ptr<SSLStream> SocketPtr;
19 * @param _log Logger object.
20 * @param io_service Service peer information.
22 TCPService::TCPService()
32 TCPService::~TCPService()
38 * Initiate a new session with the peer.
39 * @param endpoint_iterator The enpoint iterator.
40 * @return throws boost::syste::system_error if something went wrong.
42 void TCPService::connect(const std::string& _host, const std::string& _port)
44 // Init boost::system::error_code
45 boost::system::error_code err_code;
47 // Create service object. The IO_Service has to be a member
48 //boost::asio::io_service io_service;
50 // Init DNS query object
51 boost::asio::ip::tcp::resolver service_resolver(IOService);
52 boost::asio::ip::tcp::resolver::query dns_query(_host, _port);
53 boost::asio::ip::tcp::resolver::iterator end_iter;
55 // Perform the DNS query
56 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = service_resolver.resolve(dns_query, err_code);
58 throw boost::system::system_error(err_code);
60 // Init ssl context for service object
61 boost::asio::ssl::context ctx(IOService, boost::asio::ssl::context::sslv23);
62 ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
64 // Initialize the member Socket
65 Socket = SocketPtr(new SSLStream(IOService,ctx));
67 // Try to connect the Socket through all available endpoints
68 if (endpoint_iterator != end_iter)
72 Socket->lowest_layer().close(); /*lint !e534 */
73 Socket->lowest_layer().connect(*endpoint_iterator++, err_code); /*lint !e534 */
74 } while ( err_code && (endpoint_iterator != end_iter) );
77 throw boost::system::system_error(err_code);
79 // Perform SSL handshake
80 Socket->handshake(boost::asio::ssl::stream_base::client,err_code); /*lint !e534*/
82 throw boost::system::system_error(err_code);
89 * Will read all available data and return it as a string.
90 * @return The data read from the socket. Throws boost::syste::system_error if something went wrong.
92 std::string TCPService::read_from_socket()
94 // Limit stream buffer to 1MB
95 //unsigned int max_buff_size = 1024*1024;
96 //boost::asio::streambuf stream_buffer(max_buff_size);
98 // Do not limit the receive buffer size for reusability. By default, max_size == 18446744073709551615
99 boost::asio::streambuf stream_buffer;
102 boost::system::error_code error_code;
104 // Is blocking until all available data was read or buffer is full
105 size_t bytes_read = boost::asio::read(*Socket.get(),stream_buffer,boost::asio::transfer_at_least(1),error_code); /*lint !e747 */
106 if ( error_code == boost::asio::error::eof )
107 throw boost::system::system_error(boost::system::error_code(ECONNABORTED,boost::system::system_category()),"Connection closed by peer.");
109 throw boost::system::system_error(error_code);
110 else if ( bytes_read == stream_buffer.max_size() )
111 throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category()),"Could not read all available data into streambuf.");
112 else if ( bytes_read == 0 )
113 throw boost::system::system_error(boost::system::error_code(ENODATA,boost::system::system_category()),"No data available on socket.");
115 // Copy data from stream buffer to a constant buffer and create a string object from the constant buffer
116 boost::asio::streambuf::const_buffers_type const_buffer = stream_buffer.data();
117 std::string data_read(boost::asio::buffers_begin(const_buffer), boost::asio::buffers_begin(const_buffer) + bytes_read); /*lint !e713*/
124 * Writes out given data to the socket.
125 * @param data The data which will be written to the socket.
126 * @return Throws boost::syste::system_error if something went wrong.
128 void TCPService::write_to_socket(const string& data)
130 // Get the data size which will be written
131 size_t data_size = data.size();
133 // Init stream_buffer with data
134 boost::asio::streambuf stream_buffer(data_size);
135 std::ostream request_stream(&stream_buffer);
136 request_stream << data;
139 boost::system::error_code error_code;
141 size_t bytes_wrote = boost::asio::write(*Socket.get(), stream_buffer, boost::asio::transfer_at_least(data_size), error_code);
143 throw boost::system::system_error(error_code);
144 else if ( bytes_wrote != data_size )
145 throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category()),"Could not write all data to the socket.");
152 * Will close the session.
153 * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
155 void TCPService::close()
157 boost::system::error_code error_code;
159 // Shutdown send and receive channel on socket. This results in sending FIN flag.
160 Socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,error_code); /*lint !e534*/
162 throw boost::system::system_error(error_code);
164 // Closing the session.
165 Socket->lowest_layer().close( error_code ); /*lint !e534*/
167 throw boost::system::system_error(error_code);