Implemented dyndns service.
authorBjoern Sikora <bjoern.sikora@intra2net.com>
Thu, 3 Sep 2009 10:46:57 +0000 (12:46 +0200)
committerBjoern Sikora <bjoern.sikora@intra2net.com>
Thu, 3 Sep 2009 10:46:57 +0000 (12:46 +0200)
Added user agent info to curl operations.
Added access to CurlWritedataBuff.
Bug fix: Do not append IP to member BaseUrl.

src/config.cpp
src/config.h
src/dhs.cpp
src/dyndns.cpp [new file with mode: 0644]
src/dyndns.h [new file with mode: 0644]
src/httphelper.cpp
src/httphelper.h
src/logger.cpp
src/logger.h
src/main.cpp
src/updater.cpp

index a4fa6bf..a255f75 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "dhs.h"
 #include "ods.h"
+#include "dyndns.h"
 
 #include <time.h>
 #include <iostream>
@@ -260,6 +261,11 @@ Service::Ptr Config::create_service(const string &protocol,const string &hostnam
         Service::Ptr service_ods(new ODS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl));
         return service_ods;
     }
+    else if(protocol == "dyndns")
+    {
+        Service::Ptr service_dyndns(new DYNDNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
+        return service_dyndns;
+    }
     else
     {
         Log->print_unknown_protocol(protocol);
index daa169d..712eb8b 100644 (file)
@@ -15,6 +15,7 @@
 #include "logger.h"
 #include "serviceholder.h"
 #include "httphelper.h"
+#include "service.h"
 
 #include <boost/program_options.hpp>
 #include <boost/shared_ptr.hpp>
index cbefaae..c3d7f53 100644 (file)
@@ -173,13 +173,14 @@ list<string> DHS::split(const string& str,const string& delimiters) const
  */
 int DHS::perform_update(const std::string& ip)
 {
-    int ret_val = 0;
+    int ret_val = -1;
 
-    BaseUrl.append(ip);
+    string url = BaseUrl;
+    url.append(ip);
 
-    long output = HTTPHelp->http_get(BaseUrl);
+    long output = HTTPHelp->http_get(url);
 
-    get_logger()->print_http_status_code(BaseUrl,output);
+    get_logger()->print_http_status_code(url,output);
 
     if ( output == 200 )
     {
@@ -191,7 +192,7 @@ int DHS::perform_update(const std::string& ip)
     }
     else if ( output == 401 )
     {
-        get_logger()->print_http_not_authorized(BaseUrl,get_login(),get_password());
+        get_logger()->print_http_not_authorized(url,get_login(),get_password());
         // not authorized
         ret_val = -1;
     }
diff --git a/src/dyndns.cpp b/src/dyndns.cpp
new file mode 100644 (file)
index 0000000..c8eacda
--- /dev/null
@@ -0,0 +1,136 @@
+/** @file
+ * @brief DYNDNS Service class implementation. This class represents the DYNDNS service.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#include "dyndns.h"
+
+#include <time.h>
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+
+/**
+ * Default Constructor, needed for object serialization.
+ */
+DYNDNS::DYNDNS()
+{
+}
+
+
+/**
+ * Constructor.
+ * @param _hostname The hostname to update
+ * @param _login The login name.
+ * @param _password The corresponding password.
+ */
+DYNDNS::DYNDNS(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, const string& _proxy, const int _proxy_port)
+{
+    if ( _update_interval == -1 )        // If _update_interval is default po::option_desc (not specified via config)
+        set_update_interval(0);              // use default protocol value
+    else
+        set_update_interval(_update_interval);
+
+    if ( _max_updates_within_interval == -1 )
+        set_max_updates_within_interval(0);
+    else
+        set_max_updates_within_interval(_max_updates_within_interval);
+
+    if ( _dns_cache_ttl == -1 )
+        set_dns_cache_ttl(60);
+    else
+        set_dns_cache_ttl(_dns_cache_ttl);
+
+    set_protocol(_protocol);
+    set_hostname(_hostname);
+    set_login(_login);
+    set_password(_password);
+    set_logger(_logger);
+
+    // create http helper class
+    HTTPHelper::Ptr _http_help(new HTTPHelper(_logger,_proxy,_proxy_port,_login,_password));
+    HTTPHelp = _http_help;
+    _http_help.reset();
+
+    BaseUrl = assemble_base_url(get_hostname());
+}
+
+
+/**
+ * Default destructor
+ */
+DYNDNS::~DYNDNS()
+{
+}
+
+
+/**
+ * Assemble the dhs update url from the given fqhn
+ * @param hostname The fqhn hostname to update IP for.
+ * @return The assembled update url without IP.
+ */
+string DYNDNS::assemble_base_url(const string& fqhn) const
+{
+    string base_url;
+
+    base_url = "https://members.dyndns.org";
+    base_url.append("/nic/update?hostname=");
+    base_url.append(fqhn);
+    base_url.append("&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG&myip=");
+
+    return base_url;
+}
+
+
+/**
+ * Performs the Service update.
+ * @param ip IP Address to set.
+ * @return 0 if all is fine, -1 otherwise.
+ */
+int DYNDNS::perform_update(const std::string& ip)
+{
+    int ret_val = -1;
+
+    // the result string if update was successful
+    string good = "good ";
+    good.append(ip);
+
+    string url = BaseUrl;
+    url.append(ip);
+
+    long output = HTTPHelp->http_get(url);
+
+    get_logger()->print_http_status_code(url,output);
+
+    // HTTP operation completed successful, now we have to parse the data received by curl cause http status code is not significant for dyndns update errors
+    if ( output == 200 )
+    {
+        string curl_data = HTTPHelp->get_curl_data();
+
+        if ( curl_data == good )
+            ret_val = 0;
+        else if ( curl_data == "badauth" )
+            get_logger()->print_http_not_authorized(url,get_login(),get_password());
+        else
+            get_logger()->print_update_failure(url, curl_data);
+    }
+
+    return ret_val;
+}
+
+
+/**
+ * Serialize function needed by boost/serialization to define which members should be stored as the object state.
+ * @param ar Archive
+ * @param version Version
+ */
+template<class Archive>
+void DYNDNS::serialize(Archive & ar, const unsigned int version)
+{
+    ar & boost::serialization::base_object<Service>(*this);
+}
diff --git a/src/dyndns.h b/src/dyndns.h
new file mode 100644 (file)
index 0000000..2bf38db
--- /dev/null
@@ -0,0 +1,51 @@
+/** @file
+ * @brief DYNDNS Service class header. This class represents the DYNDNS service.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef DYNDNS_H
+#define DYNDNS_H
+
+#include <string>
+
+#include "service.h"
+#include "logger.h"
+
+#include <boost/serialization/array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <list>
+
+class DYNDNS : public Service
+{
+
+private:
+
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int version);
+
+    std::string BaseUrl;
+
+    HTTPHelper::Ptr HTTPHelp;
+
+    std::string assemble_base_url(const std::string& fqhn) const;
+
+public:
+
+    typedef boost::shared_ptr<DYNDNS> Ptr;
+
+    DYNDNS();
+
+    DYNDNS(const std::string& _protocol, const std::string& _hostname, const std::string& _login, const std::string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval, const int dns_cache_ttl, const std::string& proxy, const int proxy_port);
+
+    ~DYNDNS();
+
+    int perform_update(const std::string& ip);
+
+};
+
+#endif
index 036051e..5794362 100644 (file)
@@ -78,6 +78,16 @@ long HTTPHelper::http_get(const string& url)
 
 
 /**
+ * Getter for member CurlWritedataBuff
+ * @return CurlWritedataBuff
+ */
+string HTTPHelper::get_curl_data() const
+{
+    return CurlWritedataBuff;
+}
+
+
+/**
  * Initialized curl easy handle with a few options.
  * @param curl_writedata_buff Reference to a string wich will be filled with the curl result
  * @param curl_err_buff A pointer to an char array which will be filled with error message.
@@ -85,6 +95,8 @@ long HTTPHelper::http_get(const string& url)
  */
 CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const
 {
+    string user_agent = "bpdyndnsd Intra2net AG 2009";
+
     CURL *curl_easy_handle = curl_easy_init();
 
     curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1);
@@ -94,6 +106,7 @@ CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) con
     curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff);
     curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive);
     curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff);
