diff --git a/sflphone-client-gnome/src/config/accountwindow.c b/sflphone-client-gnome/src/config/accountwindow.c index 0322de739db160bf36485e75d7e0ed47dc11cb30..5954b53770c1bf444239ee74e1a5e392ff702908 100644 --- a/sflphone-client-gnome/src/config/accountwindow.c +++ b/sflphone-client-gnome/src/config/accountwindow.c @@ -38,7 +38,13 @@ #include <gtk/gtk.h> -/** Local variables */ +/** + * TODO: tidy this up + * by storing these variables + * in a private structure. + * Local variables + */ + GtkDialog * dialog; GtkWidget * hbox; GtkWidget * label; @@ -59,6 +65,14 @@ GtkWidget * scrolledWindowCredential; GtkWidget * advancedZrtpButton; GtkWidget * keyExchangeCombo; GtkWidget * useSipTlsCheckBox; + +GtkWidget * publishedAddressEntry; +GtkWidget * localAddressCombo; +GtkWidget * sameAsLocalCheckBox; +GtkWidget * publishedPortSpinBox; +GtkWidget * localPortSpinBox; + +GtkWidget * displayNameEntry; // Credentials enum { @@ -94,7 +108,7 @@ static void update_credential_cb(GtkWidget *widget, gpointer data UNUSED) gtk_list_store_set (GTK_LIST_STORE (credentialStore), &iter, column, (gchar *) gtk_entry_get_text(GTK_ENTRY(widget)), -1); } -static GtkWidget * create_account_tab(account_t **a) +static GtkWidget * create_basic_tab(account_t **a) { GtkWidget * frame; GtkWidget * table; @@ -107,7 +121,6 @@ static GtkWidget * create_account_tab(account_t **a) // Default settings gchar * curAccountID = ""; gchar * curAccountEnabled = "true"; - gchar * curAccountResolveOnce = "false"; gchar * curAccountType = "SIP"; gchar * curAlias = ""; gchar * curUsername = ""; @@ -129,7 +142,6 @@ static GtkWidget * create_account_tab(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 { @@ -418,7 +430,17 @@ static void key_exchange_changed_cb(GtkWidget *widget, gpointer data) } } -GtkWidget * create_advanced_tab(account_t **a) +static void use_sip_tls_cb(GtkWidget *widget, gpointer data) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { + DEBUG("Using sips"); + gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE); + } +} + +GtkWidget * create_security_tab(account_t **a) { GtkWidget * frame; GtkWidget * table; @@ -441,21 +463,10 @@ GtkWidget * create_advanced_tab(account_t **a) gchar * curSRTPEnabled = NULL; gchar * curKeyExchange = NULL; - gchar * curAccountResolveOnce = NULL; - gchar * curAccountExpire = NULL; gchar * curTLSEnabled = NULL; // Load from SIP/IAX/Unknown ? - if(currentAccount) { - curAccountResolveOnce = g_hash_table_lookup(currentAccount->properties, ACCOUNT_RESOLVE_ONCE); - if (curAccountResolveOnce == NULL) { - curAccountResolveOnce = "false"; - } - curAccountExpire = g_hash_table_lookup(currentAccount->properties, ACCOUNT_REGISTRATION_EXPIRE); - if (curAccountExpire == NULL) { - curAccountExpire = "600"; - } - + if(currentAccount) { curKeyExchange = g_hash_table_lookup(currentAccount->properties, ACCOUNT_KEY_EXCHANGE); if (curKeyExchange == NULL) { curKeyExchange = "none"; @@ -471,31 +482,9 @@ GtkWidget * create_advanced_tab(account_t **a) curTLSEnabled = "false"; } } - - gnome_main_section_new_with_table (_("Registration Options"), &frame, &table, 2, 3); - gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic (_("Registration _expire")); - gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, 0, 1); - gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); - entryExpire = gtk_entry_new(); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryExpire); - gtk_entry_set_text(GTK_ENTRY(entryExpire), curAccountExpire); - gtk_table_attach_defaults( GTK_TABLE( table ), entryExpire, 1, 2, 0, 1); - - entryResolveNameOnlyOnce = gtk_check_button_new_with_mnemonic(_("_Comply with RFC 3263")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(entryResolveNameOnlyOnce), - g_strcasecmp(curAccountResolveOnce,"false") == 0 ? TRUE: FALSE); - gtk_table_attach_defaults( GTK_TABLE( table ), entryResolveNameOnlyOnce, 0, 2, 1, 2); - gtk_widget_set_sensitive( GTK_WIDGET( entryResolveNameOnlyOnce ) , TRUE ); - - gtk_widget_show_all( table ); - gtk_container_set_border_width (GTK_CONTAINER(table), 10); - - gtk_widget_size_request(GTK_WIDGET(table), &requisitionTable); - + /* Credentials tree view */ - gnome_main_section_new_with_table (_("Credential informations"), &frame, &table, 1, 1); + gnome_main_section_new_with_table (_("Credential"), &frame, &table, 1, 1); gtk_container_set_border_width (GTK_CONTAINER(table), 10); gtk_table_set_row_spacings(GTK_TABLE(table), 10); gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); @@ -509,7 +498,7 @@ GtkWidget * create_advanced_tab(account_t **a) G_TYPE_STRING, // Realm G_TYPE_STRING, // Username G_TYPE_STRING, // Password - G_TYPE_POINTER // Pointer to the Object + G_TYPE_POINTER // Pointer to the Objectc ); treeViewCredential = gtk_tree_view_new_with_model(GTK_TREE_MODEL(credentialStore)); @@ -553,7 +542,7 @@ GtkWidget * create_advanced_tab(account_t **a) /* Dynamically resize the window to fit the scrolled window */ gtk_widget_size_request(GTK_WIDGET(treeViewCredential), &requisitionTreeView); - gtk_widget_set_size_request(GTK_WIDGET(scrolledWindowCredential), requisitionTable.width, requisitionTreeView.height + 20); + gtk_widget_set_size_request(GTK_WIDGET(scrolledWindowCredential), requisitionTreeView.width, requisitionTreeView.height + 20); /* Credential Buttons */ hbox = gtk_hbox_new(FALSE, 10); @@ -574,16 +563,16 @@ GtkWidget * create_advanced_tab(account_t **a) gtk_table_set_col_spacings( GTK_TABLE(table), 10); gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); - DEBUG("is TLS enabled ? %s", curTLSEnabled); - useSipTlsCheckBox = gtk_check_button_new_with_mnemonic(_("Use TLS transport (sips)")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(useSipTlsCheckBox), (g_strcmp0(curTLSEnabled, "false") == 0) ? FALSE:TRUE); - gtk_table_attach_defaults(GTK_TABLE(table), useSipTlsCheckBox, 0, 2, 0, 1); - GtkWidget * sipTlsAdvancedButton; sipTlsAdvancedButton = gtk_button_new_from_stock(GTK_STOCK_EDIT); gtk_table_attach_defaults(GTK_TABLE(table), sipTlsAdvancedButton, 2, 3, 0, 1); - //gtk_widget_set_sensitive(GTK_WIDGET(sipsTlsAdvancedButton), curTlsEnable); + gtk_widget_set_sensitive(GTK_WIDGET(sipTlsAdvancedButton), FALSE); g_signal_connect(G_OBJECT(sipTlsAdvancedButton), "clicked", G_CALLBACK(show_advanced_tls_options_cb), currentAccount->properties); + + useSipTlsCheckBox = gtk_check_button_new_with_mnemonic(_("Use TLS transport (sips)")); + g_signal_connect (useSipTlsCheckBox, "toggled", G_CALLBACK(use_sip_tls_cb), sipTlsAdvancedButton); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(useSipTlsCheckBox), (g_strcmp0(curTLSEnabled, "false") == 0) ? FALSE:TRUE); + gtk_table_attach_defaults(GTK_TABLE(table), useSipTlsCheckBox, 0, 2, 0, 1); label = gtk_label_new_with_mnemonic (_("SRTP key exchange")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); @@ -620,6 +609,157 @@ GtkWidget * create_advanced_tab(account_t **a) return ret; } +static same_as_local_cb(GtkWidget * widget, gpointer data UNUSED) +{ + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { + DEBUG("Same as local"); + gchar * ip_address = (gchar *) gtk_combo_box_get_active_text(GTK_COMBO_BOX(localAddressCombo)); + gtk_entry_set_text(GTK_ENTRY(publishedAddressEntry), ip_address); + + gchar * local_port = (gchar *) gtk_entry_get_text(GTK_ENTRY(localPortSpinBox)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(publishedPortSpinBox), g_ascii_strtod(local_port, NULL)); + + gtk_widget_set_sensitive(publishedPortSpinBox, FALSE); + gtk_widget_set_sensitive(publishedAddressEntry, FALSE); + } else { + gtk_widget_set_sensitive(publishedPortSpinBox, TRUE); + gtk_widget_set_sensitive(publishedAddressEntry, TRUE); + } +} + +GtkWidget * create_advanced_tab(account_t **a) +{ + GtkWidget * frame; + GtkWidget * table; + GtkWidget * label; + GtkWidget * ret; + GtkWidget * hbox; + + ret = gtk_vbox_new(FALSE, 10); + gtk_container_set_border_width(GTK_CONTAINER(ret), 10); + + account_t * currentAccount; + currentAccount = *a; + + gchar * resolve_once = NULL; + gchar * account_expire = NULL; + gchar * published_address; + gchar * published_port; + gchar * local_address; + gchar * local_port; + + // Load from SIP/IAX/Unknown ? + if(currentAccount) { + resolve_once = g_hash_table_lookup(currentAccount->properties, ACCOUNT_RESOLVE_ONCE); + account_expire = g_hash_table_lookup(currentAccount->properties, ACCOUNT_REGISTRATION_EXPIRE); + local_port = g_hash_table_lookup(currentAccount->properties, LOCAL_PORT); + local_address = g_hash_table_lookup(currentAccount->properties, LOCAL_ADDRESS); + published_address = g_hash_table_lookup(currentAccount->properties, PUBLISHED_ADDRESS); + published_port = g_hash_table_lookup(currentAccount->properties, PUBLISHED_PORT); + } + + gnome_main_section_new_with_table (_("Registration"), &frame, &table, 2, 3); + gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER(table), 10); + + label = gtk_label_new_with_mnemonic (_("Registration _expire")); + gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, 0, 1); + gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); + entryExpire = gtk_entry_new(); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), entryExpire); + gtk_entry_set_text(GTK_ENTRY(entryExpire), account_expire); + gtk_table_attach_defaults( GTK_TABLE( table ), entryExpire, 1, 2, 0, 1); + + entryResolveNameOnlyOnce = gtk_check_button_new_with_mnemonic(_("_Comply with RFC 3263")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(entryResolveNameOnlyOnce), + g_strcasecmp(resolve_once,"false") == 0 ? TRUE: FALSE); + gtk_table_attach_defaults( GTK_TABLE( table ), entryResolveNameOnlyOnce, 0, 2, 1, 2); + gtk_widget_set_sensitive( GTK_WIDGET( entryResolveNameOnlyOnce ) , TRUE ); + + gnome_main_section_new_with_table (_("Network"), &frame, &table, 2, 3); + gtk_box_pack_start(GTK_BOX(ret), frame, FALSE, FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER(table), 10); + + /** + * Retreive the list of IP interface from the + * the daemon and build the combo box. + */ + + GtkListStore * ipInterfaceListStore; + GtkTreeIter iter; + + ipInterfaceListStore = gtk_list_store_new( 1, G_TYPE_STRING ); + label = gtk_label_new_with_mnemonic (_("Local address")); + gtk_table_attach ( GTK_TABLE( table ), label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); + + GtkTreeIter current_local_address_iter = iter; + gchar ** iface_list = NULL; + iface_list = dbus_get_all_ip_interface(); + gchar ** iface = NULL; + + if (iface_list != NULL) { + for (iface = iface_list; *iface; iface++) { + DEBUG("Interface %s", *iface); + gtk_list_store_append(ipInterfaceListStore, &iter ); + gtk_list_store_set(ipInterfaceListStore, &iter, 0, *iface, -1 ); + + current_local_address_iter = iter; + if (g_strcmp0(*iface, local_address) == 0) { + DEBUG("Setting active local address combo box"); + current_local_address_iter = iter; + } + } + } + + localAddressCombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(ipInterfaceListStore)); + gtk_label_set_mnemonic_widget(GTK_LABEL(label), localAddressCombo); + gtk_table_attach ( GTK_TABLE( table ), localAddressCombo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + g_object_unref(G_OBJECT(ipInterfaceListStore)); + + GtkCellRenderer * ipInterfaceCellRenderer; + ipInterfaceCellRenderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(localAddressCombo), ipInterfaceCellRenderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(localAddressCombo), ipInterfaceCellRenderer, "text", 0, NULL); + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(localAddressCombo), ¤t_local_address_iter); + + /** + * Local port + */ + label = gtk_label_new_with_mnemonic (_("Local port")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); + gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); + localPortSpinBox = gtk_spin_button_new_with_range(1, 65535, 1); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), localPortSpinBox); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(localPortSpinBox), g_ascii_strtod(local_port, NULL)); + gtk_table_attach_defaults(GTK_TABLE(table), localPortSpinBox, 1, 2, 1, 2); + + sameAsLocalCheckBox = gtk_check_button_new_with_mnemonic(_("Published address and port same as local")); + g_signal_connect(sameAsLocalCheckBox, "toggled", G_CALLBACK(same_as_local_cb), sameAsLocalCheckBox); + gtk_table_attach_defaults(GTK_TABLE(table), sameAsLocalCheckBox, 0, 2, 2, 3); + gtk_widget_set_sensitive(GTK_WIDGET(sameAsLocalCheckBox), TRUE ); + + label = gtk_label_new_with_mnemonic (_("Published address")); + gtk_table_attach_defaults( GTK_TABLE( table ), label, 0, 1, 3, 4); + gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); + publishedAddressEntry = gtk_entry_new(); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), publishedAddressEntry); + gtk_entry_set_text(GTK_ENTRY(publishedAddressEntry), published_address); + gtk_table_attach_defaults( GTK_TABLE(table), publishedAddressEntry, 1, 2, 3, 4); + + label = gtk_label_new_with_mnemonic (_("Published port")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5); + gtk_misc_set_alignment(GTK_MISC (label), 0, 0.5); + publishedPortSpinBox = gtk_spin_button_new_with_range(1, 65535, 1); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), publishedPortSpinBox); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(publishedPortSpinBox), g_ascii_strtod(published_port, NULL)); + gtk_table_attach_defaults(GTK_TABLE(table), publishedPortSpinBox, 1, 2, 4, 5); + + gtk_widget_show_all(ret); + + return ret; +} + static GPtrArray * getNewCredential(GHashTable * properties) { GtkTreeIter iter; @@ -700,15 +840,20 @@ show_account_window (account_t * a) gtk_widget_show(notebook); /* General Settings */ - tab = create_account_tab(¤tAccount); + tab = create_basic_tab(¤tAccount); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tab, gtk_label_new(_("Basic"))); gtk_notebook_page_num(GTK_NOTEBOOK(notebook), tab); - + /* Advanced */ tab = create_advanced_tab(¤tAccount); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tab, gtk_label_new(_("Advanced"))); gtk_notebook_page_num(GTK_NOTEBOOK(notebook), tab); - + + /* Security */ + tab = create_security_tab(¤tAccount); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tab, gtk_label_new(_("Security"))); + gtk_notebook_page_num(GTK_NOTEBOOK(notebook), tab); + gtk_notebook_set_current_page( GTK_NOTEBOOK( notebook) , 0); response = gtk_dialog_run (GTK_DIALOG (dialog)); @@ -788,6 +933,22 @@ show_account_window (account_t * a) g_hash_table_replace(currentAccount->properties, g_strdup(TLS_ENABLE), g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(useSipTlsCheckBox)) ? "true":"false")); + g_hash_table_replace(currentAccount->properties, + g_strdup(LOCAL_PORT), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(localPortSpinBox)))); + + g_hash_table_replace(currentAccount->properties, + g_strdup(LOCAL_ADDRESS), + g_strdup((gchar *)gtk_combo_box_get_active_text(GTK_COMBO_BOX(localAddressCombo)))); + + g_hash_table_replace(currentAccount->properties, + g_strdup(PUBLISHED_PORT), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(publishedPortSpinBox)))); + + g_hash_table_replace(currentAccount->properties, + g_strdup(PUBLISHED_ADDRESS), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(publishedAddressEntry)))); + config_window_set_stun_visible(); } diff --git a/sflphone-client-gnome/src/config/tlsadvanceddialog.c b/sflphone-client-gnome/src/config/tlsadvanceddialog.c index b4b5a96bd88c46d9eb9ea3547c6968b15f08ce93..5ae677012251c2a9dbe11b2aaf36ec5837981a6c 100644 --- a/sflphone-client-gnome/src/config/tlsadvanceddialog.c +++ b/sflphone-client-gnome/src/config/tlsadvanceddialog.c @@ -28,7 +28,6 @@ void show_advanced_tls_options(GHashTable * properties) { GtkDialog * tlsDialog; - GtkWidget * image; GtkWidget * ret; tlsDialog = GTK_DIALOG(gtk_dialog_new_with_buttons (_("Advanced options for TLS"), @@ -62,65 +61,82 @@ void show_advanced_tls_options(GHashTable * properties) gtk_label_set_markup(GTK_LABEL(label), description); gtk_table_attach(GTK_TABLE(table), label, 0, 3, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - label = gtk_label_new(_("TLS listener port")); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - GtkWidget * spinTlsPort; - spinTlsPort = gtk_spin_button_new_with_range(1, 65535, 1); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinTlsPort); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinTlsPort), 5061); - gtk_table_attach(GTK_TABLE(table), spinTlsPort, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - - GHashTable * default_settings = NULL; - gchar * tls_method = NULL; - gchar * negotiation_timeout_sec = NULL; - gchar * negotiation_timeout_msec = NULL; - gchar * require_client_certificate = NULL; - gchar * verify_server = NULL; - gchar * verify_client = NULL; + gchar * tls_ca_list_file; + gchar * tls_certificate_file; + gchar * tls_private_key_file; + gchar * tls_password; + gchar * tls_method; + gchar * tls_ciphers; + gchar * tls_server_name; + gchar * verify_server; + gchar * verify_client; + gchar * require_client_certificate; + gchar * negotiation_timeout_sec; + gchar * negotiation_timeout_msec; - default_settings = dbus_get_tls_settings_default(); - if (default_settings != NULL) { - tls_method = g_hash_table_lookup(default_settings, TLS_METHOD); - negotiation_timeout_sec = g_hash_table_lookup(default_settings, TLS_NEGOTIATION_TIMEOUT_SEC); - negotiation_timeout_msec = g_hash_table_lookup(default_settings, TLS_NEGOTIATION_TIMEOUT_MSEC); - require_client_certificate = g_hash_table_lookup(default_settings, TLS_REQUIRE_CLIENT_CERTIFICATE); - verify_server = g_hash_table_lookup(default_settings, TLS_VERIFY_SERVER); - verify_client = g_hash_table_lookup(default_settings, TLS_VERIFY_CLIENT); + if (properties != NULL) { + tls_ca_list_file = g_hash_table_lookup(properties, TLS_CA_LIST_FILE); + tls_certificate_file = g_hash_table_lookup(properties, TLS_CERTIFICATE_FILE); + tls_private_key_file = g_hash_table_lookup(properties, TLS_PRIVATE_KEY_FILE); + tls_password = g_hash_table_lookup(properties, TLS_PASSWORD); + tls_method = g_hash_table_lookup(properties, TLS_METHOD); + tls_ciphers = g_hash_table_lookup(properties, TLS_CIPHERS); + tls_server_name = g_hash_table_lookup(properties, TLS_SERVER_NAME); + verify_server = g_hash_table_lookup(properties, TLS_VERIFY_SERVER); + verify_client = g_hash_table_lookup(properties, TLS_VERIFY_CLIENT); + require_client_certificate = g_hash_table_lookup(properties, TLS_REQUIRE_CLIENT_CERTIFICATE); + negotiation_timeout_sec = g_hash_table_lookup(properties, TLS_NEGOTIATION_TIMEOUT_SEC); + negotiation_timeout_msec = g_hash_table_lookup(properties, TLS_NEGOTIATION_TIMEOUT_MSEC); + + DEBUG("ca_list_file %s", tls_ca_list_file); + DEBUG("certificate_file %s", tls_certificate_file); } - + label = gtk_label_new( _("Certificate of Authority list")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach (GTK_TABLE(table), label, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - GtkWidget * fileChooser; - fileChooser = gtk_file_chooser_button_new(_("Choose a CA list file"), GTK_FILE_CHOOSER_ACTION_OPEN); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER( fileChooser) , g_get_home_dir()); - gtk_table_attach (GTK_TABLE(table), fileChooser, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - + GtkWidget * caListFileChooser; + caListFileChooser = gtk_file_chooser_button_new(_("Choose a CA list file (optional)"), GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_table_attach (GTK_TABLE(table), caListFileChooser, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + if (tls_ca_list_file == NULL) { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(caListFileChooser), g_get_home_dir()); + } else { + GFile * file = g_file_new_for_path(tls_ca_list_file); + gtk_file_chooser_set_file (GTK_FILE_CHOOSER(caListFileChooser), file, NULL); + g_object_unref(file); + } + label = gtk_label_new( _("Public endpoint certificate file")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach (GTK_TABLE(table), label, 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - fileChooser = gtk_file_chooser_button_new(_("Choose a CA list file"), GTK_FILE_CHOOSER_ACTION_OPEN); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER( fileChooser) , g_get_home_dir()); - gtk_table_attach (GTK_TABLE(table), fileChooser, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - - label = gtk_label_new_with_mnemonic (_("Certificate private key")); + GtkWidget * certificateFileChooser; + certificateFileChooser = gtk_file_chooser_button_new(_("Choose a public endpoint certificate (optional)"), GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_table_attach (GTK_TABLE(table), certificateFileChooser, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + if (tls_certificate_file == NULL) { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(caListFileChooser), g_get_home_dir()); + } else { + GFile * file = g_file_new_for_path(tls_certificate_file); + gtk_file_chooser_set_file (GTK_FILE_CHOOSER(certificateFileChooser), file, NULL); + g_object_unref(file); + } + + label = gtk_label_new(("Private key file")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_table_attach (GTK_TABLE(table), label, 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - GtkWidget * privateKeyEntry; -#if GTK_CHECK_VERSION(2,16,0) - privateKeyEntry = gtk_entry_new(); - gtk_entry_set_icon_from_stock (GTK_ENTRY (privateKeyEntry), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_DIALOG_AUTHENTICATION); -#else - privateKeyEntry = sexy_icon_entry_new(); - image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_AUTHENTICATION , GTK_ICON_SIZE_SMALL_TOOLBAR ); - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(privateKeyEntry), SEXY_ICON_ENTRY_PRIMARY , GTK_IMAGE(image) ); -#endif - gtk_entry_set_visibility(GTK_ENTRY(privateKeyEntry), FALSE); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), privateKeyEntry); - //gtk_entry_set_text(GTK_ENTRY(privateKeyEntry), curPassword); - gtk_table_attach (GTK_TABLE(table), privateKeyEntry, 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - + gtk_table_attach (GTK_TABLE(table), label, 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + GtkWidget * privateKeyFileChooser; + privateKeyFileChooser = gtk_file_chooser_button_new(_("Choose a private key file (optional)"), GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_table_attach (GTK_TABLE(table), privateKeyFileChooser, 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + + if (tls_private_key_file == NULL) { + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(privateKeyFileChooser), g_get_home_dir()); + } else { + GFile * file = g_file_new_for_path(tls_private_key_file); + gtk_file_chooser_set_file (GTK_FILE_CHOOSER(privateKeyFileChooser), file, NULL); + g_object_unref(file); + } + label = gtk_label_new_with_mnemonic (_("Password for the private key")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_table_attach (GTK_TABLE(table), label, 0, 1, 5, 6, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -135,7 +151,7 @@ void show_advanced_tls_options(GHashTable * properties) #endif gtk_entry_set_visibility(GTK_ENTRY(privateKeyPasswordEntry), FALSE); gtk_label_set_mnemonic_widget (GTK_LABEL (label), privateKeyPasswordEntry); - //gtk_entry_set_text(GTK_ENTRY(privateKeyEntry), curPassword); + gtk_entry_set_text(GTK_ENTRY(privateKeyPasswordEntry), tls_password); gtk_table_attach (GTK_TABLE(table), privateKeyPasswordEntry, 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); /* TLS protocol methods */ @@ -183,7 +199,7 @@ void show_advanced_tls_options(GHashTable * properties) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); cipherListEntry = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), cipherListEntry); - //gtk_entry_set_text(GTK_ENTRY(entryHostname), curHostname); + gtk_entry_set_text(GTK_ENTRY(cipherListEntry), tls_ciphers); gtk_table_attach (GTK_TABLE(table), cipherListEntry, 1, 2, 7, 8, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); GtkWidget * serverNameInstance; @@ -192,7 +208,7 @@ void show_advanced_tls_options(GHashTable * properties) gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); serverNameInstance = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), serverNameInstance); - //gtk_entry_set_text(GTK_ENTRY(entryHostname), curHostname); + gtk_entry_set_text(GTK_ENTRY(serverNameInstance), tls_server_name); gtk_table_attach (GTK_TABLE(table), serverNameInstance, 1, 2, 8, 9, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); label = gtk_label_new(_("Negotiation timeout (sec:msec)")); @@ -212,13 +228,13 @@ void show_advanced_tls_options(GHashTable * properties) gtk_box_pack_start_defaults(GTK_BOX(hbox), tlsTimeOutMSec); GtkWidget * verifyCertificateServer; - verifyCertificateServer = gtk_check_button_new_with_mnemonic(_("Verify incoming certificates, as a client")); + verifyCertificateServer = gtk_check_button_new_with_mnemonic(_("Verify incoming certificates, as a server")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(verifyCertificateServer), g_strcasecmp(verify_server,"true") == 0 ? TRUE: FALSE); gtk_table_attach (GTK_TABLE(table), verifyCertificateServer, 0, 1, 10, 11, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); GtkWidget * verifyCertificateClient; - verifyCertificateClient = gtk_check_button_new_with_mnemonic(_("Verify certificates from answer, as a server")); + verifyCertificateClient = gtk_check_button_new_with_mnemonic(_("Verify certificates from answer, as a client")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(verifyCertificateClient), g_strcasecmp(verify_client,"true") == 0 ? TRUE: FALSE); gtk_table_attach (GTK_TABLE(table), verifyCertificateClient, 0, 1, 11, 12, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); @@ -231,8 +247,51 @@ void show_advanced_tls_options(GHashTable * properties) gtk_widget_show_all(ret); - if(gtk_dialog_run(GTK_DIALOG(tlsDialog)) == GTK_RESPONSE_ACCEPT) { - + if(gtk_dialog_run(GTK_DIALOG(tlsDialog)) == GTK_RESPONSE_ACCEPT) { + g_hash_table_replace(properties, + g_strdup(TLS_CA_LIST_FILE), g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(caListFileChooser)))); + + g_hash_table_replace(properties, + g_strdup(TLS_CERTIFICATE_FILE), g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(certificateFileChooser)))); + + g_hash_table_replace(properties, + g_strdup(TLS_PRIVATE_KEY_FILE), g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(privateKeyFileChooser)))); + + g_hash_table_replace(properties, + g_strdup(TLS_PASSWORD), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(privateKeyPasswordEntry)))); + + g_hash_table_replace(properties, + g_strdup(TLS_METHOD), + g_strdup((gchar *)gtk_combo_box_get_active_text(GTK_COMBO_BOX(tlsProtocolMethodCombo)))); + + g_hash_table_replace(properties, + g_strdup(TLS_CIPHERS), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(cipherListEntry)))); + + g_hash_table_replace(properties, + g_strdup(TLS_SERVER_NAME), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(serverNameInstance)))); + + g_hash_table_replace(properties, + g_strdup(TLS_VERIFY_SERVER), + g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(verifyCertificateServer)) ? "true": "false")); + + g_hash_table_replace(properties, + g_strdup(TLS_VERIFY_CLIENT), + g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(verifyCertificateClient)) ? "true": "false")); + + g_hash_table_replace(properties, + g_strdup(TLS_REQUIRE_CLIENT_CERTIFICATE), + g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(requireCertificate)) ? "true": "false")); + + g_hash_table_replace(properties, + g_strdup(TLS_NEGOTIATION_TIMEOUT_SEC), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(tlsTimeOutSec)))); + + g_hash_table_replace(properties, + g_strdup(TLS_NEGOTIATION_TIMEOUT_MSEC), + g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(tlsTimeOutMSec)))); } gtk_widget_destroy (GTK_WIDGET(tlsDialog)); diff --git a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml index 43dcceefd7d5c43b816f582c5890272a718aaf5f..446196946dd8191b2ce112f6ae5b574cc3207c88 100644 --- a/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-client-gnome/src/dbus/configurationmanager-introspec.xml @@ -388,5 +388,9 @@ <arg type="a{ss}" name="details" direction="in"/> </method> + <method name="getAllIpInterface"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="list" direction="out"/> + </method> </interface> </node> diff --git a/sflphone-client-gnome/src/dbus/dbus.c b/sflphone-client-gnome/src/dbus/dbus.c index 212d9484ce3ed84387c2904ee504def8d3be4922..b73933e1da17188bf77eb0b7558922ee649c11a3 100644 --- a/sflphone-client-gnome/src/dbus/dbus.c +++ b/sflphone-client-gnome/src/dbus/dbus.c @@ -2157,3 +2157,28 @@ void dbus_set_tls_settings (account_t *a) g_error_free (error); } } + +gchar ** dbus_get_all_ip_interface(void) +{ + GError *error = NULL; + char ** array; + + if(!org_sflphone_SFLphone_ConfigurationManager_get_all_ip_interface ( configurationManagerProxy, &array, &error)) + { + if(error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) + { + ERROR ("Caught remote method (get_all_ip_interface) exception %s: %s", dbus_g_error_get_name(error), error->message); + } + else + { + ERROR("Error while calling get_all_ip_interface: %s", error->message); + } + g_error_free (error); + return NULL; + } + else{ + DEBUG ("DBus called get_all_ip_interface() on ConfigurationManager"); + return array; + } +} + diff --git a/sflphone-client-gnome/src/sflphone_const.h b/sflphone-client-gnome/src/sflphone_const.h index 7a1b5aff3821596cdc2cd1c61cc72f341119ee4f..516929916cf0dff4986a8103f3af4fe78086c438 100644 --- a/sflphone-client-gnome/src/sflphone_const.h +++ b/sflphone-client-gnome/src/sflphone_const.h @@ -68,6 +68,7 @@ #define SDES_TLS "2" #define TLS_ENABLE "TLS.enable" +#define TLS_PORT "TLS.port" #define TLS_CA_LIST_FILE "TLS.certificateListFile" #define TLS_CERTIFICATE_FILE "TLS.certificateFile" #define TLS_PRIVATE_KEY_FILE "TLS.privateKeyFile" @@ -81,6 +82,11 @@ #define TLS_NEGOTIATION_TIMEOUT_SEC "TLS.negotiationTimeoutSec" #define TLS_NEGOTIATION_TIMEOUT_MSEC "TLS.negotiationTimemoutMsec" +#define LOCAL_PORT "Account.localPort" +#define LOCAL_ADDRESS "Account.localAddress" +#define PUBLISHED_PORT "Account.publishedPort" +#define PUBLISHED_ADDRESS "Account.publishedAddress" + /** * Global logger */ diff --git a/sflphone-common/configure.ac b/sflphone-common/configure.ac index 4c818257e9ad6a624633c51722078c34b26e4d79..203ece747b64dad858ae414bcde099f2c3511d72 100644 --- a/sflphone-common/configure.ac +++ b/sflphone-common/configure.ac @@ -195,6 +195,11 @@ AC_SUBST(CCEXT2_CFLAGS) AC_SUBST(CCRTP_LIBS) AC_SUBST(CCRTP_CFLAGS) +dnl Check for OpenSSL to link against pjsip and provide SIPS TLS support + PKG_CHECK_MODULES([libssl], libssl, , AC_MSG_ERROR([libssl is required])) + AC_SUBST(libssl_CFLAGS) + AC_SUBST(libssl_LIBS) + dnl Check for libzrtpcpp, a ccRTP extension providing zrtp key exchange LIBZRTPCPP_MIN_VERSION=1.3.0 PKG_CHECK_MODULES(ZRTPCPP, libzrtpcpp >= ${LIBZRTPCPP_MIN_VERSION}) diff --git a/sflphone-common/globals.mak b/sflphone-common/globals.mak index 51fe32ac486c133abdf074e4ff5312dd3df4602a..8ea7bbfb203b48796447d476a5331de2728c7e3e 100644 --- a/sflphone-common/globals.mak +++ b/sflphone-common/globals.mak @@ -23,7 +23,7 @@ PJSIP_LIBS= \ -lpjsip-ua-sfl-$(target) \ -lpjmedia-codec-sfl-$(target) \ -lpjlib-util-sfl-$(target) \ - -lpj-sfl-$(target) + -lpj-sfl-$(target) SIP_CFLAGS=-I$(src)/libs/pjproject-$(PJSIP_VERSION)/pjsip/include \ -I$(src)/libs/pjproject-$(PJSIP_VERSION)/pjlib/include \ diff --git a/sflphone-common/src/Makefile.am b/sflphone-common/src/Makefile.am index 7b2f283c31a622cb0f9172e23d5fab2a44153700..8944e8d7e844ed0adfad6ceefc25948407940e09 100644 --- a/sflphone-common/src/Makefile.am +++ b/sflphone-common/src/Makefile.am @@ -19,7 +19,8 @@ sflphoned_SOURCES = \ sflphoned_CXXFLAGS = \ -DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" \ - @ZRTPCPP_CFLAGS@ + @ZRTPCPP_CFLAGS@ \ + @libssl_CFLAGS@ # Add here the dynamic libraries sflphoned should be linked against @@ -32,7 +33,8 @@ sflphoned_LDADD = \ @CCRTP_LIBS@ \ @ALSA_LIBS@ \ @PULSEAUDIO_LIBS@ \ - @SAMPLERATE_LIBS@ + @SAMPLERATE_LIBS@ \ + @libssl_LIBS@ # sflphoned_LDFLAGS= -pg -luuid sflphoned_LDFLAGS= -luuid diff --git a/sflphone-common/src/account.h b/sflphone-common/src/account.h index 1dc552499c9845a950741048d464de7f7f912d84..6a37fe01347c0a1e2be32cc978a00a77bd520a45 100644 --- a/sflphone-common/src/account.h +++ b/sflphone-common/src/account.h @@ -70,6 +70,14 @@ typedef enum RegistrationState { #define REALM "realm" #define DEFAULT_REALM "*" +#define LOCAL_PORT "Account.localPort" +#define LOCAL_ADDRESS "Account.localAddress" +#define PUBLISHED_PORT "Account.publishedPort" +#define PUBLISHED_ADDRESS "Account.publishedAddress" + +#define DISPLAY_NAME "Account.displayName" +#define DEFAULT_ADDRESS "0.0.0.0" + // SIP specific parameters #define SIP_PROXY "SIP.proxy" #define SIP_STUN_SERVER "STUN.server" diff --git a/sflphone-common/src/accountcreator.cpp b/sflphone-common/src/accountcreator.cpp index 8a4b1c748078c4d1c35d95cb3bd88997ed831160..b45792a8f49be4ff3f31f8d0a97d506e667e6164 100644 --- a/sflphone-common/src/accountcreator.cpp +++ b/sflphone-common/src/accountcreator.cpp @@ -19,6 +19,8 @@ */ #include "accountcreator.h" #include "sip/sipaccount.h" +#include "user_cfg.h" + #ifdef USE_IAX #include "iax/iaxaccount.h" #endif @@ -36,16 +38,17 @@ Account* AccountCreator::createAccount (AccountType type, AccountID accountID) { switch (type) { - case SIP_ACCOUNT: return new SIPAccount (accountID); break; -#ifdef USE_IAX - + case SIP_DIRECT_IP_ACCOUNT: + return new SIPAccount (IP2IP_PROFILE); + break; + #ifdef USE_IAX case IAX_ACCOUNT: return new IAXAccount (accountID); break; -#endif + #endif } return 0; diff --git a/sflphone-common/src/accountcreator.h b/sflphone-common/src/accountcreator.h index c91b3f7220567779cffa54505ce38209a19bbce6..6add7a7ac690a47ce4607a6b43453a23ca874124 100644 --- a/sflphone-common/src/accountcreator.h +++ b/sflphone-common/src/accountcreator.h @@ -34,7 +34,7 @@ public: /** * Public account type */ - enum AccountType {SIP_ACCOUNT, IAX_ACCOUNT }; + enum AccountType {SIP_ACCOUNT, SIP_DIRECT_IP_ACCOUNT, IAX_ACCOUNT }; /** * Create a new account or null diff --git a/sflphone-common/src/call.h b/sflphone-common/src/call.h index 000f2298930654374b74c21083a7edce9dead880..b46f58a6f88cf894208608974741e05349466290 100644 --- a/sflphone-common/src/call.h +++ b/sflphone-common/src/call.h @@ -26,9 +26,11 @@ #include "plug-in/audiorecorder/audiorecord.h" -#define IP_TO_IP_PATTERN "sip:" +#define SIP_SCHEME "sip:" +#define SIPS_SCHEME "sips:" + +#define CallConfigNULL NULL -#define CallConfigNULL NULL /* * @file call.h * @brief A call is the base class for protocol-based calls diff --git a/sflphone-common/src/dbus/configurationmanager-introspec.xml b/sflphone-common/src/dbus/configurationmanager-introspec.xml index 20700bd0bdc31734c167d6a3d26eff2a1a5b03ad..103d3568d14f22da5f936561ed89134260de5afe 100644 --- a/sflphone-common/src/dbus/configurationmanager-introspec.xml +++ b/sflphone-common/src/dbus/configurationmanager-introspec.xml @@ -389,5 +389,11 @@ <arg type="s" name="accountID" direction="in"/> <arg type="a{ss}" name="details" direction="in"/> </method> + + <method name="getAllIpInterface"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> + <arg type="as" name="list" direction="out"/> + </method> + </interface> </node> diff --git a/sflphone-common/src/dbus/configurationmanager.cpp b/sflphone-common/src/dbus/configurationmanager.cpp index 5edc26cf329fa80f475c11550849ec70354f5cc6..9fe007627ec4ad6989ed80780858c812770fa58b 100644 --- a/sflphone-common/src/dbus/configurationmanager.cpp +++ b/sflphone-common/src/dbus/configurationmanager.cpp @@ -23,6 +23,7 @@ #include <configurationmanager.h> #include <sstream> #include "../manager.h" +#include "sip/sipvoiplink.h" const char* ConfigurationManager::SERVER_PATH = "/org/sflphone/SFLphone/ConfigurationManager"; @@ -47,7 +48,6 @@ ConfigurationManager::getTlsSettingsDefault (void) _debug ("ConfigurationManager::getTlsDefaultSettings\n"); std::map<std::string, std::string> tlsSettingsDefault; - tlsSettingsDefault.insert(std::pair<std::string, std::string> (TLS_CA_LIST_FILE, "")); tlsSettingsDefault.insert(std::pair<std::string, std::string> (TLS_CERTIFICATE_FILE, "")); tlsSettingsDefault.insert(std::pair<std::string, std::string> (TLS_PRIVATE_KEY_FILE, "")); @@ -128,7 +128,7 @@ ConfigurationManager::getTlsSettings(const std::string& section) { std::map<std::string, std::string> tlsSettings; tlsSettings.insert(std::pair<std::string, std::string> - (TLS_ENABLE, Manager::instance().getConfigString(section, TLS_ENABLE))); + (TLS_ENABLE, Manager::instance().getConfigString(section, TLS_ENABLE))); tlsSettings.insert(std::pair<std::string, std::string> (TLS_CA_LIST_FILE, Manager::instance().getConfigString(section, TLS_CA_LIST_FILE))); tlsSettings.insert(std::pair<std::string, std::string> @@ -166,7 +166,7 @@ ConfigurationManager::setTlsSettings(const std::string& section, const std::map< if (it != details.end()) { Manager::instance().setConfig(section, TLS_ENABLE, it->second); } - + it = map_cpy.find(TLS_CA_LIST_FILE); if (it != details.end()) { Manager::instance().setConfig(section, TLS_CA_LIST_FILE, it->second); @@ -753,3 +753,17 @@ void ConfigurationManager::setHistory (const std::map <std::string, std::string> { Manager::instance().receive_history_from_client (entries); } + +std::vector<std::string> ConfigurationManager::getAllIpInterface(void) +{ + _debug ("ConfigurationManager::getAllIpInterface received\n"); + + std::vector<std::string> vector; + SIPVoIPLink * sipLink = NULL; + sipLink = SIPVoIPLink::instance (""); + if (sipLink != NULL) { + vector = sipLink->getAllIpInterface(); + } + + return vector; +} diff --git a/sflphone-common/src/dbus/configurationmanager.h b/sflphone-common/src/dbus/configurationmanager.h index c680f5d70f25a93c85bd8dabf7e439d116de804d..6bf984f69e09c91924d67046c1867768e7583f28 100644 --- a/sflphone-common/src/dbus/configurationmanager.h +++ b/sflphone-common/src/dbus/configurationmanager.h @@ -137,7 +137,8 @@ public: std::map<std::string, std::string> getTlsSettings(const std::string& accountID); void setTlsSettings(const std::string& accountID, const std::map< std::string, std::string >& details); - + + std::vector<std::string> getAllIpInterface(void); }; diff --git a/sflphone-common/src/global.h b/sflphone-common/src/global.h index 08677aed95c526584368b8db904738236b1c78d6..a660b9a8a5354734f9721a2d9bd6e7a42c470775 100644 --- a/sflphone-common/src/global.h +++ b/sflphone-common/src/global.h @@ -136,7 +136,8 @@ static const SOUND_FORMAT INT32 = 0x8; #define UNUSED __attribute__((__unused__)) -#define DEFAULT_SIP_PORT 5060 +#define DEFAULT_SIP_PORT "5060" +#define DEFAULT_SIP_TLS_PORT "5061" #define HOOK_DEFAULT_SIP_FIELD "X-sflphone-url" #define HOOK_DEFAULT_URL_COMMAND "x-www-browser" diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index b27492ff6641da217c992a6e10d9c48083d7081e..1098ae917b5dd17b437bd82ea27278e936aac643 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -28,6 +28,7 @@ #include "user_cfg.h" #include "global.h" #include "sip/sipaccount.h" + #include "audio/audiolayer.h" #include "audio/alsa/alsalayer.h" #include "audio/pulseaudio/pulselayer.h" @@ -45,12 +46,8 @@ #include <fstream> #include <sstream> #include <sys/types.h> // mkdir(2) -#include <sys/stat.h> // mkdir(2) - -//#include <cc++/file.h> - - - +#include <sys/stat.h> // mkdir(2) +#include <pwd.h> // getpwuid #define fill_config_str(name, value) \ (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str))) @@ -90,6 +87,7 @@ ManagerImpl::ManagerImpl (void) , _accountMap() , _cleaner (NULL) , _history (NULL) + , _directIpAccount (NULL) { // initialize random generator for call id @@ -1262,7 +1260,7 @@ ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) } bool -ManagerImpl::behindNat (const std::string& svr, int port) +ManagerImpl::isBehindNat (const std::string& svr, int port) { StunAddress4 stunSvrAddr; stunSvrAddr.addr = 0; @@ -1354,7 +1352,22 @@ ManagerImpl::initConfigFile (bool load_user_value, std::string alternate) _config.addDefaultValue(std::pair<std::string, std::string> (TLS_VERIFY_CLIENT, TRUE_STR), IP2IP_PROFILE); _config.addDefaultValue(std::pair<std::string, std::string> (TLS_REQUIRE_CLIENT_CERTIFICATE, TRUE_STR), IP2IP_PROFILE); _config.addDefaultValue(std::pair<std::string, std::string> (TLS_NEGOTIATION_TIMEOUT_SEC, "2"), IP2IP_PROFILE); - _config.addDefaultValue(std::pair<std::string, std::string> (TLS_NEGOTIATION_TIMEOUT_MSEC, "0"), IP2IP_PROFILE); + _config.addDefaultValue(std::pair<std::string, std::string> (TLS_NEGOTIATION_TIMEOUT_MSEC, "0"), IP2IP_PROFILE); + _config.addDefaultValue(std::pair<std::string, std::string> (LOCAL_PORT, DEFAULT_SIP_PORT), IP2IP_PROFILE); + _config.addDefaultValue(std::pair<std::string, std::string> (PUBLISHED_PORT, DEFAULT_SIP_PORT), IP2IP_PROFILE); + _config.addDefaultValue(std::pair<std::string, std::string> (LOCAL_ADDRESS, DEFAULT_ADDRESS), IP2IP_PROFILE); + _config.addDefaultValue(std::pair<std::string, std::string> (PUBLISHED_ADDRESS, DEFAULT_ADDRESS), IP2IP_PROFILE); + + // Init display name to the username under which + // this sflphone instance is running. + std::string diplayName(""); + uid_t uid = getuid(); + struct passwd * user_info = NULL; + user_info = getpwuid(uid); + if (user_info != NULL) { + diplayName = user_info->pw_name; + } + _config.addDefaultValue(std::pair<std::string, std::string> (DISPLAY_NAME, diplayName), IP2IP_PROFILE); // Signalisation settings _config.addDefaultValue(std::pair<std::string, std::string> (SYMMETRIC, TRUE_STR), SIGNALISATION); @@ -2495,7 +2508,7 @@ ManagerImpl::getAccountList() iter = _accountMap.begin (); while (iter != _accountMap.end()) { - if (iter->second != 0) { + if (iter->second != NULL) { v.push_back (iter->first.data()); } @@ -2544,6 +2557,11 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails (const Accou a.insert(std::pair<std::string, std::string> (AUTHENTICATION_USERNAME, getConfigString(accountID, AUTHENTICATION_USERNAME))); a.insert(std::pair<std::string, std::string> (CONFIG_ACCOUNT_MAILBOX, getConfigString(accountID, CONFIG_ACCOUNT_MAILBOX))); a.insert(std::pair<std::string, std::string> (CONFIG_ACCOUNT_REGISTRATION_EXPIRE, getConfigString(accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE))); + a.insert(std::pair<std::string, std::string> (LOCAL_ADDRESS, getConfigString(accountID, LOCAL_ADDRESS))); + a.insert(std::pair<std::string, std::string> (PUBLISHED_ADDRESS, getConfigString(accountID, PUBLISHED_ADDRESS))); + a.insert(std::pair<std::string, std::string> (LOCAL_PORT, getConfigString(accountID, LOCAL_PORT))); + a.insert(std::pair<std::string, std::string> (PUBLISHED_PORT, getConfigString(accountID, PUBLISHED_PORT))); + a.insert(std::pair<std::string, std::string> (DISPLAY_NAME, getConfigString(accountID, DISPLAY_NAME))); RegistrationState state; state = account->getRegistrationState(); @@ -2728,6 +2746,11 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma std::string registrationExpire; std::string hostname; + std::string displayName; + std::string localAddress; + std::string publishedAddress; + std::string localPort; + std::string publishedPort; std::string srtpEnable; std::string zrtpDisplaySas; std::string zrtpDisplaySasOnce; @@ -2735,7 +2758,7 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma std::string zrtpHelloHash; std::string srtpKeyExchange; - std::string tlsEnable; + std::string tlsEnable; std::string tlsCaListFile; std::string tlsCertificateFile; std::string tlsPrivateKeyFile; @@ -2750,6 +2773,11 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma std::string tlsNegotiationTimeoutMsec; if((iter = map_cpy.find(HOSTNAME)) != map_cpy.end()) { hostname = iter->second; } + if((iter = map_cpy.find(DISPLAY_NAME)) != map_cpy.end()) { displayName = iter->second; } + if((iter = map_cpy.find(LOCAL_ADDRESS)) != map_cpy.end()) { localAddress = iter->second; } + if((iter = map_cpy.find(PUBLISHED_ADDRESS)) != map_cpy.end()) { publishedAddress = iter->second; } + if((iter = map_cpy.find(LOCAL_PORT)) != map_cpy.end()) { localPort = iter->second; } + if((iter = map_cpy.find(PUBLISHED_PORT)) != map_cpy.end()) { publishedPort = iter->second; } if((iter = map_cpy.find(SRTP_ENABLE)) != map_cpy.end()) { srtpEnable = iter->second; } if((iter = map_cpy.find(ZRTP_DISPLAY_SAS)) != map_cpy.end()) { zrtpDisplaySas = iter->second; } if((iter = map_cpy.find(ZRTP_DISPLAY_SAS_ONCE)) != map_cpy.end()) { zrtpDisplaySasOnce = iter->second; } @@ -2779,7 +2807,12 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma if((iter = map_cpy.find(TLS_NEGOTIATION_TIMEOUT_MSEC)) != map_cpy.end()) { tlsNegotiationTimeoutMsec = iter->second; } _debug("Enable account %s\n", accountEnable.c_str()); - setConfig(accountID, HOSTNAME, hostname); + setConfig(accountID, HOSTNAME, hostname); + setConfig(accountID, LOCAL_ADDRESS, localAddress); + setConfig(accountID, PUBLISHED_ADDRESS, publishedAddress); + setConfig(accountID, LOCAL_PORT, localPort); + setConfig(accountID, PUBLISHED_PORT, publishedPort); + setConfig(accountID, DISPLAY_NAME, displayName); setConfig(accountID, SRTP_ENABLE, srtpEnable); setConfig(accountID, ZRTP_DISPLAY_SAS, zrtpDisplaySas); setConfig(accountID, ZRTP_DISPLAY_SAS_ONCE, zrtpDisplaySasOnce); @@ -2787,7 +2820,7 @@ void ManagerImpl::setAccountDetails (const std::string& accountID, const std::ma setConfig(accountID, ZRTP_HELLO_HASH, zrtpHelloHash); setConfig(accountID, SRTP_KEY_EXCHANGE, srtpKeyExchange); - setConfig(accountID, TLS_ENABLE, tlsEnable); + setConfig(accountID, TLS_ENABLE, tlsEnable); setConfig(accountID, TLS_CA_LIST_FILE, tlsCaListFile); setConfig(accountID, TLS_CERTIFICATE_FILE, tlsCertificateFile); setConfig(accountID, TLS_PRIVATE_KEY_FILE, tlsPrivateKeyFile); @@ -3059,6 +3092,22 @@ ManagerImpl::loadAccountMap() iter++; } + // Those calls that are placed to an uri that cannot be + // associated to an account are using that special account. + // An account, that is not account, in the sense of + // registration. This is useful since the Account object + // provides a handful of method that simplifies URI creation + // and loading of various settings. + _directIpAccount = AccountCreator::createAccount (AccountCreator::SIP_DIRECT_IP_ACCOUNT, ""); + if (_directIpAccount == NULL) { + _debug("Failed to create direct ip calls \"account\"\n"); + } else { + // Force the options to be loaded + // No registration in the sense of + // the REGISTER method is performed. + _directIpAccount->registerVoIPLink(); + } + _debug ("nbAccount loaded %i \n",nbAccount); return nbAccount; @@ -3097,9 +3146,15 @@ ManagerImpl::accountExists (const AccountID& accountID) Account* ManagerImpl::getAccount (const AccountID& accountID) { + // In our definition, + // this is the "direct ip calls account" + if (accountID == AccountNULL) { + return _directIpAccount; + } + AccountMap::iterator iter = _accountMap.find (accountID); if (iter == _accountMap.end()) { - return 0; + return NULL; } return iter->second; } @@ -3329,20 +3384,11 @@ void ManagerImpl::setHookSettings (const std::map<std::string, std::string>& set saveConfig (); } - - - void ManagerImpl::check_call_configuration (const CallID& id, const std::string &to, Call::CallConfiguration *callConfig) { - std::string pattern; Call::CallConfiguration config; - /* Check if the call is an IP-to-IP call */ - /* For an IP-to-IP call, we don't need any account */ - /* Pattern looked for : ip:xxx.xxx.xxx.xxx */ - pattern = to.substr (0,4); - - if (pattern==IP_TO_IP_PATTERN) { + if (to.find(SIP_SCHEME) == 0 || to.find(SIPS_SCHEME) == 0) { _debug ("Sending Sip Call \n"); config = Call::IPtoIP; } else { diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index a6daacba79de5d9c4f74aa86b79cb6b02168c061..2b9d78bb90c08572e77dd74c907c208b6361b76c 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -48,6 +48,7 @@ class GuiFramework; class TelephoneTone; class VoIPLink; class HistoryManager; +class SIPAccount; /** Define a type for a AccountMap container */ typedef std::map<AccountID, Account*> AccountMap; @@ -903,7 +904,7 @@ class ManagerImpl { * @param port On which port we want to listen to * @return true if we are behind a NAT (without error) */ - bool behindNat(const std::string& svr, int port); + bool isBehindNat(const std::string& svr, int port); /** * Init default values for the different fields in the config file. @@ -1147,6 +1148,8 @@ class ManagerImpl { /** *Contains a list of account (sip, aix, etc) and their respective voiplink/calls */ AccountMap _accountMap; + + Account * _directIpAccount; /** * Load the account from configuration diff --git a/sflphone-common/src/sip/sipaccount.cpp b/sflphone-common/src/sip/sipaccount.cpp index f26d7b1e3f6274ba096b755e7679ea109b3a61d1..ed04e13e39d78f5db73948fd5056a94d96da2a8a 100644 --- a/sflphone-common/src/sip/sipaccount.cpp +++ b/sflphone-common/src/sip/sipaccount.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2006-2009 Savoir-Faire Linux inc. * * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,14 +22,25 @@ #include "sipaccount.h" #include "manager.h" #include "user_cfg.h" +#include <pwd.h> SIPAccount::SIPAccount (const AccountID& accountID) : Account (accountID, "sip") - , _cred (NULL) - , _regc() - , _bRegister (false) - , _contact ("") - , _resolveOnce (false) + , _regc(NULL) + , _bRegister(false) + , _registrationExpire("") + , _localIpAddress("") + , _publishedIpAddress("") + , _localPort(atoi(DEFAULT_SIP_PORT)) + , _publishedPort(atoi(DEFAULT_SIP_PORT)) + , _transportType (PJSIP_TRANSPORT_UNSPECIFIED) + , _resolveOnce(false) + , _credentialCount(0) + , _cred(NULL) + , _realm(DEFAULT_REALM) + , _authenticationUsername("") + , _tlsSetting(NULL) + , _displayName("") { /* SIPVoIPlink is used as a singleton, because we want to have only one link for all the SIP accounts created */ /* So instead of creating a new instance, we just fetch the static instance, or create one if it is not yet */ @@ -38,7 +50,7 @@ SIPAccount::SIPAccount (const AccountID& accountID) /* Represents the number of SIP accounts connected the same link */ dynamic_cast<SIPVoIPLink*> (_link)->incrementClients(); - + } SIPAccount::~SIPAccount() @@ -48,26 +60,11 @@ SIPAccount::~SIPAccount() /* Delete accounts-related information */ _regc = NULL; free(_cred); - _cred = NULL; + free(_tlsSetting); } -int SIPAccount::registerVoIPLink() +int SIPAccount::initCredential(void) { - int status; - - /* Retrieve the account information */ - /* Stuff needed for SIP registration */ - - if (Manager::instance().getConfigString (_accountID, HOSTNAME).length() >= PJ_MAX_HOSTNAME) { - return !SUCCESS; - } - - setHostname (Manager::instance().getConfigString (_accountID, HOSTNAME)); - setUsername (Manager::instance().getConfigString (_accountID, USERNAME)); - setPassword (Manager::instance().getConfigString (_accountID, PASSWORD)); - _authenticationUsername = Manager::instance().getConfigString (_accountID, AUTHENTICATION_USERNAME); - _realm = Manager::instance().getConfigString (_accountID, REALM); - int credentialCount = 0; credentialCount = Manager::instance().getConfigInt (_accountID, CONFIG_CREDENTIAL_NUMBER); credentialCount += 1; @@ -124,18 +121,34 @@ int SIPAccount::registerVoIPLink() _credentialCount = credentialCount; _cred = cred_info; - _resolveOnce = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_RESOLVE_ONCE) == "1" ? true : false; + return SUCCESS; +} - if (Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE).empty()) { - _registrationExpire = DFT_EXPIRE_VALUE; - } else { - _registrationExpire = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE); + +int SIPAccount::registerVoIPLink() +{ + // Init general settings + loadConfig(); + + if (_hostname.length() >= PJ_MAX_HOSTNAME) { + return !SUCCESS; } - /* Start registration */ - status = _link->sendRegister (_accountID); - - ASSERT (status , SUCCESS); + // Init set of additional credentials, if supplied by the user + initCredential(); + + // Init TLS settings if the user wants to use TLS + bool tlsEnabled = Manager::instance().getConfigBool(_accountID, TLS_ENABLE); + if (tlsEnabled) { + _transportType = PJSIP_TRANSPORT_TLS; + initTlsConfiguration(); + } + + if (_accountID != IP2IP_PROFILE) { + // Start registration + int status = _link->sendRegister (_accountID); + ASSERT (status , SUCCESS); + } return SUCCESS; } @@ -144,6 +157,10 @@ int SIPAccount::unregisterVoIPLink() { _debug ("unregister account %s\n" , getAccountID().c_str()); + if (_accountID == IP2IP_PROFILE) { + return true; + } + if (_link->sendUnregister (_accountID)) { setRegistrationInfo (NULL); return true; @@ -152,8 +169,92 @@ int SIPAccount::unregisterVoIPLink() } -void SIPAccount::loadConfig() +pjsip_ssl_method SIPAccount::sslMethodStringToPjEnum(const std::string& method) +{ + if (method == "Default") { return PJSIP_SSL_UNSPECIFIED_METHOD; } + + if (method == "TLSv1") { return PJSIP_TLSV1_METHOD; } + + if (method == "SSLv2") { return PJSIP_SSLV2_METHOD; } + + if (method == "SSLv3") { return PJSIP_SSLV3_METHOD; } + + if (method == "SSLv23") { return PJSIP_SSLV23_METHOD; } + + return PJSIP_SSL_UNSPECIFIED_METHOD; +} + +void SIPAccount::initTlsConfiguration(void) { + /* + * Initialize structure to zero + */ + _tlsSetting = (pjsip_tls_setting *) malloc(sizeof(pjsip_tls_setting)); + + assert(_tlsSetting); + + pjsip_tls_setting_default(_tlsSetting); + + std::string tlsCaListFile = Manager::instance().getConfigString(_accountID, TLS_CA_LIST_FILE); + std::string tlsCertificateFile = Manager::instance().getConfigString(_accountID, TLS_CERTIFICATE_FILE); + std::string tlsPrivateKeyFile = Manager::instance().getConfigString(_accountID, TLS_PRIVATE_KEY_FILE); + std::string tlsPassword = Manager::instance().getConfigString(_accountID, TLS_PASSWORD); + std::string tlsMethod = Manager::instance().getConfigString(_accountID, TLS_METHOD); + std::string tlsCiphers = Manager::instance().getConfigString(_accountID, TLS_CIPHERS); + std::string tlsServerName = Manager::instance().getConfigString(_accountID, TLS_SERVER_NAME); + bool tlsVerifyServer = Manager::instance().getConfigBool(_accountID, TLS_VERIFY_SERVER); + bool tlsVerifyClient = Manager::instance().getConfigBool(_accountID, TLS_VERIFY_CLIENT); + bool tlsRequireClientCertificate = Manager::instance().getConfigBool(_accountID, TLS_REQUIRE_CLIENT_CERTIFICATE); + std::string tlsNegotiationTimeoutSec = Manager::instance().getConfigString(_accountID, TLS_NEGOTIATION_TIMEOUT_SEC); + std::string tlsNegotiationTimeoutMsec = Manager::instance().getConfigString(_accountID, TLS_NEGOTIATION_TIMEOUT_MSEC); + + pj_cstr(&_tlsSetting->ca_list_file, tlsCaListFile.c_str()); + pj_cstr(&_tlsSetting->cert_file, tlsCertificateFile.c_str()); + pj_cstr(&_tlsSetting->privkey_file, tlsPrivateKeyFile.c_str()); + pj_cstr(&_tlsSetting->password, tlsPassword.c_str()); + _tlsSetting->method = sslMethodStringToPjEnum(tlsMethod); + pj_cstr(&_tlsSetting->ciphers, tlsCiphers.c_str()); + pj_cstr(&_tlsSetting->server_name, tlsServerName.c_str()); + + _tlsSetting->verify_server = (tlsVerifyServer == true) ? PJ_TRUE: PJ_FALSE; + _tlsSetting->verify_client = (tlsVerifyClient == true) ? PJ_TRUE: PJ_FALSE; + _tlsSetting->require_client_cert = (tlsRequireClientCertificate == true) ? PJ_TRUE: PJ_FALSE; + + _tlsSetting->timeout.sec = atol(tlsNegotiationTimeoutSec.c_str()); + _tlsSetting->timeout.msec = atol(tlsNegotiationTimeoutMsec.c_str()); + +} + +void SIPAccount::loadConfig() +{ + // Load primary credential + setUsername (Manager::instance().getConfigString (_accountID, USERNAME)); + setPassword (Manager::instance().getConfigString (_accountID, PASSWORD)); + _authenticationUsername = Manager::instance().getConfigString (_accountID, AUTHENTICATION_USERNAME); + _realm = Manager::instance().getConfigString (_accountID, REALM); + _resolveOnce = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_RESOLVE_ONCE) == "1" ? true : false; + + // Load general account settings + setHostname (Manager::instance().getConfigString (_accountID, HOSTNAME)); + if (Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE).empty()) { + _registrationExpire = DFT_EXPIRE_VALUE; + } else { + _registrationExpire = Manager::instance().getConfigString (_accountID, CONFIG_ACCOUNT_REGISTRATION_EXPIRE); + } + + // Load network settings + std::string localPort = Manager::instance().getConfigString(_accountID, LOCAL_PORT); + std::string publishedPort = Manager::instance().getConfigString(_accountID, PUBLISHED_PORT); + std::stringstream ss; + ss << localPort; + ss >> _localPort; + ss << publishedPort; + ss >> _publishedPort; + + _localIpAddress = Manager::instance().getConfigString(_accountID, LOCAL_ADDRESS); + _publishedIpAddress = Manager::instance().getConfigString(_accountID, PUBLISHED_ADDRESS); + _transportType = PJSIP_TRANSPORT_UDP; + // Account generic Account::loadConfig(); } @@ -176,3 +277,162 @@ bool SIPAccount::hostnameMatch (const std::string& hostname) return (hostname == getHostname()); } +std::string SIPAccount::getMachineName(void) +{ + std::string hostname; + hostname = std::string(pj_gethostname()->ptr, pj_gethostname()->slen); + return hostname; +} + +std::string SIPAccount::getLoginName(void) +{ + std::string username; + + uid_t uid = getuid(); + struct passwd * user_info = NULL; + user_info = getpwuid(uid); + if (user_info != NULL) { + username = user_info->pw_name; + } + + return username; +} + + +std::string SIPAccount::getFromUri(void) +{ + char uri[PJSIP_MAX_URL_SIZE]; + + std::string scheme; + std::string transport; + std::string username = _username; + std::string hostname = _hostname; + + // UDP does not require the transport specification + if (_transportType == PJSIP_TRANSPORT_TLS) { + scheme = "sips:"; + transport = ";transport=" + std::string(pjsip_transport_get_type_name(_transportType)); + } else { + scheme = "sip:"; + transport = ""; + } + + // Get login name if username is not specified + if (_username.empty()) { + username = getLoginName(); + } + + // Get machine hostname if not provided + if (_hostname.empty()) { + hostname = getMachineName(); + } + + int len = pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE, + "<%s%s@%s%s>", + scheme.c_str(), + username.c_str(), + hostname.c_str(), + transport.c_str()); + + return std::string(uri, len); +} + +std::string SIPAccount::getToUri(const std::string& username) +{ + char uri[PJSIP_MAX_URL_SIZE]; + + std::string scheme; + std::string transport; + std::string hostname = _hostname; + + // UDP does not require the transport specification + if (_transportType == PJSIP_TRANSPORT_TLS) { + scheme = "sips:"; + transport = ";transport=" + std::string(pjsip_transport_get_type_name(_transportType)); + } else { + scheme = "sip:"; + transport = ""; + } + + // Check if scheme is already specified + if (username.find("sip") == 0) { + scheme = ""; + } + + // Check if hostname is already specified + if (username.find("@") != std::string::npos) { + hostname = ""; + } + + int len = pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE, + "<%s%s%s%s%s>", + scheme.c_str(), + username.c_str(), + (hostname.empty()) ? "" : "@", + hostname.c_str(), + transport.c_str()); + + return std::string(uri, len); +} + +std::string SIPAccount::getServerUri(void) +{ + char uri[PJSIP_MAX_URL_SIZE]; + + std::string scheme; + std::string transport; + + // UDP does not require the transport specification + if (_transportType == PJSIP_TRANSPORT_TLS) { + scheme = "sips:"; + transport = ";transport=" + std::string(pjsip_transport_get_type_name(_transportType)); + } else { + scheme = "sip:"; + transport = ""; + } + + int len = pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE, + "<%s%s%s>", + scheme.c_str(), + _hostname.c_str(), + transport.c_str()); + + return std::string(uri, len); +} + +std::string SIPAccount::getContactHeader(const std::string& address, const std::string& port) +{ + char contact[PJSIP_MAX_URL_SIZE]; + const char * beginquote, * endquote; + + std::string scheme; + std::string transport; + + // if IPV6, should be set to [] + beginquote = endquote = ""; + + // UDP does not require the transport specification + if (_transportType == PJSIP_TRANSPORT_TLS) { + scheme = "sips:"; + transport = ";transport=" + std::string(pjsip_transport_get_type_name(_transportType)); + } else { + scheme = "sip:"; + transport = ""; + } + + int len = pj_ansi_snprintf(contact, PJSIP_MAX_URL_SIZE, + "%s%s<%s%s%s%s%s%s:%d%s>", + _displayName.c_str(), + (_displayName.empty() ? "" : " "), + scheme.c_str(), + _username.c_str(), + (_username.empty() ? "":"@"), + beginquote, + address.c_str(), + endquote, + atoi(port.c_str()), + transport.c_str()); + + return std::string(contact, len); +} + diff --git a/sflphone-common/src/sip/sipaccount.h b/sflphone-common/src/sip/sipaccount.h index 3a4830ed2fdaedf5629e09ec7ea53cb1e658c9e1..6375f986b84d72a86db089c1070d089b04d73dea 100644 --- a/sflphone-common/src/sip/sipaccount.h +++ b/sflphone-common/src/sip/sipaccount.h @@ -4,7 +4,8 @@ * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * + * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or @@ -25,6 +26,8 @@ #include "account.h" #include "sipvoiplink.h" +#include "pjsip/sip_transport_tls.h" +#include "pjsip/sip_types.h" class SIPVoIPLink; @@ -70,10 +73,7 @@ class SIPAccount : public Account inline void setCredInfo(pjsip_cred_info *cred) {_cred = cred;} inline pjsip_cred_info *getCredInfo() {return _cred;} - - inline void setContact(const std::string &contact) {_contact = contact;} - inline std::string getContact() {return _contact;} - + inline std::string& getAuthenticationUsername(void) { return _authenticationUsername; } inline void setAuthenticationUsername(const std::string& username) { _authenticationUsername = username; } @@ -84,47 +84,211 @@ class SIPAccount : public Account bool fullMatch(const std::string& username, const std::string& hostname); bool userMatch(const std::string& username); bool hostnameMatch(const std::string& hostname); - + + /* Registration flag */ + bool isRegister() {return _bRegister;} + void setRegister(bool result) {_bRegister = result;} + + /** + * Get the registration stucture that is used + * for PJSIP in the registration process. + * Settings are loaded from configuration file. + * @param void + * @return pjsip_regc* A pointer to the registration structure + */ pjsip_regc* getRegistrationInfo( void ) { return _regc; } + + /** + * Set the registration structure that is used + * for PJSIP in the registration process; + * @pram A pointer to the new registration structure + * @return void + */ void setRegistrationInfo( pjsip_regc *regc ) { _regc = regc; } + /** + * Get the number of credentials defined for + * this account. + * @param none + * @return int The number of credentials set for this account. + */ inline int getCredentialCount(void) { return _credentialCount; } + + /** + * @return pjsip_tls_setting structure, filled from the configuration + * file, that can be used directly by PJSIP to initialize + * TLS transport. + */ + inline pjsip_tls_setting * getTlsSetting(void) { return _tlsSetting; } - /* Registration flag */ - bool isRegister() {return _bRegister;} - void setRegister(bool result) {_bRegister = result;} + /** + * @return bool Tells if current transport for that + * account is set to TLS. + */ + inline bool isTlsEnabled(void) { return (_transportType == PJSIP_TRANSPORT_TLS) ? true: false; } + + /* + * @return pj_str_t "From" uri based on account information. + * From RFC3261: "The To header field first and foremost specifies the desired + * logical" recipient of the request, or the address-of-record of the + * user or resource that is the target of this request. [...] As such, it is + * very important that the From URI not contain IP addresses or the FQDN + * of the host on which the UA is running, since these are not logical + * names." + */ + std::string getFromUri(void); - private: + /* + * This method adds the correct scheme, hostname and append + * the ;transport= parameter at the end of the uri, in accordance with RFC3261. + * It is expected that "port" is present in the internal _hostname. + * + * @return pj_str_t "To" uri based on @param username + * @param username A string formatted as : "username" + */ + std::string getToUri(const std::string& username); + /* + * In the current version of SFLPhone, "srv" uri is obtained in the preformated + * way: hostname:port. This method adds the correct scheme and append + * the ;transport= parameter at the end of the uri, in accordance with RFC3261. + * + * @return pj_str_t "server" uri based on @param hostPort + * @param hostPort A string formatted as : "hostname:port" + */ + std::string getServerUri(void); + /** - * Credential information + * @param port Optional port. Otherwise set to the port defined for that account. + * @param hostname Optional local address. Otherwise set to the hostname defined for that account. + * @return pj_str_t The contact header based on account information */ - pjsip_cred_info *_cred; + std::string getContactHeader(const std::string& address, const std::string& port); /** - * The pjsip client registration information + * Get the port on which the transport/listener should use, or is + * actually using. + * @return pj_uint16 The port used for that account + */ + inline pj_uint16_t getLocalPort(void) { return (pj_uint16_t) _localPort; } + + /** + * Set the new port on which this account is running over. + * @pram port The port used by this account. */ - pjsip_regc *_regc; + inline void setLocalPort(pj_uint16_t port) { _localPort = port; } + + /** + * Get the published port, which is the port to be advertised as the port + * for the chosen SIP transport. + * @return pj_uint16 The port used for that account + */ + inline pj_uint16_t getPublishedPort(void) { return (pj_uint16_t) _publishedPort; } + /** + * Set the published port, which is the port to be advertised as the port + * for the chosen SIP transport. + * @pram port The port used by this account. + */ + inline void setPublishedPort(pj_uint16_t port) { _publishedPort = port; } + /** - * To check if the account is registered + * Get the bound address set by the user. + * @return std::string The public IPV4 address formatted in the standard dot notation. */ - bool _bRegister; + inline std::string getLocalAddress(void) { return _localIpAddress; } - bool _resolveOnce; + /** + * Set the bound address chosen by the user. + * @param The public IPV4 address in the standard dot notation. + * @return void + */ + inline void setLocalAddress(const std::string& address) { _localIpAddress = address; } + /** + * Get the public IP address set by the user for this account. + * If this setting is not provided, the local bound adddress + * will be used. + * @return std::string The public IPV4 address formatted in the standard dot notation. + */ + inline std::string getPublishedAddress(void) { return _publishedIpAddress; } + + /** + * Set the public IP address to be used in Contact header. + * @param The public IPV4 address in the standard dot notation. + * @return void + */ + inline void setPublishedAddress(const std::string& publishedIpAddress) { _publishedIpAddress = publishedIpAddress; } + + private: + + /* Maps a string description of the SSL method + * to the corresponding enum value in pjsip_ssl_method. + * @param method The string representation + * @return pjsip_ssl_method The corresponding value in the enum + */ + pjsip_ssl_method sslMethodStringToPjEnum(const std::string& method); + /* - * SIP address + * Initializes tls settings from configuration file. + * + */ + void initTlsConfiguration(void); + + /* + * Initializes set of additional credentials, if supplied by the user. + */ + int initCredential(void); + + /** + * If username is not provided, as it happens for Direct ip calls, + * fetch the hostname of the machine on which the program is running + * onto. + * @return std::string The machine hostname as returned by pj_gethostname() */ - std::string _contact; + std::string getMachineName(void); + /** + * If username is not provided, as it happens for Direct ip calls, + * fetch the Real Name field of the user that is currently + * running this program. + * @return std::string The login name under which SFLPhone is running. + */ + std::string getLoginName(void); + + private: + + // The pjsip client registration information + pjsip_regc *_regc; + // To check if the account is registered + bool _bRegister; + + // Network settings std::string _registrationExpire; + + std::string _localIpAddress; + std::string _publishedIpAddress; - std::string _authenticationUsername; + pj_uint16_t _localPort; + pj_uint16_t _publishedPort; - std::string _realm; + pjsip_transport_type_e _transportType; + // Special hack that is not here to stay + // See #1852 + bool _resolveOnce; + + //Credential information + int _credentialCount; + pjsip_cred_info *_cred; + std::string _realm; + std::string _authenticationUsername; + + // The TLS settings, if tls is chosen as + // a sip transport. + pjsip_tls_setting * _tlsSetting; - int _credentialCount; + // Display Name that can be used in SIP URI. + std::string _displayName; }; #endif diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index 05617b3a71061c94962d147cc224d1d5a40e93fa..40f2354eea5ba42ad8f97395815bd48534c705d2 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -3,7 +3,8 @@ * * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Yun Liu <yun.liu@savoirfairelinux.com> - * + * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or @@ -29,6 +30,8 @@ #include "sip/sdp.h" #include "pjsip/sip_endpoint.h" +#include "pjsip/sip_transport_tls.h" +#include "pjsip/sip_uri.h" #include <netinet/in.h> #include <arpa/nameser.h> @@ -210,7 +213,7 @@ SIPVoIPLink::SIPVoIPLink (const AccountID& accountID) , _localExternAddress ("") , _localExternPort (0) , _audiortp (new sfl::AudioRtpFactory()) - ,_regPort (DEFAULT_SIP_PORT) + ,_regPort (atoi(DEFAULT_SIP_PORT)) , _useStun (false) , _clients (0) { @@ -366,10 +369,9 @@ SIPVoIPLink::getEvent() int SIPVoIPLink::sendRegister (AccountID id) { int expire_value; - char contactTmp[256]; - + pj_status_t status; - pj_str_t svr, aor, contact, useragent; + pj_str_t useragent; pjsip_tx_data *tdata; pjsip_host_info destination; @@ -386,6 +388,12 @@ int SIPVoIPLink::sendRegister (AccountID id) return false; } + // Resolve hostname here and keep its + // IP address for the whole time the + // account is connected. This was a + // workaround meant to help issue + // #1852 that we hope should be fixed + // soon. if (account->isResolveOnce()) { struct result result; @@ -420,26 +428,26 @@ int SIPVoIPLink::sendRegister (AccountID id) account->setHostname (addr_buf); } } + + // Launch a new TLS listener/transport + // if the user did choose it. + if (account->isTlsEnabled()) { + pj_status_t status; + + status = createTlsTransportRetryOnFailure(id); + + if (status != PJ_SUCCESS) { + _debug("Failed to initialize TLS transport for account %s\n", id.c_str()); + } + } - hostname = account->getHostname(); - - username = account->getUsername(); - password = account->getPassword(); _mutexSIP.enterMutex(); - - /* Get the client registration information for this particular account */ + // Get the client registration information for this particular account regc = account->getRegistrationInfo(); - /* TODO If the registration already exists, delete it */ - /*if(regc) { - status = pjsip_regc_destroy(regc); - regc = NULL; - PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 ); - }*/ - account->setRegister (true); - /* Set the expire value of the message from the config file */ + // Set the expire value of the message from the config file istringstream stream (account->getRegistrationExpire()); stream >> expire_value; @@ -447,7 +455,7 @@ int SIPVoIPLink::sendRegister (AccountID id) expire_value = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED; } - /* Update the state of the voip link */ + // Update the state of the voip link account->setRegistrationState (Trying); if (!validStunServer) { @@ -457,7 +465,7 @@ int SIPVoIPLink::sendRegister (AccountID id) return false; } - /* Create the registration according to the account ID */ + // Create the registration according to the account ID status = pjsip_regc_create (_endpt, (void*) account, ®c_cb, ®c); if (status != PJ_SUCCESS) { @@ -466,23 +474,43 @@ int SIPVoIPLink::sendRegister (AccountID id) return false; } - tmp = "sip:" + hostname; - - pj_strdup2 (_pool, &svr, tmp.data()); - - // tmp = "<sip:" + username + "@" + hostname + ";transport=tls>"; - tmp = "<sip:" + username + "@" + hostname + ">"; - pj_strdup2 (_pool, &aor, tmp.data()); - - _debug ("<sip:%s@%s:%d>\n", username.data(), _localExternAddress.data(), _localExternPort); - sprintf (contactTmp, "<sip:%s@%s:%d>", username.data(), _localExternAddress.data(), _localExternPort); - pj_strdup2 (_pool, &contact, contactTmp); - account->setContact (contactTmp); - - status = pjsip_regc_init (regc, &svr, &aor, &aor, 1, &contact, expire_value); //timeout); + // Creates URI + std::string fromUri; + std::string contactUri; + std::string srvUri; + std::string address; + + fromUri = account->getFromUri(); + srvUri = account->getServerUri(); + address = findLocalAddressFromUri(srvUri); + + int port = findLocalPortFromUri(srvUri); + std::stringstream ss; + std::string portStr; + ss << port; + ss >> portStr; + // DON'T FORGET TO REMOVE THIS 5061 VALUE ! + contactUri = account->getContactHeader(address, "5061"); + + _debug("sendRegister: fromUri: %s serverUri: %s contactUri: %s\n", + fromUri.c_str(), + srvUri.c_str(), + contactUri.c_str()); + + pj_str_t pjFrom; + pj_cstr(&pjFrom, fromUri.c_str()); + + pj_str_t pjContact; + pj_cstr(&pjContact, contactUri.c_str()); + + pj_str_t pjSrv; + pj_cstr(&pjSrv, srvUri.c_str()); + + // Initializes registration + status = pjsip_regc_init (regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, expire_value); if (status != PJ_SUCCESS) { - _debug ("UserAgent: Unable to initialize regc. %d\n", status); //, regc->str_srv_url.ptr); + _debug ("UserAgent: Unable to initialize account %d in sendRegister\n", status); _mutexSIP.leaveMutex(); return false; } @@ -511,6 +539,7 @@ int SIPVoIPLink::sendRegister (AccountID id) return false; } + // Send registration request status = pjsip_regc_send (regc, tdata); if (status != PJ_SUCCESS) { @@ -570,15 +599,14 @@ SIPVoIPLink::sendUnregister (AccountID id) Call* SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) { - Account* account; + SIPAccount * account = NULL; pj_status_t status; SIPCall* call = new SIPCall (id, Call::Outgoing, _pool); if (call) { account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (Manager::instance().getAccountFromCall (id))); - - if (!account) { + if (account == NULL) { _debug ("Error retrieving the account to the make the call with\n"); call->setConnectionState (Call::Disconnected); call->setState (Call::Error); @@ -587,7 +615,8 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) return call; } - call->setPeerNumber (getSipTo (toUrl, account->getHostname())); + std::string toUri = account->getToUri(toUrl); + call->setPeerNumber(toUri); setCallAudioLocal (call, getLocalIPAddress(), useStun(), getStunServer()); @@ -911,38 +940,34 @@ SIPVoIPLink::transfer (const CallID& id, const std::string& to) std::string tmp_to; pjsip_evsub *sub; pjsip_tx_data *tdata; - struct pjsip_evsub_user xfer_cb; pj_status_t status; - pj_str_t dest; AccountID account_id; - Account* account; + SIPAccount * account = NULL; call = getSIPCall (id); call->stopRecording(); account_id = Manager::instance().getAccountFromCall (id); account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (account_id)); + if (account == NULL) { + _debug("SIPVoIPLink::transfer account is null. Returning.\n"); + return false; + } + if (call==0) { _debug ("! SIP Failure: Call doesn't exist\n"); return false; } - tmp_to = SIPToHeader (to); - - if (account) { - if (tmp_to.find ("@") == std::string::npos) { - tmp_to = tmp_to + "@" + account->getHostname(); - } - } - - else { - + std::string dest; + pj_str_t pjDest; + if (to.find ("@") == std::string::npos) { + dest = account->getToUri(to); + pj_cstr(&pjDest, dest.c_str()); } - _debug ("In transfer, tmp_to is %s\n", tmp_to.data()); - - pj_strdup2 (_pool, &dest, tmp_to.data()); + _debug ("Transfering to %s\n", dest.c_str()); /* Create xfer client subscription. */ pj_bzero (&xfer_cb, sizeof (xfer_cb)); @@ -967,7 +992,7 @@ SIPVoIPLink::transfer (const CallID& id, const std::string& to) /* * Create REFER request. */ - status = pjsip_xfer_initiate (sub, &dest, &tdata); + status = pjsip_xfer_initiate (sub, &pjDest, &tdata); if (status != PJ_SUCCESS) { _debug ("UserAgent: Unable to create REFER request -- %d\n", status); @@ -1151,42 +1176,60 @@ SIPVoIPLink::SIPOutgoingInvite (SIPCall* call) bool SIPVoIPLink::SIPStartCall (SIPCall* call, const std::string& subject UNUSED) { - std::string strTo, strFrom; pj_status_t status; + pjsip_inv_session *inv; pjsip_dialog *dialog; pjsip_tx_data *tdata; - pj_str_t from, to, contact; + AccountID id; - SIPAccount *account; - pjsip_inv_session *inv; - if (!call) + if (call == NULL) return false; id = Manager::instance().getAccountFromCall (call->getCallId()); // Get the basic information about the callee account + SIPAccount * account = NULL; account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (id)); - - strTo = getSipTo (call->getPeerNumber(), account->getHostname()); - - // Generate the from URI - strFrom = "sip:" + account->getUsername() + "@" + account->getHostname(); - - _debug ("Placing new call: \nTo: %s\nFrom: %s\n", strTo.data(), strFrom.c_str()); - - // pjsip need the from and to information in pj_str_t format - pj_strdup2 (_pool, &from, strFrom.data()); - - pj_strdup2 (_pool, &to, strTo.data()); - - pj_strdup2 (_pool, &contact, account->getContact().data()); - - //_debug("%s %s %s\n", from.ptr, contact.ptr, to.ptr); - // create the dialog (UAC) - status = pjsip_dlg_create_uac (pjsip_ua_instance(), &from, - &contact, - &to, + if (account == NULL) { + _debug("Account is null in SIPStartCall\n"); + return false; + } + + // Creates URI + std::string fromUri; + std::string toUri; + std::string contactUri; + + fromUri = account->getFromUri(); + toUri = call->getPeerNumber(); // expecting a fully well formed sip uri + + std::string address = findLocalAddressFromUri(toUri); + int port = findLocalPortFromUri(toUri); + std::stringstream ss; + std::string portStr; + ss << port; + ss >> portStr; + contactUri = account->getContactHeader(address, portStr); + + _debug("SIPStartCall: fromUri: %s toUri: %s contactUri: %s\n", + fromUri.c_str(), + toUri.c_str(), + contactUri.c_str()); + + pj_str_t pjFrom; + pj_cstr(&pjFrom, fromUri.c_str()); + + pj_str_t pjContact; + pj_cstr(&pjContact, contactUri.c_str()); + + pj_str_t pjTo; + pj_cstr(&pjTo, toUri.c_str()); + + // Create the dialog (UAC) + status = pjsip_dlg_create_uac (pjsip_ua_instance(), &pjFrom, + &pjContact, + &pjTo, NULL, &dialog); @@ -1222,36 +1265,6 @@ SIPVoIPLink::SIPStartCall (SIPCall* call, const std::string& subject UNUSED) return true; } -std::string SIPVoIPLink::getSipTo (const std::string& to_url, std::string hostname) -{ - // Form the From header field basis on configuration panel - //bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true; - - // add a @host if we are registered and there is no one inside the url - if (to_url.find ("@") == std::string::npos) { // && isRegistered) { - if (!hostname.empty()) { - return SIPToHeader (to_url + "@" + hostname); - } - } - - return SIPToHeader (to_url); -} - -std::string SIPVoIPLink::SIPToHeader (const std::string& to) -{ - if (to.find ("sip:") == std::string::npos) { - return ("sip:" + to); - } else { - return to; - } -} - -bool -SIPVoIPLink::SIPCheckUrl (const std::string& url UNUSED) -{ - return true; -} - void SIPVoIPLink::SIPCallServerFailure (SIPCall *call) { @@ -1359,9 +1372,6 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to) { SIPCall *call; pj_status_t status; - std::string uri_from, uri_to, hostname; - std::ostringstream uri_contact; - pj_str_t from, str_to, contact; pjsip_dialog *dialog; pjsip_inv_session *inv; pjsip_tx_data *tdata; @@ -1370,23 +1380,22 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to) call = new SIPCall (id, Call::Outgoing, _pool); if (call) { - call->setCallConfiguration (Call::IPtoIP); - call->setPeerNumber (getSipTo (to, getLocalIPAddress())); - - // Generate the from URI - hostname = pj_gethostname()->ptr; - uri_from = "sip:" + hostname + "@" + getLocalIPAddress() ; - - // Generate the from URI - uri_to = "sip:" + to.substr (4, to.length()); - - _debug ("get local ip address: %s \n", getLocalIPAddress().c_str()); - // Generate the to URI setCallAudioLocal (call, getLocalIPAddress(), useStun(), getStunServer()); - call->initRecFileName(); + + AccountID accountId = Manager::instance().getAccountFromCall(id); + SIPAccount * account = NULL; + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(accountId)); + if (account == NULL) { + _debug("Account is null. Returning\n"); + return !PJ_SUCCESS; + } + _debug("toUri received in new_ip_to_ip call %s\n", to.c_str()); + std::string toUri = account->getToUri(to); + call->setPeerNumber(toUri); + _debug("toUri in new_ip_to_ip call %s\n", toUri.c_str()); // Building the local SDP offer call->getLocalSDP()->set_ip_address (getLocalIP()); call->getLocalSDP()->create_initial_offer(); @@ -1396,20 +1405,37 @@ bool SIPVoIPLink::new_ip_to_ip_call (const CallID& id, const std::string& to) } catch (...) { _debug ("! SIP Failure: Unable to create RTP Session in SIPVoIPLink::new_ip_to_ip_call (%s:%d)\n", __FILE__, __LINE__); } - - // Generate the contact URI - // uri_contact << "<" << uri_from << ":" << call->getLocalSDP()->get_local_extern_audio_port() << ">"; - uri_contact << "<" << uri_from << ":" << _localExternPort << ">"; - - // pjsip need the from and to information in pj_str_t format - pj_strdup2 (_pool, &from, uri_from.data()); - - pj_strdup2 (_pool, &str_to, uri_to.data()); - - pj_strdup2 (_pool, &contact, uri_contact.str().data()); - - // create the dialog (UAC) - status = pjsip_dlg_create_uac (pjsip_ua_instance(), &from, &contact, &str_to, NULL, &dialog); + + // Create URI + std::string fromUri; + std::string contactUri; + fromUri = account->getFromUri(); + + std::string address = findLocalAddressFromUri(toUri); + int port = findLocalPortFromUri(toUri); + std::stringstream ss; + std::string portStr; + ss << port; + ss >> portStr; + contactUri = account->getContactHeader(address, portStr); + + _debug("new_ip_to_ip_call: fromUri: %s toUri: %s contactUri: %s\n", + fromUri.c_str(), + toUri.c_str(), + contactUri.c_str()); + + pj_str_t pjFrom; + pj_cstr(&pjFrom, fromUri.c_str()); + + pj_str_t pjTo; + pj_cstr(&pjTo, toUri.c_str()); + + pj_str_t pjContact; + pj_cstr(&pjContact, contactUri.c_str()); + + // Create the dialog (UAC) + // (Parameters are "strduped" inside this function) + status = pjsip_dlg_create_uac (pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, NULL, &dialog); PJ_ASSERT_RETURN (status == PJ_SUCCESS, false); @@ -1580,7 +1606,7 @@ bool SIPVoIPLink::pjsip_init() PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1); - /* Start resolving STUN server */ + // Start resolving STUN server // if we useStun and we failed to receive something on port 5060, we try a random port // If use STUN server, firewall address setup if (!loadSIPLocalIP()) { @@ -1595,10 +1621,10 @@ bool SIPVoIPLink::pjsip_init() this->setStunServer (Manager::instance().getConfigString (SIGNALISATION, SIP_STUN_SERVER)); this->useStun(useStun); - if (useStun && !Manager::instance().behindNat (getStunServer(), port)) { + if (useStun && !Manager::instance().isBehindNat (getStunServer(), port)) { port = RANDOM_SIP_PORT; - if (!Manager::instance().behindNat (getStunServer(), port)) { + if (!Manager::instance().isBehindNat (getStunServer(), port)) { _debug ("UserAgent: Unable to check NAT setting\n"); validStunServer = false; return false; // hoho we can't use the random sip port too... @@ -1607,37 +1633,75 @@ bool SIPVoIPLink::pjsip_init() _localPort = port; + + // Retreive Direct IP Calls settings. + // This corresponds to the accountID set to + // AccountNULL + SIPAccount * account = NULL; + bool directIpCallsTlsEnabled = false; + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(AccountNULL)); + if (account == NULL) { + _debug("Account is null"); + } else { + directIpCallsTlsEnabled = account->isTlsEnabled(); + } + if (useStun) { - // set by last behindNat() call (ish)... + // set by last isBehindNat() call (ish)... stunServerResolve(); _localExternAddress = Manager::instance().getFirewallAddress(); - _localExternPort = Manager::instance().getFirewallPort(); - errPjsip = createUDPServer(); - - if (errPjsip != 0) { - _debug ("UserAgent: Could not initialize SIP listener on port %d\n", port); - return errPjsip; - } + _localExternPort = Manager::instance().getFirewallPort(); } else { _localExternAddress = _localIPAddress; _localExternPort = _localPort; errPjsip = createUDPServer(); + } + + // Create a UDP listener meant for all accounts + // for which TLS was not enabled + errPjsip = createUDPServer(); + + // If stun was not enabled an the above UDP server + // could not be created, then give it another try + // on a random sip port + if (errPjsip != PJ_SUCCESS && !useStun) { + _debug ("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort); + _localExternPort = _localPort = RANDOM_SIP_PORT; + + _debug ("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort); + errPjsip = createUDPServer(); - if (errPjsip != 0) { - _debug ("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort); - _localExternPort = _localPort = RANDOM_SIP_PORT; - _debug ("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort); - errPjsip = createUDPServer(); - - if (errPjsip != 0) { - _debug ("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort); - return errPjsip; - } + if (errPjsip != PJ_SUCCESS) { + _debug ("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort); + return errPjsip; } + } + + // If we use stun and UDP server creation + // failed, then just complain and return + // since retrying on a random sip port + // would just go against the need of + // using it. + if (errPjsip != PJ_SUCCESS && useStun) { + _debug("Could not create UDP server with STUN\n"); + return errPjsip; } _debug ("UserAgent: SIP Init -- listening on port %d\n", _localExternPort); + // Create a TLS listener meant for Direct IP calls + // if the user did enabled it. + if (directIpCallsTlsEnabled) { + errPjsip = createTlsTransportRetryOnFailure(AccountNULL); + } + + if (errPjsip != PJ_SUCCESS) { + _debug("pj_init(): could not start TLS transport for Direct Calls"); + } + + // TODO: For TLS, retry on random port, just we already do above + // for UDP transport. + // Initialize transaction layer status = pjsip_tsx_layer_init_module (_endpt); PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1); @@ -1778,7 +1842,6 @@ int SIPVoIPLink::createUDPServer (void) pj_strdup2 (_pool, &a_name.host, tmpIP); a_name.port = (pj_uint16_t) _localExternPort; - status = pjsip_udp_transport_start (_endpt, &bound_addr, &a_name, 1, NULL); if (status != PJ_SUCCESS) { @@ -1788,12 +1851,205 @@ int SIPVoIPLink::createUDPServer (void) _debug ("UserAgent: UDP server listening on port %d\n", _localExternPort); } - _debug ("Transport initialized successfully! \n"); return PJ_SUCCESS; } +std::string SIPVoIPLink::findLocalAddressFromUri(const std::string& uri) +{ + pj_str_t localAddress; + pjsip_transport_type_e transportType; + + // Find the transport that must be used with the given uri + pj_str_t tmp; + pj_strdup2_with_null(_pool, &tmp, uri.c_str()); + pjsip_uri * genericUri = NULL; + genericUri = pjsip_parse_uri(_pool, tmp.ptr, tmp.slen, 0); + + pj_str_t pjMachineName; + pj_strdup(_pool, &pjMachineName, pj_gethostname()); + std::string machineName(pjMachineName.ptr, pjMachineName.slen); + + if (genericUri == NULL) { + _debug("genericUri is NULL in findLocalPortFromUri\n"); + return machineName; + } + + pjsip_sip_uri * sip_uri = NULL; + sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(genericUri); + if (sip_uri == NULL) { + _debug("Invalid uri in findLocalAddressFromTransport\n"); + return machineName; + } + + if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) { + transportType = PJSIP_TRANSPORT_TLS; + } else { + transportType = PJSIP_TRANSPORT_UDP; + } + + // Get the transport manager associated with + // this endpoint + pjsip_tpmgr * tpmgr = NULL; + tpmgr = pjsip_endpt_get_tpmgr(_endpt); + if (tpmgr == NULL) { + _debug("Unexpected: Cannot get tpmgr from endpoint.\n"); + return machineName; + } + + // Find the local address (and port) based on the registered + // transports and the transport type + int port; + pj_status_t status; + status = pjsip_tpmgr_find_local_addr(tpmgr, _pool, transportType, NULL, &localAddress, &port); + if (status != PJ_SUCCESS) { + _debug("Failed to find local address from transport\n"); + return machineName; + } + + return std::string(localAddress.ptr, localAddress.slen); +} + +int SIPVoIPLink::findLocalPortFromUri(const std::string& uri) +{ + pj_str_t localAddress; + pjsip_transport_type_e transportType; + int port; + + // Find the transport that must be used with the given uri + pj_str_t tmp; + pj_strdup2_with_null(_pool, &tmp, uri.c_str()); + pjsip_uri * genericUri = NULL; + genericUri = pjsip_parse_uri(_pool, tmp.ptr, tmp.slen, 0); + if (genericUri == NULL) { + _debug("genericUri is NULL in findLocalPortFromUri\n"); + return atoi(DEFAULT_SIP_PORT); + } + + pjsip_sip_uri * sip_uri = NULL; + sip_uri = (pjsip_sip_uri*)pjsip_uri_get_uri(genericUri); + if (sip_uri == NULL) { + _debug("Invalid uri in findLocalAddressFromTransport\n"); + return atoi(DEFAULT_SIP_PORT); + } + + if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) { + transportType = PJSIP_TRANSPORT_TLS; + port = atoi(DEFAULT_SIP_TLS_PORT); + } else { + transportType = PJSIP_TRANSPORT_UDP; + port = atoi(DEFAULT_SIP_PORT); + } + + // Get the transport manager associated with + // this endpoint + pjsip_tpmgr * tpmgr = NULL; + tpmgr = pjsip_endpt_get_tpmgr(_endpt); + if (tpmgr == NULL) { + _debug("Unexpected: Cannot get tpmgr from endpoint.\n"); + return port; + } + + // Find the local address (and port) based on the registered + // transports and the transport type + + pj_status_t status; + status = pjsip_tpmgr_find_local_addr(tpmgr, _pool, transportType, NULL, &localAddress, &port); + if (status != PJ_SUCCESS) { + _debug("Failed to find local address from transport\n"); + } + + return port; +} + +pj_status_t SIPVoIPLink::createTlsTransportRetryOnFailure(AccountID id) +{ + pj_status_t success; + + // Create a TLS listener. + // Note that STUN cannot be used for + // TCP NAT traversal. At the moment (20/08/09) + // user must supply the public address/port + // manually. + success = createTlsTransport(id); + + if (success != PJ_SUCCESS) { + unsigned int randomPort = RANDOM_SIP_PORT; + + // Update new port in the corresponding SIPAccount + SIPAccount * account = NULL; + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id)); + if (account == NULL) { + _debug("createTlsTransportRetryOnFailure: Account is null. Returning"); + return !PJ_SUCCESS; + } + + account->setLocalPort((pj_uint16_t) randomPort); + + // Try to start the transport again on + // the new port. + success = createTlsTransport(id); + if (success != PJ_SUCCESS) { + _debug ("createTlsTransportRetryOnFailure: failed to retry on random port %d\n", randomPort); + return success; + } + + _debug ("createTlsTransportRetryOnFailure: TLS transport listening on port %d\n", randomPort); + } + + return PJ_SUCCESS; +} + +pj_status_t SIPVoIPLink::createTlsTransport(AccountID id) +{ + pjsip_tpfactory *tls; + pj_sockaddr_in local_addr; + pjsip_host_port a_name; + pj_status_t status; + + /* Grab the tls settings, populated + * from configuration file. + */ + SIPAccount * account = NULL; + account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id)); + if (account == NULL) { + _debug("Account is null. Returning"); + return !PJ_SUCCESS; + } + + /** + * Init local address. + * IP interface address is not specified, + * so socket will be bound to PJ_INADDR_ANY. + * If user specified port is an empty string + * or if it is equal to 0, then the port will + * be chosen automatically by the OS. + */ + pj_sockaddr_in_init(&local_addr, 0, 0); + //pj_uint16_t localTlsPort = account->getLocalPort(); + pj_uint16_t localTlsPort = 5061; + if (localTlsPort != 0) { + local_addr.sin_port = pj_htons(localTlsPort); + } + + /* Init published name */ + pj_bzero(&a_name, sizeof(pjsip_host_port)); + pj_cstr(&a_name.host, (account->getPublishedAddress()).c_str()); + a_name.port = account->getPublishedPort(); + + /* Get TLS settings. Expected to be filled */ + pjsip_tls_setting * tls_setting = account->getTlsSetting(); + + status = pjsip_tls_transport_start(_endpt, tls_setting, &local_addr, &a_name, 1, &tls); + + if (status != PJ_SUCCESS) { + _debug("Error creating SIP TLS listener (%d)\n", status); + } + + return PJ_SUCCESS; +} + bool SIPVoIPLink::loadSIPLocalIP() { @@ -2245,7 +2501,7 @@ mod_on_rx_request (pjsip_rx_data *rdata) AccountID account_id; pjsip_uri *uri; pjsip_sip_uri *sip_uri; - std::string userName, server, caller, callerServer, peerNumber; + std::string userName, server; SIPVoIPLink *link; CallID id; SIPCall* call; @@ -2298,15 +2554,15 @@ mod_on_rx_request (pjsip_rx_data *rdata) uri = rdata->msg_info.from->uri; sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri (uri); - - /* Retrieve only the fisrt characters */ - caller = std::string (sip_uri->user.ptr, sip_uri->user.slen); - callerServer = std::string (sip_uri->host.ptr, sip_uri->host.slen); - peerNumber = caller + "@" + callerServer; + // Store the peer number + char tmp[PJSIP_MAX_URL_SIZE]; + int length = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, + sip_uri, tmp, PJSIP_MAX_URL_SIZE); + + std::string peerNumber(tmp, length); // Get the server voicemail notification // Catch the NOTIFY message - if (rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD) { method_name = "NOTIFY"; // Retrieve all the message. Should contains only the method name but ... @@ -2980,7 +3236,7 @@ bool setCallAudioLocal (SIPCall* call, std::string localIP, bool stun, std::stri if (stun) { // If use Stun server - if (Manager::instance().behindNat (server, callLocalAudioPort)) { + if (Manager::instance().isBehindNat (server, callLocalAudioPort)) { callLocalExternAudioPort = Manager::instance().getFirewallPort(); } } @@ -3030,4 +3286,26 @@ std::string fetch_header_value (pjsip_msg *msg, std::string field) return url; } +std::vector<std::string> SIPVoIPLink::getAllIpInterface(void) +{ + pj_sockaddr addrList[16]; + unsigned int addrCnt = PJ_ARRAY_SIZE(addrList); + + pj_status_t success; + success = pj_enum_ip_interface (pj_AF_INET(), &addrCnt, addrList); + + std::vector<std::string> ifaceList; + if (success != PJ_SUCCESS) { + return ifaceList; + } + + _debug("Detecting available interfaces...\n"); + int i; + for (i = 0; i < addrCnt; i++) { + char tmpAddr[PJ_INET_ADDRSTRLEN]; + pj_sockaddr_print(&addrList[i], tmpAddr, sizeof(tmpAddr), 0); + ifaceList.push_back(std::string(tmpAddr)); + _debug("Local interface %s\n", tmpAddr); + } +} diff --git a/sflphone-common/src/sip/sipvoiplink.h b/sflphone-common/src/sip/sipvoiplink.h index 92a49352d8559934f13d96cff0dfd459e57ec72d..723d3240d7bd8d5ca53e96b710db8d23d41162ca 100644 --- a/sflphone-common/src/sip/sipvoiplink.h +++ b/sflphone-common/src/sip/sipvoiplink.h @@ -48,7 +48,7 @@ namespace sfl { #define RANDOM_SIP_PORT rand() % 64000 + 1024 // To set the verbosity. From 0 (min) to 6 (max) -#define PJ_LOG_LEVEL 0 +#define PJ_LOG_LEVEL 6 /** * @file sipvoiplink.h @@ -210,22 +210,6 @@ class SIPVoIPLink : public VoIPLink */ void terminateOneCall(const CallID& id); - /** - * Build a sip address with the number that you want to call - * Example: sip:124@domain.com - * @param to The header of the recipient - * @return std::string Result as a string - */ - std::string SIPToHeader(const std::string& to); - - /** - * Check if an url is sip-valid - * @param url The url to check - * @return bool True if osip tell that is valid - */ - bool SIPCheckUrl(const std::string& url); - - /** * Send an outgoing call invite * @param call The current call @@ -241,13 +225,6 @@ class SIPVoIPLink : public VoIPLink */ bool SIPStartCall(SIPCall* call, const std::string& subject); - /** - * Get the Sip TO url (add sip:, add @host, etc...) - * @param to_url The To url - * @return std::string The SIP to address - */ - std::string getSipTo(const std::string& to_url, std::string hostname); - /** * Tell the user that the call was answered * @param @@ -323,6 +300,16 @@ class SIPVoIPLink : public VoIPLink std::string get_useragent_name (void); + /** + * List all the interfaces on the system and return + * a vector list containing their IPV4 address. + * @param void + * @return std::vector<std::string> A std::string vector + * of IPV4 address available on all of the interfaces on + * the system. + */ + std::vector<std::string> getAllIpInterface(void); + private: /** * Constructor @@ -362,6 +349,34 @@ class SIPVoIPLink : public VoIPLink /** Create SIP UDP Listener */ int createUDPServer(); + /** + * Try to create a new TLS transport + * with the settings defined in the corresponding + * SIPAccount with id "id". If creatation fails + * for whatever reason, it will try to start + * it again on a randomly chosen port. + * + * A better idea would be to list all the transports + * registered to the transport manager in order to find + * an available port. Note that creation might also fail + * for other reason than just a wrong port. + * + * @param id The account id for which a tranport must + * be created. + * @return pj_status_t PJ_SUCCESS on success + */ + pj_status_t createTlsTransportRetryOnFailure(AccountID id); + + /** + * Try to create a TLS transport with the settings + * defined in the corresponding SIPAccount with id + * "id". + * @param id The account id for which a transport must + * be created. + * @return pj_status_t PJ_SUCCESS on success + */ + pj_status_t createTlsTransport(AccountID id); + bool loadSIPLocalIP(); std::string getLocalIP() {return _localExternAddress;} @@ -393,6 +408,24 @@ class SIPVoIPLink : public VoIPLink /* Number of SIP accounts connected to the link */ int _clients; + + /* + * Get the correct address to use (ie advertised) from + * a uri. The corresponding transport that should be used + * with that uri will be discovered. + * + * @param uri The uri from which we want to discover the address to use + * @return pj_str_t The extern (public) address + */ + std::string findLocalAddressFromUri(const std::string& uri); + + /* + * Does the same as findLocalAddressFromUri but returns a port. + * @param uri The uri from which we want to discover the address to use + * @return int The extern (public) port + */ + int findLocalPortFromUri(const std::string& uri); }; + #endif