Commit 06e50570 authored by Yann Diorcet's avatar Yann Diorcet

uPnP: Add api

Improve protection agains bufferoverflows
Improve multi thread data access protection
parent 57785176
......@@ -59,6 +59,7 @@ int upnp_igd_is_started(upnp_igd_context *igd_ctxt);
int upnp_igd_stop(upnp_igd_context*igd_ctxt);
MS2_PUBLIC void upnp_igd_destroy(upnp_igd_context *igd_ctxt);
MS2_PUBLIC char *upnp_igd_get_local_ipaddress(upnp_igd_context *igd_ctxt);
MS2_PUBLIC const char *upnp_igd_get_device_id(upnp_igd_context *igd_ctxt);
MS2_PUBLIC const char *upnp_igd_get_external_ipaddress(upnp_igd_context *igd_ctxt);
MS2_PUBLIC const char *upnp_igd_get_connection_status(upnp_igd_context *igd_ctxt);
MS2_PUBLIC int upnp_igd_get_nat_enabled(upnp_igd_context *igd_ctxt);
......@@ -66,6 +67,8 @@ MS2_PUBLIC int upnp_igd_get_nat_enabled(upnp_igd_context *igd_ctxt);
MS2_PUBLIC int upnp_igd_add_port_mapping(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping);
MS2_PUBLIC int upnp_igd_delete_port_mapping(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping);
int upnp_refresh(upnp_igd_context *igd_ctxt);
MS2_PUBLIC int upnp_igd_refresh(upnp_igd_context *igd_ctxt);
MS2_PUBLIC void upnp_igd_set_devices_timeout(upnp_igd_context *igd_ctxt, int seconds);
MS2_PUBLIC int upnp_igd_get_devices_timeout(upnp_igd_context *igd_ctxt);
#endif //_UPNP_IGD_H__
......@@ -185,6 +185,9 @@ void upnp_igd_verify_timeouts(upnp_igd_context *igd_ctxt, int incr) {
prevdevnode = NULL;
curdevnode = igd_ctxt->devices;
while (curdevnode) {
if(curdevnode->device.advr_time_out > igd_ctxt->max_adv_timeout) {
curdevnode->device.advr_time_out = igd_ctxt->max_adv_timeout;
}
curdevnode->device.advr_time_out -= incr;
upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "IGD device: %s[%s] | Advertisement Timeout: %d",
curdevnode->device.friendly_name,
......@@ -237,7 +240,7 @@ void *upnp_igd_timer_loop(void *args) {
struct timeval tp;
/* how often to verify the timeouts, in seconds */
static int incr = 30;
int incr = igd_ctxt->timer_timeout;
// Update timeout
gettimeofday(&tp, NULL);
......@@ -414,10 +417,10 @@ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, st
/* Create a new device node */
deviceNode = (upnp_igd_device_node *) malloc(sizeof(upnp_igd_device_node));
memset(deviceNode->device.services, '\0', sizeof(upnp_igd_service) * IGD_SERVICE_SERVCOUNT);
strcpy(deviceNode->device.udn, UDN);
strcpy(deviceNode->device.desc_doc_url, d_event->Location);
strcpy(deviceNode->device.friendly_name, friendlyName);
strcpy(deviceNode->device.pres_url, presURL);
strncpy(deviceNode->device.udn, UDN, sizeof(deviceNode->device.udn));
strncpy(deviceNode->device.desc_doc_url, d_event->Location, sizeof(deviceNode->device.desc_doc_url));
strncpy(deviceNode->device.friendly_name, friendlyName, sizeof(deviceNode->device.friendly_name));
strncpy(deviceNode->device.pres_url, presURL, sizeof(deviceNode->device.pres_url));
deviceNode->device.advr_time_out = d_event->Expires;
// Reset values
......@@ -442,15 +445,19 @@ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, st
} else {
upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Could not find Service: %s", IGDServiceType[service]);
}
if(serviceId != NULL)
strcpy(deviceNode->device.services[service].service_id, serviceId);
strcpy(deviceNode->device.services[service].service_type, IGDServiceName[service]);
if(controlURL != NULL)
strcpy(deviceNode->device.services[service].control_url, controlURL);
if(event_url != NULL)
strcpy(deviceNode->device.services[service].event_url, event_url);
if(eventSID != NULL)
strcpy(deviceNode->device.services[service].sid, eventSID);
if(serviceId != NULL) {
upnp_igd_strncpy(deviceNode->device.services[service].service_id, serviceId, sizeof(deviceNode->device.services[service].service_id));
}
upnp_igd_strncpy(deviceNode->device.services[service].service_type, IGDServiceName[service], sizeof(deviceNode->device.services[service].service_type));
if(controlURL != NULL) {
upnp_igd_strncpy(deviceNode->device.services[service].control_url, controlURL, sizeof(deviceNode->device.services[service].control_url));
}
if(event_url != NULL) {
upnp_igd_strncpy(deviceNode->device.services[service].event_url, event_url, sizeof(deviceNode->device.services[service].event_url));
}
if(eventSID != NULL) {
upnp_igd_strncpy(deviceNode->device.services[service].sid, eventSID, sizeof(deviceNode->device.services[service].sid));
}
for (var = 0; var < IGDVarCount[service]; var++) {
deviceNode->device.services[service].variables[var] = (char *)malloc(IGD_MAX_VAL_LEN);
strcpy(deviceNode->device.services[service].variables[var], "");
......@@ -519,15 +526,22 @@ void upnp_igd_add_device(upnp_igd_context *igd_ctxt, IXML_Document *desc_doc, st
int upnp_igd_refresh(upnp_igd_context* igd_ctxt) {
int ret;
ithread_mutex_lock(&igd_ctxt->mutex);
upnp_igd_remove_all(igd_ctxt);
upnp_igd_print(igd_ctxt, UPNP_IGD_MESSAGE, "IGD client searching...");
ret = UpnpSearchAsync(igd_ctxt->upnp_handle, 5, IGDDeviceType, igd_ctxt);
if (UPNP_E_SUCCESS != ret) {
upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "Error sending search request%d", ret);
ithread_mutex_unlock(&igd_ctxt->mutex);
return -1;
}
ithread_mutex_unlock(&igd_ctxt->mutex);
upnp_context_handle_callbacks(igd_ctxt);
return 0;
}
......@@ -586,7 +600,7 @@ void upnp_igd_handle_get_var(upnp_igd_context* igd_ctxt, const char *controlURL,
for (variable = 0; variable < IGDVarCount[service]; variable++) {
if (strcmp(IGDVarName[service][variable], varName) == 0) {
if(strcmp(tmpdevnode->device.services[service].variables[variable], varValue)) {
strcpy(tmpdevnode->device.services[service].variables[variable], varValue);
upnp_igd_strncpy(tmpdevnode->device.services[service].variables[variable], varValue, IGD_MAX_VAR_LEN);
upnp_igd_var_updated(igd_ctxt, tmpdevnode, service, variable, varValue);
}
break;
......@@ -625,7 +639,7 @@ void upnp_igd_handle_send_action(upnp_igd_context* igd_ctxt, const char *control
long unsigned int length1;
int j;
char *tmpstate = NULL;
char variable_name[IGD_MAX_VAR_LEN + 3];
char variable_name[sizeof("New") + IGD_MAX_VAR_LEN];
ithread_mutex_lock(&igd_ctxt->devices_mutex);
......@@ -648,7 +662,7 @@ void upnp_igd_handle_send_action(upnp_igd_context* igd_ctxt, const char *control
tmpstate = upnp_igd_get_element_value(igd_ctxt, variable);
if (tmpstate) {
if(strcmp(tmpdevnode->device.services[service].variables[j], tmpstate)) {
strcpy(tmpdevnode->device.services[service].variables[j], tmpstate);
upnp_igd_strncpy(tmpdevnode->device.services[service].variables[j], tmpstate, IGD_MAX_VAR_LEN);
upnp_igd_var_updated(igd_ctxt, tmpdevnode, service, j, tmpdevnode->device.services[service].variables[j]);
}
}
......@@ -718,7 +732,7 @@ void upnp_igd_state_update(upnp_igd_context* igd_ctxt, upnp_igd_device_node *dev
tmpstate = upnp_igd_get_element_value(igd_ctxt, variable);
if (tmpstate) {
if(strcmp(values[j], tmpstate)) {
strcpy(values[j], tmpstate);
upnp_igd_strncpy(values[j], tmpstate, IGD_MAX_VAR_LEN);
upnp_igd_var_updated(igd_ctxt, device_node, service, j, values[j]);
}
}
......@@ -800,7 +814,7 @@ void upnp_igd_handle_subscribe_update(upnp_igd_context* igd_ctxt, const char *ev
for (service = 0; service < IGD_SERVICE_SERVCOUNT; service++) {
if (strcmp(tmpdevnode->device.services[service].event_url, event_url) == 0) {
upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Received IGD %s Event Renewal for event_url %s", IGDServiceName[service], event_url);
strcpy(tmpdevnode->device.services[service].sid, sid);
upnp_igd_strncpy(tmpdevnode->device.services[service].sid, sid, sizeof(tmpdevnode->device.services[service].sid));
break;
}
}
......@@ -951,6 +965,8 @@ upnp_igd_context* upnp_igd_create(upnp_igd_callback_function cb_fct, upnp_igd_pr
igd_ctxt->callback_events = NULL;
igd_ctxt->print_fct = print_fct;
igd_ctxt->cookie = cookie;
igd_ctxt->max_adv_timeout = 60*3;
igd_ctxt->timer_timeout = igd_ctxt->max_adv_timeout/2;
igd_ctxt->upnp_handle = -1;
igd_ctxt->client_count = 0;
igd_ctxt->timer_thread = (ithread_t)NULL;
......@@ -1072,10 +1088,10 @@ int upnp_igd_start(upnp_igd_context*igd_ctxt) {
/* Initialize timer stuff */
ithread_create(&igd_ctxt->timer_thread, NULL, upnp_igd_timer_loop, igd_ctxt);
ret = upnp_igd_refresh(igd_ctxt);
ithread_mutex_unlock(&igd_ctxt->mutex);
ret = upnp_igd_refresh(igd_ctxt);
return ret;
}
......@@ -1110,7 +1126,7 @@ int upnp_igd_is_started(upnp_igd_context *igd_ctxt) {
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
int upnp_igd_stop(upnp_igd_context*igd_ctxt) {
int upnp_igd_stop(upnp_igd_context *igd_ctxt) {
ithread_mutex_lock(&igd_ctxt->mutex);
if(igd_ctxt->upnp_handle == -1) {
......@@ -1183,3 +1199,42 @@ void upnp_igd_destroy(upnp_igd_context* igd_ctxt) {
free(igd_ctxt);
}
/********************************************************************************
* upnp_igd_set_device_timeout
*
* Description:
* Set devices lease time
*
* Parameters:
* igd_ctxt -- The upnp igd context
* seconds -- The number of seconds
*
********************************************************************************/
void upnp_igd_set_devices_timeout(upnp_igd_context *igd_ctxt, int seconds) {
ithread_mutex_lock(&igd_ctxt->mutex);
igd_ctxt->max_adv_timeout = seconds;
igd_ctxt->timer_timeout = igd_ctxt->max_adv_timeout/2;
ithread_mutex_unlock(&igd_ctxt->mutex);
}
/********************************************************************************
* upnp_igd_get_device_timeout
*
* Description:
* Get devices lease time
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
int upnp_igd_get_devices_timeout(upnp_igd_context *igd_ctxt) {
int ret;
ithread_mutex_lock(&igd_ctxt->mutex);
ret = igd_ctxt->max_adv_timeout;
ithread_mutex_unlock(&igd_ctxt->mutex);
return ret;
}
#include "mediastreamer2/upnp_igd.h"
#include "upnp_igd_utils.h"
#include "upnp_igd_private.h"
#include <string.h>
#include <stdio.h>
......@@ -115,6 +116,7 @@ char *upnp_igd_get_local_ipaddress(upnp_igd_context *igd_ctxt) {
*
********************************************************************************/
const char *upnp_igd_get_external_ipaddress(upnp_igd_context* igd_ctxt) {
static char ret[IGD_MAX_VAL_LEN];
const char *address = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
......@@ -122,6 +124,9 @@ const char *upnp_igd_get_external_ipaddress(upnp_igd_context* igd_ctxt) {
if(address != NULL) {
if(strlen(address) == 0) {
address = NULL;
} else {
upnp_igd_strncpy(ret, address, sizeof(ret));
address = ret;
}
}
}
......@@ -129,6 +134,35 @@ const char *upnp_igd_get_external_ipaddress(upnp_igd_context* igd_ctxt) {
return address;
}
/********************************************************************************
* upnp_igd_get_device_id
*
* Description:
* Return the device identifier NULL if doesn't exist.
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
MS2_PUBLIC const char *upnp_igd_get_device_id(upnp_igd_context *igd_ctxt) {
static char ret[250];
const char *id = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
id = igd_ctxt->devices->device.udn;
if(id != NULL) {
if(strlen(id) == 0) {
id = NULL;
} else {
upnp_igd_strncpy(ret, id, sizeof(ret));
id = ret;
}
}
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return id;
}
/********************************************************************************
* upnp_igd_get_connection_status
......@@ -141,6 +175,7 @@ const char *upnp_igd_get_external_ipaddress(upnp_igd_context* igd_ctxt) {
*
********************************************************************************/
const char *upnp_igd_get_connection_status(upnp_igd_context *igd_ctxt) {
static char ret[IGD_MAX_VAL_LEN];
const char *status = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
......@@ -148,6 +183,9 @@ const char *upnp_igd_get_connection_status(upnp_igd_context *igd_ctxt) {
if(status != NULL) {
if(strlen(status) == 0) {
status = NULL;
} else {
upnp_igd_strncpy(ret, status, sizeof(ret));
status = ret;
}
}
}
......
......@@ -61,6 +61,9 @@ struct _upnp_igd_context {
ithread_t timer_thread;
ithread_cond_t timer_cond;
ithread_mutex_t timer_mutex;
int timer_timeout;
int max_adv_timeout;
UpnpClient_Handle upnp_handle;
......
......@@ -35,6 +35,12 @@
#include <string.h>
#include <stdlib.h>
char *upnp_igd_strncpy(char * destination, const char * source, size_t num) {
char * ret = strncpy(destination, source, num - 1);
destination[num - 1] = '\0';
return ret;
}
void upnp_context_add_client(upnp_igd_context *igd_ctxt) {
ithread_mutex_lock(&igd_ctxt->client_mutex);
igd_ctxt->client_count++;
......
......@@ -4,6 +4,8 @@
#include "mediastreamer2/upnp_igd.h"
#include <upnp.h>
char *upnp_igd_strncpy(char * destination, const char * source, size_t num);
void upnp_igd_print(upnp_igd_context *uIGD, upnp_igd_print_level level, const char *fmt, ...);
void upnp_igd_print_event_type(upnp_igd_context *uIGD, upnp_igd_print_level level, Upnp_EventType S);
void upnp_igd_print_event(upnp_igd_context *uIGD, upnp_igd_print_level level, Upnp_EventType EventType, void *Event);
......
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