From 14d4f141e43bfec75c3e4ef3b7e76e6e1866f990 Mon Sep 17 00:00:00 2001
From: pierre-luc <pierre-luc@aqra.ca>
Date: Mon, 20 Jul 2009 18:31:06 -0400
Subject: [PATCH] [#1852] If chosen by the user, the hostname can now be solved
 and used for the whole time the user is connected to his/her SIP provider.
 This should be considered as a workaround, waiting to see if PJSIP will
 implement a non rfc-compliant solution to that issue.

---
 .../src/config/accountwindow.c                | 26 ++++++--
 sflphone-client-gnome/src/sflphone_const.h    | 13 ++--
 sflphone-common/src/account.h                 |  2 +
 sflphone-common/src/managerimpl.cpp           |  2 +
 sflphone-common/src/sipaccount.cpp            |  6 +-
 sflphone-common/src/sipaccount.h              |  3 +
 sflphone-common/src/sipvoiplink.cpp           | 66 ++++++++++++++++++-
 7 files changed, 101 insertions(+), 17 deletions(-)

diff --git a/sflphone-client-gnome/src/config/accountwindow.c b/sflphone-client-gnome/src/config/accountwindow.c
index 198d0c9eba..3db8a4ee86 100644
--- a/sflphone-client-gnome/src/config/accountwindow.c
+++ b/sflphone-client-gnome/src/config/accountwindow.c
@@ -50,6 +50,7 @@ GtkWidget * entryUsername;
 GtkWidget * entryHostname;
 GtkWidget * entryPassword;
 GtkWidget * entryMailbox;
+GtkWidget * entryResolveNameOnlyOnce;
 
 /* Signal to entryProtocol 'changed' */
     void
@@ -78,6 +79,7 @@ show_account_window (account_t * a)
     // Default settings
     gchar * curAccountID = "";
     gchar * curAccountEnabled = "TRUE";
+    gchar * curAccountResolveOnce = "FALSE";
     gchar * curAccountType = "SIP";
     gchar * curAlias = "";
     gchar * curUsername = "";
@@ -102,6 +104,7 @@ show_account_window (account_t * a)
         curPassword = g_hash_table_lookup(currentAccount->properties, ACCOUNT_PASSWORD);
         curUsername = g_hash_table_lookup(currentAccount->properties, ACCOUNT_USERNAME);
         curMailbox = g_hash_table_lookup(currentAccount->properties, ACCOUNT_MAILBOX);
+        curAccountResolveOnce = g_hash_table_lookup(currentAccount->properties, ACCOUNT_RESOLVE_ONCE);
     }
     else
     {
@@ -126,7 +129,7 @@ show_account_window (account_t * a)
     gtk_box_pack_start(GTK_BOX(dialog->vbox), frame, FALSE, FALSE, 0);
     gtk_widget_show(frame);
 
-    table = gtk_table_new ( 8, 2  ,  FALSE/* homogeneous */);
+    table = gtk_table_new (10, 2  ,  FALSE/* homogeneous */);
     gtk_table_set_row_spacings( GTK_TABLE(table), 10);
     gtk_table_set_col_spacings( GTK_TABLE(table), 10);
     gtk_widget_show(table);
@@ -194,8 +197,14 @@ show_account_window (account_t * a)
     gtk_entry_set_text(GTK_ENTRY(entryHostname), curHostname);
     gtk_table_attach ( GTK_TABLE( table ), entryHostname, 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
+    entryResolveNameOnlyOnce = gtk_check_button_new_with_mnemonic(_("_Resolve host name only once for the session"));
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(entryResolveNameOnlyOnce),
+            g_strcasecmp(curAccountResolveOnce,"TRUE") == 0 ? TRUE: FALSE);
+    gtk_table_attach ( GTK_TABLE( table ), entryResolveNameOnlyOnce, 0, 2, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_widget_set_sensitive( GTK_WIDGET( entryResolveNameOnlyOnce ) , TRUE );
+    
     label = gtk_label_new_with_mnemonic (_("_User name"));
-    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
     gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
 #if GTK_CHECK_VERSION(2,16,0)
 	entryUsername = gtk_entry_new();
@@ -207,10 +216,10 @@ show_account_window (account_t * a)
 #endif
     gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryUsername);
     gtk_entry_set_text(GTK_ENTRY(entryUsername), curUsername);
-    gtk_table_attach ( GTK_TABLE( table ), entryUsername, 1, 2, 6, 7, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), entryUsername, 1, 2, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
     label = gtk_label_new_with_mnemonic (_("_Password"));
-    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
     gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
 #if GTK_CHECK_VERSION(2,16,0)
 	entryPassword = gtk_entry_new();
@@ -223,15 +232,15 @@ show_account_window (account_t * a)
     gtk_entry_set_visibility(GTK_ENTRY(entryPassword), FALSE);
     gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryPassword);
     gtk_entry_set_text(GTK_ENTRY(entryPassword), curPassword);
