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

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__
This diff is collapsed.
#ifndef _UPNP_IGD_UTILS_H__
#define _UPNP_IGD_UTILS_H__
#include "mediastreamer2/upnp_igd.h"
#include <upnp.h>
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);
char *upnp_igd_get_first_document_item(upnp_igd_context *uIGD, IXML_Document *doc, const char *item);
char *upnp_igd_get_element_value(upnp_igd_context *uIGD, IXML_Element *element);
char *upnp_igd_get_first_element_item(upnp_igd_context *uIGD,IXML_Element *element, const char *item);
int upnp_igd_get_find_and_parse_service(upnp_igd_context *uIGD, IXML_Document *DescDoc, const char *location,
const char *serviceType, char **serviceId, char **eventURL, char **controlURL);
#endif //_UPNP_IGD_UTILS_H__
......@@ -25,7 +25,13 @@ tones_SOURCES=tones.c
TEST_DEPLIBS=\
$(top_builddir)/src/libmediastreamer_base.la \
$(top_builddir)/src/libmediastreamer_base.la
if BUILD_VOIP_LIBRARY
TEST_DEPLIBS+= $(top_builddir)/src/libmediastreamer_voip.la
endif
TEST_DEPLIBS+=\
$(ORTP_LIBS) \
$(ALSA_LIBS) \
$(ARTS_LIBS) \
......@@ -36,10 +42,6 @@ TEST_DEPLIBS=\
$(VIDEO_LIBS) \
$(PCAP_LIBS)
if BUILD_VOIP_LIBRARY
TEST_DEPLIBS+=$(top_builddir)/src/libmediastreamer_voip.la
endif
if ORTP_ENABLED
if MS2_FILTERS
bin_PROGRAMS=mediastream
......
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