]> sjero.net Git - linphone/commitdiff
Improve uPnP
authorYann Diorcet <yann.diorcet@belledonne-communications.com>
Tue, 8 Jan 2013 16:06:27 +0000 (17:06 +0100)
committerYann Diorcet <yann.diorcet@belledonne-communications.com>
Tue, 8 Jan 2013 16:06:27 +0000 (17:06 +0100)
coreapi/linphonecore.c
coreapi/upnp.c
coreapi/upnp.h

index b277d8ae4833497a7089f6b2d5e8b7d5003d596f..17b1c84b94807fe75d1fc9ccabfa67f9166cdcdd 100644 (file)
@@ -2714,20 +2714,20 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
                                        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;
+                       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);
        }else{
@@ -3000,6 +3000,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);
@@ -4958,6 +4963,11 @@ static void linphone_core_uninit(LinphoneCore *lc)
                usleep(50000);
 #endif
        }
+
+#ifdef BUILD_UPNP
+       upnp_context_uninit(lc);
+#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");
@@ -4983,10 +4993,6 @@ static void linphone_core_uninit(LinphoneCore *lc)
        lc->config = NULL; /* Mark the config as NULL to block further calls */
        sip_setup_unregister_all();
 
-#ifdef BUILD_UPNP
-       upnp_context_uninit(lc);
-#endif  //BUILD_UPNP
-
        ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy);
        lc->call_logs=ms_list_free(lc->call_logs);
        
index 336e0b78fdb141b8b4eca865cfdc20a32284fbaa..3a68cbcbedfd92c030884aaea4b1db9aebc99773 100644 (file)
@@ -20,7 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "upnp.h"
 #include "private.h"
 
-#define UPNP_MAX_RETRY 4
+#define UPNP_ADD_MAX_RETRY 4
+#define UPNP_REMOVE_MAX_RETRY 4
 #define UPNP_SECTION_NAME "uPnP"
 
 /* Define private types */
@@ -57,8 +58,8 @@ void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *po
 void upnp_port_binding_release(UpnpPortBinding *port);
 
 MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc);
-int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port);
-int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port);
+void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port);
+void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port);
 
 int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port);
 int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port);
@@ -113,6 +114,9 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                        lupnp->state = LinphoneUpnpStateNotAvailable;
                } else {
                        ms_message("uPnP IGD: Connected");
+                       if(lupnp->state != LinphoneUpnpStateOk) {
+                               lupnp->clean = TRUE; // Remove saved port mapping configurations
+                       }
                        lupnp->state = LinphoneUpnpStateOk;
                }
 
@@ -126,17 +130,18 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping);
                upnp_config_add_port_binding(lc, port_mapping);
 
+               lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping);
                upnp_port_binding_release(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 a new random port
                if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) {
                        upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
                }
 
+               lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping);
                upnp_port_binding_release(port_mapping);
                break;
 
@@ -147,6 +152,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping);
                upnp_config_remove_port_binding(lc, port_mapping);
 
+               lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping);
                upnp_port_binding_release(port_mapping);
                break;
 
@@ -158,6 +164,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                        upnp_config_remove_port_binding(lc, port_mapping);
                }
 
+               lupnp->pending_bindings = ms_list_remove(lupnp->pending_bindings, port_mapping);
                upnp_port_binding_release(port_mapping);
                break;
 
@@ -165,6 +172,13 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                break;
        }
 
+       if(lupnp->pending_bindings == NULL) {
+               if(lupnp->cleaning == TRUE) {
+                       lupnp->emit = TRUE; // Emit port bindings
+                       lupnp->cleaning = FALSE;
+               }
+               pthread_cond_signal(&lupnp->cond);
+       }
        ms_mutex_unlock(&lupnp->mutex);
 }
 
@@ -179,9 +193,15 @@ int upnp_context_init(LinphoneCore *lc) {
        const char *ip_address;
 
        ms_mutex_init(&lupnp->mutex, NULL);
-       lupnp->pending_configs = NULL;
+       ms_cond_init(&lupnp->cond, NULL);
+
+       lupnp->pending_bindings = NULL;
+       lupnp->adding_configs = NULL;
+       lupnp->removing_configs = NULL;
+       lupnp->clean = FALSE;
+       lupnp->cleaning = FALSE;
+       lupnp->emit = FALSE;
        lupnp->state = LinphoneUpnpStateIdle;
-       lupnp->old_state = LinphoneUpnpStateIdle;
        ms_message("uPnP IGD: Init");
 
        linphone_core_get_sip_transports(lc, &transport);
@@ -238,22 +258,62 @@ int upnp_context_init(LinphoneCore *lc) {
 void upnp_context_uninit(LinphoneCore *lc) {
        UpnpContext *lupnp = &lc->upnp;
 
-       // Not need, all hooks are removed before
-       //linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc);
+       /*
+        * 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) {
-               upnp_port_binding_release(lupnp->sip_udp);
+               upnp_context_send_remove_port_binding(lc, lupnp->sip_udp);
+               lupnp->sip_udp = NULL;
        }
        if(lupnp->sip_tcp != NULL) {
-               upnp_port_binding_release(lupnp->sip_tcp);
+               upnp_context_send_remove_port_binding(lc, lupnp->sip_tcp);
+               lupnp->sip_tcp = NULL;
        }
        if(lupnp->sip_tls != NULL) {
-               upnp_port_binding_release(lupnp->sip_tls);
+               upnp_context_send_remove_port_binding(lc, 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->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(lc);
+
+       /* Release port bindings */
+       if(lupnp->sip_udp != NULL) {
+               upnp_port_binding_release(lupnp->sip_udp);
+               lupnp->sip_udp = NULL;
+       }
+       if(lupnp->sip_tcp != NULL) {
+               upnp_port_binding_release(lupnp->sip_tcp);
+               lupnp->sip_tcp = NULL;
+       }
+       if(lupnp->sip_tls != NULL) {
+               upnp_port_binding_release(lupnp->sip_tls);
+               lupnp->sip_tcp = NULL;
+       }
+
+       /* Release lists */
+       ms_list_for_each(lupnp->adding_configs,(void (*)(void*))upnp_port_binding_release);
+       lupnp->adding_configs = ms_list_free(lupnp->adding_configs);
+       ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release);
+       lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
+       ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))upnp_port_binding_release);
+       lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings);
+
        ms_mutex_destroy(&lupnp->mutex);
+       ms_cond_destroy(&lupnp->cond);
 
        ms_message("uPnP IGD: Uninit");
 }
@@ -270,10 +330,12 @@ int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port)
                return -2;
        }
 
-       if(port->retry >= UPNP_MAX_RETRY) {
+       if(port->retry >= UPNP_ADD_MAX_RETRY) {
                ret = -1;
        } else {
                mapping.cookie = 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)
@@ -305,10 +367,12 @@ int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *por
                return -2;
        }
 
-       if(port->retry >= UPNP_MAX_RETRY) {
+       if(port->retry >= UPNP_REMOVE_MAX_RETRY) {
                ret = -1;
        } else {
                mapping.cookie = 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;
@@ -344,11 +408,15 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
                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;
-               call->upnp_session->audio->rtp->external_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;
-               call->upnp_session->audio->rtcp->external_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(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) {
                        // Add audio port binding
                        upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp);
@@ -370,11 +438,15 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
                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;
-               call->upnp_session->video->rtp->external_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;
-               call->upnp_session->video->rtcp->external_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(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) {
                        // Add video port binding
                        upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp);
@@ -392,6 +464,12 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
        }
 
        ms_mutex_unlock(&lupnp->mutex);
+
+       /*
+        * Update uPnP call state
+        */
+       upnp_call_process(call);
+
        return ret;
 }
 
