Adapt to boost 1.44.0
[bpdyndnsd] / src / tcp_service.cpp
CommitLineData
6650af14
BS
1/** @file
2 * @brief TCPService class header. This class represents a TCP client.
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
9
4de6a9b8 10#include "tcp_service.hpp"
6650af14
BS
11
12typedef boost::shared_ptr<SSLStream> SocketPtr;
13
14using namespace std;
15
16
17/**
18 * Constructor
19 * @param _log Logger object.
20 * @param io_service Service peer information.
21 */
22TCPService::TCPService()
23 : Socket()
24 , IOService()
25{
26}
27
28
29/**
30 * Default destrucotr.
31 */
32TCPService::~TCPService()
33{
34}
35
36
37/**
38 * Initiate a new session with the peer.
39 * @param endpoint_iterator The enpoint iterator.
c9d27cb6 40 * @return throws boost::syste::system_error if something went wrong.
6650af14 41 */
557b6f56 42void TCPService::connect(const std::string& _host, const std::string& _port)
6650af14
BS
43{
44 // Init boost::system::error_code
c730deea 45 boost::system::error_code err_code;
6650af14
BS
46
47 // Create service object. The IO_Service has to be a member
48 //boost::asio::io_service io_service;
49
50 // Init DNS query object
c730deea
BS
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;
6650af14
BS
54
55 // Perform the DNS query
c730deea
BS
56 boost::asio::ip::tcp::resolver::iterator endpoint_iterator = service_resolver.resolve(dns_query, err_code);
57 if ( err_code )
58 throw boost::system::system_error(err_code);
6650af14
BS
59
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);
63
64 // Initialize the member Socket
c3c84086 65 Socket = SocketPtr(new SSLStream(IOService,ctx));
6650af14
BS
66
67 // Try to connect the Socket through all available endpoints
c730deea 68 if (endpoint_iterator != end_iter)
6650af14
BS
69 {
70 do
71 {
557b6f56
BS
72 Socket->lowest_layer().close(); /*lint !e534 */
73 Socket->lowest_layer().connect(*endpoint_iterator++, err_code); /*lint !e534 */
c730deea 74 } while ( err_code && (endpoint_iterator != end_iter) );
6650af14 75 }
c730deea
BS
76 if ( err_code )
77 throw boost::system::system_error(err_code);
6650af14
BS
78
79 // Perform SSL handshake
557b6f56 80 Socket->handshake(boost::asio::ssl::stream_base::client,err_code); /*lint !e534*/
c730deea
BS
81 if ( err_code )
82 throw boost::system::system_error(err_code);
6650af14 83
c9d27cb6 84 return;
6650af14
BS
85}
86
87
88/**
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.
91 */
557b6f56 92std::string TCPService::read_from_socket()
6650af14
BS
93{
94 // Limit stream buffer to 1MB
95 //unsigned int max_buff_size = 1024*1024;
96 //boost::asio::streambuf stream_buffer(max_buff_size);
97
98 // Do not limit the receive buffer size for reusability. By default, max_size == 18446744073709551615
99 boost::asio::streambuf stream_buffer;
100
c730deea 101 // Init error_code
6650af14
BS
102 boost::system::error_code error_code;
103
104 // Is blocking until all available data was read or buffer is full
08a5a621 105 size_t bytes_read = boost::asio::read(*Socket.get(),stream_buffer,boost::asio::transfer_at_least(1),error_code); /*lint !e747 */
6650af14 106 if ( error_code == boost::asio::error::eof )
83a271a9 107 throw boost::system::system_error(boost::system::error_code(ECONNABORTED,boost::system::system_category()),"Connection closed by peer.");
6650af14
BS
108 else if (error_code)
109 throw boost::system::system_error(error_code);
110 else if ( bytes_read == stream_buffer.max_size() )
83a271a9 111 throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category()),"Could not read all available data into streambuf.");
6650af14 112 else if ( bytes_read == 0 )
83a271a9 113 throw boost::system::system_error(boost::system::error_code(ENODATA,boost::system::system_category()),"No data available on socket.");
6650af14
BS
114
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();
08a5a621 117 std::string data_read(boost::asio::buffers_begin(const_buffer), boost::asio::buffers_begin(const_buffer) + bytes_read); /*lint !e713*/
6650af14
BS
118
119 return data_read;
120}
121
122
123/**
124 * Writes out given data to the socket.
125 * @param data The data which will be written to the socket.
83ae2edf 126 * @return Throws boost::syste::system_error if something went wrong.
6650af14 127 */
557b6f56 128void TCPService::write_to_socket(const string& data)
6650af14
BS
129{
130 // Get the data size which will be written
c730deea 131 size_t data_size = data.size();
6650af14
BS
132
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;
137
08a5a621 138 // Init error_code
6650af14
BS
139 boost::system::error_code error_code;
140
08a5a621 141 size_t bytes_wrote = boost::asio::write(*Socket.get(), stream_buffer, boost::asio::transfer_at_least(data_size), error_code);
6650af14
BS
142 if (error_code)
143 throw boost::system::system_error(error_code);
144 else if ( bytes_wrote != data_size )
83a271a9 145 throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category()),"Could not write all data to the socket.");
6650af14 146
83ae2edf 147 return;
6650af14
BS
148}
149
150
151/**
152 * Will close the session.
153 * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
154 */
557b6f56 155void TCPService::close()
6650af14
BS
156{
157 boost::system::error_code error_code;
158
159 // Shutdown send and receive channel on socket. This results in sending FIN flag.
557b6f56 160 Socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,error_code); /*lint !e534*/
6650af14
BS
161 if ( error_code )
162 throw boost::system::system_error(error_code);
163
164 // Closing the session.
557b6f56 165 Socket->lowest_layer().close( error_code ); /*lint !e534*/
6650af14
BS
166 if ( error_code )
167 throw boost::system::system_error(error_code);
168
31beb90a 169 return;
6650af14 170}