From: Yann Diorcet Date: Wed, 13 Feb 2013 10:55:05 +0000 (+0100) Subject: Fix loop in upnp context release X-Git-Url: http://sjero.net/git/?p=linphone;a=commitdiff_plain;h=ee6366003f803184830617e21e3bb709c9f09a8c Fix loop in upnp context release Add upnp public function Add upnp jni Improve uPnP support when a device is removed --- diff --git a/README b/README index 7e68bb19..05b0b1dc 100644 --- a/README +++ b/README @@ -15,6 +15,8 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - libavcodec (ffmpeg) - libswscale (part of ffmpeg too) for better scaling performance - theora (optional) + + if you want uPnP support: + - libupnp with their corresponding -dev or -devel package if you don't use source packages. diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8930f3a8..1be92ef3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -697,6 +697,8 @@ static void sip_config_read(LinphoneCore *lc) lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); lc->sip_conf.register_only_when_network_is_up= lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); + lc->sip_conf.register_only_when_upnp_is_ok= + lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000); @@ -4123,6 +4125,31 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ return lc->net_conf.stun_server; } +bool_t linphone_core_upnp_available(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return TRUE; +#else + return FALSE; +#endif //BUILD_UPNP +} + +LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return linphone_upnp_context_get_state(lc->upnp); +#else + return LinphoneUpnpStateNotAvailable; +#endif //BUILD_UPNP +} + +const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return linphone_upnp_context_get_external_ipaddress(lc->upnp); +#else + return NULL; +#endif //BUILD_UPNP +} + + const char * linphone_core_get_relay_addr(const LinphoneCore *lc){ return lc->net_conf.relay; } @@ -4977,7 +5004,7 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833); lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up); - + lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 4d4a9198..1de97d0b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1105,6 +1105,36 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); const char * linphone_core_get_stun_server(const LinphoneCore *lc); +/** + * @ingroup network_parameters + * Return the availability of uPnP. + * + * @param lc #LinphoneCore + * @return true if uPnP is available otherwise return false. + */ +bool_t linphone_core_upnp_available(const LinphoneCore *lc); + +/** + * @ingroup network_parameters + * Return the internal state of uPnP. + * + * @param lc #LinphoneCore + * @return an LinphoneUpnpState. + */ +LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); + +/** + * @ingroup network_parameters + * Return the external ip address of router. + * In some cases the uPnP can have an external ip address but not a usable uPnP + * (state different of Ok). + * + * @param lc #LinphoneCore + * @return a null terminated string containing the external ip address. If the + * the external ip address is not available return null. + */ +const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc); + void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr); const char *linphone_core_get_nat_address(const LinphoneCore *lc); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 81179be5..64897b21 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2288,6 +2288,19 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getConfig(JNIEnv *env, return (jlong) linphone_core_get_config((LinphoneCore *)lc); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_upnpAvailable(JNIEnv *env, jobject thiz, jlong lc) { + return (jboolean) linphone_core_upnp_available((LinphoneCore *)lc); +} + +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getUpnpState(JNIEnv *env, jobject thiz, jlong lc) { + return (jint) linphone_core_get_upnp_state((LinphoneCore *)lc); +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getUpnpExternalIpaddress(JNIEnv *env, jobject thiz, jlong lc) { + jstring jvalue = env->NewStringUTF(linphone_core_get_upnp_external_ipaddress((LinphoneCore *)lc)); + return jvalue; +} + extern "C" jlong Java_org_linphone_core_LpConfigImpl_newLpConfigImpl(JNIEnv *env, jobject thiz, jstring file) { const char *cfile = env->GetStringUTFChars(file, NULL); LpConfig *lp = lp_config_new(cfile); diff --git a/coreapi/private.h b/coreapi/private.h index 1f3ed6ab..e4420d9b 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -429,6 +429,7 @@ typedef struct sip_config bool_t ipv6_enabled; bool_t sdp_200_ack; bool_t register_only_when_network_is_up; + bool_t register_only_when_upnp_is_ok; bool_t ping_with_options; bool_t auto_net_state_mon; bool_t tcp_tls_keepalive; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index bb6c8ec6..fb650c85 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1082,7 +1082,8 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ if (cfg->type && cfg->ssctx==NULL){ linphone_proxy_config_activate_sip_setup(cfg); } - if (!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) + if ((!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) && + (!lc->sip_conf.register_only_when_upnp_is_ok || linphone_core_get_upnp_state(lc) == LinphoneUpnpStateOk)) linphone_proxy_config_register(cfg); if (cfg->publish && cfg->publish_op==NULL){ linphone_proxy_config_send_publish(cfg,lc->presence_mode); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 5ef70ba2..d86c8a42 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -133,6 +133,8 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { old_state = lupnp->state; switch(event) { + case UPNP_IGD_DEVICE_ADDED: + case UPNP_IGD_DEVICE_REMOVED: case UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED: case UPNP_IGD_NAT_ENABLED_CHANGED: case UPNP_IGD_CONNECTION_STATUS_CHANGED: @@ -315,15 +317,12 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) { /* 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 */ @@ -381,6 +380,10 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind upnp_igd_port_mapping mapping; char description[128]; int ret; + + if(lupnp->state != LinphoneUpnpStateOk) { + return -2; + } // Compute port binding state if(port->state != LinphoneUpnpStateAdding) { @@ -435,6 +438,10 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) { upnp_igd_port_mapping mapping; int ret; + + if(lupnp->state != LinphoneUpnpStateOk) { + return -2; + } // Compute port binding state if(port->state != LinphoneUpnpStateRemoving) { @@ -848,16 +855,18 @@ UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *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, + ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d (retry %d)", msg, (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", port->external_port, port->local_addr, - port->local_port); + port->local_port, + port->retry - 1); } else { - ortp_log(level, "uPnP IGD: %s %s|%d->%d", msg, + ortp_log(level, "uPnP IGD: %s %s|%d->%d (retry %d)", msg, (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP", port->external_port, - port->local_port); + port->local_port, + port->retry - 1); } } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 08371f51..11a7c275 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -278,6 +278,56 @@ public interface LinphoneCore { return mValue; } } + + static public class UpnpState { + static private Vector values = new Vector(); + /** + * Idle + */ + static public UpnpState Idle = new UpnpState(0, "Idle"); + /** + * Pending + */ + static public UpnpState Pending = new UpnpState(1, "Pending"); + /** + * Adding + */ + static public UpnpState Adding = new UpnpState(2, "Adding"); + /** + * Removing + */ + static public UpnpState Removing = new UpnpState(3, "Removing"); + /** + * Not Available + */ + static public UpnpState NotAvailable = new UpnpState(4, "Not available"); + /** + * Ok + */ + static public UpnpState Ok = new UpnpState(5, "Ok"); + /** + * Ko + */ + static public UpnpState Ko = new UpnpState(6, "Ko"); + protected final int mValue; + private final String mStringValue; + + private UpnpState(int value, String stringValue) { + mValue = value; + values.addElement(this); + mStringValue = stringValue; + } + public static UpnpState fromInt(int value) { + for (int i = 0; i < values.size(); i++) { + UpnpState mstate = (UpnpState) values.elementAt(i); + if (mstate.mValue == value) return mstate; + } + throw new RuntimeException("UpnpState not found [" + value + "]"); + } + public String toString() { + return mStringValue; + } + } /** * Set the context of creation of the LinphoneCore. @@ -882,4 +932,30 @@ public interface LinphoneCore { * the config file with your own sections */ LpConfig getConfig(); + + + /** + * Return the availability of uPnP. + * + * @return true if uPnP is available otherwise return false. + */ + public boolean upnpAvailable(); + + /** + * Return the internal state of uPnP. + * + * @return an UpnpState. + */ + public UpnpState getUpnpState(); + + /** + * Return the external ip address of router. + * In some cases the uPnP can have an external ip address but not a usable uPnP + * (state different of Ok). + * + * @return a null terminated string containing the external ip address. If the + * the external ip address is not available return null. + */ + public String getUpnpExternalIpaddress(); + } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 02e31f9a..2d42c8f5 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -872,4 +872,19 @@ class LinphoneCoreImpl implements LinphoneCore { long configPtr=getConfig(nativePtr); return new LpConfigImpl(configPtr); } + + private native boolean upnpAvailable(long ptr); + public boolean upnpAvailable() { + return upnpAvailable(nativePtr); + } + + private native int getUpnpState(long ptr); + public UpnpState getUpnpState() { + return UpnpState.fromInt(getUpnpState(nativePtr)); + } + + private native String getUpnpExternalIpaddress(long ptr); + public String getUpnpExternalIpaddress() { + return getUpnpExternalIpaddress(nativePtr); + } }