]> sjero.net Git - linphone/commitdiff
Merge branch 'master' of git.linphone.org:linphone into upnp
authorYann Diorcet <yann.diorcet@belledonne-communications.com>
Thu, 17 Jan 2013 14:34:58 +0000 (15:34 +0100)
committerYann Diorcet <yann.diorcet@belledonne-communications.com>
Thu, 17 Jan 2013 14:34:58 +0000 (15:34 +0100)
Conflicts:
coreapi/linphone_tunnel.cc
mediastreamer2

20 files changed:
configure.ac
console/commands.c
coreapi/Makefile.am
coreapi/callbacks.c
coreapi/linphone_tunnel.cc
coreapi/linphone_tunnel.h
coreapi/linphone_tunnel_config.c [new file with mode: 0644]
coreapi/linphone_tunnel_stubs.c [new file with mode: 0644]
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/misc.c
coreapi/private.h
coreapi/proxy.c
coreapi/upnp.c [new file with mode: 0644]
coreapi/upnp.h [new file with mode: 0644]
gtk/Makefile.am
gtk/parameters.ui
gtk/propertybox.c
mediastreamer2

index 1d8f92278e81e4d598fb275a9eda0d3831ec3a9c..9e6364c37e6d8bf4453b30177be8a97092eb6572 100644 (file)
@@ -148,6 +148,32 @@ AC_ARG_ENABLE(tools,
         *) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
       esac],[build_tools=check])
 
+dnl check for installed version of libupnp
+AC_ARG_ENABLE(upnp,
+      [AS_HELP_STRING([--disable-upnp], [Disable uPnP support])],
+      [case "${enableval}" in
+        yes) build_upnp=true ;;
+        no)  build_upnp=false ;;
+        *) AC_MSG_ERROR(bad value ${enableval} for --disable-upnp) ;;
+      esac],[build_upnp=auto])
+
+if test "$build_upnp" != "false" ; then
+PKG_CHECK_MODULES([LIBUPNP], [libupnp], [build_upnp=true],
+       [
+               if test "$build_upnp" == "true" ; then
+                       AC_MSG_ERROR([libupnp not found.])
+               else
+                       build_upnp=false
+               fi
+       ])
+
+fi
+
+AM_CONDITIONAL(BUILD_UPNP, test x$build_upnp != xfalse)
+if test "$build_upnp" != "false" ; then
+       AC_DEFINE(BUILD_UPNP, 1, [Define if upnp enabled])
+fi
+
 dnl check libxml2 (needed for tools)
 if test "$build_tools" != "false" ; then
        PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[],
index 472531795efa2d9655afdcc0412226533586d9ee..3ec2ed65b2a09266e6f716d50f0f79e3ae4b0498 100644 (file)
@@ -206,7 +206,7 @@ static LPC_COMMAND commands[] = {
        { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
                "'autoanswer'       \t: show current autoanswer mode\n"
                "'autoanswer enable'\t: enable autoanswer mode\n"
-               "'autoanswer disable'\t: disable autoanswer mode \n"},
+               "'autoanswer disable'\t: disable autoanswer mode��\n"},
        { "proxy", lpc_cmd_proxy, "Manage proxies",
                "'proxy list' : list all proxy setups.\n"
                "'proxy add' : add a new proxy setup.\n"
@@ -896,6 +896,9 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
                case LinphonePolicyUseIce:
                        linphonec_out("Using ice with stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
                        break;
+               case LinphonePolicyUseUpnp:
+                       linphonec_out("Using uPnP IGD protocol\n");
+                       break;
        }
        return 1;
 }
index 790612cab48b7b59ece5d5664e575cc6b78b077e..eab65b147577d072245bb4fb5c60a00908a815ec 100644 (file)
@@ -47,15 +47,21 @@ liblinphone_la_SOURCES=\
        lsd.c linphonecore_utils.h \
        ec-calibrator.c \
        conference.c \
-       linphone_tunnel.cc \
        $(GITVERSION_FILE)
+
+if BUILD_UPNP
+liblinphone_la_SOURCES+=upnp.c upnp.h
+endif
        
 if BUILD_WIZARD
 liblinphone_la_SOURCES+=sipwizard.c 
 endif
 
+liblinphone_la_SOURCES+=linphone_tunnel_config.c
 if BUILD_TUNNEL
-liblinphone_la_SOURCES+=TunnelManager.cc TunnelManager.hh 
+liblinphone_la_SOURCES+=linphone_tunnel.cc TunnelManager.cc TunnelManager.hh 
+else
+liblinphone_la_SOURCES+=linphone_tunnel_stubs.c
 endif
 
 
index 1f7ff42fd19636c1c02678b74f7bc70e0cdaca41..ab5fb780bb27617f82189935ddeab3740173d624 100644 (file)
@@ -261,6 +261,13 @@ static void call_received(SalOp *h){
                ms_message("Defer ringing to gather ICE candidates");
                return;
        }
+#ifdef BUILD_UPNP
+       if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) && (call->upnp_session != NULL)) {
+               /* Defer ringing until the end of the ICE candidates gathering process. */
+               ms_message("Defer ringing to gather uPnP candidates");
+               return;
+       }
+#endif //BUILD_UPNP
 
        linphone_core_notify_incoming_call(lc,call);
 }
@@ -334,6 +341,11 @@ static void call_accepted(SalOp *op){
        if (call->ice_session != NULL) {
                linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
        }
+#ifdef BUILD_UPNP
+       if (call->upnp_session != NULL) {
+               linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op));
+       }
+#endif //BUILD_UPNP
 
        md=sal_call_get_final_media_description(op);
        call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
@@ -425,6 +437,12 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){
                linphone_core_update_ice_from_remote_media_description(call,rmd);
                linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session);
        }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_upnp_from_remote_media_description(call, rmd);
+               linphone_core_update_local_media_description_from_upnp(call->localdesc,call->upnp_session);
+       }
+#endif //BUILD_UPNP
        sal_call_accept(call->op);
        md=sal_call_get_final_media_description(call->op);
        if (md && !sal_media_description_empty(md))
@@ -520,6 +538,10 @@ static void call_terminated(SalOp *op, const char *from){
        if (lc->vtable.display_status!=NULL)
                lc->vtable.display_status(lc,_("Call terminated."));
 
+#ifdef BUILD_UPNP
+       linphone_call_delete_upnp_session(call);
+#endif //BUILD_UPNP
+
        linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
 }
 
@@ -616,6 +638,11 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
                /*resume to the call that send us the refer automatically*/
                linphone_core_resume_call(lc,call->referer);
        }
+
+#ifdef BUILD_UPNP
+       linphone_call_delete_upnp_session(call);
+#endif //BUILD_UPNP
+
        if (sr == SalReasonDeclined) {
                call->reason=LinphoneReasonDeclined;
                linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
index c76441f5a7f5f3b321ba50d5e8499a6f89ab8bc4..f0de56694d02a564cf1ea8376a981d2b584b6c8b 100644 (file)
@@ -23,9 +23,7 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifdef TUNNEL_ENABLED
 #include "TunnelManager.hh"
-#endif
 #include "linphone_tunnel.h"
 #include "linphonecore.h"
 #include "private.h"
@@ -35,67 +33,6 @@ LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){
        return lc->tunnel;
 }
 
-struct _LinphoneTunnelConfig {
-       char *host;
-       int port;
-       int remote_udp_mirror_port;
-       int delay;      
-};
-
-LinphoneTunnelConfig *linphone_tunnel_config_new() {
-       LinphoneTunnelConfig *ltc = ms_new0(LinphoneTunnelConfig,1);
-       ltc->remote_udp_mirror_port = 12345;
-       ltc->delay = 1000;
-       return ltc;
-}
-
-void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host) {
-       if(tunnel->host != NULL) {
-               ms_free(tunnel->host);
-               tunnel->host = NULL;
-       }
-       if(host != NULL && strlen(host)) {
-               tunnel->host = ms_strdup(host);
-       }
-}
-
-const char *linphone_tunnel_config_get_host(LinphoneTunnelConfig *tunnel) {
-       return tunnel->host;
-}
-
-void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port) {
-       tunnel->port = port;
-}
-
-int linphone_tunnel_config_get_port(LinphoneTunnelConfig *tunnel) {
-       return tunnel->port;
-}
-
-void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port) {
-       tunnel->remote_udp_mirror_port = remote_udp_mirror_port;
-}
-
-int linphone_tunnel_config_get_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel) {
-       return tunnel->remote_udp_mirror_port;
-}
-
-void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay) {
-       tunnel->delay = delay;
-}
-
-int linphone_tunnel_config_get_delay(LinphoneTunnelConfig *tunnel) {
-       return tunnel->delay;
-}
-
-void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel) {
-       if(tunnel->host != NULL) {
-               ms_free(tunnel->host);
-       }
-       ms_free(tunnel);
-}
-
-#ifdef TUNNEL_ENABLED
-
 struct _LinphoneTunnel {
        belledonnecomm::TunnelManager *manager;
        MSList *config_list;
@@ -122,16 +59,16 @@ void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
 
 static char *linphone_tunnel_config_to_string(const LinphoneTunnelConfig *tunnel_config) {
        char *str = NULL;
-       if(tunnel_config->remote_udp_mirror_port != -1) {
+       if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) != -1) {
                str = ms_strdup_printf("%s:%d:%d:%d", 
-                       tunnel_config->host,
-                       tunnel_config->port,
-                       tunnel_config->remote_udp_mirror_port,
-                       tunnel_config->delay);
+                       linphone_tunnel_config_get_host(tunnel_config),
+                       linphone_tunnel_config_get_port(tunnel_config),
+                       linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
+                       linphone_tunnel_config_get_delay(tunnel_config));
        } else {
                str = ms_strdup_printf("%s:%d",
-                       tunnel_config->host,
-                       tunnel_config->port);
+                       linphone_tunnel_config_get_host(tunnel_config),
+                       linphone_tunnel_config_get_port(tunnel_config));
        }
        return str;
 }
