Commit 73a772ac authored by Yann Diorcet's avatar Yann Diorcet
Browse files

upnp_igd: avoid dead lock when using callback

parent 44992c09
......@@ -85,9 +85,7 @@ int upnp_igd_delete_node(upnp_igd_context *igd_ctxt, upnp_igd_device_node *node)
free(node);
node = NULL;
if(igd_ctxt->callback_fct != NULL) {
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_DEVICE_REMOVED, NULL);
}
upnp_context_add_callback(igd_ctxt, UPNP_IGD_DEVICE_REMOVED, NULL);
return 0;
}
......@@ -243,18 +241,19 @@ void *upnp_igd_timer_loop(void *args) {
// Update timeout
gettimeofday(&tp, NULL);
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += incr;
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += incr;
ithread_mutex_lock(&igd_ctxt->timer_mutex);
while(ithread_cond_timedwait(&igd_ctxt->timer_cond, &igd_ctxt->timer_mutex, &ts) == ETIMEDOUT) {
upnp_igd_verify_timeouts(igd_ctxt, incr);
upnp_context_handle_callbacks(igd_ctxt);
// Update timeout
gettimeofday(&tp, NULL);
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += incr;
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += incr;
}
ithread_mutex_unlock(&igd_ctxt->timer_mutex);
......@@ -473,9 +472,14 @@ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, st
igd_ctxt->devices = deviceNode;
}
if(igd_ctxt->callback_fct != NULL) {
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_DEVICE_ADDED, NULL);
}
// Ask some details
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetNATRSIPStatus", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
// Usefull on some router
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetStatusInfo", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetExternalIPAddress", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
upnp_context_add_callback(igd_ctxt, UPNP_IGD_DEVICE_ADDED, NULL);
if (serviceId)
free(serviceId);
......@@ -483,13 +487,6 @@ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, st
free(controlURL);
if (event_url)
free(event_url);
// Ask some details
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetNATRSIPStatus", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
// Usefull on some router
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetStatusInfo", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
upnp_igd_send_action(igd_ctxt, deviceNode, IGD_SERVICE_WANIPCONNECTION, "GetExternalIPAddress", NULL, NULL, 0, upnp_igd_callback, igd_ctxt);
}
}
......@@ -553,14 +550,12 @@ void upnp_igd_var_updated(upnp_igd_context* igd_ctxt, upnp_igd_device_node *devi
upnp_igd_print(igd_ctxt, UPNP_IGD_MESSAGE, "IGD device: %s[%s] | %s.%s = %s",
device_node->device.friendly_name, device_node->device.udn,
IGDServiceName[service], IGDVarName[service][variable], varValue);
if(igd_ctxt->callback_fct != NULL) {
if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_EXTERNAL_IP_ADDRESS) {
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED, (void*)varValue);
} else if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_NAT_ENABLED) {
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_NAT_ENABLED_CHANGED, (void*)varValue);
} else if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_CONNECTION_STATUS) {
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_CONNECTION_STATUS_CHANGED, (void*)varValue);
}
if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_EXTERNAL_IP_ADDRESS) {
upnp_context_add_callback(igd_ctxt, UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED, (void*)varValue);
} else if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_NAT_ENABLED) {
upnp_context_add_callback(igd_ctxt, UPNP_IGD_NAT_ENABLED_CHANGED, (void*)varValue);
} else if(service == IGD_SERVICE_WANIPCONNECTION && variable == IGD_SERVICE_WANIPCONNECTION_CONNECTION_STATUS) {
upnp_context_add_callback(igd_ctxt, UPNP_IGD_CONNECTION_STATUS_CHANGED, (void*)varValue);
}
}
......@@ -837,7 +832,7 @@ int upnp_igd_callback(Upnp_EventType event_type, void* event, void *cookie) {
int ret = 1;
upnp_igd_context *igd_ctxt = (upnp_igd_context*)cookie;
upnp_igd_print_event(igd_ctxt, UPNP_IGD_DEBUG, event_type, event);
switch(event_type) {
switch(event_type) {
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
case UPNP_DISCOVERY_SEARCH_RESULT: {
struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)event;
......@@ -924,9 +919,11 @@ int upnp_igd_callback(Upnp_EventType event_type, void* event, void *cookie) {
break;
default:
break;
}
}
upnp_context_handle_callbacks(igd_ctxt);
return ret;
return ret;
}
......@@ -950,6 +947,8 @@ upnp_igd_context* upnp_igd_create(upnp_igd_callback_function cb_fct, upnp_igd_pr
upnp_igd_context *igd_ctxt = (upnp_igd_context*)malloc(sizeof(upnp_igd_context));
igd_ctxt->devices = NULL;
igd_ctxt->callback_fct = cb_fct;
igd_ctxt->callback_events = NULL;
igd_ctxt->print_fct = print_fct;
igd_ctxt->cookie = cookie;
igd_ctxt->upnp_handle = -1;
igd_ctxt->timer_thread = (ithread_t)NULL;
......@@ -961,9 +960,15 @@ upnp_igd_context* upnp_igd_create(upnp_igd_callback_function cb_fct, upnp_igd_pr
ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP);
ithread_mutex_init(&igd_ctxt->print_mutex, &attr);
ithread_mutexattr_destroy(&attr);
ithread_mutex_lock(&igd_ctxt->print_mutex);
igd_ctxt->print_fct = print_fct;
ithread_mutex_unlock(&igd_ctxt->print_mutex);
}
/* Initialize print mutex */
{
ithread_mutexattr_t attr;
ithread_mutexattr_init(&attr);
ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP);
ithread_mutex_init(&igd_ctxt->callback_mutex, &attr);
ithread_mutexattr_destroy(&attr);
}
/* Initialize device mutex */
......@@ -1105,8 +1110,13 @@ void upnp_igd_destroy(upnp_igd_context* igd_ctxt) {
if(igd_ctxt->upnp_handle != -1) {
upnp_igd_stop(igd_ctxt);
}
upnp_context_free_callbacks(igd_ctxt);
ithread_mutex_destroy(&igd_ctxt->devices_mutex);
ithread_mutex_destroy(&igd_ctxt->callback_mutex);
ithread_cond_destroy(&igd_ctxt->timer_cond);
ithread_mutex_destroy(&igd_ctxt->timer_mutex);
......
......@@ -34,23 +34,21 @@ int upnp_igd_port_mapping_handle_action(upnp_igd_port_mapping_context *igd_port_
while (tmpdevnode) {
for (service = 0; service < IGD_SERVICE_SERVCOUNT; service++) {
if (strcmp(tmpdevnode->device.services[service].control_url, controlURL) == 0) {
if(igd_ctxt->callback_fct != NULL) {
node = ixmlNode_getFirstChild(&action->n);
if(node && node->nodeType == eELEMENT_NODE) {
ctmpstate = ixmlNode_getLocalName(node);
if(ctmpstate != NULL) {
igd_port_mapping_ctxt->mapping.retvalue = errcode; // Set the return value
if(strcmp(ctmpstate, "AddPortMapping") == 0) {
if(errcode == UPNP_E_SUCCESS)
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_PORT_MAPPING_ADD_SUCCESS, &igd_port_mapping_ctxt->mapping);
else
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_PORT_MAPPING_ADD_FAILURE, &igd_port_mapping_ctxt->mapping);
} else if(strcmp(ctmpstate, "DeletePortMapping") == 0) {
if(errcode == UPNP_E_SUCCESS)
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS, &igd_port_mapping_ctxt->mapping);
else
igd_ctxt->callback_fct(igd_ctxt->cookie, UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE, &igd_port_mapping_ctxt->mapping);
}
node = ixmlNode_getFirstChild(&action->n);
if(node && node->nodeType == eELEMENT_NODE) {
ctmpstate = ixmlNode_getLocalName(node);
if(ctmpstate != NULL) {
igd_port_mapping_ctxt->mapping.retvalue = errcode; // Set the return value
if(strcmp(ctmpstate, "AddPortMapping") == 0) {
if(errcode == UPNP_E_SUCCESS)
upnp_context_add_callback(igd_ctxt, UPNP_IGD_PORT_MAPPING_ADD_SUCCESS, &igd_port_mapping_ctxt->mapping);
else
upnp_context_add_callback(igd_ctxt, UPNP_IGD_PORT_MAPPING_ADD_FAILURE, &igd_port_mapping_ctxt->mapping);
} else if(strcmp(ctmpstate, "DeletePortMapping") == 0) {
if(errcode == UPNP_E_SUCCESS)
upnp_context_add_callback(igd_ctxt, UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS, &igd_port_mapping_ctxt->mapping);
else
upnp_context_add_callback(igd_ctxt, UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE, &igd_port_mapping_ctxt->mapping);
}
}
}
......@@ -82,6 +80,8 @@ int upnp_igd_port_mapping_callback(Upnp_EventType event_type, void* event, void
break;
}
upnp_context_handle_callbacks(igd_port_mapping_ctxt->igd_ctxt);
upnp_igd_port_mapping_context_destroy(igd_port_mapping_ctxt);
return ret;
......
......@@ -45,6 +45,16 @@ typedef struct _upnp_igd_device_node {
struct _upnp_igd_device_node *next;
} upnp_igd_device_node;
typedef struct _upnp_igd_callback_event {
upnp_igd_event event;
void *arg;
} upnp_igd_callback_event;
typedef struct _upnp_igd_callback_event_node {
struct _upnp_igd_callback_event event;
struct _upnp_igd_callback_event_node *next;
} upnp_igd_callback_event_node;
struct _upnp_igd_context {
ithread_t timer_thread;
ithread_cond_t timer_cond;
......@@ -56,6 +66,9 @@ struct _upnp_igd_context {
upnp_igd_device_node *devices;
upnp_igd_callback_function callback_fct;
upnp_igd_callback_event_node *callback_events;
ithread_mutex_t callback_mutex;
ithread_mutex_t print_mutex;
upnp_igd_print_function print_fct;
void *cookie;
......@@ -69,6 +82,10 @@ extern const char *IGDVarName[IGD_SERVICE_SERVCOUNT][IGD_MAXVARS];
extern char IGDVarCount[IGD_SERVICE_SERVCOUNT];
extern int IGDTimeOut[IGD_SERVICE_SERVCOUNT];
void upnp_context_add_callback(upnp_igd_context *igd_ctx, upnp_igd_event event, void *arg);
void upnp_context_handle_callbacks(upnp_igd_context *igd_ctx);
void upnp_context_free_callbacks(upnp_igd_context *igd_ctx);
int upnp_igd_callback(Upnp_EventType event_type, void* event, void *cookie);
int upnp_igd_send_action(upnp_igd_context* igd_ctxt, upnp_igd_device_node *device_node, int service,
const char *actionname, const char **param_name, const char **param_val, int param_count,
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment