Fix 'occurred' typo
[bpdyndnsd] / src / tcp_service.cpp
... / ...
CommitLineData
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.hpp"
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.
40 * @return throws boost::syste::system_error if something went wrong.
41 */
42void TCPService::connect(const std::string& _host, const std::string& _port)
43{
44 // Init boost::system::error_code
45 boost::system::error_code err_code;
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
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;
54
55 // Perform the DNS query
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);
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
65 Socket = SocketPtr(new SSLStream(IOService,ctx));
66
67 // Try to connect the Socket through all available endpoints
68 if (endpoint_iterator != end_iter)
69 {
70 do
71 {
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) );
75 }
76 if ( err_code )
77 throw boost::system::system_error(err_code);
78
79 // Perform SSL handshake
80 Socket->handshake(boost::asio::ssl::stream_base::client,err_code); /*lint !e534*/
81 if ( err_code )
82 throw boost::system::system_error(err_code);
83
84 return;
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 */
92std::string TCPService::read_from_socket()
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
101 // Init error_code
102 boost::system::error_code error_code;
103
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.");
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); /*lint !e713*/
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.
126 * @return Throws boost::syste::system_error if something went wrong.
127 */
128void TCPService::write_to_socket(const string& data)
129{
130 // Get the data size which will be written
131 size_t data_size = data.size();
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 error_code
139 boost::system::error_code error_code;
140
141 size_t bytes_wrote = boost::asio::write(*Socket.get(), stream_buffer, boost::asio::transfer_at_least(data_size), error_code);
142 if (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.");
146
147 return;
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 */
155void TCPService::close()
156{
157 boost::system::error_code error_code;
158
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*/
161 if ( error_code )
162 throw boost::system::system_error(error_code);
163
164 // Closing the session.
165 Socket->lowest_layer().close( error_code ); /*lint !e534*/
166 if ( error_code )
167 throw boost::system::system_error(error_code);
168
169 return;
170}