@@ -209,11 +146,14 @@ static void linphone_tunnel_save_config(LinphoneTunnel *tunnel) {
 
 
 static void linphone_tunnel_add_server_intern(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config) {
-       if(tunnel_config->remote_udp_mirror_port == -1) {
-               bcTunnel(tunnel)->addServer(tunnel_config->host, tunnel_config->port);
+       if(linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config) == -1) {
+               bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), 
+                       linphone_tunnel_config_get_port(tunnel_config));
        } else {
-               bcTunnel(tunnel)->addServer(tunnel_config->host, tunnel_config->port, 
-                       tunnel_config->remote_udp_mirror_port, tunnel_config->delay);
+               bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config), 
+                       linphone_tunnel_config_get_port(tunnel_config), 
+                       linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config), 
+                       linphone_tunnel_config_get_delay(tunnel_config));
        }
        tunnel->config_list = ms_list_append(tunnel->config_list, tunnel_config);
 }
@@ -385,60 +325,3 @@ void linphone_tunnel_configure(LinphoneTunnel *tunnel){
        linphone_tunnel_enable(tunnel, enabled);
 }
 
-#else
-
-/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/
-
-void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
-}
-
-
-void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){
-}
-
-void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){
-}
-
-const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){
-       return NULL;
-}
-
-void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){
-}
-
-void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){
-}
-
-bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){
-       return FALSE;
-}
-
-
-void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){
-}
-
-void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){
-}
-
-void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){
-}
-
-void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){
-}
-
-void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){
-}
-
-void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){
-}
-
-void linphone_tunnel_configure(LinphoneTunnel *tunnel){
-}
-
-
-#endif
-
-
-
-
-
index 03c568e4e4aca24d9e2673f536ea9f20fa8349bd..e42a054dcc4023bb9385979eb788f28b3f650c0f 100644 (file)
@@ -68,7 +68,7 @@ void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *h
  *
  * @param tunnel configuration object
  */
-const char *linphone_tunnel_config_get_host(LinphoneTunnelConfig *tunnel);
+const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel);
 
 /**
  * Set tls port of server.
@@ -83,7 +83,7 @@ void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port);
  *
  * @param tunnel configuration object
  */
-int linphone_tunnel_config_get_port(LinphoneTunnelConfig *tunnel);
+int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel);
 
 /**
  * Set the remote port on the tunnel server side used to test udp reachability. 
@@ -98,7 +98,7 @@ void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tun
  *
  * @param tunnel configuration object
  */
-int linphone_tunnel_config_get_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel);
+int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel);
 
 /**
  * Set the udp packet round trip delay in ms for a tunnel configuration.
@@ -113,7 +113,7 @@ void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay);
  * 
  * @param tunnel configuration object
  */
-int linphone_tunnel_config_get_delay(LinphoneTunnelConfig *tunnel);
+int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel);
 
 /**
  * Destroy a tunnel configuration
diff --git a/coreapi/linphone_tunnel_config.c b/coreapi/linphone_tunnel_config.c
new file mode 100644 (file)
index 0000000..f385680
--- /dev/null
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *            linphone_tunnel_config.c
+ *
+ *  Copyright  2012  Belledonne Communications
+ ****************************************************************************/
+
+/*
+ *  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "linphone_tunnel.h"
+
+struct _LinphoneTunnelConfig {
+       char *host;
+       int port;
+       int remote_udp_mirror_port;
+       int delay;      
+};
+
+LinphoneTunnelConfig *linphone_tunnel_config_new() {
+       LinphoneTunnelConfig *ltc = ms_new0(LinphoneTunnelConfig,1);
+       ltc->remote_udp_mirror_port = 12345;
+       ltc->delay = 1000;
+       return ltc;
+}
+
+void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host) {
+       if(tunnel->host != NULL) {
+               ms_free(tunnel->host);
+               tunnel->host = NULL;
+       }
+       if(host != NULL && strlen(host)) {
+               tunnel->host = ms_strdup(host);
+       }
+}
+
+const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel) {
+       return tunnel->host;
+}
+
+void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port) {
+       tunnel->port = port;
+}
+
+int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel) {
+       return tunnel->port;
+}
+
+void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port) {
+       tunnel->remote_udp_mirror_port = remote_udp_mirror_port;
+}
+
+int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel) {
+       return tunnel->remote_udp_mirror_port;
+}
+
+void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay) {
+       tunnel->delay = delay;
+}
+
+int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel) {
+       return tunnel->delay;
+}
+
+void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel) {
+       if(tunnel->host != NULL) {
+               ms_free(tunnel->host);
+       }
+       ms_free(tunnel);
+}
+
diff --git a/coreapi/linphone_tunnel_stubs.c b/coreapi/linphone_tunnel_stubs.c
new file mode 100644 (file)
index 0000000..0560b39
--- /dev/null
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *            linphone_tunnel.cc
+ *
+ *  Fri Dec 9, 2011
+ *  Copyright  2011  Belledonne Communications
+ *  Author: Guillaume Beraudo
+ *  Email: guillaume dot beraudo at linphone dot org
+ ****************************************************************************/
+
+/*
+ *  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "linphone_tunnel.h"
+#include "linphonecore.h"
+#include "private.h"
+#include "lpconfig.h"
+
+
+LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){
+       return lc->tunnel;
+}
+
+/*stubs to avoid to have #ifdef TUNNEL_ENABLED in upper layers*/
+
+void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
+}
+
+
+void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){
+}
+
+void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){
+}
+
+const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel){
+        return NULL;
+}
+
+void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){
+}
+
+void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){
+}
+
+bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel){
+        return FALSE;
+}
+
+
+void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler){
+}
+
+void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel *tunnel, const char* username,const char* passwd){
+}
+
+void linphone_tunnel_set_http_proxy(LinphoneTunnel*tunnel, const char *host, int port, const char* username,const char* passwd){
+}
+
+void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd){
+}
+
+void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){
+}
+
+void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){
+}
+
+void linphone_tunnel_configure(LinphoneTunnel *tunnel){
+}
+
index 3bf93f78e8afd68d52d646da6dab448ebe1931f0..f4525399be2895d6f28c6e22b864790c151ffb17 100644 (file)
@@ -283,6 +283,11 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
                linphone_core_update_local_media_description_from_ice(md, call->ice_session);
                linphone_core_update_ice_state_in_call_stats(call);
        }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
+       }
+#endif  //BUILD_UPNP
        linphone_address_destroy(addr);
        call->localdesc=md;
        if (old_md) sal_media_description_unref(old_md);
@@ -449,6 +454,11 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
        if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
                call->ping_time=linphone_core_run_stun_tests(call->core,call);
        }
+#ifdef BUILD_UPNP
+       if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
+               call->upnp_session = linphone_upnp_session_new(call);
+       }
+#endif //BUILD_UPNP
        call->camera_active=params->has_video;
        
        discover_mtu(lc,linphone_address_get_domain (to));
@@ -510,6 +520,19 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
                case LinphonePolicyUseStun:
                        call->ping_time=linphone_core_run_stun_tests(call->core,call);
                        /* No break to also destroy ice session in this case. */
+                       break;
+               case LinphonePolicyUseUpnp:
+#ifdef BUILD_UPNP
+               call->upnp_session = linphone_upnp_session_new(call);
+               if (call->upnp_session != NULL) {
+                       linphone_call_init_media_streams(call);
+                       if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
+                               /* uPnP port mappings failed, proceed with the call anyway. */
+                               linphone_call_delete_upnp_session(call);
+                       }
+               }
+#endif //BUILD_UPNP
+                       break;
                default:
                        break;
        }
@@ -658,6 +681,9 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
 
 static void linphone_call_destroy(LinphoneCall *obj)
 {
+#ifdef BUILD_UPNP
+       linphone_call_delete_upnp_session(obj);
+#endif //BUILD_UPNP
        linphone_call_delete_ice_session(obj);
        if (obj->op!=NULL) {
                sal_op_release(obj->op);
@@ -1715,6 +1741,15 @@ void linphone_call_delete_ice_session(LinphoneCall *call){
        }
 }
 
+#ifdef BUILD_UPNP
+void linphone_call_delete_upnp_session(LinphoneCall *call){
+       if(call->upnp_session!=NULL) {
+               linphone_upnp_session_destroy(call->upnp_session);
+               call->upnp_session=NULL;
+       }
+}
+#endif //BUILD_UPNP
+
 static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
        audio_stream_get_local_rtp_stats (st,&log->local_stats);
        log->quality=audio_stream_get_average_quality_rating(st);
@@ -2025,6 +2060,11 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
                report_bandwidth(call,as,vs);
                ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
        }
