Last linter optimizations.
[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
10#include "tcp_service.h"
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
c730deea 105 size_t bytes_read = boost::asio::read(*Socket.get(),stream_buffer,boost::asio::transfer_at_least(1),error_code);
6650af14
BS
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.");
108 else if (error_code)
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.");
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();
117 std::string data_read(boost::asio::buffers_begin(const_buffer), boost::asio::buffers_begin(const_buffer) + bytes_read);
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
138 // Init bytes_read and the error_code
c730deea 139 size_t bytes_wrote = 0;
6650af14
BS
140 boost::system::error_code error_code;
141
142 bytes_wrote = boost::asio::write(*Socket.get(), stream_buffer, boost::asio::transfer_at_least(data_size), error_code);
143 if (error_code)
144 throw boost::system::system_error(error_code);
145 else if ( bytes_wrote != data_size )
146 throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category),"Could not write all data to the socket.");
147
83ae2edf 148 return;
6650af14
BS
149}
150
151
152/**
153 * Will close the session.
154 * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
155 */
557b6f56 156void TCPService::close()
6650af14
BS
157{
158 boost::system::error_code error_code;
159
160 // Shutdown send and receive channel on socket. This results in sending FIN flag.
557b6f56 161 Socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,error_code); /*lint !e534*/
6650af14
BS
162 if ( error_code )
163 throw boost::system::system_error(error_code);
164
165 // Closing the session.
557b6f56 166 Socket->lowest_layer().close( error_code ); /*lint !e534*/
6650af14
BS
167 if ( error_code )
168 throw boost::system::system_error(error_code);
169
31beb90a 170 return;
6650af14 171}