-    gtk_table_attach ( GTK_TABLE( table ), entryPassword, 1, 2, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), entryPassword, 1, 2, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
     label = gtk_label_new_with_mnemonic (_("_Voicemail number"));
-    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 9, 10, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
     gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5);
     entryMailbox = gtk_entry_new();
     gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryMailbox);
     gtk_entry_set_text(GTK_ENTRY(entryMailbox), curMailbox);
-    gtk_table_attach ( GTK_TABLE( table ), entryMailbox, 1, 2, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+    gtk_table_attach ( GTK_TABLE( table ), entryMailbox, 1, 2, 9, 10, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
     gtk_widget_show_all( table );
     gtk_container_set_border_width (GTK_CONTAINER(table), 10);
@@ -244,6 +253,9 @@ show_account_window (account_t * a)
         g_hash_table_replace(currentAccount->properties,
                 g_strdup(ACCOUNT_ENABLED),
                 g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(entryEnabled)) ? "TRUE": "FALSE"));
+        g_hash_table_replace(currentAccount->properties,
+                g_strdup(ACCOUNT_RESOLVE_ONCE),
+                g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(entryResolveNameOnlyOnce)) ? "TRUE": "FALSE"));
         g_hash_table_replace(currentAccount->properties,
                 g_strdup(ACCOUNT_ALIAS),
                 g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(entryAlias))));
diff --git a/sflphone-client-gnome/src/sflphone_const.h b/sflphone-client-gnome/src/sflphone_const.h
index a98c08525b..387098d4cb 100644
--- a/sflphone-client-gnome/src/sflphone_const.h
+++ b/sflphone-client-gnome/src/sflphone_const.h
@@ -44,14 +44,15 @@
 #define UNUSED  __attribute__((__unused__))
 
 #define ACCOUNT_TYPE               "Account.type"
-#define ACCOUNT_ALIAS		   "Account.alias"
-#define ACCOUNT_ENABLED		   "Account.enable"
-#define ACCOUNT_MAILBOX		   "Account.mailbox"
-#define ACCOUNT_HOSTNAME      "hostname"
-#define ACCOUNT_USERNAME      "username"
-#define ACCOUNT_PASSWORD       "password"
+#define ACCOUNT_ALIAS		       "Account.alias"
+#define ACCOUNT_ENABLED		       "Account.enable"
+#define ACCOUNT_MAILBOX		       "Account.mailbox"
+#define ACCOUNT_HOSTNAME           "hostname"
+#define ACCOUNT_USERNAME           "username"
+#define ACCOUNT_PASSWORD           "password"
 #define ACCOUNT_SIP_STUN_SERVER	   "STUN.server"
 #define ACCOUNT_SIP_STUN_ENABLED   "STUN.enable"
+#define ACCOUNT_RESOLVE_ONCE       "Account.resolveOnce"
 
 /**
  * Global logger
diff --git a/sflphone-common/src/account.h b/sflphone-common/src/account.h
index 97e0b2bb3c..0f3e3239b9 100644
--- a/sflphone-common/src/account.h
+++ b/sflphone-common/src/account.h
@@ -58,6 +58,8 @@ typedef enum RegistrationState {
 #define CONFIG_ACCOUNT_ALIAS  "Account.alias"
 #define CONFIG_ACCOUNT_MAILBOX	"Account.mailbox"
 #define CONFIG_ACCOUNT_ENABLE	"Account.enable"
+#define CONFIG_ACCOUNT_RESOLVE_ONCE "Account.resolveOnce"
+
 #define HOSTNAME        "hostname"
 #define USERNAME        "username"
 #define PASSWORD        "password"
diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp
index 0b020633f3..2f5a2b720a 100644
--- a/sflphone-common/src/managerimpl.cpp
+++ b/sflphone-common/src/managerimpl.cpp
@@ -2449,6 +2449,7 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails (const Accou
 
     a.insert (std::pair<std::string, std::string> (CONFIG_ACCOUNT_ALIAS, getConfigString (accountID, CONFIG_ACCOUNT_ALIAS)));
     a.insert (std::pair<std::string, std::string> (CONFIG_ACCOUNT_ENABLE, getConfigString (accountID, CONFIG_ACCOUNT_ENABLE) == "1" ? "TRUE": "FALSE"));
+    a.insert (std::pair<std::string, std::string> (CONFIG_ACCOUNT_RESOLVE_ONCE, getConfigString (accountID, CONFIG_ACCOUNT_RESOLVE_ONCE) == "1" ? "TRUE": "FALSE"));
     a.insert (std::pair<std::string, std::string> (
                   "Status",
                   (state == Registered ? "REGISTERED":
@@ -2483,6 +2484,7 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma
 
     setConfig (accountID, CONFIG_ACCOUNT_ALIAS, (*details.find (CONFIG_ACCOUNT_ALIAS)).second);
     setConfig (accountID, CONFIG_ACCOUNT_ENABLE, (*details.find (CONFIG_ACCOUNT_ENABLE)).second == "TRUE" ? "1": "0");
+    setConfig (accountID, CONFIG_ACCOUNT_RESOLVE_ONCE, (*details.find (CONFIG_ACCOUNT_RESOLVE_ONCE)).second == "TRUE" ? "1": "0");
     setConfig (accountID, CONFIG_ACCOUNT_TYPE, accountType);
     setConfig (accountID, USERNAME, (*details.find (USERNAME)).second);
     setConfig (accountID, PASSWORD, (*details.find (PASSWORD)).second);
diff --git a/sflphone-common/src/sipaccount.cpp b/sflphone-common/src/sipaccount.cpp
index 3d141db0ef..09e4b5364e 100644
--- a/sflphone-common/src/sipaccount.cpp
+++ b/sflphone-common/src/sipaccount.cpp
@@ -25,8 +25,9 @@
 SIPAccount::SIPAccount (const AccountID& accountID)
         : Account (accountID, "sip")
         , _cred (NULL)
-        , _contact ("")
         , _bRegister (false)
+        , _contact ("")
+        , _resolveOnce (false)
         , _regc()
 {
     /* SIPVoIPlink is used as a singleton, because we want to have only one link for all the SIP accounts created */
@@ -59,7 +60,8 @@ int SIPAccount::registerVoIPLink()
     setHostname (Manager::instance().getConfigString (_accountID, HOSTNAME));
     setUsername (Manager::instance().getConfigString (_accountID, USERNAME));
     setPassword (Manager::instance().getConfigString (_accountID, PASSWORD));
-
+    _resolveOnce = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_RESOLVE_ONCE) == "1" ? true : false;
+    
     /* Start registration */
     status = _link->sendRegister (_accountID);
     ASSERT (status , SUCCESS);
diff --git a/sflphone-common/src/sipaccount.h b/sflphone-common/src/sipaccount.h
index a9925d734f..e1db28ce1e 100644
--- a/sflphone-common/src/sipaccount.h
+++ b/sflphone-common/src/sipaccount.h
@@ -85,6 +85,7 @@ class SIPAccount : public Account
         bool isRegister() {return _bRegister;}
         void setRegister(bool result) {_bRegister = result;}
 
+        inline bool isResolveOnce(void) { return _resolveOnce; }
 
     private:
 
@@ -107,6 +108,8 @@ class SIPAccount : public Account
          * SIP address
          */
         std::string _contact;