+
+#ifdef BUILD_UPNP
+       linphone_upnp_call_process(call);
+#endif //BUILD_UPNP
+
 #ifdef VIDEO_ENABLED
        if (call->videostream!=NULL) {
                OrtpEvent *ev;
index ee0be33be22e2cfe0e59c2c9b17fcdad1d111b76..9545af23ffc2cdfec817f7769838e70c1360133d 100644 (file)
@@ -67,7 +67,6 @@ static void linphone_core_free_hooks(LinphoneCore *lc);
 #include "enum.h"
 
 const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
-void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result);
 static void toggle_video_preview(LinphoneCore *lc, bool_t val);
 
 /* relative path where is stored local ring*/
@@ -1224,6 +1223,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
        lc->tunnel=linphone_core_tunnel_new(lc);
        if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
 #endif
+#ifdef BUILD_UPNP
+       lc->upnp = linphone_upnp_context_new(lc);
+#endif  //BUILD_UPNP
        if (lc->vtable.display_status)
                lc->vtable.display_status(lc,_("Ready"));
        lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
@@ -1317,6 +1319,14 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result
                strncpy(result,ip,LINPHONE_IPADDR_SIZE);
                return;
        }
+#ifdef BUILD_UPNP
+       else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
+                       linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
+               ip = linphone_upnp_context_get_external_ipaddress(lc->upnp);
+               strncpy(result,ip,LINPHONE_IPADDR_SIZE);
+               return;
+       }
+#endif  //BUILD_UPNP
        if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0)
                return;
        /*else fallback to SAL routine that will attempt to find the most realistic interface */
@@ -2008,6 +2018,12 @@ void linphone_core_iterate(LinphoneCore *lc){
                                linphone_call_delete_ice_session(call);
                                linphone_call_stop_media_streams_for_ice_gathering(call);
                        }
+#ifdef BUILD_UPNP
+                       if (call->upnp_session != NULL) {
+                               ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway.");
+                               linphone_call_delete_upnp_session(call);
+                       }
+#endif //BUILD_UPNP
                        linphone_core_start_invite(lc,call);
                }
                if (call->state==LinphoneCallIncomingReceived){
@@ -2261,6 +2277,7 @@ static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphonePr
 
 int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){
        bool_t ice_ready = FALSE;
+       bool_t upnp_ready = FALSE;
        bool_t ping_ready = FALSE;
 
        if (call->ice_session != NULL) {
@@ -2268,13 +2285,20 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c
        } else {
                ice_ready = TRUE;
        }
+#ifdef BUILD_UPNP
+       if (call->upnp_session != NULL) {
+               if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE;
+       } else {
+               upnp_ready = TRUE;
+       }
+#endif //BUILD_UPNP
        if (call->ping_op != NULL) {
                if (call->ping_replied == TRUE) ping_ready = TRUE;
        } else {
                ping_ready = TRUE;
        }
 
-       if ((ice_ready == TRUE) && (ping_ready == TRUE)) {
+       if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) {
                return linphone_core_start_invite(lc, call);
        }
        return 0;
@@ -2422,7 +2446,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
        LinphoneAddress *parsed_url2=NULL;
        char *real_url=NULL;
        LinphoneCall *call;
-       bool_t use_ice = FALSE;
+       bool_t defer = FALSE;
 
        linphone_core_preempt_sound_resources(lc);
        
@@ -2475,9 +2499,21 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
                        linphone_call_delete_ice_session(call);
                        linphone_call_stop_media_streams_for_ice_gathering(call);
                } else {
-                       use_ice = TRUE;
+                       defer = TRUE;
                }
        }
+       else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
+#ifdef BUILD_UPNP
+               linphone_call_init_media_streams(call);
+               call->start_time=time(NULL);
+               if (linphone_core_update_upnp(lc,call)<0) {
+                       /* uPnP port mappings failed, proceed with the call anyway. */
+                       linphone_call_delete_upnp_session(call);
+               } else {
+                       defer = TRUE;
+               }
+#endif //BUILD_UPNP
+       }
 
        if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
                /*defer the start of the call after the OPTIONS ping*/
@@ -2487,7 +2523,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
                sal_op_set_user_pointer(call->ping_op,call);
                call->start_time=time(NULL);
        }else{
-               if (use_ice==FALSE) linphone_core_start_invite(lc,call);
+               if (defer==FALSE) linphone_core_start_invite(lc,call);
        }
 
        if (real_url!=NULL) ms_free(real_url);
@@ -2641,9 +2677,14 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
 int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
        const char *subject;
        call->camera_active=call->params.has_video;
-       if (call->ice_session != NULL)
+       if (call->ice_session != NULL) {
                linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
-
+       }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+       }
+#endif //BUILD_UPNP
        if (call->params.in_conference){
                subject="Conference";
        }else{
@@ -2675,21 +2716,53 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
                linphone_call_set_state(call,LinphoneCallUpdating,"Updating call");
 #ifdef VIDEO_ENABLED
                bool_t has_video = call->params.has_video;
-               if ((call->ice_session != NULL) && (call->videostream != NULL) && !params->has_video) {
-                       ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list);
-                       call->videostream->ms.ice_check_list = NULL;
+
+               // Video removing
+               if((call->videostream != NULL) && !params->has_video) {
+                       if (call->ice_session != NULL) {
+                               ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list);
+                               call->videostream->ms.ice_check_list = NULL;
+                       }
+#ifdef BUILD_UPNP
+                       if(call->upnp_session != NULL) {
+                               if (linphone_core_update_upnp(lc, call)<0) {
+                                       /* uPnP port mappings failed, proceed with the call anyway. */
+                                       linphone_call_delete_upnp_session(call);
+                               }
+                       }
+#endif //BUILD_UPNP
                }
+
                call->params = *params;
                linphone_call_make_local_media_description(lc, call);
-               if ((call->ice_session != NULL) && !has_video && call->params.has_video) {
-                       /* Defer call update until the ICE candidates gathering process has finished. */
-                       ms_message("Defer call update to gather ICE candidates");
-                       linphone_call_init_video_stream(call);
-                       video_stream_prepare_video(call->videostream);
-                       if (linphone_core_gather_ice_candidates(lc,call)<0) {
-                               /* Ice candidates gathering failed, proceed with the call anyway. */
-                               linphone_call_delete_ice_session(call);
-                       } else return err;
+
+               // Video adding
+               if (!has_video && call->params.has_video) {
+                       if (call->ice_session != NULL) {
+                               /* Defer call update until the ICE candidates gathering process has finished. */
+                               ms_message("Defer call update to gather ICE candidates");
+                               linphone_call_init_video_stream(call);
+                               video_stream_prepare_video(call->videostream);
+                               if (linphone_core_gather_ice_candidates(lc,call)<0) {
+                                       /* Ice candidates gathering failed, proceed with the call anyway. */
+                                       linphone_call_delete_ice_session(call);
+                               } else {
+                                       return err;
+                               }
+                       }
+#ifdef BUILD_UPNP
+                       if(call->upnp_session != NULL) {
+                               ms_message("Defer call update to add uPnP port mappings");
+                               linphone_call_init_video_stream(call);
+                               video_stream_prepare_video(call->videostream);
+                               if (linphone_core_update_upnp(lc, call)<0) {
+                                       /* uPnP port mappings failed, proceed with the call anyway. */
+                                       linphone_call_delete_upnp_session(call);
+                               } else {
+                                       return err;
+                               }
+                       }
+#endif //BUILD_UPNP
                }
 #endif
                err = linphone_core_start_update_call(lc, call);
@@ -2739,6 +2812,11 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
                }
                linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
        }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+       }
+#endif //BUILD_UPNP
        sal_call_set_local_media_description(call->op,call->localdesc);
        sal_call_accept(call->op);
        md=sal_call_get_final_media_description(call->op);
@@ -2805,8 +2883,25 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
                                } else return 0;
                        }
                }
-#endif
+#endif //VIDEO_ENABLED
        }
+
+#if BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
+#ifdef VIDEO_ENABLED
+               if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
+                       linphone_call_init_video_stream(call);
+                       video_stream_prepare_video(call->videostream);
+                       if (linphone_core_update_upnp(lc, call)<0) {
+                               /* uPnP update failed, proceed with the call anyway. */
+                               linphone_call_delete_upnp_session(call);
+                       } else return 0;
+               }
+#endif //VIDEO_ENABLED
+       }
+#endif //BUILD_UPNP
+
        linphone_core_start_accept_call_update(lc, call);
        return 0;
 }
@@ -2944,6 +3039,11 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e
                lc->ringstream=NULL;
        }
        linphone_call_stop_media_streams(call);
+
+#ifdef BUILD_UPNP
+       linphone_call_delete_upnp_session(call);
+#endif //BUILD_UPNP
+
        if (lc->vtable.display_status!=NULL)
                lc->vtable.display_status(lc,_("Call aborted") );
        linphone_call_set_state(call,LinphoneCallError,error);
@@ -2962,6 +3062,11 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){
        }
 
        linphone_call_stop_media_streams(call);
+
+#ifdef BUILD_UPNP
+       linphone_call_delete_upnp_session(call);
+#endif //BUILD_UPNP
+
        if (lc->vtable.display_status!=NULL)
                lc->vtable.display_status(lc,_("Call ended") );
        linphone_call_set_state(call,LinphoneCallEnd,"Call terminated");
