diff --git a/plugins/sip/calls-sip-call.c b/plugins/sip/calls-sip-call.c index 8a1981f..c75e392 100644 --- a/plugins/sip/calls-sip-call.c +++ b/plugins/sip/calls-sip-call.c @@ -50,6 +50,7 @@ enum { PROP_0, PROP_CALL_HANDLE, + PROP_IP, PROP_LAST_PROP }; static GParamSpec *props[PROP_LAST_PROP]; @@ -61,6 +62,8 @@ struct _CallsSipCall CallsSipMediaManager *manager; CallsSipMediaPipeline *pipeline; + char *ip; + guint lport_rtp; guint lport_rtcp; guint rport_rtp; @@ -138,6 +141,7 @@ calls_sip_call_answer (CallsCall *call) calls_sip_call_setup_local_media_connection (self, local_port, local_port + 1); local_sdp = calls_sip_media_manager_get_capabilities (self->manager, + self->ip, local_port, FALSE, self->codecs); @@ -205,6 +209,11 @@ calls_sip_call_set_property (GObject *object, self->nh = g_value_get_pointer (value); break; + case PROP_IP: + g_free (self->ip); + self->ip = g_value_dup_string (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -243,6 +252,7 @@ calls_sip_call_finalize (GObject *object) } g_clear_pointer (&self->codecs, g_list_free); g_clear_pointer (&self->remote, g_free); + g_clear_pointer (&self->ip, g_free); G_OBJECT_CLASS (calls_sip_call_parent_class)->finalize (object); } @@ -266,7 +276,14 @@ calls_sip_call_class_init (CallsSipCallClass *klass) "NUA handle", "The used NUA handler", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_CALL_HANDLE, props[PROP_CALL_HANDLE]); + + props[PROP_IP] = + g_param_spec_string ("own-ip", + "Own IP", + "Own IP for media and SDP", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } @@ -353,14 +370,16 @@ calls_sip_call_activate_media (CallsSipCall *self, CallsSipCall * calls_sip_call_new (const gchar *id, gboolean inbound, + const char *own_ip, nua_handle_t *handle) { g_return_val_if_fail (id, NULL); return g_object_new (CALLS_TYPE_SIP_CALL, - "nua-handle", handle, "id", id, "inbound", inbound, + "own-ip", own_ip, + "nua-handle", handle, NULL); } diff --git a/plugins/sip/calls-sip-call.h b/plugins/sip/calls-sip-call.h index ea12b04..5b8e593 100644 --- a/plugins/sip/calls-sip-call.h +++ b/plugins/sip/calls-sip-call.h @@ -37,6 +37,7 @@ G_DECLARE_FINAL_TYPE (CallsSipCall, calls_sip_call, CALLS, SIP_CALL, CallsCall) CallsSipCall *calls_sip_call_new (const gchar *number, gboolean inbound, + const char *own_ip, nua_handle_t *handle); void calls_sip_call_setup_remote_media_connection (CallsSipCall *self, const char *remote, diff --git a/plugins/sip/calls-sip-media-manager.c b/plugins/sip/calls-sip-media-manager.c index 27d7b49..759be4e 100644 --- a/plugins/sip/calls-sip-media-manager.c +++ b/plugins/sip/calls-sip-media-manager.c @@ -52,6 +52,9 @@ typedef struct _CallsSipMediaManager GObject parent; char *session_ip; + int address_family; + struct addrinfo hints; + CallsSettings *settings; GList *preferred_codecs; } CallsSipMediaManager; @@ -59,6 +62,34 @@ typedef struct _CallsSipMediaManager G_DEFINE_TYPE (CallsSipMediaManager, calls_sip_media_manager, G_TYPE_OBJECT); +static const char * +get_address_family_string (CallsSipMediaManager *self, + const char *ip) +{ + struct addrinfo *result = NULL; + const char *family; + + if (getaddrinfo (ip, NULL, &self->hints, &result) != 0) { + g_warning ("Cannot parse session IP %s", ip); + return NULL; + } + + /* check if IP is IPv4 or IPv6. We need to specify this in the c= line of SDP */ + self->address_family = result->ai_family; + + if (result->ai_family == AF_INET) + family = "IP4"; + else if (result->ai_family == AF_INET6) + family = "IP6"; + else + family = NULL; + + freeaddrinfo (result); + + return family; +} + + static void on_notify_preferred_audio_codecs (CallsSipMediaManager *self) { @@ -167,6 +198,10 @@ calls_sip_media_manager_init (CallsSipMediaManager *self) G_CALLBACK (on_notify_preferred_audio_codecs), self); on_notify_preferred_audio_codecs (self); + + /* Hints are used with getaddrinfo() when setting the session IP */ + self->hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST; + self->hints.ai_family = AF_UNSPEC; } @@ -198,6 +233,7 @@ calls_sip_media_manager_default (void) */ char * calls_sip_media_manager_get_capabilities (CallsSipMediaManager *self, + const char *own_ip, guint port, gboolean use_srtp, GList *supported_codecs) @@ -206,6 +242,7 @@ calls_sip_media_manager_get_capabilities (CallsSipMediaManager *self, g_autoptr (GString) media_line = NULL; g_autoptr (GString) attribute_lines = NULL; GList *node; + const char *address_family_string; g_return_val_if_fail (CALLS_IS_SIP_MEDIA_MANAGER (self), NULL); @@ -237,12 +274,16 @@ calls_sip_media_manager_get_capabilities (CallsSipMediaManager *self, g_string_append_printf (attribute_lines, "a=rtcp:%d\r\n", port + 1); done: - if (self->session_ip && *self->session_ip) + if (own_ip && *own_ip) + address_family_string = get_address_family_string (self, own_ip); + + if (own_ip && *own_ip && address_family_string) return g_strdup_printf ("v=0\r\n" - "s=%s\r\n" + "c=IN %s %s\r\n" "%s\r\n" "%s\r\n", - self->session_ip, + address_family_string, + own_ip, media_line->str, attribute_lines->str); else @@ -266,12 +307,14 @@ calls_sip_media_manager_get_capabilities (CallsSipMediaManager *self, */ char * calls_sip_media_manager_static_capabilities (CallsSipMediaManager *self, + const char *own_ip, guint port, gboolean use_srtp) { g_return_val_if_fail (CALLS_IS_SIP_MEDIA_MANAGER (self), NULL); return calls_sip_media_manager_get_capabilities (self, + own_ip, port, use_srtp, self->preferred_codecs); @@ -348,7 +391,21 @@ calls_sip_media_manager_set_session_ip (CallsSipMediaManager *self, g_clear_pointer (&self->session_ip, g_free); if (session_ip && *session_ip) { + struct addrinfo *result = NULL; + + if (getaddrinfo (session_ip, NULL, &self->hints, &result) != 0) { + g_warning ("Cannot parse session IP %s", session_ip); + return; + } + + /* check if IP is IPv4 or IPv6. We need to specify this in the c= line of SDP */ + self->address_family = result->ai_family; + g_debug ("Setting session IP to %s", session_ip); + + g_free (self->session_ip); self->session_ip = g_strdup (session_ip); + + freeaddrinfo (result); } } diff --git a/plugins/sip/calls-sip-media-manager.h b/plugins/sip/calls-sip-media-manager.h index 428c49d..279e727 100644 --- a/plugins/sip/calls-sip-media-manager.h +++ b/plugins/sip/calls-sip-media-manager.h @@ -39,14 +39,16 @@ G_DECLARE_FINAL_TYPE (CallsSipMediaManager, calls_sip_media_manager, CALLS, SIP_ CallsSipMediaManager* calls_sip_media_manager_default (void); gchar* calls_sip_media_manager_get_capabilities (CallsSipMediaManager *self, - guint port, - gboolean use_srtp, - GList *supported_codecs); + const char *own_ip, + guint port, + gboolean use_srtp, + GList *supported_codecs); gchar* calls_sip_media_manager_static_capabilities (CallsSipMediaManager *self, - guint port, - gboolean use_srtp); + const char *own_ip, + guint port, + gboolean use_srtp); gboolean calls_sip_media_manager_supports_media (CallsSipMediaManager *self, - const char *media_type); + const char *media_type); MediaCodecInfo* get_best_codec (CallsSipMediaManager *self); GList * calls_sip_media_manager_codec_candidates (CallsSipMediaManager *self); GList * calls_sip_media_manager_get_codecs_from_sdp (CallsSipMediaManager *self, diff --git a/plugins/sip/calls-sip-origin.c b/plugins/sip/calls-sip-origin.c index 5890d94..fc79a5e 100644 --- a/plugins/sip/calls-sip-origin.c +++ b/plugins/sip/calls-sip-origin.c @@ -111,6 +111,8 @@ struct _CallsSipOrigin gboolean auto_connect; gboolean direct_mode; gboolean can_tel; + + char *own_ip; gint local_port; const char *protocol_prefix; @@ -229,7 +231,7 @@ add_call (CallsSipOrigin *self, call_address = address_split[1]; } - sip_call = calls_sip_call_new (call_address, inbound, handle); + sip_call = calls_sip_call_new (call_address, inbound, self->own_ip, handle); g_assert (sip_call != NULL); if (self->oper->call_handle) @@ -251,6 +253,7 @@ add_call (CallsSipOrigin *self, calls_sip_call_setup_local_media_connection (sip_call, local_port, local_port + 1); local_sdp = calls_sip_media_manager_static_capabilities (self->media_manager, + self->own_ip, local_port, FALSE); @@ -424,9 +427,10 @@ sip_r_register (int status, g_debug ("REGISTER successful"); origin->state = CALLS_ACCOUNT_ONLINE; nua_get_params (nua, TAG_ANY (), TAG_END()); + if (sip->sip_contact && sip->sip_contact->m_url && sip->sip_contact->m_url->url_host) { - calls_sip_media_manager_set_session_ip (origin->media_manager, - sip->sip_contact->m_url->url_host); + g_free (origin->own_ip); + origin->own_ip = g_strdup (sip->sip_contact->m_url->url_host); } } else if (status == 401 || status == 407) { @@ -1317,6 +1321,8 @@ calls_sip_origin_dispose (GObject *object) { CallsSipOrigin *self = CALLS_SIP_ORIGIN (object); + g_clear_pointer (&self->own_ip, g_free); + if (!self->use_direct_connection && self->state == CALLS_ACCOUNT_ONLINE) go_online (CALLS_ACCOUNT (self), FALSE); diff --git a/tests/test-sip.c b/tests/test-sip.c index 8a19cff..d0847b8 100644 --- a/tests/test-sip.c +++ b/tests/test-sip.c @@ -445,7 +445,7 @@ test_sip_media_manager (void) /* PCMA RTP */ sdp_message = - calls_sip_media_manager_get_capabilities (manager, 40002, FALSE, codecs); + calls_sip_media_manager_get_capabilities (manager, NULL, 40002, FALSE, codecs); g_assert_true (sdp_message); g_assert_true (find_string_in_sdp_message (sdp_message, @@ -461,7 +461,7 @@ test_sip_media_manager (void) /* PCMA SRTP */ sdp_message = - calls_sip_media_manager_get_capabilities (manager, 42002, TRUE, codecs); + calls_sip_media_manager_get_capabilities (manager, NULL, 42002, TRUE, codecs); g_assert_true (sdp_message); g_assert_true (find_string_in_sdp_message (sdp_message, "m=audio 42002 RTP/SAVP 8")); @@ -475,7 +475,7 @@ test_sip_media_manager (void) codecs = g_list_append (NULL, media_codec_by_name ("G722")); sdp_message = - calls_sip_media_manager_get_capabilities (manager, 42042, FALSE, codecs); + calls_sip_media_manager_get_capabilities (manager, NULL, 42042, FALSE, codecs); g_assert_true (sdp_message); g_assert_true (find_string_in_sdp_message (sdp_message, @@ -496,7 +496,7 @@ test_sip_media_manager (void) codecs = g_list_append (codecs, media_codec_by_name ("PCMA")); sdp_message = - calls_sip_media_manager_get_capabilities (manager, 33340, FALSE, codecs); + calls_sip_media_manager_get_capabilities (manager, NULL, 33340, FALSE, codecs); g_assert_true (sdp_message); g_assert_true (find_string_in_sdp_message (sdp_message, @@ -520,7 +520,7 @@ test_sip_media_manager (void) codecs = g_list_append (codecs, media_codec_by_name ("PCMU")); sdp_message = - calls_sip_media_manager_get_capabilities (manager, 18098, TRUE, codecs); + calls_sip_media_manager_get_capabilities (manager, NULL, 18098, TRUE, codecs); g_assert_true (sdp_message); g_assert_true (find_string_in_sdp_message (sdp_message, @@ -535,7 +535,7 @@ test_sip_media_manager (void) g_test_expect_message ("CallsSipMediaManager", G_LOG_LEVEL_WARNING, "No supported codecs found. Can't build meaningful SDP message"); sdp_message = - calls_sip_media_manager_get_capabilities (manager, 25048, FALSE, NULL); + calls_sip_media_manager_get_capabilities (manager, NULL, 25048, FALSE, NULL); g_test_assert_expected_messages (); g_assert_true (sdp_message);