+    curl_easy_setopt(curl_easy_handle,CURLOPT_USERAGENT,&user_agent);
 
     if ( !Proxy.empty() )
     {
index b63e45c..97df6b8 100644 (file)
@@ -46,6 +46,8 @@ public:
 
     long http_get(const std::string& ip);
 
+    std::string get_curl_data() const;
+
     // libcurl is a C library, so we have to make the callback member function static :-(
     static int http_receive(char *inBuffer, size_t size, size_t nmemb, std::string *outBuffer);
 };
index 9fe824f..27a0d7b 100644 (file)
@@ -1249,7 +1249,7 @@ void Logger::print_curl_data(const string& curl_writedata_buff) const
     if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
     {
         ostringstream msg;
-        msg << "Data received by curl:\n" << curl_writedata_buff << endl;
+        msg << "Data received by curl: " << curl_writedata_buff << endl;
         log_notice(msg.str(),level);
     }
 }
@@ -1267,7 +1267,7 @@ void Logger::print_http_not_authorized(const string& url, const string& username
     if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
     {
         ostringstream msg;
-        msg << "Not authorized to perform update operation on url: " << url << "\n Please check username and password: " << username << ":" << password << endl;
+        msg << "Not authorized to perform update operation on url: " << url << " Please check username and password: " << username << ":" << password << endl;
         log_warning(msg.str(),level);
     }
 }
@@ -1288,3 +1288,20 @@ void Logger::print_http_status_code(const std::string& url, const long http_code
         log_notice(msg.str(),level);
     }
 }
+
+
+/**
+ * Generic failure while trying to update service
+ * @param url The requested URL
+ * @param curl_data The received curl_data from the server
+ */
+void Logger::print_update_failure(const string& url, const string& curl_data) const
+{
+    int level = 0;
+    if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
+    {
+        ostringstream msg;
+        msg << "Problem while trying to updating service. Requested URL: " << url << " Error Code from Server: " << curl_data << endl;
+        log_warning(msg.str(),level);
+    }
+}
index 710be11..f13da6d 100644 (file)
@@ -189,6 +189,8 @@ public:
     void print_http_not_authorized(const std::string& url, const std::string& username, const std::string& password) const;
 
     void print_http_status_code(const std::string& url, const long http_code) const;
+
+    void print_update_failure(const std::string& url, const std::string& curl_data) const;
 };
 
 #endif
index ed86fd2..55ab56d 100644 (file)
@@ -38,6 +38,7 @@
 #include "iphelper.cpp"
 #include "httphelper.cpp"
 #include "serializeservicecontainer.cpp"
+#include "dyndns.cpp"
 
 
 using namespace std;
index d966d14..e1fa1ae 100644 (file)
@@ -19,6 +19,7 @@
 // Following boost macros are needed for serialization of derived classes through a base class pointer (Service *).
 BOOST_CLASS_EXPORT_GUID(ODS, "ODS")
 BOOST_CLASS_EXPORT_GUID(DHS, "DHS")
+BOOST_CLASS_EXPORT_GUID(DYNDNS, "DYNDNS")
 
 namespace fs = boost::filesystem;