@@ -3101,8 +3206,14 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call)
                return -1;
        }
        linphone_call_make_local_media_description(lc,call);
-       if (call->ice_session != NULL)
+       if (call->ice_session != NULL) {
                linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
+       }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+       }
+#endif //BUILD_UPNP
        if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){
                sal_media_description_set_dir(call->localdesc,SalStreamSendOnly);
                subject="Call on hold";
@@ -3180,8 +3291,14 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call)
        if (call->audiostream) audio_stream_play(call->audiostream, NULL);
 
        linphone_call_make_local_media_description(lc,the_call);
-       if (call->ice_session != NULL)
+       if (call->ice_session != NULL) {
                linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
+       }
+#ifdef BUILD_UPNP
+       if(call->upnp_session != NULL) {
+               linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+       }
+#endif //BUILD_UPNP
        sal_call_set_local_media_description(call->op,call->localdesc);
        sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
        if (call->params.in_conference && !call->current_params.in_conference) subject="Conference";
@@ -4892,6 +5009,12 @@ static void linphone_core_uninit(LinphoneCore *lc)
                usleep(50000);
 #endif
        }
+
+#ifdef BUILD_UPNP
+       linphone_upnp_context_destroy(lc->upnp);
+       lc->upnp = NULL;
+#endif  //BUILD_UPNP
+
        if (lc->friends)
                ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions);
        linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");
index 55198e319929fb2532e51ac140770748748d00fd..1003e9546acc4fc934cd0cbaf35decfdaccf55b6 100644 (file)
@@ -885,7 +885,8 @@ typedef enum _LinphoneFirewallPolicy{
        LinphonePolicyNoFirewall,
        LinphonePolicyUseNatAddress,
        LinphonePolicyUseStun,
-       LinphonePolicyUseIce
+       LinphonePolicyUseIce,
+       LinphonePolicyUseUpnp,
 } LinphoneFirewallPolicy;
 
 typedef enum _LinphoneWaitingState{
index 53f0d65cfb6d8115b31ed6f54b1a06e71cf9dabb..68d467599ce0e6e6934da913cf9236b0ed3bea80 100644 (file)
@@ -1021,14 +1021,15 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
                if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
                        && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK))
                {
-                       getnameinfo(ifp->ifa_addr,
+                       if(getnameinfo(ifp->ifa_addr,
                                                (type == AF_INET6) ?
                                                sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
-                                               address, size, NULL, 0, NI_NUMERICHOST);
-                       if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
-                               /*ms_message("getifaddrs() found %s",address);*/
-                               ret++;
-                               break;
+                                               address, size, NULL, 0, NI_NUMERICHOST) == 0) {
+                               if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
+                                       /*ms_message("getifaddrs() found %s",address);*/
+                                       ret++;
+                                       break;
+                               }
                        }
                }
        }
@@ -1099,26 +1100,26 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
 }
 
 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
-       strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
+        strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
 #ifdef HAVE_GETIFADDRS
-       if (dest==NULL) {
-               /*we use getifaddrs for lookup of default interface */
-               int found_ifs;
-       
-               found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
-               if (found_ifs==1){
-                       return 0;
-               }else if (found_ifs<=0){
-                       /*absolutely no network on this machine */
-                       return -1;
-               }
-       }
+        if (dest==NULL) {
+                /*we use getifaddrs for lookup of default interface */
+                int found_ifs;
+
+                found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
+                if (found_ifs==1){
+                        return 0;
+                }else if (found_ifs<=0){
+                        /*absolutely no network on this machine */
+                        return -1;
+                }
+        }
 #endif
-       /*else use connect to find the best local ip address */
-       if (type==AF_INET)
-               dest="87.98.157.38"; /*a public IP address*/
-       else dest="2a00:1450:8002::68";
-       return get_local_ip_for_with_connect(type,dest,result);
+        /*else use connect to find the best local ip address */
+        if (type==AF_INET)
+                dest="87.98.157.38"; /*a public IP address*/
+        else dest="2a00:1450:8002::68";
+        return get_local_ip_for_with_connect(type,dest,result);
 }
 
 #ifndef WIN32
index 29d31b7c6f62260c5534df2c34d238a17f11e7da..41449dc9e062ef1ba8fc93d255848f90fe68cea7 100644 (file)
 extern "C" {
 #endif
 #include "linphonecore.h"
+#include "linphonefriend.h"
 #include "linphone_tunnel.h"
 #include "linphonecore_utils.h"
 #include "sal.h"
+#include "sipsetup.h"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -38,6 +40,9 @@ extern "C" {
 #include "mediastreamer2/ice.h"
 #include "mediastreamer2/mediastream.h"
 #include "mediastreamer2/msconference.h"
+#ifdef BUILD_UPNP
+#include "upnp.h"
+#endif  //BUILD_UPNP
 
 #ifndef LIBLINPHONE_VERSION
 #define LIBLINPHONE_VERSION LINPHONE_VERSION
@@ -145,6 +150,9 @@ struct _LinphoneCall
        OrtpEvQueue *videostream_app_evq;
        CallCallbackObj nextVideoFrameDecoded;
        LinphoneCallStats stats[2];
+#ifdef BUILD_UPNP
+       UpnpSession *upnp_session;
+#endif //BUILD_UPNP
        IceSession *ice_session;
        LinphoneChatMessage* pending_message;
        int ping_time;
@@ -284,6 +292,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call);
 void linphone_call_stop_video_stream(LinphoneCall *call);
 void linphone_call_stop_media_streams(LinphoneCall *call);
 void linphone_call_delete_ice_session(LinphoneCall *call);
+void linphone_call_delete_upnp_session(LinphoneCall *call);
 void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
 void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md);
 
@@ -561,8 +570,8 @@ struct _LinphoneCore
        bool_t network_reachable;
        bool_t use_preview_window;
        
-        time_t network_last_check;
-        bool_t network_last_status;
+       time_t network_last_check;
+       bool_t network_last_status;
 
        bool_t ringstream_autorelease;
        bool_t pad[3];
@@ -571,13 +580,16 @@ struct _LinphoneCore
        LinphoneTunnel *tunnel;
        char* device_id;
        MSList *last_recv_msg_ids;
+#ifdef BUILD_UPNP
+       UpnpContext *upnp;
+#endif //BUILD_UPNP
 };
 
 LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);
 void linphone_tunnel_destroy(LinphoneTunnel *tunnel);
 void linphone_tunnel_configure(LinphoneTunnel *tunnel);
 void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler);
-       
+
 bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
 int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call);
 int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call);
@@ -645,6 +657,9 @@ void call_logs_write_to_config_file(LinphoneCore *lc);
 int linphone_core_get_edge_bw(LinphoneCore *lc);
 int linphone_core_get_edge_ptime(LinphoneCore *lc);
 
+int linphone_upnp_init(LinphoneCore *lc);
+void linphone_upnp_destroy(LinphoneCore *lc);
+
 #ifdef __cplusplus
 }
 #endif
