Commit 2e0ef7e3 authored by Yann Diorcet's avatar Yann Diorcet
Browse files

Merge branch 'upnp'

parents 3a231efb b21f3042
......@@ -531,6 +531,26 @@ AC_SUBST(SPANDSP_LIBS)
fi
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_GSM, test x$build_gsm = xyes )
AM_CONDITIONAL(BUILD_G726, test "$have_spandsp" = "true" )
......@@ -545,7 +565,7 @@ AM_CONDITIONAL(BUILD_FFMPEG, test "$ffmpeg" = "true")
AM_CONDITIONAL(BUILD_SDL,test "$sdl_found" = "true" )
AM_CONDITIONAL(BUILD_X11_XV, test "$enable_xv" = "true" )
AM_CONDITIONAL(BUILD_X11_GL, test "$enable_gl" = "true" )
AM_CONDITIONAL(BUILD_UPNP, test "$build_upnp" = "true" )
dnl *********************************************
dnl Enable/disable oRTP dependency
......
......@@ -2,6 +2,7 @@
mediastreamer2_includedir=$(includedir)/mediastreamer2
mediastreamer2_include_HEADERS= ice.h \
upnp_igd.h \
mscodecutils.h \
msfilter.h \
msqueue.h \
......
#ifndef _UPNP_IGD_H__
#define _UPNP_IGD_H__
#include <stdarg.h>
typedef enum _upnp_igd_print_level {
UPNP_IGD_DEBUG = 0,
UPNP_IGD_MESSAGE,
UPNP_IGD_WARNING,
UPNP_IGD_ERROR
} upnp_igd_print_level;
typedef enum _upnp_igd_ip_protocol {
UPNP_IGD_IP_PROTOCOL_UDP = 0,
UPNP_IGD_IP_PROTOCOL_TCP
} upnp_igd_ip_protocol;
typedef enum _upnp_igd_event {
UPNP_IGD_EXTERNAL_IPADDRESS_CHANGED = 0,
UPNP_IGD_NAT_ENABLED_CHANGED,
UPNP_IGD_CONNECTION_STATUS_CHANGED,
UPNP_IGD_PORT_MAPPING_ADD_SUCCESS,
UPNP_IGD_PORT_MAPPING_ADD_FAILURE,
UPNP_IGD_PORT_MAPPING_REMOVE_SUCCESS,
UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE,
UPNP_IGD_DEVICE_ADDED = 100,
UPNP_IGD_DEVICE_REMOVED,
} upnp_igd_event;
typedef struct _upnp_igd_port_mapping {
upnp_igd_ip_protocol protocol;
const char* local_host;
int local_port;
const char* remote_host;
int remote_port;
const char* description;
void *cookie;
int retvalue;
} upnp_igd_port_mapping;
typedef void (*upnp_igd_callback_function)(void *cookie, upnp_igd_event event, void *arg);
typedef void (*upnp_igd_print_function)(void *cookie, upnp_igd_print_level level, const char *fmt, va_list list);
typedef struct _upnp_igd_context upnp_igd_context;
upnp_igd_context* upnp_igd_create(upnp_igd_callback_function cb_fct, upnp_igd_print_function print_fct, void *cookie);
int upnp_igd_start(upnp_igd_context*igd_ctxt);
int upnp_igd_is_started(upnp_igd_context *igd_ctxt);
int upnp_igd_stop(upnp_igd_context*igd_ctxt);
void upnp_igd_destroy(upnp_igd_context *igd_ctxt);
char *upnp_igd_get_local_ipaddress(upnp_igd_context *igd_ctxt);
const char *upnp_igd_get_external_ipaddress(upnp_igd_context *igd_ctxt);
const char *upnp_igd_get_connection_status(upnp_igd_context *igd_ctxt);
int upnp_igd_get_nat_enabled(upnp_igd_context *igd_ctxt);
int upnp_igd_add_port_mapping(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping);
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);
#endif //_UPNP_IGD_H__
......@@ -239,7 +239,13 @@ endif BUILD_VIDEO
endif MS2_FILTERS
if BUILD_UPNP
libmediastreamer_voip_la_SOURCES+= upnp/upnp_igd.c \
upnp/upnp_igd_private.h \
upnp/upnp_igd_cmd.c \
upnp/upnp_igd_utils.c \
upnp/upnp_igd_utils.h
endif
basedescs.h: Makefile $(libmediastreamer_base_la_SOURCES)
builddir=`pwd` && cd $(srcdir) && \
......@@ -333,6 +339,11 @@ endif
libmediastreamer_voip_la_LDFLAGS= $(libmediastreamer_base_la_LDFLAGS)
if BUILD_UPNP
AM_CFLAGS+=$(LIBUPNP_CFLAGS) -D_GNU_SOURCE
libmediastreamer_voip_la_LIBADD+= $(LIBUPNP_LIBS)
endif
if BUILD_IOS
libmediastreamer_voip_la_LDFLAGS+= -framework CoreGraphics
endif
......
This diff is collapsed.
#include "mediastreamer2/upnp_igd.h"
#include "upnp_igd_private.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _upnp_igd_port_mapping_context {
upnp_igd_context *igd_ctxt;
upnp_igd_port_mapping mapping;
} upnp_igd_port_mapping_context;
upnp_igd_port_mapping_context * upnp_igd_port_mapping_context_create(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping) {
upnp_igd_port_mapping_context *igd_port_mapping_ctxt = (upnp_igd_port_mapping_context *)malloc(sizeof(upnp_igd_port_mapping_context));
igd_port_mapping_ctxt->igd_ctxt = igd_ctxt;
memcpy(&igd_port_mapping_ctxt->mapping, mapping, sizeof(upnp_igd_port_mapping));
return igd_port_mapping_ctxt;
}
void upnp_igd_port_mapping_context_destroy(upnp_igd_port_mapping_context *igd_port_mapping_ctxt) {
free(igd_port_mapping_ctxt);
}
int upnp_igd_port_mapping_handle_action(upnp_igd_port_mapping_context *igd_port_mapping_ctxt, int errcode, const char *controlURL, IXML_Document *action, IXML_Document *result) {
upnp_igd_device_node *tmpdevnode;
int service;
IXML_Node *node;
const char *ctmpstate = NULL;
upnp_igd_context *igd_ctxt = igd_port_mapping_ctxt->igd_ctxt;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
tmpdevnode = igd_ctxt->devices;
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);
}
}
}
}
break;
}
}
tmpdevnode = tmpdevnode->next;
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return 0;
}
int upnp_igd_port_mapping_callback(Upnp_EventType event_type, void* event, void *cookie) {
int ret = 1;
upnp_igd_port_mapping_context *igd_port_mapping_ctxt = (upnp_igd_port_mapping_context*)cookie;
ret = upnp_igd_callback(event_type, event, igd_port_mapping_ctxt->igd_ctxt);
switch(event_type) {
case UPNP_CONTROL_ACTION_COMPLETE: {
struct Upnp_Action_Complete *a_event = (struct Upnp_Action_Complete *)event;
upnp_igd_port_mapping_handle_action(igd_port_mapping_ctxt, a_event->ErrCode, UPNP_STRING(a_event->CtrlUrl), a_event->ActionRequest, a_event->ActionResult);
}
break;
default:
break;
}
upnp_igd_port_mapping_context_destroy(igd_port_mapping_ctxt);
return ret;
}
/********************************************************************************
* upnp_igd_get_local_ipaddress
*
* Description:
* Return the local ip address or NULL if doesn't exist.
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
char *upnp_igd_get_local_ipaddress(upnp_igd_context *igd_ctxt) {
return UpnpGetServerIpAddress();
}
/********************************************************************************
* upnp_igd_get_external_ipaddress
*
* Description:
* Return the external ip address or NULL if doesn't exist.
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
const char *upnp_igd_get_external_ipaddress(upnp_igd_context* igd_ctxt) {
const char *address = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
address = igd_ctxt->devices->device.services[IGD_SERVICE_WANIPCONNECTION].variables[IGD_SERVICE_WANIPCONNECTION_EXTERNAL_IP_ADDRESS];
if(address != NULL) {
if(strlen(address) == 0) {
address = NULL;
}
}
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return address;
}
/********************************************************************************
* upnp_igd_get_connection_status
*
* Description:
* Return the connection status or NULL if doesn't exist.
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
const char *upnp_igd_get_connection_status(upnp_igd_context *igd_ctxt) {
const char *status = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
status = igd_ctxt->devices->device.services[IGD_SERVICE_WANIPCONNECTION].variables[IGD_SERVICE_WANIPCONNECTION_CONNECTION_STATUS];
if(status != NULL) {
if(strlen(status) == 0) {
status = NULL;
}
}
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return status;
}
/********************************************************************************
* upnp_igd_get_nat_enabled
*
* Description:
* Return 1 if the nat is enabled otherwise 0.
*
* Parameters:
* igd_ctxt -- The upnp igd context
*
********************************************************************************/
int upnp_igd_get_nat_enabled(upnp_igd_context *igd_ctxt) {
int enabled = 0;
const char *status = NULL;
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL) {
status = igd_ctxt->devices->device.services[IGD_SERVICE_WANIPCONNECTION].variables[IGD_SERVICE_WANIPCONNECTION_NAT_ENABLED];
if(status != NULL) {
if(strcmp(status, "1") == 0) {
enabled = 1;
}
}
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return enabled;
}
/********************************************************************************
* upnp_igd_add_port_mapping
*
* Description:
* Add a port mapping.
*
* Parameters:
* igd_ctxt -- The upnp igd context
* mapping -- The port mapping to add
*
********************************************************************************/
int upnp_igd_add_port_mapping(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping) {
int ret;
char local_port_str[6], remote_port_str[6];
upnp_igd_port_mapping_context * upnp_igd_port_mapping_ctxt = NULL;
const char* variables[]={
"NewProtocol",
"NewInternalClient",
"NewInternalPort",
"NewRemoteHost",
"NewExternalPort",
"NewPortMappingDescription",
"NewLeaseDuration",
"NewEnabled"
};
const char* values[]={
NULL,
NULL,
local_port_str,
NULL,
remote_port_str,
NULL,
"0",
"1"
};
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL && mapping != NULL && mapping->remote_host != NULL && mapping->local_host != NULL) {
/* Set values */
values[0] = (mapping->protocol == UPNP_IGD_IP_PROTOCOL_UDP)? "UDP": "TCP";
values[1] = mapping->local_host;
values[3] = mapping->remote_host;
values[5] = mapping->description;
/* Convert int to str */
snprintf(local_port_str, sizeof(local_port_str)/sizeof(local_port_str[0]), "%d", mapping->local_port);
snprintf(remote_port_str, sizeof(remote_port_str)/sizeof(remote_port_str[0]), "%d", mapping->remote_port);
upnp_igd_port_mapping_ctxt = upnp_igd_port_mapping_context_create(igd_ctxt, mapping);
ret = upnp_igd_send_action(igd_ctxt, igd_ctxt->devices, IGD_SERVICE_WANIPCONNECTION, "AddPortMapping",
variables, values, sizeof(values)/sizeof(values[0]),
upnp_igd_port_mapping_callback, upnp_igd_port_mapping_ctxt);
} else {
ret = 1;
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return ret;
}
/********************************************************************************
* upnp_igd_delete_port_mapping
*
* Description:
* Delete a port mapping.
*
* Parameters:
* igd_ctxt -- The upnp igd context
* protocol -- The protocol of map (UDP/TCP)
* remote_host -- The remote host of map
* remote_port -- The remote port of map
*
********************************************************************************/
int upnp_igd_delete_port_mapping(upnp_igd_context *igd_ctxt, const upnp_igd_port_mapping *mapping) {
int ret;
char remote_port_str[6];
upnp_igd_port_mapping_context * upnp_igd_port_mapping_ctxt = NULL;
const char* variables[]={
"NewProtocol",
"NewRemoteHost",
"NewExternalPort",
};
const char* values[]={
NULL,
NULL,
remote_port_str
};
ithread_mutex_lock(&igd_ctxt->devices_mutex);
if(igd_ctxt->devices != NULL && mapping != NULL && mapping->remote_host != NULL) {
/* Set values */
values[0] = (mapping->protocol == UPNP_IGD_IP_PROTOCOL_UDP)? "UDP": "TCP";
values[1] = mapping->remote_host;
/* Convert int to str */
snprintf(remote_port_str, sizeof(remote_port_str)/sizeof(remote_port_str[0]), "%d", mapping->remote_port);
upnp_igd_port_mapping_ctxt = upnp_igd_port_mapping_context_create(igd_ctxt, mapping);
ret = upnp_igd_send_action(igd_ctxt, igd_ctxt->devices, IGD_SERVICE_WANIPCONNECTION, "DeletePortMapping",
variables, values, sizeof(values)/sizeof(values[0]),
upnp_igd_port_mapping_callback, upnp_igd_port_mapping_ctxt);
} else {
ret = -1;
}
ithread_mutex_unlock(&igd_ctxt->devices_mutex);
return ret;
}
#ifndef _UPNP_IGD_PRIVATE_H__
#define _UPNP_IGD_PRIVATE_H__
#include "mediastreamer2/upnp_igd.h"
#include <upnp.h>
#include <ithread.h>
enum {
IGD_SERVICE_WANIPCONNECTION = 0,
IGD_SERVICE_SERVCOUNT
};
enum {
IGD_SERVICE_WANIPCONNECTION_EXTERNAL_IP_ADDRESS = 0,
IGD_SERVICE_WANIPCONNECTION_NAT_ENABLED,
IGD_SERVICE_WANIPCONNECTION_CONNECTION_STATUS,
IGD_SERVICE_WANIPCONNECTION_VARCOUNT
};
#define IGD_MAXVARS 3
#define IGD_MAX_VAL_LEN 256
#define IGD_MAX_VAR_LEN 256
typedef struct _upnp_igd_service {
char service_id[NAME_SIZE];
char service_type[NAME_SIZE];
char *variables[IGD_MAXVARS];
char event_url[NAME_SIZE];
char control_url[NAME_SIZE];
char sid[NAME_SIZE];
} upnp_igd_service;
typedef struct _upnp_igd_device {
char udn[250];
char desc_doc_url[250];
char friendly_name[250];
char pres_url[250];
int advr_time_out;
struct _upnp_igd_service services[IGD_SERVICE_SERVCOUNT];
} upnp_igd_device;
typedef struct _upnp_igd_device_node {
struct _upnp_igd_device device;
struct _upnp_igd_device_node *next;
} upnp_igd_device_node;
struct _upnp_igd_context {
ithread_t timer_thread;
ithread_cond_t timer_cond;
ithread_mutex_t timer_mutex;
UpnpClient_Handle upnp_handle;
ithread_mutex_t devices_mutex;
upnp_igd_device_node *devices;
upnp_igd_callback_function callback_fct;
ithread_mutex_t print_mutex;
upnp_igd_print_function print_fct;
void *cookie;
};
#if UPNP_VERSION <= 10606
#define UPNP_STRING(x) (x)
#else
#define UPNP_STRING(x) UpnpString_get_String(x)
#endif
extern const char *IGDDeviceType;
extern const char *IGDServiceType[];
extern const char *IGDServiceName[];
extern const char *IGDVarName[IGD_SERVICE_SERVCOUNT][IGD_MAXVARS];
extern char IGDVarCount[IGD_SERVICE_SERVCOUNT];
extern int IGDTimeOut[IGD_SERVICE_SERVCOUNT];
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,
Upnp_FunPtr fun, const void *cookie);
int upnp_igd_get_var(upnp_igd_context* igd_ctxt, upnp_igd_device_node *device_node, int service, int variable,
Upnp_FunPtr fun, const void *cookie);
#endif //_UPNP_IGD_PRIVATE_H__
/*******************************************************************************
*
* Copyright (c) 2000-2003 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#include "upnp_igd_utils.h"
#include "upnp_igd_private.h"
#include <upnptools.h>
#include <string.h>
#include <stdlib.h>
void upnp_igd_print(upnp_igd_context *uIGD, upnp_igd_print_level level, const char *fmt, ...) {
va_list ap;
/* Protect both the display and the static buffer with the mutex */
ithread_mutex_lock(&uIGD->print_mutex);
va_start(ap, fmt);
if (uIGD->print_fct) {
uIGD->print_fct(uIGD->cookie, level, fmt, ap);
}
va_end(ap);
ithread_mutex_unlock(&uIGD->print_mutex);
}
void upnp_igd_print_event_type(upnp_igd_context *uIGD, upnp_igd_print_level level, Upnp_EventType S) {
switch (S) {
/* Discovery */
case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
upnp_igd_print(uIGD, level, "UPNP_DISCOVERY_ADVERTISEMENT_ALIVE");
break;
case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE:
upnp_igd_print(uIGD, level, "UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE");
break;
case UPNP_DISCOVERY_SEARCH_RESULT:
upnp_igd_print(uIGD, level, "UPNP_DISCOVERY_SEARCH_RESULT");
break;
case UPNP_DISCOVERY_SEARCH_TIMEOUT:
upnp_igd_print(uIGD, level, "UPNP_DISCOVERY_SEARCH_TIMEOUT");
break;
/* SOAP */
case UPNP_CONTROL_ACTION_REQUEST:
upnp_igd_print(uIGD, level, "UPNP_CONTROL_ACTION_REQUEST");
break;
case UPNP_CONTROL_ACTION_COMPLETE:
upnp_igd_print(uIGD, level, "UPNP_CONTROL_ACTION_COMPLETE");
break;
case UPNP_CONTROL_GET_VAR_REQUEST:
upnp_igd_print(uIGD, level, "UPNP_CONTROL_GET_VAR_REQUEST");
break;
case UPNP_CONTROL_GET_VAR_COMPLETE:
upnp_igd_print(uIGD, level, "UPNP_CONTROL_GET_VAR_COMPLETE");
break;
/* GENA */
case UPNP_EVENT_SUBSCRIPTION_REQUEST:
upnp_igd_print(uIGD, level, "UPNP_EVENT_SUBSCRIPTION_REQUEST");
break;
case UPNP_EVENT_RECEIVED:
upnp_igd_print(uIGD, level, "UPNP_EVENT_RECEIVED");
break;
case UPNP_EVENT_RENEWAL_COMPLETE:
upnp_igd_print(uIGD, level, "UPNP_EVENT_RENEWAL_COMPLETE");
break;
case UPNP_EVENT_SUBSCRIBE_COMPLETE:
upnp_igd_print(uIGD, level, "UPNP_EVENT_SUBSCRIBE_COMPLETE");
break;
case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
upnp_igd_print(uIGD, level, "UPNP_EVENT_UNSUBSCRIBE_COMPLETE");
break;
case UPNP_EVENT_AUTORENEWAL_FAILED:
upnp_igd_print(uIGD, level, "UPNP_EVENT_AUTORENEWAL_FAILED");
break;
case UPNP_EVENT_SUBSCRIPTION_EXPIRED:
upnp_igd_print(uIGD, level, "UPNP_EVENT_SUBSCRIPTION_EXPIRED");
break;
}
}