@@ -516,64 +594,85 @@ int upnp_call_process(LinphoneCall *call) {
 
 bool_t linphone_core_upnp_hook(void *data) {
        char key[64];
-       MSList *port_bindings = NULL;
-       MSList *port_bindings_item;
+       MSList *list = NULL;
+       MSList *item;
        UpnpPortBinding *port_mapping;
        LinphoneCore *lc = (LinphoneCore *)data;
+       LinphoneCall *call;
        UpnpContext *lupnp = &lc->upnp;
        ms_mutex_lock(&lupnp->mutex);
 
-       if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) {
+       if(lupnp->clean && !lupnp->cleaning) {
+               lupnp->clean = FALSE;
                // Remove old mapping
-               port_bindings = upnp_config_list_port_bindings(lc->config);
-               if(port_bindings != NULL) {
-                       for(port_bindings_item = port_bindings;port_bindings_item != NULL; port_bindings_item = port_bindings_item->next) {
-                               port_mapping = (UpnpPortBinding *)port_bindings_item->data;
-                               //TODO: Don't send id it's udp/tcp/tls port binding
+               list = upnp_config_list_port_bindings(lc->config);
+               if(list == NULL) {
+                       lupnp->emit = TRUE;
+               } else {
+                       lupnp->cleaning = TRUE;
+                       for(item = list;item != NULL; item = item->next) {
+                               port_mapping = (UpnpPortBinding *)item->data;
                                upnp_context_send_remove_port_binding(lc, port_mapping);
                        }
-                       ms_list_for_each(port_bindings,(void (*)(void*))upnp_port_binding_release);
-                       port_bindings = ms_list_free(port_bindings);
+                       ms_list_for_each(list,(void (*)(void*))upnp_port_binding_release);
+                       list = ms_list_free(list);
                }
        }
 
-       if(lupnp->state == LinphoneUpnpStateOk && lupnp->old_state != LinphoneUpnpStateOk) {
-               // Add port bindings
+       if(lupnp->emit) {
+               lupnp->emit = FALSE;
+
+               /* Force port bindings */
                if(lupnp->sip_udp != NULL) {
+                       lupnp->sip_udp->state = LinphoneUpnpStateIdle;
                        upnp_context_send_add_port_binding(lc, lupnp->sip_udp);
                }
                if(lupnp->sip_tcp != NULL) {
+                       lupnp->sip_udp->state = LinphoneUpnpStateIdle;
                        upnp_context_send_add_port_binding(lc, lupnp->sip_tcp);
                }
                if(lupnp->sip_tls != NULL) {
+                       lupnp->sip_udp->state = LinphoneUpnpStateIdle;
                        upnp_context_send_add_port_binding(lc, lupnp->sip_tls);
                }
-       }
-
-       /* Update configs */
-       for(port_bindings_item = lupnp->pending_configs;port_bindings_item!=NULL;port_bindings_item=port_bindings_item->next) {
-               port_mapping = (UpnpPortBinding *)port_bindings_item->data;
-               if(port_mapping->state == LinphoneUpnpStateAdding) {
-                       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(lc->config, UPNP_SECTION_NAME, key, "uPnP");
-                       upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping);
-               }
-               if(port_mapping->state == LinphoneUpnpStateRemoving) {
-                       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(lc->config, UPNP_SECTION_NAME, key, NULL);
-                       upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping);
+               list = lc->calls;
+               while(list != NULL) {
+                       call = (LinphoneCall *)list->data;
+                       call->upnp_session->audio->rtp->state = LinphoneUpnpStateIdle;
+                       call->upnp_session->audio->rtcp->state = LinphoneUpnpStateIdle;
+                       call->upnp_session->video->rtp->state = LinphoneUpnpStateIdle;
+                       call->upnp_session->video->rtcp->state = LinphoneUpnpStateIdle;
+                       linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL);
+                       list = list->next;
                }
        }
-       ms_list_for_each(lupnp->pending_configs,(void (*)(void*))upnp_port_binding_release);
-       lupnp->pending_configs = ms_list_free(lupnp->pending_configs);
 
-       lupnp->old_state = lupnp->state;
+       /* 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(lc->config, UPNP_SECTION_NAME, key, "uPnP");
+               upnp_port_binding_log(ORTP_DEBUG, "Configuration: Added port binding", port_mapping);
+       }
+       ms_list_for_each(lupnp->adding_configs,(void (*)(void*))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(lc->config, UPNP_SECTION_NAME, key, NULL);
+               upnp_port_binding_log(ORTP_DEBUG, "Configuration: Removed port binding", port_mapping);
+       }
+       ms_list_for_each(lupnp->removing_configs,(void (*)(void*))upnp_port_binding_release);
+       lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
+
        ms_mutex_unlock(&lupnp->mutex);
        return TRUE;
 }
@@ -687,7 +786,9 @@ UpnpStream* upnp_stream_new() {
 
 void upnp_stream_destroy(UpnpStream* stream) {
        upnp_port_binding_release(stream->rtp);
+       stream->rtp = NULL;
        upnp_port_binding_release(stream->rtcp);
+       stream->rtcp = NULL;
        ms_free(stream);
 }
 
@@ -779,66 +880,60 @@ MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc) {
        return retList;
 }
 
-int upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) {
+void upnp_config_add_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) {
        UpnpContext *lupnp = &lc->upnp;
-       MSList *list = lupnp->pending_configs;
+       MSList *list;
        UpnpPortBinding *list_port;
-       bool_t remove = FALSE;
-       bool_t add = TRUE;
+
+       list = lupnp->removing_configs;
        while(list != NULL) {
                list_port = (UpnpPortBinding *)list->data;
                if(upnp_port_binding_equal(list_port, port) == TRUE) {
-                       if(list_port->state == LinphoneUpnpStateAdding) {
-                               add = FALSE;
-                               break;
-                       }
-                       if(list_port->state == LinphoneUpnpStateRemoving) {
-                               remove = TRUE;
-                               break;
-                       }
+                       lupnp->removing_configs = ms_list_remove(lupnp->removing_configs, list_port);
+                       upnp_port_binding_release(list_port);
+                       return;
                }
                list = ms_list_next(list);
        }
 
-       if(remove) {
-               lupnp->pending_configs = ms_list_remove(list, list_port);
-       } else if(add) {
-               list_port = upnp_port_binding_copy(port);
-               list_port->state = LinphoneUpnpStateAdding;
-               lupnp->pending_configs = ms_list_append(list, list_port);
+       list = lupnp->adding_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(upnp_port_binding_equal(list_port, port) == TRUE) {
+                       return;
+               }
+               list = ms_list_next(list);
        }
 
-       return 0;
+       list_port = upnp_port_binding_copy(port);
+       lupnp->adding_configs = ms_list_append(lupnp->adding_configs, list_port);
 }
 
-int upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) {
+void upnp_config_remove_port_binding(LinphoneCore *lc, const UpnpPortBinding *port) {
        UpnpContext *lupnp = &lc->upnp;
-       MSList *list = lupnp->pending_configs;
+       MSList *list;
        UpnpPortBinding *list_port;
-       bool_t remove = FALSE;
-       bool_t add = TRUE;
+
+       list = lupnp->adding_configs;
        while(list != NULL) {
                list_port = (UpnpPortBinding *)list->data;
-               if(upnp_port_binding_equal(list_port, port)) {
-                       if(list_port->state == LinphoneUpnpStateRemoving) {
-                               add = FALSE;
-                               break;
-                       }
-                       if(list_port->state == LinphoneUpnpStateAdding) {
-                               remove = TRUE;
-                               break;
-                       }
+               if(upnp_port_binding_equal(list_port, port) == TRUE) {
+                       lupnp->adding_configs = ms_list_remove(lupnp->adding_configs, list_port);
+                       upnp_port_binding_release(list_port);
+                       return;
                }
                list = ms_list_next(list);
        }
 
-       if(remove) {
-               lupnp->pending_configs = ms_list_remove(list, list_port);
-       } else if(add) {
-               list_port = upnp_port_binding_copy(port);
-               list_port->state = LinphoneUpnpStateRemoving;
-               lupnp->pending_configs = ms_list_append(list, list_port);
+       list = lupnp->removing_configs;
+       while(list != NULL) {
+               list_port = (UpnpPortBinding *)list->data;
+               if(upnp_port_binding_equal(list_port, port) == TRUE) {
+                       return;
+               }
+               list = ms_list_next(list);
        }
 
-       return 0;
+       list_port = upnp_port_binding_copy(port);
+       lupnp->removing_configs = ms_list_append(lupnp->removing_configs, list_port);
 }
index b515d041087d56a3018d4a5ecd5276b900507a06..04281c7379b84aecd54725eef9aca52e4348093f 100644 (file)
@@ -65,10 +65,17 @@ typedef struct _UpnpContext {
        UpnpPortBinding *sip_tls;
        UpnpPortBinding *sip_udp;
        UpnpState state;
-       UpnpState old_state;
-       MSList *pending_configs;
+       MSList *removing_configs;
+       MSList *adding_configs;
+       MSList *pending_bindings;
+
+       bool_t clean; // True if at the next loop clean the port bindings
+       bool_t cleaning; // True if the cleaning processing;
+       bool_t emit; // True if at the next loop emit the port bindings
 
        ms_mutex_t mutex;
+       ms_cond_t cond;
+
 } UpnpContext;
 
 void linphone_core_update_local_media_description_from_upnp(SalMediaDescription *desc, UpnpSession *session);