index a109a3be2daac126e73c473198b36dcd53cce7db..bb6c8ec6a0100384dcb62d449e0cccca7e6d8078 100644 (file)
@@ -427,7 +427,7 @@ static dial_plan_t const dial_plans[]={
     {"Congo Democratic Republic"       ,"CD"           , "243"     , 9         , "00"  },
     {"Cook Islands"                 ,"CK"              , "682"     , 5         , "00"  },
     {"Costa Rica"                   ,"CR"              , "506"     , 8     , "00"      },
-    {"C\99te d'Ivoire"               ,"AD"               , "225"     , 8     , "00"  },
+    {"C�te d'Ivoire"             ,"AD"               , "225"     , 8     , "00"  },
     {"Croatia"                      ,"HR"              , "385"     , 9         , "00"  },
     {"Cuba"                         ,"CU"              , "53"      , 8     , "119" },
     {"Cyprus"                       ,"CY"              , "357"     , 8     , "00"      },
@@ -545,7 +545,7 @@ static dial_plan_t const dial_plans[]={
     {"Portugal"                     ,"PT"              , "351"     , 9     , "00"      },
     {"Puerto Rico"                  ,"PR"              , "1"       , 10        , "011" },
     {"Qatar"                        ,"QA"              , "974"     , 8     , "00"  },
-    {"R\8eunion Island"                          ,"RE"           , "262"     , 9     , "011"     },
+    {"R�union Island"                                ,"RE"           , "262"     , 9     , "011"     },
     {"Romania"                      ,"RO"              , "40"      , 9     , "00"      },
     {"Russian Federation"           ,"RU"              , "7"       , 10        , "8"   },
     {"Rwanda"                       ,"RW"              , "250"     , 9         , "00"  },
@@ -556,7 +556,7 @@ static dial_plan_t const dial_plans[]={
     {"Saint Vincent and the Grenadines","VC"   , "1"       , 10        , "011" },
     {"Samoa"                        ,"WS"              , "685"     , 7     , "0"       },
     {"San Marino"                   ,"SM"              , "378"     , 10        , "00"  },
-    {"S\8bo Tom\8e and Pr\92ncipe"        ,"ST"              , "239"     , 7         , "00"  },
+    {"S�o Tom� and Pr�ncipe"        ,"ST"                , "239"     , 7         , "00"  },
     {"Saudi Arabia"                 ,"SA"              , "966"     , 9         , "00"  },
     {"Senegal"                      ,"SN"              , "221"     , 9     , "00"  },
     {"Serbia"                       ,"RS"              , "381"     , 9     , "00"  },
diff --git a/coreapi/upnp.c b/coreapi/upnp.c
new file mode 100644 (file)
index 0000000..d2a9a24
--- /dev/null
@@ -0,0 +1,1060 @@
+/*
+linphone
+Copyright (C) 2012  Belledonne Communications SARL
+
+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 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "upnp.h"
+#include "private.h"
+
+#define UPNP_ADD_MAX_RETRY 4
+#define UPNP_REMOVE_MAX_RETRY 4
+#define UPNP_SECTION_NAME "uPnP"
+
+/* Define private types */
+typedef struct _LpItem{
+       char *key;
+       char *value;
+} LpItem;
+
+typedef struct _LpSection{
+       char *name;
+       MSList *items;
+} LpSection;
+
+typedef struct _LpConfig{
+       FILE *file;
+       char *filename;
+       MSList *sections;
+       int modified;
+       int readonly;
+} LpConfig;
+
+/* Declare private functions */
+LpSection *lp_config_find_section(LpConfig *lpconfig, const char *name);
+void lp_section_remove_item(LpSection *sec, LpItem *item);
+void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value);
+
+/*
+ * uPnP Definitions
+ */
+
+typedef struct _UpnpPortBinding {
+       ms_mutex_t mutex;
+       LinphoneUpnpState state;
+       upnp_igd_ip_protocol protocol;
+       char local_addr[LINPHONE_IPADDR_SIZE];
+       int local_port;
+       char external_addr[LINPHONE_IPADDR_SIZE];
+       int external_port;
+       int retry;
+       int ref;
+       bool_t to_remove;
+       bool_t to_add;
+} UpnpPortBinding;
+
+typedef struct _UpnpStream {
+       UpnpPortBinding *rtp;
+       UpnpPortBinding *rtcp;
+       LinphoneUpnpState state;
+} UpnpStream;
+
+struct _UpnpSession {
+       LinphoneCall *call;
+       UpnpStream *audio;
+       UpnpStream *video;
+       LinphoneUpnpState state;
+};
+
+struct _UpnpContext {
+       LinphoneCore *lc;
+       upnp_igd_context *upnp_igd_ctxt;
+       UpnpPortBinding *sip_tcp;
+       UpnpPortBinding *sip_tls;
+       UpnpPortBinding *sip_udp;
+       LinphoneUpnpState state;
+       MSList *removing_configs;
+       MSList *adding_configs;
+       MSList *pending_bindings;
+
+       ms_mutex_t mutex;
+       ms_cond_t empty_cond;
+
+};
+
+
+bool_t linphone_core_upnp_hook(void *data);
+void linphone_core_upnp_refresh(UpnpContext *ctx);
+
+UpnpPortBinding *linphone_upnp_port_binding_new();
+UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port);
+bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
+UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port);
+UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port);
+void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
+void linphone_upnp_port_binding_release(UpnpPortBinding *port);
+
+MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc);
+void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
+void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
+
+int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
+int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
+
+
+/**
+ * uPnP Callbacks
+ */
+
+/* Convert uPnP IGD logs to ortp logs */
+void linphone_upnp_igd_print(void *cookie, upnp_igd_print_level level, const char *fmt, va_list list) {
+       int ortp_level = ORTP_DEBUG;
+       switch(level) {
+       case UPNP_IGD_MESSAGE:
+               ortp_level = ORTP_MESSAGE;
+               break;
+       case UPNP_IGD_WARNING:
+               ortp_level = ORTP_DEBUG; // Too verbose otherwise
+               break;
+       case UPNP_IGD_ERROR:
+               ortp_level = ORTP_DEBUG; // Too verbose otherwise
+               break;
+       default:
+               break;
+       }
+       ortp_logv(ortp_level, fmt, list);
+}
+
+void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
+       UpnpContext *lupnp = (UpnpContext *)cookie;
+       upnp_igd_port_mapping *mapping = NULL;
+       UpnpPortBinding *port_mapping = NULL;
+       const char *ip_address = NULL;
+       const char *connection_status = NULL;
+       bool_t nat_enabled = FALSE;
+       ms_mutex_lock(&lupnp->mutex);
+       LinphoneUpnpState old_state = lupnp->state;
+
+       switch(event) {
+       case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED:
+       case UPNP_IGD_NAT_ENABLED_CHANGED:
+       case UPNP_IGD_CONNECTION_STATUS_CHANGED:
+               ip_address = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
+               connection_status = upnp_igd_get_connection_status(lupnp->upnp_igd_ctxt);
+               nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt);
+
+               if(ip_address == NULL || connection_status == NULL) {
+                       ms_message("uPnP IGD: Pending");
+                       lupnp->state = LinphoneUpnpStatePending;
+               } else if(strcasecmp(connection_status, "Connected")  || !nat_enabled) {
+                       ms_message("uPnP IGD: Not Available");
+                       lupnp->state = LinphoneUpnpStateNotAvailable;
+               } else {
+                       ms_message("uPnP IGD: Connected");
+                       lupnp->state = LinphoneUpnpStateOk;
+                       if(old_state != LinphoneUpnpStateOk) {
+                               linphone_core_upnp_refresh(lupnp);
+                       }
+               }
+
+               break;
+
+       case UPNP_IGD_PORT_MAPPING_ADD_SUCCESS:
+               mapping = (upnp_igd_port_mapping *) arg;
+               port_mapping = (UpnpPortBinding*) mapping->cookie;
+               port_mapping->external_port = mapping->remote_port;
+               port_mapping->state = LinphoneUpnpStateOk;
+               linphone_upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping);
+               linphone_upnp_config_add_port_binding(lupnp, port_mapping);
+
+               break;
+
+       case UPNP_IGD_PORT_MAPPING_ADD_FAILURE:
+               mapping = (upnp_igd_port_mapping *) arg;
+               port_mapping = (UpnpPortBinding*) mapping->cookie;
+               port_mapping->external_port = -1; //Force random external port
+               if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) {
+                       linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
+               }
+
+               break;
+
+       case UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS:
+               mapping = (upnp_igd_port_mapping *) arg;
+               port_mapping = (UpnpPortBinding*) mapping->cookie;
+               port_mapping->state = LinphoneUpnpStateIdle;
+               linphone_upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping);
+               linphone_upnp_config_remove_port_binding(lupnp, port_mapping);
+
+               break;
+
+       case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE:
+               mapping = (upnp_igd_port_mapping *) arg;
+               port_mapping = (UpnpPortBinding*) mapping->cookie;
+               if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) {
+                       linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping);
+                       linphone_upnp_config_remove_port_binding(lupnp, port_mapping);
+               }
+
+               break;
+
+       default:
+               break;
+       }
+
+       if(port_mapping != NULL) {
+               /*
+                * Execute delayed actions
+                */
+               if(port_mapping->to_remove) {
+                       if(port_mapping->state == LinphoneUpnpStateOk) {
+                               port_mapping->to_remove = FALSE;
+                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
+                       } else if(port_mapping->state == LinphoneUpnpStateKo) {
+                               port_mapping->to_remove = FALSE;
+                       }
+               }
+               if(port_mapping->to_add) {
+                       if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) {
+                               port_mapping->to_add = FALSE;
+                               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
+                       }
+               }
+
+               lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping);
+               linphone_upnp_port_binding_release(port_mapping);
+       }
+
+       /*
+        * If there is no pending binding emit a signal
+        */
+       if(lupnp->pending_bindings == NULL) {
+               pthread_cond_signal(&lupnp->empty_cond);
+       }
+       ms_mutex_unlock(&lupnp->mutex);
+}
+
+
+/**
+ * uPnP Context
+ */
+
+UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
+       LCSipTransports transport;
+       UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1);
+       const char *ip_address;
+
+       ms_mutex_init(&lupnp->mutex, NULL);
+       ms_cond_init(&lupnp->empty_cond, NULL);
+
+       lupnp->lc = lc;
+       lupnp->pending_bindings = NULL;
+       lupnp->adding_configs = NULL;
+       lupnp->removing_configs = NULL;
+       lupnp->state = LinphoneUpnpStateIdle;
+       ms_message("uPnP IGD: New %p for core %p", lupnp, lc);
+
+       linphone_core_get_sip_transports(lc, &transport);
+       if(transport.udp_port != 0) {
+               lupnp->sip_udp = linphone_upnp_port_binding_new();
+               lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
+               lupnp->sip_udp->local_port = transport.udp_port;
+               lupnp->sip_udp->external_port = transport.udp_port;
+       } else {
+               lupnp->sip_udp = NULL;
+       }
+       if(transport.tcp_port != 0) {
+               lupnp->sip_tcp = linphone_upnp_port_binding_new();
+               lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
+               lupnp->sip_tcp->local_port = transport.tcp_port;
+               lupnp->sip_tcp->external_port = transport.tcp_port;
+       } else {
+               lupnp->sip_tcp = NULL;
+       }
+       if(transport.tls_port != 0) {
+               lupnp->sip_tls = linphone_upnp_port_binding_new();
+               lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
+               lupnp->sip_tls->local_port = transport.tls_port;
+               lupnp->sip_tls->external_port = transport.tls_port;
+       } else {
+               lupnp->sip_tls = NULL;
+       }
+
+       linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp);
+
+       lupnp->upnp_igd_ctxt = NULL;
+       lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, lupnp);
+       if(lupnp->upnp_igd_ctxt == NULL) {
+               lupnp->state = LinphoneUpnpStateKo;
+               ms_error("Can't create uPnP IGD context");
+               return NULL;
+       }
+
+       ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
+       if(lupnp->sip_udp != NULL) {
+               strncpy(lupnp->sip_udp->local_addr, ip_address, sizeof(lupnp->sip_udp->local_addr));
+       }
+       if(lupnp->sip_tcp != NULL) {
+               strncpy(lupnp->sip_tcp->local_addr, ip_address, sizeof(lupnp->sip_tcp->local_addr));
+       }
+       if(lupnp->sip_tls != NULL) {
+               strncpy(lupnp->sip_tls->local_addr, ip_address, sizeof(lupnp->sip_tls->local_addr));
+       }
+
+       lupnp->state = LinphoneUpnpStatePending;
+       return lupnp;
+}
+
+void linphone_upnp_context_destroy(UpnpContext *lupnp) {
+       /*
+        * Not need, all hooks are removed before
+        * linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc);
+     */
+
+       /* Send port binding removes */
+       if(lupnp->sip_udp != NULL) {
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp);
+               lupnp->sip_udp = NULL;
+       }
+       if(lupnp->sip_tcp != NULL) {
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp);
+               lupnp->sip_tcp = NULL;
+       }
+       if(lupnp->sip_tls != NULL) {
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls);
+               lupnp->sip_tcp = NULL;
+       }
+
+       /* Wait all pending bindings are done */
+       ms_message("uPnP IGD: Wait all pending port bindings ...");
+       ms_mutex_lock(&lupnp->mutex);
+       ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex);
+       ms_mutex_unlock(&lupnp->mutex);
+
+       if(lupnp->upnp_igd_ctxt != NULL) {
+               upnp_igd_destroy(lupnp->upnp_igd_ctxt);
+       }
+
+       /* Run one time the hook for configuration update */
+       linphone_core_upnp_hook(lupnp);
+
+       /* Release port bindings */
+       if(lupnp->sip_udp != NULL) {
+               linphone_upnp_port_binding_release(lupnp->sip_udp);
+               lupnp->sip_udp = NULL;
+       }
+       if(lupnp->sip_tcp != NULL) {
+               linphone_upnp_port_binding_release(lupnp->sip_tcp);
+               lupnp->sip_tcp = NULL;
+       }
+       if(lupnp->sip_tls != NULL) {
+               linphone_upnp_port_binding_release(lupnp->sip_tls);
+               lupnp->sip_tcp = NULL;
+       }
+
+       /* Release lists */
+       ms_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release);
+       lupnp->adding_configs = ms_list_free(lupnp->adding_configs);
+       ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release);
+       lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
+       ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release);
+       lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings);
+
+       ms_mutex_destroy(&lupnp->mutex);
+       ms_cond_destroy(&lupnp->empty_cond);
+
+       ms_message("uPnP IGD: destroy %p", lupnp);
+       ms_free(lupnp);
+}
+
+LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) {
+       return ctx->state;
+}
+
+const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) {
+       return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt);
+}
+
+int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
+       upnp_igd_port_mapping mapping;
+       char description[128];
+       int ret;
+
+       // Compute port binding state
+       if(port->state != LinphoneUpnpStateAdding) {
+               port->to_remove = FALSE;
+               switch(port->state) {
+                       case LinphoneUpnpStateKo:
+                       case LinphoneUpnpStateIdle: {
+                               port->retry = 0;
+                               port->state = LinphoneUpnpStateAdding;
+                       }
+                       break;
+                       case LinphoneUpnpStateRemoving: {
+                               port->to_add = TRUE;
+                               return 0;
+                       }
+                       break;
+                       default:
+                               return 0;
+               }
+       }
+
+       if(port->retry >= UPNP_ADD_MAX_RETRY) {
+               ret = -1;
+       } else {
+               mapping.cookie = linphone_upnp_port_binding_retain(port);
+               lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie);
+
+               mapping.local_port = port->local_port;
+               mapping.local_host = port->local_addr;
+               if(port->external_port == -1)
+                       mapping.remote_port = rand()%(0xffff - 1024) + 1024;
+               else
+                       mapping.remote_port = port->external_port;
+               mapping.remote_host = "";
+               snprintf(description, 128, "%s %s at %s:%d",
+                               PACKAGE_NAME,
+                               (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP": "UDP",
+                               port->local_addr, port->local_port);
+               mapping.description = description;
+               mapping.protocol = port->protocol;
+
+               port->retry++;
+               linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to add port binding", port);
+               ret = upnp_igd_add_port_mapping(lupnp->upnp_igd_ctxt, &mapping);
+       }
+       if(ret != 0) {
+               port->state = LinphoneUpnpStateKo;
+       }
+       return ret;
+}
+
+int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
+       upnp_igd_port_mapping mapping;
+       int ret;
+
+       // Compute port binding state
+       if(port->state != LinphoneUpnpStateRemoving) {
+               port->to_add = FALSE;
+               switch(port->state) {
+                       case LinphoneUpnpStateOk: {
+                               port->retry = 0;
+                               port->state = LinphoneUpnpStateRemoving;
+                       }
+                       break;
+                       case LinphoneUpnpStateAdding: {
+                               port->to_remove = TRUE;
+                               return 0;
+                       }
+                       break;
+                       default:
+                               return 0;
+               }
+       }
+
+       if(port->retry >= UPNP_REMOVE_MAX_RETRY) {
+               ret = -1;
+       } else {
+               mapping.cookie = linphone_upnp_port_binding_retain(port);
+               lupnp->pending_bindings = ms_list_append(lupnp->pending_bindings, mapping.cookie);
+
+               mapping.remote_port = port->external_port;
+               mapping.remote_host = "";
+               mapping.protocol = port->protocol;
+               port->retry++;
+               linphone_upnp_port_binding_log(ORTP_MESSAGE, "Try to remove port binding", port);
+               ret = upnp_igd_delete_port_mapping(lupnp->upnp_igd_ctxt, &mapping);
+       }
+       if(ret != 0) {
+               port->state = LinphoneUpnpStateKo;
+       }
+       return ret;
+}
+
+/*
+ * uPnP Core interfaces
+ */
+
+int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) {
+       LinphoneCore *lc = call->core;
+       UpnpContext *lupnp = lc->upnp;
+       int ret = -1;
+       const char *local_addr, *external_addr;
+
+       if(lupnp == NULL) {
+               return ret;
+       }
+
+       ms_mutex_lock(&lupnp->mutex);
+       // Don't handle when the call
+       if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
+               ret = 0;
+               local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
+               external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
+
+               /*
+                * Audio part
+                */
+               strncpy(call->upnp_session->audio->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
+               strncpy(call->upnp_session->audio->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
+               call->upnp_session->audio->rtp->local_port = call->audio_port;
+               if(call->upnp_session->audio->rtp->external_port == -1) {
+                       call->upnp_session->audio->rtp->external_port = call->audio_port;
+               }
+               strncpy(call->upnp_session->audio->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
+               strncpy(call->upnp_session->audio->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
+               call->upnp_session->audio->rtcp->local_port = call->audio_port+1;
+               if(call->upnp_session->audio->rtcp->external_port == -1) {
+                       call->upnp_session->audio->rtcp->external_port = call->audio_port+1;
+               }
+               if(audio) {
+                       // Add audio port binding
+                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp);
+                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp);
+               } else {
+                       // Remove audio port binding
+                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp);
+                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp);
+               }
+
+               /*
+                * Video part
+                */
+               strncpy(call->upnp_session->video->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
+               strncpy(call->upnp_session->video->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
+               call->upnp_session->video->rtp->local_port = call->video_port;
+               if(call->upnp_session->video->rtp->external_port == -1) {
+                       call->upnp_session->video->rtp->external_port = call->video_port;
+               }
+               strncpy(call->upnp_session->video->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
+               strncpy(call->upnp_session->video->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
+               call->upnp_session->video->rtcp->local_port = call->video_port+1;
+               if(call->upnp_session->video->rtcp->external_port == -1) {
+                       call->upnp_session->video->rtcp->external_port = call->video_port+1;
+               }
+               if(video) {
+                       // Add video port binding
+                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp);
+                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp);
+               } else {
+                       // Remove video port binding
+                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp);
+                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp);
+               }
+       }
+
+       ms_mutex_unlock(&lupnp->mutex);
+
+       /*
+        * Update uPnP call state
+        */
+       linphone_upnp_call_process(call);
+
+       return ret;
+}
+
+
+int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
+       bool_t audio = FALSE;
+       bool_t video = FALSE;
+       int i;
+       const SalStreamDescription *stream;
+
+       for (i = 0; i < md->nstreams; i++) {
+               stream = &md->streams[i];
+               if(stream->type == SalAudio) {
+                       audio = TRUE;
+               } else if(stream->type == SalVideo) {
+                       video = TRUE;
+               }
+       }
+
+       return linphone_core_update_upnp_audio_video(call, audio, video);
+}
+
+int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) {
+       return linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL);
+}
+
+int linphone_upnp_call_process(LinphoneCall *call) {
+       LinphoneCore *lc = call->core;
+       UpnpContext *lupnp = lc->upnp;
+       int ret = -1;
+       LinphoneUpnpState oldState;
+
+       if(lupnp == NULL) {
+               return ret;
+       }
+
+       ms_mutex_lock(&lupnp->mutex);
+
+       // Don't handle when the call
+       if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
+               ret = 0;
+
+               /*
+                * Update Audio state
+                */
+               if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) &&
+                               (call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) {
+                       call->upnp_session->audio->state = LinphoneUpnpStateOk;
+               } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
+                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
+                       call->upnp_session->audio->state = LinphoneUpnpStatePending;
+               } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
+                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
+                       call->upnp_session->audio->state = LinphoneUpnpStateKo;
+               } else {
+                       call->upnp_session->audio->state = LinphoneUpnpStateIdle;
+               }
+
+               /*
+                * Update Video state
+                */
+               if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) &&
+                               (call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) {
+                       call->upnp_session->video->state = LinphoneUpnpStateOk;
+               } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->video->rtp->state == LinphoneUpnpStateRemoving ||
+                               call->upnp_session->video->rtcp->state == LinphoneUpnpStateAdding ||
+                               call->upnp_session->video->rtcp->state == LinphoneUpnpStateRemoving) {
+                       call->upnp_session->video->state = LinphoneUpnpStatePending;
+               } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateKo ||
+                               call->upnp_session->video->rtp->state == LinphoneUpnpStateKo) {
+                       call->upnp_session->video->state = LinphoneUpnpStateKo;
+               } else {
+                       call->upnp_session->video->state = LinphoneUpnpStateIdle;
+               }
+
+               /*
+                * Update session state
+                */
+               oldState = call->upnp_session->state;
+               if(call->upnp_session->audio->state == LinphoneUpnpStateOk &&
+                       call->upnp_session->video->state == LinphoneUpnpStateOk) {
+                       call->upnp_session->state = LinphoneUpnpStateOk;
+               } else if(call->upnp_session->audio->state == LinphoneUpnpStatePending ||
+                               call->upnp_session->video->state == LinphoneUpnpStatePending) {
+                       call->upnp_session->state = LinphoneUpnpStatePending;
+               } else if(call->upnp_session->audio->state == LinphoneUpnpStateKo ||
+                               call->upnp_session->video->state == LinphoneUpnpStateKo) {
+                       call->upnp_session->state = LinphoneUpnpStateKo;
+               } else {
+                       call->upnp_session->state = LinphoneUpnpStateIdle;
+               }
+
+               /* When change is done proceed update */
+               if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
+                               (call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) {
+                       if(call->upnp_session->state == LinphoneUpnpStateOk)
+                               ms_message("uPnP IGD: uPnP for Call %p is ok", call);
+                       else
+                               ms_message("uPnP IGD: uPnP for Call %p is ko", call);
+
+                       switch (call->state) {
+                               case LinphoneCallUpdating:
+                                       linphone_core_start_update_call(lc, call);
+                                       break;
+                               case LinphoneCallUpdatedByRemote:
+                                       linphone_core_start_accept_call_update(lc, call);
+                                       break;
+                               case LinphoneCallOutgoingInit:
+                                       linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
+                                       break;
+                               case LinphoneCallIdle:
+                                       linphone_core_notify_incoming_call(lc, call);
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       ms_mutex_unlock(&lupnp->mutex);
+       return ret;
+}
+
+void linphone_core_upnp_refresh(UpnpContext *lupnp) {
+       MSList *global_list = NULL;
+       MSList *list = NULL;
+       MSList *item;
+       LinphoneCall *call;
+       UpnpPortBinding *port_mapping, *port_mapping2;
+
+       ms_message("uPnP IGD: Refresh mappings");
+
+       /* Remove context port bindings */
+       if(lupnp->sip_udp != NULL) {
+               global_list = ms_list_append(global_list, lupnp->sip_udp);
+       }
+       if(lupnp->sip_tcp != NULL) {
+               global_list = ms_list_append(global_list, lupnp->sip_tcp);
+       }
+       if(lupnp->sip_tls != NULL) {
+               global_list = ms_list_append(global_list, lupnp->sip_tls);
+       }
+
+       /* Remove call port bindings */
+       list = lupnp->lc->calls;
+       while(list != NULL) {
+               call = (LinphoneCall *)list->data;
+               if(call->upnp_session != NULL) {
+                       global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
+                       global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
+                       global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
+                       global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
+               }
+               list = list->next;
+       }
+
+       // Remove port binding configurations
+       list = linphone_upnp_config_list_port_bindings(lupnp->lc->config);
+       for(item = list;item != NULL; item = item->next) {
+                       port_mapping = (UpnpPortBinding *)item->data;
+                       port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping);
+                       if(port_mapping2 == NULL) {
+                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
+                       } else if(port_mapping2->state == LinphoneUpnpStateIdle){
+                               /* Force to remove */
+                               port_mapping2->state = LinphoneUpnpStateOk;
+                       }
+       }
+       ms_list_for_each(list, (void (*)(void*))linphone_upnp_port_binding_release);
+       list = ms_list_free(list);
+
+
+       // (Re)Add removed port bindings
+       list = global_list;
+       while(list != NULL) {
+               port_mapping = (UpnpPortBinding *)list->data;
+               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
+               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
+               list = list->next;
+       }
+       global_list = ms_list_free(global_list);
+}
+
+bool_t linphone_core_upnp_hook(void *data) {
+       char key[64];
+       MSList *item;
+       UpnpPortBinding *port_mapping;
+       UpnpContext *lupnp = (UpnpContext *)data;
+       ms_mutex_lock(&lupnp->mutex);
+
+       /* Add configs */
+       for(item = lupnp->adding_configs;item!=NULL;item=item->next) {
+               port_mapping = (UpnpPortBinding *)item->data;
+               snprintf(key, sizeof(key), "%s-%d-%d",
+                                       (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+                                                       port_mapping->external_port,
+                                                       port_mapping->local_port);
+               lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, "uPnP");
+               linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping);
+       }
+       ms_list_for_each(lupnp->adding_configs,(void (*)(void*))linphone_upnp_port_binding_release);
+       lupnp->adding_configs = ms_list_free(lupnp->adding_configs);
+
+       /* Remove configs */
+       for(item = lupnp->removing_configs;item!=NULL;item=item->next) {
+               port_mapping = (UpnpPortBinding *)item->data;
+               snprintf(key, sizeof(key), "%s-%d-%d",
+                                       (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+                                                       port_mapping->external_port,
+                                                       port_mapping->local_port);
+               lp_config_set_string(lupnp->lc->config, UPNP_SECTION_NAME, key, NULL);
+               linphone_upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping);
+       }
+       ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release);
+       lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
+
+       ms_mutex_unlock(&lupnp->mutex);
+       return TRUE;
+}
+
+int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session) {
+       int i;
+       SalStreamDescription *stream;
+       UpnpStream *upnpStream;
+
+       for (i = 0; i < desc->nstreams; i++) {
+               stream = &desc->streams[i];
+               upnpStream = NULL;
+               if(stream->type == SalAudio) {
+                       upnpStream = session->audio;
+               } else if(stream->type == SalVideo) {
+                       upnpStream = session->video;
+               }
+               if(upnpStream != NULL) {
+                       if(upnpStream->rtp->state == LinphoneUpnpStateOk) {
+                               strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE);
+                               stream->rtp_port = upnpStream->rtp->external_port;
+                       }
+                       if(upnpStream->rtcp->state == LinphoneUpnpStateOk) {
+                               strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE);
+                               stream->rtcp_port = upnpStream->rtcp->external_port;
+                       }
+               }
+       }
+       return 0;
+}
+
+
+/*
+ * uPnP Port Binding
+ */
+
+UpnpPortBinding *linphone_upnp_port_binding_new() {
+       UpnpPortBinding *port = NULL;
+       port = ms_new0(UpnpPortBinding,1);
+       ms_mutex_init(&port->mutex, NULL);
+       port->state = LinphoneUpnpStateIdle;
+       port->local_addr[0] = '\0';
+       port->local_port = -1;
+       port->external_addr[0] = '\0';
+       port->external_port = -1;
+       port->to_remove = FALSE;
+       port->to_add = FALSE;
+       port->ref = 1;
+       return port;
+}
+
+UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) {
+       UpnpPortBinding *new_port = NULL;
+       new_port = ms_new0(UpnpPortBinding,1);
+       memcpy(new_port, port, sizeof(UpnpPortBinding));
+       ms_mutex_init(&new_port->mutex, NULL);
+       new_port->ref = 1;
+       return new_port;
+}
+
+void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port) {
+       if(strlen(port->local_addr)) {
+               ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d", msg,
+                                                       (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+                                                                       port->external_port,
+                                                                       port->local_addr,
+                                                                       port->local_port);
+       } else {
+               ortp_log(level, "uPnP IGD: %s %s|%d->%d", msg,
+                                                       (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+                                                                       port->external_port,
+                                                                       port->local_port);
+       }
+}
+
+bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) {
+       return port1->protocol == port2->protocol &&
+                       port1->local_port == port2->local_port &&
+                       port1->external_port == port2->external_port;
+}
+
+UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port) {
+       UpnpPortBinding *port_mapping;
+       while(list != NULL) {
+               port_mapping = (UpnpPortBinding *)list->data;
+               if(linphone_upnp_port_binding_equal(port, port_mapping)) {
+                       return port_mapping;
+               }
+               list = list->next;
+       }
+
+       return NULL;
+}
+
+UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port) {
+       ms_mutex_lock(&port->mutex);
+       port->ref++;
+       ms_mutex_unlock(&port->mutex);
+       return port;
+}
+
+void linphone_upnp_port_binding_release(UpnpPortBinding *port) {
+       ms_mutex_lock(&port->mutex);
+       if(--port->ref == 0) {
+               ms_mutex_unlock(&port->mutex);
+               ms_mutex_destroy(&port->mutex);
+               ms_free(port);
+               return;
+       }
+       ms_mutex_unlock(&port->mutex);
+}
+
+
+/*
+ * uPnP Stream
+ */
+
+UpnpStream* linphone_upnp_stream_new() {
+       UpnpStream *stream = ms_new0(UpnpStream,1);
+       stream->state = LinphoneUpnpStateIdle;
+       stream->rtp = linphone_upnp_port_binding_new();
+       stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
+       stream->rtcp = linphone_upnp_port_binding_new();
+       stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
+       return stream;
+}
+
+void linphone_upnp_stream_destroy(UpnpStream* stream) {
+       linphone_upnp_port_binding_release(stream->rtp);
+       stream->rtp = NULL;
+       linphone_upnp_port_binding_release(stream->rtcp);
+       stream->rtcp = NULL;
+       ms_free(stream);
+}
+
+
+/*
+ * uPnP Session
+ */
+
+UpnpSession* linphone_upnp_session_new(LinphoneCall* call) {
+       UpnpSession *session = ms_new0(UpnpSession,1);
+       session->call = call;
+       session->state = LinphoneUpnpStateIdle;
+       session->audio = linphone_upnp_stream_new();
+       session->video = linphone_upnp_stream_new();
+       return session;
+}
+
+void linphone_upnp_session_destroy(UpnpSession *session) {
+       LinphoneCore *lc = session->call->core;
+
+       if(lc->upnp != NULL) {
+               /* Remove bindings */
+               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp);
+               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp);
+               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp);
+               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp);
+       }
+
+       linphone_upnp_stream_destroy(session->audio);
+       linphone_upnp_stream_destroy(session->video);
+       ms_free(session);
+}
+
+LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) {
+       return session->state;
+}
+
+/*
+ * uPnP Config
+ */
+
+MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc) {
+       char protocol_str[4]; // TCP or UDP
+       upnp_igd_ip_protocol protocol;
+       int external_port;
+       int local_port;
+       MSList *retList = NULL;
+       UpnpPortBinding *port;
+       bool_t valid;
+       MSList *elem;
+       LpItem *item;
+       LpSection *sec=lp_config_find_section(lpc, UPNP_SECTION_NAME);
+       if(sec == NULL)
+               return retList;
+
+       elem = sec->items;
+       while(elem != NULL) {
+               item=(LpItem*)elem->data;
+               valid = TRUE;
+               if(sscanf(item->key, "%3s-%i-%i", protocol_str, &external_port, &local_port) == 3) {
+                       if(strcasecmp(protocol_str, "TCP") == 0) {
+                               protocol = UPNP_IGD_IP_PROTOCOL_TCP;
+                       } else if(strcasecmp(protocol_str, "UDP") == 0) {
+                               protocol = UPNP_IGD_IP_PROTOCOL_UDP;
+                       } else {
+                               valid = FALSE;
+                       }
+                       if(valid) {
+                               port = linphone_upnp_port_binding_new();
+                               port->state = LinphoneUpnpStateOk;
+                               port->protocol = protocol;
+                               port->external_port = external_port;
+                               port->local_port = local_port;
+                               retList = ms_list_append(retList, port);
+                       }
+               } else {
+                       valid = FALSE;
+               }
+               elem = ms_list_next(elem);
+               if(!valid) {
+                       ms_warning("uPnP configuration invalid line: %s", item->key);
+                       lp_section_remove_item(sec, item);
+               }
+       }
+
+       return retList;
+}
+
+void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) {
+       MSList *list;
+       UpnpPortBinding *list_port;
+
+       list = lupnp->removing_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) {
+                       lupnp->removing_configs = ms_list_remove(lupnp->removing_configs, list_port);
+                       linphone_upnp_port_binding_release(list_port);
+                       return;
+               }
+               list = ms_list_next(list);
+       }
+
+       list = lupnp->adding_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) {
+                       return;
+               }
+               list = ms_list_next(list);
+       }
+
+       list_port = linphone_upnp_port_binding_copy(port);
+       lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port);
+}
+
+void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port) {
+       MSList *list;
+       UpnpPortBinding *list_port;
+
+       list = lupnp->adding_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) {
+                       lupnp->adding_configs = ms_list_remove(lupnp->adding_configs, list_port);
+                       linphone_upnp_port_binding_release(list_port);
+                       return;
+               }
+               list = ms_list_next(list);
+       }
+
+       list = lupnp->removing_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(linphone_upnp_port_binding_equal(list_port, port) == TRUE) {
+                       return;
+               }
+               list = ms_list_next(list);
+       }
+
+       list_port = linphone_upnp_port_binding_copy(port);
+       lupnp->removing_configs = ms_list_append(lupnp->removing_configs, list_port);
+}
diff --git a/coreapi/upnp.h b/coreapi/upnp.h
new file mode 100644 (file)
index 0000000..a98e155
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+linphone
+Copyright (C) 2012  Belledonne Communications SARL
+
+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 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifndef LINPHONE_UPNP_H
+#define LINPHONE_UPNP_H
+
+#include "mediastreamer2/upnp_igd.h"
+#include "linphonecore.h"
+#include "sal.h"
+
+typedef enum {
+       LinphoneUpnpStateIdle,
+       LinphoneUpnpStatePending, // Only used by uPnP context
+       LinphoneUpnpStateAdding,   // Only used by port binding
+       LinphoneUpnpStateRemoving, // Only used by port binding
+       LinphoneUpnpStateNotAvailable,  // Only used by uPnP context
+       LinphoneUpnpStateOk,
+       LinphoneUpnpStateKo,
+} LinphoneUpnpState;
+
+typedef struct _UpnpSession UpnpSession;
+typedef struct _UpnpContext UpnpContext;
+
+int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session);
+int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
+int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call);
+
+int linphone_upnp_call_process(LinphoneCall *call);
+UpnpSession* linphone_upnp_session_new(LinphoneCall *call);
+void linphone_upnp_session_destroy(UpnpSession* session);
+LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session);
+
+UpnpContext *linphone_upnp_context_new(LinphoneCore *lc);
+void linphone_upnp_context_destroy(UpnpContext *ctx);
+LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx);
+const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx);
+
+#endif //LINPHONE_UPNP_H
index 78f5d0de7e22cc5b851500d0d3a2cbe9f53a8ad3..f89ea151f017cb393aea669107fd69e10441daf1 100644 (file)
@@ -53,10 +53,11 @@ linphone_SOURCES+=  \
                        setupwizard.c
 endif
 
