Added net_helper and corresponding classes.
--- /dev/null
+/** @file
+ * @brief The abstract IPService interface. This class represents all IP services.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef IPSERVICE_H
+#define IPSERVICE_H
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+
+
+class IPService
+{
+public:
+
+ typedef boost::shared_ptr<IPService> Ptr;
+
+ virtual int connect(const std::string& _hostname, const std::string& _port) = 0;
+
+ virtual std::string read_from_socket() = 0;
+
+ virtual int write_to_socket(const std::string& data) = 0;
+
+ virtual int close() = 0;
+};
+
+#endif
#include "config.cpp"
#include "logger.cpp"
-#include "service.cpp"
#include "serviceholder.cpp"
#include "updater.cpp"
#include "ip_addr_helper.cpp"
+#include "net_helper.cpp"
+#include "tcp_service.cpp"
#include "httphelper.cpp"
#include "serializeservicecontainer.cpp"
#include "util.cpp"
+#include "service.cpp"
#include "service_dyndns.cpp"
#include "service_dyns.cpp"
#include "service_ods.cpp"
#include "service_zoneedit.cpp"
#include "service_gnudip.cpp"
+
using namespace std;
Updater::Ptr updater;
--- /dev/null
+/** @file
+ * @brief TcpIpHelper class implementation. This class represents a Helper to easily perform tcp/ip operations.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#include "net_helper.h"
+#include "tcp_service.h"
+
+
+using namespace std;
+
+
+/**
+ * Constructor.
+ * @param _log Logger
+ * @param _host Host
+ * @param _port Port
+ */
+NetHelper::NetHelper( const Logger::Ptr _log )
+ : Log(_log)
+{
+ IPService::Ptr _ip_service_ptr(new TCPService());
+ IPServicePtr.swap(_ip_service_ptr);
+}
+
+
+/**
+ * Default destructor
+ */
+NetHelper::~NetHelper()
+{
+}
+
+
+/**
+ * Open the connection to the peer.
+ * @return 0 if all is fine, -1 on error.
+ */
+int NetHelper::open_connection(const string& hostname, const string& port)
+{
+ try
+ {
+ IPServicePtr->connect(hostname,port);
+ }
+ catch ( boost::system::system_error boost_exception )
+ {
+ ostringstream out;
+ out << "NetHelper::open_connection(): " << boost_exception.what() << " Host: " << hostname << " Port: " << port;
+ Log->print_network_error(out.str());
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * Send the given data
+ * @param data Data to send
+ * @return 0 if all is fine, -1 on error.
+ */
+int NetHelper::send_data(const std::string& data)
+{
+ try
+ {
+ IPServicePtr->write_to_socket(data);
+ }
+ catch ( boost::system::system_error boost_exception )
+ {
+ ostringstream out;
+ out << "NetHelper::send_data(): " << boost_exception.what() << " Data to be send: " << data;
+ Log->print_network_error(out.str());
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * Receive all available data from the peer.
+ * @return The data received.
+ */
+std::string NetHelper::receive_data()
+{
+ string received_data;
+ try
+ {
+ received_data = IPServicePtr->read_from_socket();
+ }
+ catch ( boost::system::system_error boost_exception )
+ {
+ ostringstream out;
+ out << "NetHelper::receive_data(): " << boost_exception.what();
+ Log->print_network_error(out.str());
+ return "";
+ }
+ return received_data;
+}
+
+
+/**
+ * Close the active session.
+ * @return 0 if all is fine, -1 on error
+ */
+int NetHelper::close_connection()
+{
+ try
+ {
+ IPServicePtr->close();
+ }
+ catch ( boost::system::system_error boost_exception )
+ {
+ ostringstream out;
+ out << "NetHelper::close_connection(): " << boost_exception.what();
+ Log->print_network_error(out.str());
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/** @file
+ * @brief NetHelper class header. This class represents a Helper to easily perform tcp/ip operations.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef NETHELPER_H
+#define NETHELPER_H
+
+#include "logger.h"
+#include "ip_service.h"
+
+#include <boost/shared_ptr.hpp>
+
+
+class NetHelper
+{
+private:
+
+ Logger::Ptr Log;
+ IPService::Ptr IPServicePtr;
+
+public:
+
+ typedef boost::shared_ptr<NetHelper> Ptr;
+
+ NetHelper(const Logger::Ptr _log);
+
+ ~NetHelper();
+
+ int open_connection(const std::string& _host, const std::string& _port);
+
+ int send_data(const std::string& data);
+
+ std::string receive_data();
+
+ int close_connection();
+
+};
+
+#endif
*/
#include "service_ods.h"
+#include "net_helper.h"
#include <time.h>
* @param _password The corresponding password.
*/
ServiceOds::ServiceOds(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval, const int _dns_cache_ttl)
+ : UpdateServer("update.ods.org")
+ , Port("7071")
{
if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config)
set_update_interval(15); // use default protocol value
*/
int ServiceOds::perform_update(const std::string& ip)
{
+ // First of all create a boost shared pointer to the NetHelper.
+ NetHelper::Ptr connection(new NetHelper(get_logger()));
+
+ // Then open the connection to the ODS update server.
+ if (connection->open_connection(UpdateServer,Port) != 0)
+ return -1;
+
+ // Receive the server greeting.
+ string server_greeting = connection->receive_data();
+ if ( server_greeting.empty() )
+ return -1;
+
+ // Send login command
+ ostringstream login;
+ login << "LOGIN " << get_login() << " " << get_password() << endl;
+ if (connection->send_data(login.str()))
+ return -1;
+
+ // Receive login reply
+ string login_reply = connection->receive_data();
+ if ( login_reply.empty() )
+ return -1;
+ else
+ {
+ // Get the return code out of the received data
+ string status_code = Util::parse_status_code(login_reply);
+ if ( status_code == "520" )
+ {
+ // Login failed
+ get_logger()->print_service_not_authorized(UpdateServer,get_login(),get_password());
+ connection->close_connection();
+ return -1;
+ }
+ else if ( status_code != "225" )
+ {
+ // Undefined protocol error, Log login_reply
+ get_logger()->print_undefined_protocol_error("ODS",login_reply);
+ connection->close_connection();
+ return -1;
+ }
+ }
+
+ // Successfully loged in, status_code should be 225
+
+ // Send update request
+ ostringstream update_request;
+ update_request << "ADDRR " << get_hostname() << " NS " << ip << endl;
+ if (connection->send_data(update_request.str()))
+ return -1;
+
+ // Receive update request server reply
+ string update_reply = connection->receive_data();
+ if ( server_greeting.empty() )
+ return -1;
+ else
+ {
+ // Get the return code out of the received data
+ string status_code = Util::parse_status_code(login_reply);
+ if ( status_code != "795" )
+ {
+ get_logger()->print_undefined_protocol_error("ODS",update_reply);
+ connection->close_connection();
+ return -1;
+ }
+ }
+
+ // Successfully updated host
+ connection->close_connection();
return 0;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int version);
+ std::string UpdateServer;
+ std::string Port;
+
public:
typedef boost::shared_ptr<ServiceOds> Ptr;
--- /dev/null
+/** @file
+ * @brief TCPService class header. This class represents a TCP client.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#include "tcp_service.h"
+
+typedef boost::shared_ptr<SSLStream> SocketPtr;
+
+using namespace std;
+
+
+/**
+ * Constructor
+ * @param _log Logger object.
+ * @param io_service Service peer information.
+ */
+TCPService::TCPService()
+ : Socket()
+ , IOService()
+{
+}
+
+
+/**
+ * Default destrucotr.
+ */
+TCPService::~TCPService()
+{
+}
+
+
+/**
+ * Initiate a new session with the peer.
+ * @param endpoint_iterator The enpoint iterator.
+ * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
+ */
+int TCPService::connect(const std::string& _host, const std::string& _port) throw (boost::system::system_error)
+{
+ // Init boost::system::error_code
+ boost::system::error_code error_code;
+
+ // Create service object. The IO_Service has to be a member
+ //boost::asio::io_service io_service;
+
+ // Init DNS query object
+ boost::asio::ip::tcp::resolver resolver(IOService);
+ boost::asio::ip::tcp::resolver::query query(_host, _port);
+ boost::asio::ip::tcp::resolver::iterator end;
+
+ // Perform the DNS query
+ boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query, error_code);
+ if ( error_code )
+ throw boost::system::system_error(error_code);
+
+ // Init ssl context for service object
+ boost::asio::ssl::context ctx(IOService, boost::asio::ssl::context::sslv23);
+ ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
+
+ // Initialize the member Socket
+ SocketPtr _socket_ptr(new SSLStream(IOService,ctx));
+ Socket.swap(_socket_ptr);
+
+ // Try to connect the Socket through all available endpoints
+ if (endpoint_iterator != end)
+ {
+ do
+ {
+ Socket->lowest_layer().close();
+ Socket->lowest_layer().connect(*endpoint_iterator++, error_code);
+ } while ( error_code && (endpoint_iterator != end) );
+ }
+ if ( error_code )
+ throw boost::system::system_error(error_code);
+
+ // Perform SSL handshake
+ Socket->handshake(boost::asio::ssl::stream_base::client,error_code);
+ if ( error_code )
+ throw boost::system::system_error(error_code);
+
+ return 0;
+}
+
+
+/**
+ * Will read all available data and return it as a string.
+ * @return The data read from the socket. Throws boost::syste::system_error if something went wrong.
+ */
+std::string TCPService::read_from_socket() throw (boost::system::system_error)
+{
+ // Limit stream buffer to 1MB
+ //unsigned int max_buff_size = 1024*1024;
+ //boost::asio::streambuf stream_buffer(max_buff_size);
+
+ // Do not limit the receive buffer size for reusability. By default, max_size == 18446744073709551615
+ boost::asio::streambuf stream_buffer;
+
+ // Init bytes_read and the error_code
+ unsigned int bytes_read = 0;
+ boost::system::error_code error_code;
+
+ // Is blocking until all available data was read or buffer is full
+ bytes_read = boost::asio::read(*Socket.get(),stream_buffer,boost::asio::transfer_at_least(1),error_code);
+ if ( error_code == boost::asio::error::eof )
+ throw boost::system::system_error(boost::system::error_code(ECONNABORTED,boost::system::system_category),"Connection closed by peer.");
+ else if (error_code)
+ throw boost::system::system_error(error_code);
+ else if ( bytes_read == stream_buffer.max_size() )
+ throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category),"Could not read all available data into streambuf.");
+ else if ( bytes_read == 0 )
+ throw boost::system::system_error(boost::system::error_code(ENODATA,boost::system::system_category),"No data available on socket.");
+
+ // Copy data from stream buffer to a constant buffer and create a string object from the constant buffer
+ boost::asio::streambuf::const_buffers_type const_buffer = stream_buffer.data();
+ std::string data_read(boost::asio::buffers_begin(const_buffer), boost::asio::buffers_begin(const_buffer) + bytes_read);
+
+ return data_read;
+}
+
+
+/**
+ * Writes out given data to the socket.
+ * @param data The data which will be written to the socket.
+ * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
+ */
+int TCPService::write_to_socket(const string& data) throw (boost::system::system_error)
+{
+ // Get the data size which will be written
+ unsigned int data_size = data.size();
+
+ // Init stream_buffer with data
+ boost::asio::streambuf stream_buffer(data_size);
+ std::ostream request_stream(&stream_buffer);
+ request_stream << data;
+
+ // Init bytes_read and the error_code
+ unsigned int bytes_wrote = 0;
+ boost::system::error_code error_code;
+
+ bytes_wrote = boost::asio::write(*Socket.get(), stream_buffer, boost::asio::transfer_at_least(data_size), error_code);
+ if (error_code)
+ throw boost::system::system_error(error_code);
+ else if ( bytes_wrote != data_size )
+ throw boost::system::system_error(boost::system::error_code(ENOBUFS,boost::system::system_category),"Could not write all data to the socket.");
+
+ return 0;
+}
+
+
+/**
+ * Will close the session.
+ * @return 0 if all is fine, throws boost::syste::system_error if something went wrong.
+ */
+int TCPService::close() throw (boost::system::system_error)
+{
+ boost::system::error_code error_code;
+
+ // Shutdown send and receive channel on socket. This results in sending FIN flag.
+ Socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both,error_code);
+ if ( error_code )
+ throw boost::system::system_error(error_code);
+
+ // Closing the session.
+ Socket->lowest_layer().close( error_code );
+ if ( error_code )
+ throw boost::system::system_error(error_code);
+
+ return 0;
+}
--- /dev/null
+/** @file
+ * @brief TCPService class header. This class represents a TCP client.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef TCPSERVICE_H
+#define TCPSERVICE_H
+
+#include "logger.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+
+typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
+
+class TCPService : public IPService
+{
+
+private:
+
+ boost::shared_ptr<SSLStream> Socket;
+ // IOService has to be a member, otherwise the socket.close() operation will throw "mutex: Invalid argument"
+ // Bug in boost::asio ? Cause no docs found concerning this issue. The socket.close() operation is trying to clean up io_service.
+ boost::asio::io_service IOService;
+
+public:
+
+ typedef boost::shared_ptr<TCPService> Ptr;
+
+ TCPService();
+
+ ~TCPService();
+
+ virtual int connect(const std::string& _hostname, const std::string& _port) throw (boost::system::system_error);
+
+ std::string read_from_socket() throw (boost::system::system_error);
+
+ int write_to_socket(const std::string& data) throw (boost::system::system_error);
+
+ int close() throw (boost::system::system_error);
+};
+
+#endif