+        
+        bool _resolveOnce;
 };
 
 #endif
diff --git a/sflphone-common/src/sipvoiplink.cpp b/sflphone-common/src/sipvoiplink.cpp
index 6d01264343..fadfc65986 100644
--- a/sflphone-common/src/sipvoiplink.cpp
+++ b/sflphone-common/src/sipvoiplink.cpp
@@ -24,6 +24,7 @@
 #include "sipcall.h"
 #include "sipaccount.h"
 #include "audio/audiortp.h"
+#include "pjsip/sip_endpoint.h"
 
 #include <netinet/in.h>
 #include <arpa/nameser.h>
@@ -31,6 +32,11 @@
 
 #define CAN_REINVITE        1
 
+struct result
+{
+    pj_status_t             status;
+    pjsip_server_addresses  servers;
+};
 
 const pj_str_t STR_USER_AGENT = { (char*) "User-Agent", 10 };
 
@@ -141,6 +147,11 @@ void on_rx_offer (pjsip_inv_session *inv, const pjmedia_sdp_session *offer);
  */
 void regc_cb (struct pjsip_regc_cbparam *param);
 
+/*
+ * DNS Callback used in workaround for bug #1852
+ */
+static void dns_cb(pj_status_t status, void *token, const struct pjsip_server_addresses *addr);
+
 /*
  * Called to handle incoming requests outside dialogs
  * @param   rdata
@@ -329,18 +340,59 @@ SIPVoIPLink::getEvent()
 
 int SIPVoIPLink::sendRegister (AccountID id)
 {
-    pj_status_t status;
     int expire_value;
     char contactTmp[256];
+    
+    pj_status_t status;
     pj_str_t svr, aor, contact, useragent;
     pjsip_tx_data *tdata;
+    pjsip_host_info destination;
+    
     std::string tmp, hostname, username, password;
-    SIPAccount *account;
+    SIPAccount *account = NULL;
     pjsip_regc *regc;
     pjsip_generic_string_hdr *h;
     pjsip_hdr hdr_list;
 
     account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id));
+    if(account == NULL) {
+        _debug("In sendRegister: account is null");
+        return false; 
+    }
+    
+    if(account->isResolveOnce()) {
+        struct result result;
+        destination.type = PJSIP_TRANSPORT_UNSPECIFIED;
+        destination.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UNSPECIFIED);    
+        destination.addr.host = pj_str(const_cast<char*> ((account->getHostname()).c_str()));
+        destination.addr.port = 0;
+        
+        result.status = 0x12345678;
+        
+        pjsip_endpt_resolve(_endpt, _pool, &destination, &result, &dns_cb);
+        
+        /* The following magic number and construct are inspired from dns_test.c
+         * in test-pjsip directory.
+         */
+        while (result.status == 0x12345678) {
+            pj_time_val timeout = { 1, 0 };
+            pjsip_endpt_handle_events(_endpt, &timeout);
+            _debug("status : %d\n", result.status);	
+        }
+        
+        if(result.status != PJ_SUCCESS) {
+            _debug("Failed to resolve hostname only once."
+                   " Default resolver will be used on"
+                   " hostname for all requests.\n");
+        } else {
+            _debug("%d servers where obtained from name resolution.\n", result.servers.count);
+            char addr_buf[80];
+            
+            pj_sockaddr_print((pj_sockaddr_t*) &result.servers.entry[0].addr, addr_buf, sizeof(addr_buf), 3);
+            account->setHostname(addr_buf);
+        }
+    } 
+    
     hostname = account->getHostname();
     username = account->getUsername();
     password = account->getPassword(); 
@@ -1813,6 +1865,16 @@ int getModId()
     return _mod_ua.id;
 }
 
+static void dns_cb(pj_status_t status, void *token, const struct pjsip_server_addresses *addr)
+{
+    struct result * result = (struct result*) token;
+
+    result->status = status;
+    if (status == PJ_SUCCESS) {
+        pj_memcpy(&result->servers, addr, sizeof(*addr));
+    }
+}
+
 void set_voicemail_info (AccountID account, pjsip_msg_body *body)
 {
 
-- 
GitLab