-linphone_LDADD=$(ORTP_LIBS) \
-               $(MEDIASTREAMER_LIBS) \
+linphone_LDADD=\
                $(top_builddir)/coreapi/liblinphone.la \
-                       $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) 
+               $(ORTP_LIBS) \
+               $(MEDIASTREAMER_LIBS) \
+               $(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) 
 
 
 if BUILD_WIN32
index 130b7e7c5db51bbb9fda99d2de3ac3b1dba58780..e4a6430fa2e409785f63e4c7c851003031ae51c0 100644 (file)
                             <property name="position">3</property>
                           </packing>
                         </child>
+                        <child>
+                          <object class="GtkRadioButton" id="use_upnp">
+                            <property name="label" translatable="yes">Behind NAT / Firewall (use uPnP)</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">no_nat</property>
+                            <signal name="toggled" handler="linphone_gtk_use_upnp_toggled" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
                         <child>
                           <object class="GtkHBox" id="hbox24">
                             <property name="visible">True</property>
index 41fe854ed6c69068151be5c2b3bcc3bf66f9ef03..c2258ea57c175a8878b91b798e8285caca266012 100644 (file)
@@ -236,6 +236,11 @@ void linphone_gtk_use_ice_toggled(GtkWidget *w){
                linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseIce);
 }
 
+void linphone_gtk_use_upnp_toggled(GtkWidget *w){
+       if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
+               linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseUpnp);
+}
+
 void linphone_gtk_mtu_changed(GtkWidget *w){
        if (GTK_WIDGET_SENSITIVE(w))
                linphone_core_set_mtu(linphone_gtk_get_core(),gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)));
@@ -1074,6 +1079,9 @@ void linphone_gtk_show_parameters(void){
                case LinphonePolicyUseIce:
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_ice")),TRUE);
                break;
+               case LinphonePolicyUseUpnp:
+                       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE);
+               break;
        }
        mtu=linphone_core_get_mtu(lc);
        if (mtu<=0){
index d5811e376759433da3c19585b2d8d0329e1c06b2..1cf3b8e36d832d763220b762c6bceef0db88c04c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d5811e376759433da3c19585b2d8d0329e1c06b2
+Subproject commit 1cf3b8e36d832d763220b762c6bceef0db88c04c