
git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/trunk@368 119443c7-1b9e-41f8-b6fc-b9c35fce742c
4839 lines
143 KiB
C
4839 lines
143 KiB
C
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "config.h"
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
#include <assert.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
#ifndef WIN32
|
|
#include <arpa/inet.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/utsname.h>
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
#if defined(_sun)
|
|
#include <sys/sockio.h>
|
|
#include <fcntl.h>
|
|
#elif defined(BSD) && BSD >= 199306
|
|
#include <ifaddrs.h>
|
|
#endif
|
|
#endif /* WIN32 */
|
|
|
|
|
|
#include "upnpapi.h"
|
|
#include "httpreadwrite.h"
|
|
#include "membuffer.h"
|
|
#include "ssdplib.h"
|
|
#include "soaplib.h"
|
|
#include "ThreadPool.h"
|
|
#include "sysdep.h"
|
|
#include "uuid.h"
|
|
|
|
|
|
// Needed for GENA
|
|
#include "gena.h"
|
|
#include "miniserver.h"
|
|
#include "service_table.h"
|
|
|
|
|
|
#ifdef INTERNAL_WEB_SERVER
|
|
#include "urlconfig.h"
|
|
#include "VirtualDir.h"
|
|
#include "webserver.h"
|
|
#endif // INTERNAL_WEB_SERVER
|
|
|
|
|
|
// This structure is for virtual directory callbacks
|
|
struct VirtualDirCallbacks virtualDirCallback;
|
|
|
|
//
|
|
virtualDirList *pVirtualDirList;
|
|
|
|
// Mutex to synchronize the subscription handling at the client side
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
ithread_mutex_t GlobalClientSubscribeMutex;
|
|
#endif /* INCLUDE_CLIENT_APIS */
|
|
|
|
// rwlock to synchronize handles (root device or control point handle)
|
|
ithread_rwlock_t GlobalHndRWLock;
|
|
|
|
// Mutex to synchronize the uuid creation process
|
|
ithread_mutex_t gUUIDMutex;
|
|
|
|
ithread_mutex_t gSDKInitMutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
TimerThread gTimerThread;
|
|
|
|
ThreadPool gSendThreadPool;
|
|
ThreadPool gRecvThreadPool;
|
|
ThreadPool gMiniServerThreadPool;
|
|
|
|
// Flag to indicate the state of web server
|
|
WebServerState bWebServerState = WEB_SERVER_DISABLED;
|
|
|
|
// Static buffer to contain interface name. (extern'ed in upnp.h)
|
|
char gIF_NAME[LINE_SIZE] = { '\0' };
|
|
|
|
// Static buffer to contain interface IPv4 address. (extern'ed in upnp.h)
|
|
char gIF_IPV4[22]/* INET_ADDRSTRLEN*/ = { '\0' };
|
|
|
|
// Static buffer to contain interface IPv6 address. (extern'ed in upnp.h)
|
|
char gIF_IPV6[65]/* INET6_ADDRSTRLEN*/ = { '\0' };
|
|
|
|
// Contains interface index. (extern'ed in upnp.h)
|
|
int gIF_INDEX = -1;
|
|
|
|
// local IPv4 and IPv6 ports for the mini-server
|
|
unsigned short LOCAL_PORT_V4;
|
|
unsigned short LOCAL_PORT_V6;
|
|
|
|
// UPnP device and control point handle table
|
|
void *HandleTable[NUM_HANDLE];
|
|
|
|
// a local dir which serves as webserver root
|
|
extern membuffer gDocumentRootDir;
|
|
|
|
// Maximum content-length that the SDK will process on an incoming packet.
|
|
// Content-Length exceeding this size will be not processed and error 413
|
|
// (HTTP Error Code) will be returned to the remote end point.
|
|
size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; // in bytes
|
|
|
|
// Global variable to denote the state of Upnp SDK
|
|
// = 0 if uninitialized, = 1 if initialized.
|
|
int UpnpSdkInit = 0;
|
|
|
|
// Global variable to denote the state of Upnp SDK client registration.
|
|
// = 0 if unregistered, = 1 if registered.
|
|
int UpnpSdkClientRegistered = 0;
|
|
|
|
// Global variable to denote the state of Upnp SDK IPv4 device registration.
|
|
// = 0 if unregistered, = 1 if registered.
|
|
int UpnpSdkDeviceRegisteredV4 = 0;
|
|
|
|
// Global variable to denote the state of Upnp SDK IPv6 device registration.
|
|
// = 0 if unregistered, = 1 if registered.
|
|
int UpnpSdkDeviceregisteredV6 = 0;
|
|
|
|
// Global variable used in discovery notifications.
|
|
Upnp_SID gUpnpSdkNLSuuid;
|
|
|
|
|
|
// FIXME Put this declaration in the proper header file
|
|
static int
|
|
GetDescDocumentAndURL( IN Upnp_DescType descriptionType,
|
|
IN char *description,
|
|
IN unsigned int bufferLen,
|
|
IN int config_baseURL,
|
|
IN int AddressFamily,
|
|
OUT IXML_Document ** xmlDoc,
|
|
OUT char descURL[LINE_SIZE] );
|
|
|
|
|
|
/******************************************************************************/
|
|
int UpnpInit(IN const char *HostIP, IN unsigned short DestPort)
|
|
{
|
|
int retVal;
|
|
|
|
ithread_mutex_lock( &gSDKInitMutex );
|
|
|
|
// Check if we're already initialized.
|
|
if( UpnpSdkInit == 1 ) {
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Perform initialization preamble.
|
|
retVal = UpnpInitPreamble();
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return retVal;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpInit with HostIP=%s, DestPort=%d.\n",
|
|
HostIP ? HostIP : "", DestPort );
|
|
|
|
// Verify HostIP, if provided, or find it ourselves.
|
|
if( HostIP != NULL ) {
|
|
strncpy( gIF_IPV4, HostIP, sizeof(gIF_IPV4) );
|
|
} else {
|
|
if( getlocalhostname( gIF_IPV4, sizeof(gIF_IPV4) ) != UPNP_E_SUCCESS ) {
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
}
|
|
|
|
// Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized.
|
|
UpnpSdkInit = 1;
|
|
|
|
// Finish initializing the SDK.
|
|
retVal = UpnpInitStartServers( DestPort );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
UpnpSdkInit = 0;
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return retVal;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Host Ip: %s Host Port: %d\n", gIF_IPV4,
|
|
LOCAL_PORT_V4 );
|
|
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
int UpnpInit2(IN const char *IfName, IN unsigned short DestPort)
|
|
{
|
|
int retVal;
|
|
|
|
ithread_mutex_lock( &gSDKInitMutex );
|
|
|
|
// Check if we're already initialized.
|
|
if( UpnpSdkInit == 1 ) {
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Perform initialization preamble.
|
|
retVal = UpnpInitPreamble();
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return retVal;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpInit2 with IfName=%s, DestPort=%d.\n",
|
|
IfName ? IfName : "", DestPort );
|
|
|
|
// Retrieve interface information (Addresses, index, etc).
|
|
retVal = UpnpGetIfInfo( IfName );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return retVal;
|
|
}
|
|
|
|
// Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized.
|
|
UpnpSdkInit = 1;
|
|
|
|
// Finish initializing the SDK.
|
|
retVal = UpnpInitStartServers( DestPort );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
UpnpSdkInit = 0;
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
return retVal;
|
|
}
|
|
|
|
ithread_mutex_unlock( &gSDKInitMutex );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
int UpnpFinish()
|
|
{
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
UpnpDevice_Handle device_handle;
|
|
#endif
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
UpnpClient_Handle client_handle;
|
|
#endif
|
|
struct Handle_Info *temp;
|
|
|
|
#ifdef WIN32
|
|
// WSACleanup();
|
|
#endif
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Inside UpnpFinish: UpnpSdkInit is %d\n", UpnpSdkInit);
|
|
if (UpnpSdkInit == 1) {
|
|
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpFinish: UpnpSdkInit is ONE\n");
|
|
}
|
|
PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool");
|
|
PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool");
|
|
PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool");
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
if (GetDeviceHandleInfo(AF_INET, &device_handle, &temp) == HND_DEVICE ) {
|
|
UpnpUnRegisterRootDevice(device_handle);
|
|
}
|
|
if (GetDeviceHandleInfo(AF_INET6, &device_handle, &temp) == HND_DEVICE ) {
|
|
UpnpUnRegisterRootDevice(device_handle);
|
|
}
|
|
#endif
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
if (GetClientHandleInfo(&client_handle, &temp) == HND_CLIENT) {
|
|
UpnpUnRegisterClient( client_handle );
|
|
}
|
|
#endif
|
|
|
|
TimerThreadShutdown(&gTimerThread);
|
|
StopMiniServer();
|
|
|
|
#if EXCLUDE_WEB_SERVER == 0
|
|
web_server_destroy();
|
|
#endif
|
|
|
|
ThreadPoolShutdown(&gMiniServerThreadPool);
|
|
ThreadPoolShutdown(&gRecvThreadPool);
|
|
ThreadPoolShutdown(&gSendThreadPool);
|
|
|
|
PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool");
|
|
PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool");
|
|
PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool");
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
ithread_mutex_destroy(&GlobalClientSubscribeMutex);
|
|
#endif
|
|
ithread_rwlock_destroy(&GlobalHndRWLock);
|
|
ithread_mutex_destroy(&gUUIDMutex);
|
|
|
|
// remove all virtual dirs
|
|
UpnpRemoveAllVirtualDirs();
|
|
|
|
// allow static linking
|
|
#ifdef WIN32
|
|
#ifdef PTW32_STATIC_LIB
|
|
pthread_win32_thread_detach_np();
|
|
#endif
|
|
#endif
|
|
|
|
UpnpSdkInit = 0;
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Exiting UpnpFinish : UpnpSdkInit is :%d:\n", UpnpSdkInit);
|
|
UpnpCloseLog();
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
unsigned short UpnpGetServerPort()
|
|
{
|
|
if (UpnpSdkInit != 1) {
|
|
return 0;
|
|
}
|
|
|
|
return LOCAL_PORT_V4;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
unsigned short UpnpGetServerPort6()
|
|
{
|
|
if (UpnpSdkInit != 1) {
|
|
return 0;
|
|
}
|
|
|
|
return LOCAL_PORT_V6;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
char *UpnpGetServerIpAddress()
|
|
{
|
|
if (UpnpSdkInit != 1) {
|
|
return NULL;
|
|
}
|
|
|
|
return gIF_IPV4;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
char *UpnpGetServerIp6Address()
|
|
{
|
|
if( UpnpSdkInit != 1 ) {
|
|
return NULL;
|
|
}
|
|
|
|
return gIF_IPV6;
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
int UpnpRegisterRootDevice(
|
|
IN const char *DescUrl,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie,
|
|
OUT UpnpDevice_Handle * Hnd )
|
|
{
|
|
|
|
struct Handle_Info *HInfo;
|
|
int retVal = 0;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Inside UpnpRegisterRootDevice\n" );
|
|
|
|
HandleLock();
|
|
if( Hnd == NULL || Fun == NULL ||
|
|
DescUrl == NULL || strlen( DescUrl ) == 0 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( UpnpSdkDeviceRegisteredV4 == 1 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_ALREADY_REGISTERED;
|
|
}
|
|
|
|
if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
|
|
if( HInfo == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
HandleTable[*Hnd] = HInfo;
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Root device URL is %s\n", DescUrl );
|
|
|
|
HInfo->aliasInstalled = 0;
|
|
HInfo->HType = HND_DEVICE;
|
|
strcpy( HInfo->DescURL, DescUrl );
|
|
HInfo->Callback = Fun;
|
|
HInfo->Cookie = ( void * )Cookie;
|
|
HInfo->MaxAge = DEFAULT_MAXAGE;
|
|
HInfo->DeviceList = NULL;
|
|
HInfo->ServiceList = NULL;
|
|
HInfo->DescDocument = NULL;
|
|
CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); )
|
|
CLIENTONLY( HInfo->ClientSubList = NULL; )
|
|
HInfo->MaxSubscriptions = UPNP_INFINITE;
|
|
HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
|
|
HInfo->DeviceAf = AF_INET;
|
|
|
|
if( ( retVal =
|
|
UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) )
|
|
!= UPNP_E_SUCCESS ) {
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
return retVal;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: Valid Description\n" );
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: DescURL : %s\n",
|
|
HInfo->DescURL );
|
|
|
|
HInfo->DeviceList =
|
|
ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" );
|
|
if( !HInfo->DeviceList ) {
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
|
|
ixmlDocument_free( HInfo->DescDocument );
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: No devices found for RootDevice\n" );
|
|
return UPNP_E_INVALID_DESC;
|
|
}
|
|
|
|
HInfo->ServiceList = ixmlDocument_getElementsByTagName(
|
|
HInfo->DescDocument, "serviceList" );
|
|
if( !HInfo->ServiceList ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: No services found for RootDevice\n" );
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: Gena Check\n" );
|
|
//*******************************
|
|
// GENA SET UP
|
|
//*******************************
|
|
if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument,
|
|
&HInfo->ServiceTable, HInfo->DescURL ) ) {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: GENA Service Table \n" );
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Here are the known services: \n" );
|
|
printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API );
|
|
} else {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"\nUpnpRegisterRootDevice2: Empty service table\n" );
|
|
}
|
|
|
|
UpnpSdkDeviceRegisteredV4 = 1;
|
|
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Exiting RegisterRootDevice Successfully\n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
/******************************************************************************/
|
|
int UpnpRegisterRootDevice2(
|
|
IN Upnp_DescType descriptionType,
|
|
IN const char *description_const,
|
|
IN size_t bufferLen, // ignored unless descType == UPNPREG_BUF_DESC
|
|
IN int config_baseURL,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie,
|
|
OUT UpnpDevice_Handle * Hnd )
|
|
{
|
|
struct Handle_Info *HInfo;
|
|
int retVal = 0;
|
|
char *description = ( char * )description_const;
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Inside UpnpRegisterRootDevice2\n" );
|
|
|
|
if( Hnd == NULL || Fun == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleLock();
|
|
if( UpnpSdkDeviceRegisteredV4 == 1 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_ALREADY_REGISTERED;
|
|
}
|
|
|
|
if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
|
|
if( HInfo == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
HandleTable[*Hnd] = HInfo;
|
|
|
|
// prevent accidental removal of a non-existent alias
|
|
HInfo->aliasInstalled = 0;
|
|
|
|
retVal = GetDescDocumentAndURL(
|
|
descriptionType, description, bufferLen,
|
|
config_baseURL, AF_INET,
|
|
&HInfo->DescDocument, HInfo->DescURL );
|
|
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
return retVal;
|
|
}
|
|
|
|
HInfo->aliasInstalled = ( config_baseURL != 0 );
|
|
HInfo->HType = HND_DEVICE;
|
|
|
|
HInfo->Callback = Fun;
|
|
HInfo->Cookie = ( void * )Cookie;
|
|
HInfo->MaxAge = DEFAULT_MAXAGE;
|
|
HInfo->DeviceList = NULL;
|
|
HInfo->ServiceList = NULL;
|
|
|
|
CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); )
|
|
CLIENTONLY( HInfo->ClientSubList = NULL; )
|
|
HInfo->MaxSubscriptions = UPNP_INFINITE;
|
|
HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
|
|
HInfo->DeviceAf = AF_INET;
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: Valid Description\n" );
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: DescURL : %s\n",
|
|
HInfo->DescURL );
|
|
|
|
HInfo->DeviceList =
|
|
ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" );
|
|
|
|
if( !HInfo->DeviceList ) {
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ); )
|
|
ixmlDocument_free( HInfo->DescDocument );
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: No devices found for RootDevice\n" );
|
|
return UPNP_E_INVALID_DESC;
|
|
}
|
|
|
|
HInfo->ServiceList = ixmlDocument_getElementsByTagName(
|
|
HInfo->DescDocument, "serviceList" );
|
|
if( !HInfo->ServiceList ) {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: No services found for RootDevice\n" );
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: Gena Check\n" );
|
|
//*******************************
|
|
// GENA SET UP
|
|
//*******************************
|
|
if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument,
|
|
&HInfo->ServiceTable, HInfo->DescURL ) ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice2: GENA Service Table\n" );
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Here are the known services: \n" );
|
|
printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API );
|
|
} else {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"\nUpnpRegisterRootDevice2: Empty service table\n" );
|
|
}
|
|
|
|
UpnpSdkDeviceRegisteredV4 = 1;
|
|
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting RegisterRootDevice2 Successfully\n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
/******************************************************************************/
|
|
int UpnpRegisterRootDevice3(
|
|
IN const char *DescUrl,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie,
|
|
OUT UpnpDevice_Handle * Hnd,
|
|
IN const int AddressFamily )
|
|
{
|
|
struct Handle_Info *HInfo;
|
|
int retVal = 0;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Inside UpnpRegisterRootDevice\n" );
|
|
|
|
HandleLock();
|
|
if( Hnd == NULL || Fun == NULL ||
|
|
DescUrl == NULL || strlen( DescUrl ) == 0 ||
|
|
(AddressFamily != AF_INET && AddressFamily != AF_INET6) ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( ( AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 1 ) ||
|
|
( AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 1 ) ) {
|
|
HandleUnlock();
|
|
return UPNP_E_ALREADY_REGISTERED;
|
|
}
|
|
|
|
if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
|
|
if( HInfo == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
HandleTable[*Hnd] = HInfo;
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Root device URL is %s\n", DescUrl );
|
|
|
|
HInfo->aliasInstalled = 0;
|
|
HInfo->HType = HND_DEVICE;
|
|
strcpy( HInfo->DescURL, DescUrl );
|
|
HInfo->Callback = Fun;
|
|
HInfo->Cookie = ( void * )Cookie;
|
|
HInfo->MaxAge = DEFAULT_MAXAGE;
|
|
HInfo->DeviceList = NULL;
|
|
HInfo->ServiceList = NULL;
|
|
HInfo->DescDocument = NULL;
|
|
CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); )
|
|
CLIENTONLY( HInfo->ClientSubList = NULL; )
|
|
HInfo->MaxSubscriptions = UPNP_INFINITE;
|
|
HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
|
|
HInfo->DeviceAf = AddressFamily;
|
|
|
|
if( ( retVal =
|
|
UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) )
|
|
!= UPNP_E_SUCCESS ) {
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
return retVal;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: Valid Description\n" );
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: DescURL : %s\n",
|
|
HInfo->DescURL );
|
|
|
|
HInfo->DeviceList =
|
|
ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" );
|
|
if( !HInfo->DeviceList ) {
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) );
|
|
ixmlDocument_free( HInfo->DescDocument );
|
|
FreeHandle( *Hnd );
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: No devices found for RootDevice\n" );
|
|
return UPNP_E_INVALID_DESC;
|
|
}
|
|
|
|
HInfo->ServiceList = ixmlDocument_getElementsByTagName(
|
|
HInfo->DescDocument, "serviceList" );
|
|
if( !HInfo->ServiceList ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: No services found for RootDevice\n" );
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: Gena Check\n" );
|
|
//*******************************
|
|
// GENA SET UP
|
|
//*******************************
|
|
if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument,
|
|
&HInfo->ServiceTable, HInfo->DescURL ) ) {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"UpnpRegisterRootDevice: GENA Service Table \n" );
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Here are the known services: \n" );
|
|
printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API );
|
|
} else {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"\nUpnpRegisterRootDevice2: Empty service table\n" );
|
|
}
|
|
|
|
if( AddressFamily == AF_INET )
|
|
UpnpSdkDeviceRegisteredV4 = 1;
|
|
else
|
|
UpnpSdkDeviceregisteredV6 = 1;
|
|
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Exiting RegisterRootDevice Successfully\n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
int UpnpUnRegisterRootDevice(IN UpnpDevice_Handle Hnd)
|
|
{
|
|
int retVal = 0;
|
|
struct Handle_Info *HInfo = NULL;
|
|
|
|
// struct Handle_Info *info=NULL;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Inside UpnpUnRegisterRootDevice \n" );
|
|
#if EXCLUDE_GENA == 0
|
|
if( genaUnregisterDevice( Hnd ) != UPNP_E_SUCCESS )
|
|
return UPNP_E_INVALID_HANDLE;
|
|
#endif
|
|
|
|
HandleLock();
|
|
if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
#if EXCLUDE_SSDP == 0
|
|
retVal = AdvertiseAndReply( -1, Hnd, 0, ( struct sockaddr * )NULL,
|
|
( char * )NULL, ( char * )NULL,
|
|
( char * )NULL, HInfo->MaxAge );
|
|
#endif
|
|
|
|
HandleLock();
|
|
if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
//info = (struct Handle_Info *) HandleTable[Hnd];
|
|
ixmlNodeList_free( HInfo->DeviceList );
|
|
ixmlNodeList_free( HInfo->ServiceList );
|
|
ixmlDocument_free( HInfo->DescDocument );
|
|
|
|
CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ); )
|
|
|
|
#ifdef INTERNAL_WEB_SERVER
|
|
if( HInfo->aliasInstalled ) {
|
|
web_server_set_alias( NULL, NULL, 0, 0 );
|
|
}
|
|
#endif // INTERNAL_WEB_SERVER
|
|
|
|
if( HInfo->DeviceAf == AF_INET ) {
|
|
UpnpSdkDeviceRegisteredV4 = 0;
|
|
} else if( HInfo->DeviceAf == AF_INET6 ) {
|
|
UpnpSdkDeviceregisteredV6 = 0;
|
|
}
|
|
|
|
FreeHandle( Hnd );
|
|
HandleUnlock();
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Exiting UpnpUnRegisterRootDevice \n" );
|
|
|
|
return retVal;
|
|
|
|
}
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
|
|
/*****************************************************************************/
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
int UpnpRegisterClient(
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie,
|
|
OUT UpnpClient_Handle *Hnd)
|
|
{
|
|
struct Handle_Info *HInfo;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpRegisterClient \n" );
|
|
if( Fun == NULL || Hnd == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleLock();
|
|
|
|
if( UpnpSdkClientRegistered ) {
|
|
HandleUnlock();
|
|
return UPNP_E_ALREADY_REGISTERED;
|
|
}
|
|
if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) );
|
|
if( HInfo == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
HInfo->HType = HND_CLIENT;
|
|
HInfo->Callback = Fun;
|
|
HInfo->Cookie = ( void * )Cookie;
|
|
HInfo->ClientSubList = NULL;
|
|
ListInit( &HInfo->SsdpSearchList, NULL, NULL );
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
HInfo->MaxAge = 0;
|
|
HInfo->MaxSubscriptions = UPNP_INFINITE;
|
|
HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE;
|
|
#endif
|
|
|
|
HandleTable[*Hnd] = HInfo;
|
|
UpnpSdkClientRegistered = 1;
|
|
|
|
HandleUnlock();
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpRegisterClient \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
|
|
|
|
/*****************************************************************************/
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
int UpnpUnRegisterClient(IN UpnpClient_Handle Hnd)
|
|
{
|
|
struct Handle_Info *HInfo;
|
|
ListNode *node = NULL;
|
|
SsdpSearchArg *searchArg = NULL;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpUnRegisterClient \n" );
|
|
HandleLock();
|
|
if( !UpnpSdkClientRegistered ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
#if EXCLUDE_GENA == 0
|
|
if( genaUnregisterClient( Hnd ) != UPNP_E_SUCCESS )
|
|
return UPNP_E_INVALID_HANDLE;
|
|
#endif
|
|
HandleLock();
|
|
if( GetHandleInfo( Hnd, &HInfo ) == UPNP_E_INVALID_HANDLE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
//clean up search list
|
|
node = ListHead( &HInfo->SsdpSearchList );
|
|
while( node != NULL ) {
|
|
searchArg = ( SsdpSearchArg * ) node->item;
|
|
if( searchArg ) {
|
|
free( searchArg->searchTarget );
|
|
free( searchArg );
|
|
}
|
|
ListDelNode( &HInfo->SsdpSearchList, node, 0 );
|
|
node = ListHead( &HInfo->SsdpSearchList );
|
|
}
|
|
|
|
ListDestroy( &HInfo->SsdpSearchList, 0 );
|
|
FreeHandle( Hnd );
|
|
UpnpSdkClientRegistered = 0;
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpUnRegisterClient \n" );
|
|
return UPNP_E_SUCCESS;
|
|
|
|
}
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
|
|
|
|
// *************************************************************
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
#ifdef INTERNAL_WEB_SERVER
|
|
|
|
/**************************************************************************
|
|
* Function: GetNameForAlias
|
|
*
|
|
* Parameters:
|
|
* IN char *name: name of the file
|
|
* OUT char** alias: pointer to alias string
|
|
*
|
|
* Description:
|
|
* This function determines alias for given name which is a file name
|
|
* or URL.
|
|
*
|
|
* Return Values:
|
|
* UPNP_E_SUCCESS on success, nonzero on failure.
|
|
***************************************************************************/
|
|
static int
|
|
GetNameForAlias( IN char *name,
|
|
OUT char **alias )
|
|
{
|
|
char *ext;
|
|
char *al;
|
|
|
|
ext = strrchr( name, '.' );
|
|
if( ext == NULL || strcasecmp( ext, ".xml" ) != 0 ) {
|
|
return UPNP_E_EXT_NOT_XML;
|
|
}
|
|
|
|
al = strrchr( name, '/' );
|
|
if( al == NULL ) {
|
|
*alias = name;
|
|
} else {
|
|
*alias = al;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: get_server_addr
|
|
*
|
|
* Parameters:
|
|
* OUT struct sockaddr* serverAddr: pointer to server address
|
|
* structure
|
|
*
|
|
* Description:
|
|
* This function fills the sockadr with IPv4 miniserver information.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
static void
|
|
get_server_addr( OUT struct sockaddr *serverAddr )
|
|
{
|
|
struct sockaddr_in* sa4 = (struct sockaddr_in*)serverAddr;
|
|
|
|
memset( serverAddr, 0, sizeof(struct sockaddr_storage) );
|
|
|
|
sa4->sin_family = AF_INET;
|
|
inet_pton( AF_INET, gIF_IPV4, &sa4->sin_addr );
|
|
sa4->sin_port = htons( LOCAL_PORT_V4 );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: get_server_addr6
|
|
*
|
|
* Parameters:
|
|
* OUT struct sockaddr* serverAddr: pointer to server address
|
|
* structure
|
|
*
|
|
* Description:
|
|
* This function fills the sockadr with IPv6 miniserver information.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
static void
|
|
get_server_addr6( OUT struct sockaddr *serverAddr )
|
|
{
|
|
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)serverAddr;
|
|
|
|
memset( serverAddr, 0, sizeof(struct sockaddr_storage) );
|
|
|
|
sa6->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6, gIF_IPV6, &sa6->sin6_addr );
|
|
sa6->sin6_port = htons( LOCAL_PORT_V6 );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: GetDescDocumentAndURL ( In the case of device)
|
|
*
|
|
* Parameters:
|
|
* IN Upnp_DescType descriptionType: pointer to server address
|
|
* structure
|
|
* IN char* description:
|
|
* IN unsigned int bufferLen:
|
|
* IN int config_baseURL:
|
|
* IN int AddressFamily:
|
|
* OUT IXML_Document **xmlDoc:
|
|
* OUT char descURL[LINE_SIZE]:
|
|
*
|
|
* Description:
|
|
* This function fills the sockadr_in with miniserver information.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
static int
|
|
GetDescDocumentAndURL( IN Upnp_DescType descriptionType,
|
|
IN char *description,
|
|
IN unsigned int bufferLen,
|
|
IN int config_baseURL,
|
|
IN int AddressFamily,
|
|
OUT IXML_Document ** xmlDoc,
|
|
OUT char descURL[LINE_SIZE] )
|
|
{
|
|
int retVal = 0;
|
|
char *membuf = NULL;
|
|
char aliasStr[LINE_SIZE];
|
|
char *temp_str = NULL;
|
|
FILE *fp = NULL;
|
|
off_t fileLen;
|
|
size_t num_read;
|
|
time_t last_modified;
|
|
struct stat file_info;
|
|
struct sockaddr_storage serverAddr;
|
|
int rc = UPNP_E_SUCCESS;
|
|
|
|
if( description == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
// non-URL description must have configuration specified
|
|
if( descriptionType != UPNPREG_URL_DESC && ( !config_baseURL ) ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
// get XML doc and last modified time
|
|
if( descriptionType == UPNPREG_URL_DESC ) {
|
|
if( ( retVal =
|
|
UpnpDownloadXmlDoc( description,
|
|
xmlDoc ) ) != UPNP_E_SUCCESS ) {
|
|
return retVal;
|
|
}
|
|
last_modified = time( NULL );
|
|
} else if( descriptionType == UPNPREG_FILENAME_DESC ) {
|
|
retVal = stat( description, &file_info );
|
|
if( retVal == -1 ) {
|
|
return UPNP_E_FILE_NOT_FOUND;
|
|
}
|
|
fileLen = file_info.st_size;
|
|
last_modified = file_info.st_mtime;
|
|
|
|
if( ( fp = fopen( description, "rb" ) ) == NULL ) {
|
|
return UPNP_E_FILE_NOT_FOUND;
|
|
}
|
|
|
|
if( ( membuf = ( char * )malloc( fileLen + 1 ) ) == NULL ) {
|
|
fclose( fp );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
num_read = fread( membuf, 1, fileLen, fp );
|
|
if( num_read != fileLen ) {
|
|
fclose( fp );
|
|
free( membuf );
|
|
return UPNP_E_FILE_READ_ERROR;
|
|
}
|
|
|
|
membuf[fileLen] = 0;
|
|
fclose( fp );
|
|
rc = ixmlParseBufferEx( membuf, xmlDoc );
|
|
free( membuf );
|
|
} else if( descriptionType == UPNPREG_BUF_DESC ) {
|
|
last_modified = time( NULL );
|
|
rc = ixmlParseBufferEx( description, xmlDoc );
|
|
} else {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( rc != IXML_SUCCESS && descriptionType != UPNPREG_URL_DESC ) {
|
|
if( rc == IXML_INSUFFICIENT_MEMORY ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
} else {
|
|
return UPNP_E_INVALID_DESC;
|
|
}
|
|
}
|
|
// determine alias
|
|
if( config_baseURL ) {
|
|
if( descriptionType == UPNPREG_BUF_DESC ) {
|
|
strcpy( aliasStr, "description.xml" );
|
|
} else // URL or filename
|
|
{
|
|
retVal = GetNameForAlias( description, &temp_str );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
ixmlDocument_free( *xmlDoc );
|
|
return retVal;
|
|
}
|
|
if( strlen( temp_str ) > ( LINE_SIZE - 1 ) ) {
|
|
ixmlDocument_free( *xmlDoc );
|
|
free( temp_str );
|
|
return UPNP_E_URL_TOO_BIG;
|
|
}
|
|
strcpy( aliasStr, temp_str );
|
|
}
|
|
|
|
if(AddressFamily == AF_INET)
|
|
get_server_addr( (struct sockaddr*)&serverAddr );
|
|
else
|
|
get_server_addr6( (struct sockaddr*)&serverAddr );
|
|
|
|
// config
|
|
retVal = configure_urlbase( *xmlDoc, (struct sockaddr*)&serverAddr,
|
|
aliasStr, last_modified, descURL );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
ixmlDocument_free( *xmlDoc );
|
|
return retVal;
|
|
}
|
|
} else // manual
|
|
{
|
|
if( strlen( description ) > ( LINE_SIZE - 1 ) ) {
|
|
ixmlDocument_free( *xmlDoc );
|
|
return UPNP_E_URL_TOO_BIG;
|
|
}
|
|
strcpy( descURL, description );
|
|
}
|
|
|
|
assert( *xmlDoc != NULL );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
#else // no web server
|
|
|
|
/**************************************************************************
|
|
* Function: GetDescDocumentAndURL ( In the case of control point)
|
|
*
|
|
* Parameters:
|
|
* IN Upnp_DescType descriptionType: pointer to server address
|
|
* structure
|
|
* IN char* description:
|
|
* IN unsigned int bufferLen:
|
|
* IN int config_baseURL:
|
|
* IN int AddressFamily:
|
|
* OUT IXML_Document **xmlDoc:
|
|
* OUT char *descURL:
|
|
*
|
|
* Description:
|
|
* This function fills the sockadr_in with miniserver information.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
static int
|
|
GetDescDocumentAndURL( IN Upnp_DescType descriptionType,
|
|
IN char *description,
|
|
IN unsigned int bufferLen,
|
|
IN int config_baseURL,
|
|
IN int AddressFamily,
|
|
OUT IXML_Document ** xmlDoc,
|
|
OUT char *descURL )
|
|
{
|
|
int retVal;
|
|
|
|
if( ( descriptionType != UPNPREG_URL_DESC ) || config_baseURL ) {
|
|
return UPNP_E_NO_WEB_SERVER;
|
|
}
|
|
|
|
if( description == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( strlen( description ) > ( LINE_SIZE - 1 ) ) {
|
|
return UPNP_E_URL_TOO_BIG;
|
|
}
|
|
strcpy( descURL, description );
|
|
|
|
if( ( retVal =
|
|
UpnpDownloadXmlDoc( description, xmlDoc ) ) != UPNP_E_SUCCESS ) {
|
|
return retVal;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
#endif // INTERNAL_WEB_SERVER
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// SSDP interface
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
#if EXCLUDE_SSDP == 0
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSendAdvertisement
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle Hnd: handle of the device instance
|
|
* IN int Exp : Timer for resending the advertisement
|
|
*
|
|
* Description:
|
|
* This function sends the device advertisement. It also schedules a
|
|
* job for the next advertisement after "Exp" time.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd,
|
|
IN int Exp )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal = 0,
|
|
*ptrMx;
|
|
upnp_timeout *adEvent;
|
|
ThreadPoolJob job;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSendAdvertisement \n" );
|
|
|
|
HandleLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( Exp < 1 )
|
|
Exp = DEFAULT_MAXAGE;
|
|
SInfo->MaxAge = Exp;
|
|
HandleUnlock();
|
|
retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr * )NULL,
|
|
( char * )NULL, ( char * )NULL,
|
|
( char * )NULL, Exp );
|
|
|
|
if( retVal != UPNP_E_SUCCESS )
|
|
return retVal;
|
|
ptrMx = ( int * )malloc( sizeof( int ) );
|
|
if( ptrMx == NULL )
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
adEvent = ( upnp_timeout * ) malloc( sizeof( upnp_timeout ) );
|
|
|
|
if( adEvent == NULL ) {
|
|
free( ptrMx );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
*ptrMx = Exp;
|
|
adEvent->handle = Hnd;
|
|
adEvent->Event = ptrMx;
|
|
|
|
HandleLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
free( adEvent );
|
|
free( ptrMx );
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
#ifdef SSDP_PACKET_DISTRIBUTE
|
|
TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
if( ( retVal = TimerThreadSchedule( &gTimerThread,
|
|
( ( Exp / 2 ) -
|
|
( AUTO_ADVERTISEMENT_TIME ) ),
|
|
REL_SEC, &job, SHORT_TERM,
|
|
&( adEvent->eventId ) ) )
|
|
!= UPNP_E_SUCCESS ) {
|
|
HandleUnlock();
|
|
free( adEvent );
|
|
free( ptrMx );
|
|
return retVal;
|
|
}
|
|
#else
|
|
TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout );
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
if( ( retVal = TimerThreadSchedule( &gTimerThread,
|
|
Exp - AUTO_ADVERTISEMENT_TIME,
|
|
REL_SEC, &job, SHORT_TERM,
|
|
&( adEvent->eventId ) ) )
|
|
!= UPNP_E_SUCCESS ) {
|
|
HandleUnlock();
|
|
free( adEvent );
|
|
free( ptrMx );
|
|
return retVal;
|
|
}
|
|
#endif
|
|
|
|
HandleUnlock();
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSendAdvertisement \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpSendAdvertisement *********************/
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
#endif
|
|
#if EXCLUDE_SSDP == 0
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSearchAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: handle of the control point instance
|
|
* IN int Mx : Maximum time to wait for the search reply
|
|
* IN const char *Target_const:
|
|
* IN const void *Cookie_const:
|
|
*
|
|
* Description:
|
|
* This function searches for the devices for the provided maximum time.
|
|
* It is a asynchronous function. It schedules a search job and returns.
|
|
* client is notified about the search results after search timer.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSearchAsync( IN UpnpClient_Handle Hnd,
|
|
IN int Mx,
|
|
IN const char *Target_const,
|
|
IN const void *Cookie_const )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
char *Target = ( char * )Target_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSearchAsync \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( Mx < 1 )
|
|
Mx = DEFAULT_MX;
|
|
|
|
if( Target == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleUnlock();
|
|
SearchByTarget( Mx, Target, ( void * )Cookie_const );
|
|
|
|
//HandleUnlock();
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSearchAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpSearchAsync *********************/
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// GENA interface
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#if EXCLUDE_GENA == 0
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSetMaxSubscriptions
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle Hnd: The handle of the device for which
|
|
* the maximum subscriptions is being set.
|
|
* IN int MaxSubscriptions: The maximum number of subscriptions to be
|
|
* allowed per service.
|
|
*
|
|
* Description:
|
|
* This function sets the maximum subscriptions of the control points
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSetMaxSubscriptions( IN UpnpDevice_Handle Hnd,
|
|
IN int MaxSubscriptions )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSetMaxSubscriptions \n" );
|
|
|
|
HandleLock();
|
|
if( ( ( MaxSubscriptions != UPNP_INFINITE )
|
|
&& ( MaxSubscriptions < 0 ) )
|
|
|| ( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
SInfo->MaxSubscriptions = MaxSubscriptions;
|
|
HandleUnlock();
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSetMaxSubscriptions \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /***************** End of UpnpSetMaxSubscriptions ********************/
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSetMaxSubscriptionTimeOut
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle Hnd: The handle of the device for which the
|
|
* maximum subscription time-out is being set.
|
|
* IN int MaxSubscriptionTimeOut:The maximum subscription time-out
|
|
* to be accepted
|
|
*
|
|
* Description:
|
|
* This function sets the maximum subscription timer. Control points
|
|
* will require to send the subscription request before timeout.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSetMaxSubscriptionTimeOut( IN UpnpDevice_Handle Hnd,
|
|
IN int MaxSubscriptionTimeOut )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSetMaxSubscriptionTimeOut \n" );
|
|
|
|
HandleLock();
|
|
|
|
if( ( ( MaxSubscriptionTimeOut != UPNP_INFINITE )
|
|
&& ( MaxSubscriptionTimeOut < 0 ) )
|
|
|| ( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
|
|
SInfo->MaxSubscriptionTimeOut = MaxSubscriptionTimeOut;
|
|
HandleUnlock();
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSetMaxSubscriptionTimeOut \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpSetMaxSubscriptionTimeOut ******************/
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSubscribeAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point for which
|
|
* the subscription request is to be sent.
|
|
* IN const char * EvtUrl_const: URL that control point wants to
|
|
* subscribe
|
|
* IN int TimeOut: The requested subscription time. Upon
|
|
* return, it contains the actual subscription time
|
|
* returned from the service
|
|
* IN Upnp_FunPtr Fun : callback function to tell result of the
|
|
* subscription request
|
|
* IN const void * Cookie_const: cookie passed by client to give back
|
|
* in the callback function.
|
|
*
|
|
* Description:
|
|
* This function performs the same operation as UpnpSubscribeAsync
|
|
* but returns immediately and calls the registered callback function
|
|
* when the operation is complete.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSubscribeAsync( IN UpnpClient_Handle Hnd,
|
|
IN const char *EvtUrl_const,
|
|
IN int TimeOut,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
char *EvtUrl = ( char * )EvtUrl_const;
|
|
ThreadPoolJob job;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSubscribeAsync \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( EvtUrl == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( Fun == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
HandleUnlock();
|
|
|
|
Param = (struct UpnpNonblockParam *)
|
|
malloc(sizeof (struct UpnpNonblockParam));
|
|
if( Param == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
Param->FunName = SUBSCRIBE;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->Url, EvtUrl );
|
|
Param->TimeOut = TimeOut;
|
|
Param->Fun = Fun;
|
|
Param->Cookie = ( void * )Cookie_const;
|
|
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSubscribeAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpSubscribeAsync *********************/
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSubscribe
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point.
|
|
* IN const char *PublisherUrl: The URL of the service to subscribe to.
|
|
* INOUT int *TimeOut: Pointer to a variable containing the requested
|
|
* subscription time. Upon return, it contains the
|
|
* actual subscription time returned from the service.
|
|
* OUT Upnp_SID SubsId: Pointer to a variable to receive the
|
|
* subscription ID (SID).
|
|
*
|
|
* Description:
|
|
* This function registers a control point to receive event
|
|
* notifications from another device. This operation is synchronous
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int UpnpSubscribe(
|
|
IN UpnpClient_Handle Hnd,
|
|
IN const char *EvtUrl_const,
|
|
INOUT int *TimeOut,
|
|
OUT Upnp_SID SubsId)
|
|
{
|
|
int retVal;
|
|
struct Handle_Info *SInfo = NULL;
|
|
UpnpString *EvtUrl = UpnpString_new();
|
|
UpnpString *SubsIdTmp = UpnpString_new();
|
|
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSubscribe\n");
|
|
|
|
if (UpnpSdkInit != 1) {
|
|
retVal = UPNP_E_FINISH;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (EvtUrl == NULL) {
|
|
retVal = UPNP_E_OUTOF_MEMORY;
|
|
goto exit_function;
|
|
}
|
|
if (EvtUrl_const == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
UpnpString_set_String(EvtUrl, EvtUrl_const);
|
|
|
|
if (SubsIdTmp == NULL) {
|
|
retVal = UPNP_E_OUTOF_MEMORY;
|
|
goto exit_function;
|
|
}
|
|
if (SubsId == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
UpnpString_set_String(SubsIdTmp, SubsId);
|
|
|
|
if (TimeOut == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
|
|
HandleReadLock();
|
|
if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) {
|
|
HandleUnlock();
|
|
retVal = UPNP_E_INVALID_HANDLE;
|
|
goto exit_function;
|
|
}
|
|
HandleUnlock();
|
|
|
|
retVal = genaSubscribe(Hnd, EvtUrl, TimeOut, SubsIdTmp);
|
|
strcpy(SubsId, UpnpString_get_String(SubsIdTmp));
|
|
|
|
exit_function:
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSubscribe, retVal=%d\n", retVal);
|
|
|
|
UpnpString_delete(SubsIdTmp);
|
|
UpnpString_delete(EvtUrl);
|
|
|
|
return retVal;
|
|
}
|
|
#endif /* INCLUDE_CLIENT_APIS */
|
|
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpUnSubscribe
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point.
|
|
* IN const Upnp_SID SubsId: The ID returned when the control point
|
|
* subscribed to the service.
|
|
*
|
|
* Description:
|
|
* This function removes the subscription of a control point from a
|
|
* service previously subscribed to using UpnpSubscribe or
|
|
* UpnpSubscribeAsync. This is a synchronous call.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int UpnpUnSubscribe(IN UpnpClient_Handle Hnd, IN const Upnp_SID SubsId)
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
UpnpString *SubsIdTmp = UpnpString_new();
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribe\n");
|
|
|
|
if (UpnpSdkInit != 1) {
|
|
retVal = UPNP_E_FINISH;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (SubsIdTmp == NULL) {
|
|
retVal = UPNP_E_OUTOF_MEMORY;
|
|
goto exit_function;
|
|
}
|
|
if (SubsId == NULL) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
UpnpString_set_String(SubsIdTmp, SubsId);
|
|
|
|
HandleReadLock();
|
|
if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) {
|
|
HandleUnlock();
|
|
retVal = UPNP_E_INVALID_HANDLE;
|
|
goto exit_function;
|
|
}
|
|
HandleUnlock();
|
|
|
|
retVal = genaUnSubscribe(Hnd, SubsIdTmp);
|
|
|
|
exit_function:
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpUnSubscribe, retVal=%d\n", retVal);
|
|
|
|
UpnpString_delete(SubsIdTmp);
|
|
|
|
return retVal;
|
|
}
|
|
#endif /* INCLUDE_CLIENT_APIS */
|
|
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpUnSubscribeAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the subscribed control point.
|
|
* IN Upnp_SID SubsId: The ID returned when the control point
|
|
* subscribed to the service.
|
|
* IN Upnp_FunPtr Fun: Pointer to a callback function to be called
|
|
* when the operation is complete.
|
|
* IN const void *Cookie:Pointer to user data to pass to the
|
|
* callback function when invoked.
|
|
*
|
|
* Description:
|
|
* This function removes a subscription of a control point
|
|
* from a service previously subscribed to using UpnpSubscribe or
|
|
* UpnpSubscribeAsync,generating a callback when the operation is complete.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int UpnpUnSubscribeAsync(
|
|
IN UpnpClient_Handle Hnd,
|
|
IN Upnp_SID SubsId,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
int retVal;
|
|
ThreadPoolJob job;
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribeAsync\n");
|
|
|
|
if (UpnpSdkInit != 1) {
|
|
retVal = UPNP_E_FINISH;
|
|
goto exit_function;
|
|
}
|
|
|
|
if (SubsId == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
if (Fun == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
|
|
HandleReadLock();
|
|
if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) {
|
|
HandleUnlock();
|
|
retVal = UPNP_E_INVALID_HANDLE;
|
|
goto exit_function;
|
|
}
|
|
HandleUnlock();
|
|
|
|
Param = (struct UpnpNonblockParam *)malloc(sizeof(struct UpnpNonblockParam));
|
|
if (Param == NULL) {
|
|
retVal = UPNP_E_OUTOF_MEMORY;
|
|
goto exit_function;
|
|
}
|
|
|
|
Param->FunName = UNSUBSCRIBE;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->SubsId, SubsId );
|
|
Param->Fun = Fun;
|
|
Param->Cookie = (void *)Cookie_const;
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
exit_function:
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnSubscribeAsync\n");
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif /* INCLUDE_CLIENT_APIS */
|
|
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpRenewSubscription
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point that
|
|
* is renewing the subscription.
|
|
* INOUT int *TimeOut: Pointer to a variable containing the
|
|
* requested subscription time. Upon return,
|
|
* it contains the actual renewal time.
|
|
* IN const Upnp_SID SubsId: The ID for the subscription to renew.
|
|
*
|
|
* Description:
|
|
* This function renews a subscription that is about to
|
|
* expire. This function is synchronous.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int UpnpRenewSubscription(
|
|
IN UpnpClient_Handle Hnd,
|
|
INOUT int *TimeOut,
|
|
IN const Upnp_SID SubsId )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
UpnpString *SubsIdTmp = UpnpString_new();
|
|
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRenewSubscription\n");
|
|
|
|
if (UpnpSdkInit != 1) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
if (SubsIdTmp == NULL) {
|
|
retVal = UPNP_E_OUTOF_MEMORY;
|
|
goto exit_function;
|
|
}
|
|
if (SubsId == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
UpnpString_set_String(SubsIdTmp, SubsId);
|
|
|
|
if (TimeOut == NULL) {
|
|
retVal = UPNP_E_INVALID_PARAM;
|
|
goto exit_function;
|
|
}
|
|
|
|
HandleReadLock();
|
|
if (GetHandleInfo(Hnd, &SInfo) != HND_CLIENT) {
|
|
HandleUnlock();
|
|
retVal = UPNP_E_INVALID_HANDLE;
|
|
goto exit_function;
|
|
}
|
|
HandleUnlock();
|
|
|
|
retVal = genaRenewSubscription(Hnd, SubsIdTmp, TimeOut);
|
|
|
|
exit_function:
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpRenewSubscription, retVal=%d\n", retVal);
|
|
|
|
UpnpString_delete(SubsIdTmp);
|
|
|
|
return retVal;
|
|
}
|
|
#endif /* INCLUDE_CLIENT_APIS */
|
|
|
|
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpRenewSubscriptionAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point that
|
|
* is renewing the subscription.
|
|
* IN int TimeOut: The requested subscription time. The
|
|
* actual timeout value is returned when
|
|
* the callback function is called.
|
|
* IN Upnp_SID SubsId: The ID for the subscription to renew.
|
|
* IN Upnp_FunPtr Fun: Pointer to a callback function to be
|
|
* invoked when the renewal is complete.
|
|
* IN const void *Cookie : Pointer to user data passed
|
|
* to the callback function when invoked.
|
|
*
|
|
* Description:
|
|
* This function renews a subscription that is about
|
|
* to expire, generating a callback when the operation is complete.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpRenewSubscriptionAsync( IN UpnpClient_Handle Hnd,
|
|
INOUT int TimeOut,
|
|
IN Upnp_SID SubsId,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
ThreadPoolJob job;
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpRenewSubscriptionAsync \n" );
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( SubsId == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( Fun == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
HandleUnlock();
|
|
|
|
Param =
|
|
( struct UpnpNonblockParam * )
|
|
malloc( sizeof( struct UpnpNonblockParam ) );
|
|
if( Param == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
Param->FunName = RENEW;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->SubsId, SubsId );
|
|
Param->Fun = Fun;
|
|
Param->Cookie = ( void * )Cookie_const;
|
|
Param->TimeOut = TimeOut;
|
|
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpRenewSubscriptionAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpRenewSubscriptionAsync *******************/
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpNotify
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle: The handle to the device sending the event.
|
|
* IN const char *DevID: The device ID of the subdevice of the
|
|
* service generating the event.
|
|
* IN const char *ServID: The unique identifier of the service
|
|
* generating the event.
|
|
* IN const char **VarName: Pointer to an array of variables that
|
|
* have changed.
|
|
* IN const char **NewVal: Pointer to an array of new values for
|
|
* those variables.
|
|
* IN int cVariables: The count of variables included in this
|
|
* notification.
|
|
*
|
|
* Description:
|
|
* This function sends out an event change notification to all
|
|
* control points subscribed to a particular service. This function is
|
|
* synchronous and generates no callbacks.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpNotify( IN UpnpDevice_Handle Hnd,
|
|
IN const char *DevID_const,
|
|
IN const char *ServName_const,
|
|
IN const char **VarName_const,
|
|
IN const char **NewVal_const,
|
|
IN int cVariables )
|
|
{
|
|
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
char *DevID = ( char * )DevID_const;
|
|
char *ServName = ( char * )ServName_const;
|
|
char **VarName = ( char ** )VarName_const;
|
|
char **NewVal = ( char ** )NewVal_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpNotify \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( DevID == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServName == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( VarName == NULL || NewVal == NULL || cVariables < 0 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleUnlock();
|
|
retVal =
|
|
genaNotifyAll( Hnd, DevID, ServName, VarName, NewVal, cVariables );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpNotify \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpNotify *********************/
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpNotifyExt
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle: The handle to the device sending the
|
|
* event.
|
|
* IN const char *DevID: The device ID of the subdevice of the
|
|
* service generating the event.
|
|
* IN const char *ServID: The unique identifier of the service
|
|
* generating the event.
|
|
* IN IXML_Document *PropSet: The DOM document for the property set.
|
|
* Property set documents must conform to the XML schema
|
|
* defined in section 4.3 of the Universal Plug and Play
|
|
* Device Architecture specification.
|
|
*
|
|
* Description:
|
|
* This function is similar to UpnpNotify except that it takes
|
|
* a DOM document for the event rather than an array of strings. This
|
|
* function is synchronous and generates no callbacks.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpNotifyExt( IN UpnpDevice_Handle Hnd,
|
|
IN const char *DevID_const,
|
|
IN const char *ServName_const,
|
|
IN IXML_Document * PropSet )
|
|
{
|
|
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
char *DevID = ( char * )DevID_const;
|
|
char *ServName = ( char * )ServName_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpNotify \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( DevID == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServName == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleUnlock();
|
|
retVal = genaNotifyAllExt( Hnd, DevID, ServName, PropSet );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpNotify \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpNotify *********************/
|
|
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpAcceptSubscription
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle Hnd: The handle of the device.
|
|
* IN const char *DevID: The device ID of the subdevice of the
|
|
* service generating the event.
|
|
* IN const char *ServID: The unique service identifier of the
|
|
* service generating the event.
|
|
* IN const char **VarName: Pointer to an array of event variables.
|
|
* IN const char **NewVal: Pointer to an array of values for
|
|
* the event variables.
|
|
* IN int cVariables: The number of event variables in VarName.
|
|
* IN Upnp_SID SubsId: The subscription ID of the newly
|
|
* registered control point.
|
|
*
|
|
* Description:
|
|
* This function accepts a subscription request and sends
|
|
* out the current state of the eventable variables for a service.
|
|
* The device application should call this function when it receives a
|
|
* UPNP_EVENT_SUBSCRIPTION_REQUEST callback. This function is sychronous
|
|
* and generates no callbacks.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int UpnpAcceptSubscription(
|
|
IN UpnpDevice_Handle Hnd,
|
|
IN const char *DevID_const,
|
|
IN const char *ServName_const,
|
|
IN const char **VarName_const,
|
|
IN const char **NewVal_const,
|
|
int cVariables,
|
|
IN const Upnp_SID SubsId)
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
char *DevID = ( char * )DevID_const;
|
|
char *ServName = ( char * )ServName_const;
|
|
char **VarName = ( char ** )VarName_const;
|
|
char **NewVal = ( char ** )NewVal_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpAcceptSubscription \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( DevID == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServName == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( SubsId == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( VarName == NULL || NewVal == NULL || cVariables < 0 ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleUnlock();
|
|
retVal =
|
|
genaInitNotify( Hnd, DevID, ServName, VarName, NewVal, cVariables,
|
|
SubsId );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpAcceptSubscription \n" );
|
|
return retVal;
|
|
|
|
} /***************** End of UpnpAcceptSubscription *********************/
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpAcceptSubscriptionExt
|
|
*
|
|
* Parameters:
|
|
* IN UpnpDevice_Handle Hnd: The handle of the device.
|
|
* IN const char *DevID: The device ID of the subdevice of the
|
|
* service generating the event.
|
|
* IN const char *ServID: The unique service identifier of the service
|
|
* generating the event.
|
|
* IN IXML_Document *PropSet: The DOM document for the property set.
|
|
* Property set documents must conform to the XML schema
|
|
* defined in section 4.3 of the Universal Plug and Play
|
|
* Device Architecture specification.
|
|
* IN Upnp_SID SubsId: The subscription ID of the newly
|
|
* registered control point.
|
|
*
|
|
* Description:
|
|
* This function is similar to UpnpAcceptSubscription except that it
|
|
* takes a DOM document for the variables to event rather than an array
|
|
* of strings. This function is sychronous and generates no callbacks.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpAcceptSubscriptionExt( IN UpnpDevice_Handle Hnd,
|
|
IN const char *DevID_const,
|
|
IN const char *ServName_const,
|
|
IN IXML_Document * PropSet,
|
|
IN Upnp_SID SubsId )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal;
|
|
char *DevID = ( char * )DevID_const;
|
|
char *ServName = ( char * )ServName_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpAcceptSubscription \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_DEVICE ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
if( DevID == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServName == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( SubsId == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( PropSet == NULL ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
HandleUnlock();
|
|
retVal = genaInitNotifyExt( Hnd, DevID, ServName, PropSet, SubsId );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpAcceptSubscription \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpAcceptSubscription *********************/
|
|
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
#endif // EXCLUDE_GENA == 0
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// SOAP interface
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#if EXCLUDE_SOAP == 0
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSendAction
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point
|
|
* sending the action.
|
|
* IN const char *ActionURL: The action URL of the service.
|
|
* IN const char *ServiceType: The type of the service.
|
|
* IN const char *DevUDN: This parameter is ignored.
|
|
* IN IXML_Document *Action: The DOM document for the action.
|
|
* OUT IXML_Document **RespNode: The DOM document for the response
|
|
* to the action. The UPnP Library allocates this document
|
|
* and the caller needs to free it.
|
|
*
|
|
* Description:
|
|
* This function sends a message to change a state variable in a service.
|
|
* This is a synchronous call that does not return until the action is
|
|
* complete.
|
|
*
|
|
* Note that a positive return value indicates a SOAP-protocol error code.
|
|
* In this case, the error description can be retrieved from RespNode.
|
|
* A negative return value indicates a UPnP Library error.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSendAction( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *ServiceType_const,
|
|
IN const char *DevUDN_const,
|
|
IN IXML_Document * Action,
|
|
OUT IXML_Document ** RespNodePtr )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal = 0;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *ServiceType = ( char * )ServiceType_const;
|
|
|
|
//char *DevUDN = (char *)DevUDN_const; // udn not used?
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSendAction \n" );
|
|
if(DevUDN_const !=NULL) {
|
|
UpnpPrintf(UPNP_ALL,API,__FILE__,__LINE__,"non NULL DevUDN is ignored\n");
|
|
}
|
|
DevUDN_const = NULL;
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( ServiceType == NULL || Action == NULL || RespNodePtr == NULL
|
|
|| DevUDN_const != NULL ) {
|
|
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
retVal = SoapSendAction( ActionURL, ServiceType, Action, RespNodePtr );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSendAction \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpSendAction *********************/
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSendActionEx
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point sending
|
|
* the action.
|
|
* IN const char *ActionURL_const: The action URL of the service.
|
|
* IN const char *ServiceType_const: The type of the service.
|
|
* IN const char *DevUDN_const: This parameter is ignored.
|
|
* IN IXML_Document *Header: The DOM document for the SOAP header.
|
|
* This may be NULL if the header is not required.
|
|
* IN IXML_Document *Action: The DOM document for the action.
|
|
* OUT IXML_Document **RespNodePtr: The DOM document for the response to
|
|
* the action. The UPnP library allocates this document and the
|
|
* caller needs to free it.
|
|
*
|
|
* Description:
|
|
* this function sends a message to change a state variable in a
|
|
* service. This is a synchronous call that does not return until the
|
|
* action is complete.
|
|
*
|
|
* Note that a positive return value indicates a SOAP-protocol error code.
|
|
* In this case, the error description can be retrieved from {\bf RespNode}.
|
|
* A negative return value indicates a UPnP Library error.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSendActionEx( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *ServiceType_const,
|
|
IN const char *DevUDN_const,
|
|
IN IXML_Document * Header,
|
|
IN IXML_Document * Action,
|
|
OUT IXML_Document ** RespNodePtr )
|
|
{
|
|
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal = 0;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *ServiceType = ( char * )ServiceType_const;
|
|
|
|
//char *DevUDN = (char *)DevUDN_const; // udn not used?
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSendActionEx \n" );
|
|
|
|
if( Header == NULL ) {
|
|
retVal = UpnpSendAction( Hnd, ActionURL_const, ServiceType_const,
|
|
DevUDN_const, Action, RespNodePtr );
|
|
return retVal;
|
|
}
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServiceType == NULL || Action == NULL || RespNodePtr == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
retVal = SoapSendActionEx( ActionURL, ServiceType, Header,
|
|
Action, RespNodePtr );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSendAction \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpSendActionEx *********************/
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSendActionAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point
|
|
* sending the action.
|
|
* IN const char *ActionURL: The action URL of the service.
|
|
* IN const char *ServiceType: The type of the service.
|
|
* IN const char *DevUDN: This parameter is ignored.
|
|
* IN IXML_Document *Action: The DOM document for the action to
|
|
* perform on this device.
|
|
* IN Upnp_FunPtr Fun: Pointer to a callback function to
|
|
* be invoked when the operation completes
|
|
* IN const void *Cookie: Pointer to user data that to be
|
|
* passed to the callback when invoked.
|
|
*
|
|
* Description:
|
|
* this function sends a message to change a state variable
|
|
* in a service, generating a callback when the operation is complete.
|
|
* See UpnpSendAction for comments on positive return values. These
|
|
* positive return values are sent in the event struct associated with the
|
|
* UPNP_CONTROL_ACTION_COMPLETE event.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSendActionAsync( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *ServiceType_const,
|
|
IN const char *DevUDN_const,
|
|
IN IXML_Document * Act,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
ThreadPoolJob job;
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
DOMString tmpStr;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *ServiceType = ( char * )ServiceType_const;
|
|
|
|
//char *DevUDN = (char *)DevUDN_const;
|
|
int rc;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSendActionAsync \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServiceType == NULL ||
|
|
Act == NULL || Fun == NULL || DevUDN_const != NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
tmpStr = ixmlPrintNode( ( IXML_Node * ) Act );
|
|
if( tmpStr == NULL ) {
|
|
return UPNP_E_INVALID_ACTION;
|
|
}
|
|
|
|
Param =
|
|
( struct UpnpNonblockParam * )
|
|
malloc( sizeof( struct UpnpNonblockParam ) );
|
|
|
|
if( Param == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
Param->FunName = ACTION;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->Url, ActionURL );
|
|
strcpy( Param->ServiceType, ServiceType );
|
|
|
|
rc = ixmlParseBufferEx( tmpStr, &( Param->Act ) );
|
|
if( rc != IXML_SUCCESS ) {
|
|
free( Param );
|
|
ixmlFreeDOMString( tmpStr );
|
|
if( rc == IXML_INSUFFICIENT_MEMORY ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
} else {
|
|
return UPNP_E_INVALID_ACTION;
|
|
}
|
|
}
|
|
ixmlFreeDOMString( tmpStr );
|
|
Param->Cookie = ( void * )Cookie_const;
|
|
Param->Fun = Fun;
|
|
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSendActionAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpSendActionAsync *********************/
|
|
|
|
/*************************************************************************
|
|
* Function: UpnpSendActionExAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point
|
|
* sending the action.
|
|
* IN const char *ActionURL_const: The action URL of the service.
|
|
* IN const char *ServiceType_const: The type of the service.
|
|
* IN const char *DevUDN_const: This parameter is ignored.
|
|
* IN IXML_Document *Header: The DOM document for the SOAP header.
|
|
* This may be NULL if the header is not required.
|
|
* IN IXML_Document *Act: The DOM document for the action to
|
|
* perform on this device.
|
|
* IN Upnp_FunPtr Fun: Pointer to a callback function to be invoked
|
|
* when the operation completes.
|
|
* IN const void *Cookie_const: Pointer to user data that to be
|
|
* passed to the callback when invoked.
|
|
*
|
|
* Description:
|
|
* this function sends sends a message to change a state variable
|
|
* in a service, generating a callback when the operation is complete.
|
|
* See UpnpSendAction for comments on positive return values. These
|
|
* positive return values are sent in the event struct associated with
|
|
* the UPNP_CONTROL_ACTION_COMPLETE event.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpSendActionExAsync( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *ServiceType_const,
|
|
IN const char *DevUDN_const,
|
|
IN IXML_Document * Header,
|
|
IN IXML_Document * Act,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
DOMString tmpStr;
|
|
DOMString headerStr = NULL;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *ServiceType = ( char * )ServiceType_const;
|
|
ThreadPoolJob job;
|
|
int retVal = 0;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpSendActionExAsync \n" );
|
|
|
|
if( Header == NULL ) {
|
|
retVal = UpnpSendActionAsync( Hnd, ActionURL_const,
|
|
ServiceType_const, DevUDN_const, Act,
|
|
Fun, Cookie_const );
|
|
return retVal;
|
|
}
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( ServiceType == NULL || Act == NULL || Fun == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
headerStr = ixmlPrintNode( ( IXML_Node * ) Header );
|
|
|
|
tmpStr = ixmlPrintNode( ( IXML_Node * ) Act );
|
|
if( tmpStr == NULL ) {
|
|
return UPNP_E_INVALID_ACTION;
|
|
}
|
|
|
|
Param =
|
|
( struct UpnpNonblockParam * )
|
|
malloc( sizeof( struct UpnpNonblockParam ) );
|
|
if( Param == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
Param->FunName = ACTION;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->Url, ActionURL );
|
|
strcpy( Param->ServiceType, ServiceType );
|
|
retVal = ixmlParseBufferEx( headerStr, &( Param->Header ) );
|
|
if( retVal != IXML_SUCCESS ) {
|
|
ixmlFreeDOMString( tmpStr );
|
|
ixmlFreeDOMString( headerStr );
|
|
if( retVal == IXML_INSUFFICIENT_MEMORY ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
} else {
|
|
return UPNP_E_INVALID_ACTION;
|
|
}
|
|
}
|
|
|
|
retVal = ixmlParseBufferEx( tmpStr, &( Param->Act ) );
|
|
if( retVal != IXML_SUCCESS ) {
|
|
ixmlFreeDOMString( tmpStr );
|
|
ixmlFreeDOMString( headerStr );
|
|
ixmlDocument_free( Param->Header );
|
|
if( retVal == IXML_INSUFFICIENT_MEMORY ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
} else {
|
|
return UPNP_E_INVALID_ACTION;
|
|
}
|
|
|
|
}
|
|
|
|
ixmlFreeDOMString( tmpStr );
|
|
ixmlFreeDOMString( headerStr );
|
|
|
|
Param->Cookie = ( void * )Cookie_const;
|
|
Param->Fun = Fun;
|
|
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpSendActionAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpSendActionExAsync *********************/
|
|
|
|
/*************************************************************************
|
|
* Function: UpnpGetServiceVarStatusAsync
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point.
|
|
* IN const char *ActionURL: The URL of the service.
|
|
* IN const char *VarName: The name of the variable to query.
|
|
* IN Upnp_FunPtr Fun: Pointer to a callback function to
|
|
* be invoked when the operation is complete.
|
|
* IN const void *Cookie: Pointer to user data to pass to the
|
|
* callback function when invoked.
|
|
*
|
|
* Description:
|
|
* this function queries the state of a variable of a
|
|
* service, generating a callback when the operation is complete.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpGetServiceVarStatusAsync( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *VarName_const,
|
|
IN Upnp_FunPtr Fun,
|
|
IN const void *Cookie_const )
|
|
{
|
|
ThreadPoolJob job;
|
|
struct Handle_Info *SInfo = NULL;
|
|
struct UpnpNonblockParam *Param;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *VarName = ( char * )VarName_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpGetServiceVarStatusAsync \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( VarName == NULL || Fun == NULL )
|
|
return UPNP_E_INVALID_PARAM;
|
|
|
|
Param =
|
|
( struct UpnpNonblockParam * )
|
|
malloc( sizeof( struct UpnpNonblockParam ) );
|
|
if( Param == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
Param->FunName = STATUS;
|
|
Param->Handle = Hnd;
|
|
strcpy( Param->Url, ActionURL );
|
|
strcpy( Param->VarName, VarName );
|
|
Param->Fun = Fun;
|
|
Param->Cookie = ( void * )Cookie_const;
|
|
|
|
TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param );
|
|
TPJobSetFreeFunction( &job, ( free_routine ) free );
|
|
|
|
TPJobSetPriority( &job, MED_PRIORITY );
|
|
|
|
ThreadPoolAdd( &gSendThreadPool, &job, NULL );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpGetServiceVarStatusAsync \n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
|
|
} /****************** End of UpnpGetServiceVarStatusAsync ****************/
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpGetServiceVarStatus
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: The handle of the control point.
|
|
* IN const char *ActionURL: The URL of the service.
|
|
* IN const char *VarName: The name of the variable to query.
|
|
* OUT DOMString *StVarVal: The pointer to store the value
|
|
* for VarName. The UPnP Library allocates this string and
|
|
* the caller needs to free it.
|
|
*
|
|
* Description:
|
|
* this function queries the state of a state variable of a service on
|
|
* another device. This is a synchronous call. A positive return value
|
|
* indicates a SOAP error code, whereas a negative return code indicates
|
|
* a UPnP SDK error code.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpGetServiceVarStatus( IN UpnpClient_Handle Hnd,
|
|
IN const char *ActionURL_const,
|
|
IN const char *VarName_const,
|
|
OUT DOMString * StVar )
|
|
{
|
|
struct Handle_Info *SInfo = NULL;
|
|
int retVal = 0;
|
|
char *StVarPtr;
|
|
char *ActionURL = ( char * )ActionURL_const;
|
|
char *VarName = ( char * )VarName_const;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpGetServiceVarStatus \n" );
|
|
|
|
HandleReadLock();
|
|
if( GetHandleInfo( Hnd, &SInfo ) != HND_CLIENT ) {
|
|
HandleUnlock();
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
|
|
HandleUnlock();
|
|
|
|
if( ActionURL == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
if( VarName == NULL || StVar == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
retVal = SoapGetServiceVarStatus( ActionURL, VarName, &StVarPtr );
|
|
*StVar = StVarPtr;
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpGetServiceVarStatus \n" );
|
|
|
|
return retVal;
|
|
|
|
} /****************** End of UpnpGetServiceVarStatus *********************/
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
#endif // EXCLUDE_SOAP
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Client API's
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpOpenHttpPost
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
|
|
int
|
|
UpnpOpenHttpPost( IN const char *url,
|
|
IN OUT void **handle,
|
|
IN const char *contentType,
|
|
IN int contentLength,
|
|
IN int timeout )
|
|
{
|
|
return http_OpenHttpPost( url, handle, contentType, contentLength,
|
|
timeout );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpWriteHttpPost
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpWriteHttpPost( IN void *handle,
|
|
IN char *buf,
|
|
IN unsigned int *size,
|
|
IN int timeout )
|
|
{
|
|
return http_WriteHttpPost( handle, buf, size, timeout );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpCloseHttpPost
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpCloseHttpPost( IN void *handle,
|
|
IN OUT int *httpStatus,
|
|
int timeout )
|
|
{
|
|
return http_CloseHttpPost( handle, httpStatus, timeout );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpOpenHttpGet
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpOpenHttpGet( IN const char *url_str,
|
|
IN OUT void **Handle,
|
|
IN OUT char **contentType,
|
|
OUT int *contentLength,
|
|
OUT int *httpStatus,
|
|
IN int timeout )
|
|
{
|
|
return http_OpenHttpGet( url_str, Handle, contentType, contentLength,
|
|
httpStatus, timeout );
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpOpenHttpGetProxy
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpOpenHttpGetProxy( IN const char *url_str,
|
|
IN const char *proxy_str,
|
|
IN OUT void **Handle,
|
|
IN OUT char **contentType,
|
|
OUT int *contentLength,
|
|
OUT int *httpStatus,
|
|
IN int timeout )
|
|
{
|
|
return http_OpenHttpGetProxy( url_str, proxy_str, Handle, contentType, contentLength,
|
|
httpStatus, timeout );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpOpenHttpGetEx
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpOpenHttpGetEx( IN const char *url_str,
|
|
IN OUT void **Handle,
|
|
IN OUT char **contentType,
|
|
OUT int *contentLength,
|
|
OUT int *httpStatus,
|
|
IN int lowRange,
|
|
IN int highRange,
|
|
IN int timeout )
|
|
{
|
|
return http_OpenHttpGetEx( url_str,
|
|
Handle,
|
|
contentType,
|
|
contentLength,
|
|
httpStatus, lowRange, highRange, timeout );
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpCancelHttpGet
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpCancelHttpGet( IN void *Handle )
|
|
{
|
|
return http_CancelHttpGet( Handle );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpCloseHttpGet
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpCloseHttpGet( IN void *Handle )
|
|
{
|
|
return http_CloseHttpGet( Handle );
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpReadHttpGet
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpReadHttpGet( IN void *Handle,
|
|
IN OUT char *buf,
|
|
IN OUT unsigned int *size,
|
|
IN int timeout )
|
|
{
|
|
return http_ReadHttpGet( Handle, buf, size, timeout );
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpHttpGetProgress
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful.
|
|
* UPNP_E_INVALID_PARAM if the provided pointers were invalid.
|
|
***************************************************************************/
|
|
int
|
|
UpnpHttpGetProgress( IN void *Handle,
|
|
OUT unsigned int *length,
|
|
OUT unsigned int *total )
|
|
{
|
|
return http_HttpGetProgress(Handle, length, total);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpDownloadUrlItem
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpDownloadUrlItem( const char *url,
|
|
char **outBuf,
|
|
char *contentType )
|
|
{
|
|
int ret_code;
|
|
int dummy;
|
|
|
|
if( url == NULL || outBuf == NULL || contentType == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
ret_code = http_Download( url, HTTP_DEFAULT_TIMEOUT, outBuf, &dummy,
|
|
contentType );
|
|
if( ret_code > 0 ) {
|
|
// error reply was received
|
|
ret_code = UPNP_E_INVALID_URL;
|
|
}
|
|
|
|
return ret_code;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpDownloadXmlDoc
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else sends appropriate error.
|
|
***************************************************************************/
|
|
int
|
|
UpnpDownloadXmlDoc( const char *url,
|
|
IXML_Document ** xmlDoc )
|
|
{
|
|
int ret_code;
|
|
char *xml_buf;
|
|
char content_type[LINE_SIZE];
|
|
|
|
if( url == NULL || xmlDoc == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
ret_code = UpnpDownloadUrlItem( url, &xml_buf, content_type );
|
|
if( ret_code != UPNP_E_SUCCESS ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"retCode: %d\n", ret_code );
|
|
return ret_code;
|
|
}
|
|
|
|
if( strncasecmp( content_type, "text/xml", strlen( "text/xml" ) ) ) {
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Not text/xml\n" );
|
|
// Linksys WRT54G router returns
|
|
// "CONTENT-TYPE: application/octet-stream".
|
|
// Let's be nice to Linksys and try to parse document anyway.
|
|
// If the data sended is not a xml file, ixmlParseBufferEx
|
|
// will fail and the function will return UPNP_E_INVALID_DESC too.
|
|
#if 0
|
|
free( xml_buf );
|
|
return UPNP_E_INVALID_DESC;
|
|
#endif
|
|
}
|
|
|
|
ret_code = ixmlParseBufferEx( xml_buf, xmlDoc );
|
|
free( xml_buf );
|
|
|
|
if( ret_code != IXML_SUCCESS ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"Invalid desc\n" );
|
|
if( ret_code == IXML_INSUFFICIENT_MEMORY ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
} else {
|
|
return UPNP_E_INVALID_DESC;
|
|
}
|
|
} else {
|
|
#ifdef DEBUG
|
|
xml_buf = ixmlPrintNode( ( IXML_Node * ) * xmlDoc );
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Printing the Parsed xml document \n %s\n", xml_buf );
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"****************** END OF Parsed XML Doc *****************\n" );
|
|
ixmlFreeDOMString( xml_buf );
|
|
#endif
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpDownloadXmlDoc\n" );
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// UPNP-API Internal function implementation
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifdef WIN32
|
|
/****************************************************************************
|
|
* Function: WinsockInit
|
|
*
|
|
* Parameters: NONE
|
|
*
|
|
* Description: (Windows Only)
|
|
* Initializes the Windows Winsock library.
|
|
*
|
|
* Return Values:
|
|
* UPNP_E_SUCCESS on success, UPNP_E_INIT_FAILED on failure.
|
|
*****************************************************************************/
|
|
int WinsockInit( void )
|
|
{
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int err;
|
|
|
|
wVersionRequested = MAKEWORD( 2, 2 );
|
|
|
|
err = WSAStartup( wVersionRequested, &wsaData );
|
|
if ( err != 0 ) {
|
|
/* Tell the user that we could not find a usable */
|
|
/* WinSock DLL. */
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
|
|
/* Confirm that the WinSock DLL supports 2.2.*/
|
|
/* Note that if the DLL supports versions greater */
|
|
/* than 2.2 in addition to 2.2, it will still return */
|
|
/* 2.2 in wVersion since that is the version we */
|
|
/* requested. */
|
|
|
|
if ( LOBYTE( wsaData.wVersion ) != 2 ||
|
|
HIBYTE( wsaData.wVersion ) != 2 ) {
|
|
/* Tell the user that we could not find a usable */
|
|
/* WinSock DLL. */
|
|
WSACleanup( );
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************
|
|
* Function: UpnpInitPreamble
|
|
*
|
|
* Parameters: (none)
|
|
*
|
|
* Description:
|
|
* This function performs the initial steps in initializing the UPnP SDK.
|
|
* - Winsock library is initialized for the process (Windows specific).
|
|
* - The logging (for debug messages) is initialized.
|
|
* - Mutexes, Handle table and thread pools are allocated and initialized.
|
|
* - Callback functions for SOAP and GENA are set, if they're enabled.
|
|
* - The SDK timer thread is initialized.
|
|
*
|
|
* Returns:
|
|
* UPNP_E_SUCCESS on success
|
|
*****************************************************************************/
|
|
int UpnpInitPreamble()
|
|
{
|
|
uuid_upnp nls_uuid;
|
|
int retVal = 0;
|
|
|
|
#ifdef WIN32
|
|
retVal = WinsockInit();
|
|
if( retVal != UPNP_E_SUCCESS ){
|
|
return retVal;
|
|
}
|
|
/* The WinSock DLL is acceptable. Proceed. */
|
|
#endif
|
|
|
|
srand( (unsigned int)time( NULL ) ); // needed by SSDP or other parts
|
|
|
|
// Initialize debug output.
|
|
retVal = UpnpInitLog();
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
// UpnpInitLog does not return a valid UPNP_E_*
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInitPreamble\n" );
|
|
|
|
// Initialize SDK global mutexes.
|
|
retVal = UpnpInitMutexes();
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
return retVal;
|
|
}
|
|
|
|
// Create the NLS uuid.
|
|
uuid_create(&nls_uuid);
|
|
uuid_unpack(&nls_uuid, gUpnpSdkNLSuuid);
|
|
|
|
// Init the handle list.
|
|
HandleLock();
|
|
InitHandleList();
|
|
HandleUnlock();
|
|
|
|
// Initialize SDK global thread pools.
|
|
retVal = UpnpInitThreadPools();
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
return retVal;
|
|
}
|
|
|
|
#if EXCLUDE_SOAP == 0
|
|
SetSoapCallback( soap_device_callback );
|
|
#endif
|
|
|
|
#if EXCLUDE_GENA == 0
|
|
SetGenaCallback( genaCallback );
|
|
#endif
|
|
|
|
// Initialize the SDK timer thread.
|
|
retVal = TimerThreadInit( &gTimerThread, &gSendThreadPool );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
UpnpFinish();
|
|
return retVal;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function: UpnpInitMutexes
|
|
*
|
|
* Parameters: (none)
|
|
*
|
|
* Description:
|
|
* This function initializes the global mutexes used by the UPnP SDK.
|
|
*
|
|
* Returns:
|
|
* UPNP_E_SUCCESS on success
|
|
* UPNP_E_INIT_FAILED if a mutex could not be initialized.
|
|
*****************************************************************************/
|
|
int UpnpInitMutexes( void )
|
|
{
|
|
#ifdef __CYGWIN__
|
|
/* On Cygwin, pthread_mutex_init() fails without this memset. */
|
|
/* TODO: Fix Cygwin so we don't need this memset(). */
|
|
memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock));
|
|
#endif
|
|
if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) {
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
|
|
if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) {
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
// initialize subscribe mutex
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) {
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
#endif
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function: UpnpInitThreadPools
|
|
*
|
|
* Parameters: (none)
|
|
*
|
|
* Description:
|
|
* This function initializes the global threadm pools used by the UPnP SDK.
|
|
*
|
|
* Returns:
|
|
* UPNP_E_SUCCESS on success
|
|
* UPNP_E_INIT_FAILED if a mutex could not be initialized.
|
|
*****************************************************************************/
|
|
int UpnpInitThreadPools( void )
|
|
{
|
|
ThreadPoolAttr attr;
|
|
|
|
TPAttrInit( &attr );
|
|
TPAttrSetMaxThreads( &attr, MAX_THREADS );
|
|
TPAttrSetMinThreads( &attr, MIN_THREADS );
|
|
TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD );
|
|
TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME );
|
|
TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL );
|
|
|
|
if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) {
|
|
UpnpSdkInit = 0;
|
|
UpnpFinish();
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
|
|
if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) {
|
|
UpnpSdkInit = 0;
|
|
UpnpFinish();
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
|
|
if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) {
|
|
UpnpSdkInit = 0;
|
|
UpnpFinish();
|
|
return UPNP_E_INIT_FAILED;
|
|
}
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Function: UpnpInitStartServers
|
|
*
|
|
* Parameters:
|
|
* IN short DestPort: Local Port to listen for incoming connections
|
|
*
|
|
* Description:
|
|
* This function finishes initializing the UPnP SDK.
|
|
* - The MiniServer is started, if enabled.
|
|
* - The WebServer is started, if enabled.
|
|
*
|
|
* Returns:
|
|
* UPNP_E_SUCCESS on success
|
|
* UPNP_E_INIT_FAILED if a mutex could not be initialized.
|
|
*****************************************************************************/
|
|
int UpnpInitStartServers( IN unsigned short DestPort )
|
|
{
|
|
int retVal = 0;
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Entering UpnpInitStartServers\n" );
|
|
|
|
#if EXCLUDE_MINISERVER == 0
|
|
LOCAL_PORT_V4 = DestPort;
|
|
LOCAL_PORT_V6 = DestPort;
|
|
retVal = StartMiniServer( &LOCAL_PORT_V4, &LOCAL_PORT_V6 );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"Miniserver failed to start" );
|
|
UpnpFinish();
|
|
return retVal;
|
|
}
|
|
#endif
|
|
|
|
#if EXCLUDE_WEB_SERVER == 0
|
|
membuffer_init( &gDocumentRootDir );
|
|
retVal = UpnpEnableWebserver( WEB_SERVER_ENABLED );
|
|
if( retVal != UPNP_E_SUCCESS ) {
|
|
UpnpFinish();
|
|
return retVal;
|
|
}
|
|
#endif
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInitStartServers\n" );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpGetIfInfo
|
|
*
|
|
* Parameters:
|
|
* char * IfName: Interface name (can be NULL).
|
|
*
|
|
* Description:
|
|
* This function will retrieve interface information and keep it in global
|
|
* variables. If NULL, we'll find the first suitable interface for
|
|
* operation.
|
|
* The interface must fulfill these requirements:
|
|
* - Be UP.
|
|
* - Not be LOOPBACK.
|
|
* - Support MULTICAST.
|
|
* - Have a valid IPv4 or IPv6 address.
|
|
* We'll retrieve the following information from the interface:
|
|
* - gIF_NAME -> Interface name (by input or found).
|
|
* - gIF_IPV4 -> IPv4 address (if any).
|
|
* - gIF_IPV6 -> IPv6 address (if any).
|
|
* - gIF_INDEX -> Interface index number.
|
|
*
|
|
* Return Values:
|
|
* UPNP_E_SUCCESS on success
|
|
*
|
|
***************************************************************************/
|
|
int UpnpGetIfInfo( const char * IfName )
|
|
{
|
|
#ifdef WIN32
|
|
// ----------------------------------------------------
|
|
// WIN32 implementation will use the IpHlpAPI library.
|
|
// ----------------------------------------------------
|
|
PIP_ADAPTER_ADDRESSES adapts = NULL;
|
|
PIP_ADAPTER_ADDRESSES adapts_item;
|
|
PIP_ADAPTER_UNICAST_ADDRESS uni_addr;
|
|
SOCKADDR* ip_addr;
|
|
struct in_addr v4_addr;
|
|
struct in6_addr v6_addr;
|
|
ULONG adapts_sz = 0;
|
|
ULONG ret;
|
|
int ifname_found = 0;
|
|
int valid_addr_found = 0;
|
|
|
|
// Get Adapters addresses required size.
|
|
ret = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz );
|
|
if( ret != ERROR_BUFFER_OVERFLOW ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"GetAdaptersAddresses failed to find list of adapters\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Allocate enough memory.
|
|
adapts = (PIP_ADAPTER_ADDRESSES)malloc( adapts_sz );
|
|
if( adapts == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
// Do the call that will actually return the info.
|
|
ret = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz );
|
|
if( ret != ERROR_SUCCESS ) {
|
|
free( adapts );
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"GetAdaptersAddresses failed to find list of adapters\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Copy interface name, if it was provided.
|
|
if( IfName != NULL ) {
|
|
if( strlen(IfName) > sizeof(gIF_NAME) )
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
|
|
strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
}
|
|
|
|
adapts_item = adapts;
|
|
while( adapts_item != NULL ) {
|
|
|
|
if( adapts_item->Flags & IP_ADAPTER_NO_MULTICAST ) {
|
|
continue;
|
|
}
|
|
|
|
if( ifname_found == 0 ) {
|
|
// We have found a valid interface name. Keep it.
|
|
strncpy( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
} else {
|
|
if( strncmp( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ) != 0 ) {
|
|
// This is not the interface we're looking for.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Loop thru this adapter's unicast IP addresses.
|
|
uni_addr = adapts_item->FirstUnicastAddress;
|
|
while( uni_addr ) {
|
|
ip_addr = uni_addr->Address.lpSockaddr;
|
|
switch( ip_addr->sa_family ) {
|
|
case AF_INET:
|
|
memcpy( &v4_addr, &((struct sockaddr_in *)ip_addr)->sin_addr, sizeof(v4_addr) );
|
|
valid_addr_found = 1;
|
|
break;
|
|
case AF_INET6:
|
|
// Only keep IPv6 link-local addresses.
|
|
if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ip_addr)->sin6_addr) ) {
|
|
memcpy( &v6_addr, &((struct sockaddr_in6 *)ip_addr)->sin6_addr, sizeof(v6_addr) );
|
|
valid_addr_found = 1;
|
|
}
|
|
break;
|
|
default:
|
|
if( valid_addr_found == 0 ) {
|
|
// Address is not IPv4 or IPv6 and no valid address has
|
|
// yet been found for this interface. Discard interface name.
|
|
ifname_found = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Next address.
|
|
uni_addr = uni_addr->Next;
|
|
}
|
|
|
|
if( valid_addr_found == 1 ) {
|
|
gIF_INDEX = adapts_item->IfIndex;
|
|
break;
|
|
}
|
|
|
|
// Next adapter.
|
|
adapts_item = adapts_item->Next;
|
|
}
|
|
|
|
// Failed to find a valid interface, or valid address.
|
|
if( ifname_found == 0 || valid_addr_found == 0 ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"Failed to find an adapter with valid IP addresses for use.\n" );
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
}
|
|
|
|
inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4));
|
|
inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6));
|
|
#elif (defined(BSD) && BSD >= 199306)
|
|
struct ifaddrs *ifap, *ifa;
|
|
struct in_addr v4_addr;
|
|
struct in6_addr v6_addr;
|
|
int ifname_found = 0;
|
|
int valid_addr_found = 0;
|
|
|
|
// Copy interface name, if it was provided.
|
|
if( IfName != NULL ) {
|
|
if( strlen(IfName) > sizeof(gIF_NAME) )
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
|
|
strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
}
|
|
|
|
// Get system interface addresses.
|
|
if( getifaddrs(&ifap) != 0 ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"getifaddrs failed to find list of addresses\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// cycle through available interfaces and their addresses.
|
|
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
|
|
{
|
|
// Skip LOOPBACK interfaces, DOWN interfaces and interfaces that
|
|
// don't support MULTICAST.
|
|
if( ( ifa->ifa_flags & IFF_LOOPBACK )
|
|
|| ( !( ifa->ifa_flags & IFF_UP ) )
|
|
|| ( !( ifa->ifa_flags & IFF_MULTICAST ) ) ) {
|
|
continue;
|
|
}
|
|
|
|
if( ifname_found == 0 ) {
|
|
// We have found a valid interface name. Keep it.
|
|
strncpy( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
} else {
|
|
if( strncmp( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ) != 0 ) {
|
|
// This is not the interface we're looking for.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Keep interface addresses for later.
|
|
switch( ifa->ifa_addr->sa_family )
|
|
{
|
|
case AF_INET:
|
|
memcpy( &v4_addr, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, sizeof(v4_addr) );
|
|
valid_addr_found = 1;
|
|
break;
|
|
case AF_INET6:
|
|
// Only keep IPv6 link-local addresses.
|
|
if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr) ) {
|
|
memcpy( &v6_addr, &((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr, sizeof(v6_addr) );
|
|
valid_addr_found = 1;
|
|
}
|
|
break;
|
|
default:
|
|
if( valid_addr_found == 0 ) {
|
|
// Address is not IPv4 or IPv6 and no valid address has
|
|
// yet been found for this interface. Discard interface name.
|
|
ifname_found = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
freeifaddrs(ifap);
|
|
|
|
// Failed to find a valid interface, or valid address.
|
|
if( ifname_found == 0 || valid_addr_found == 0 ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"Failed to find an adapter with valid IP addresses for use.\n" );
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
}
|
|
|
|
inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4));
|
|
inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6));
|
|
gIF_INDEX = if_nametoindex(gIF_NAME);
|
|
#else
|
|
char szBuffer[MAX_INTERFACES * sizeof( struct ifreq )];
|
|
struct ifconf ifConf;
|
|
struct ifreq ifReq;
|
|
FILE* inet6_procfd;
|
|
int i;
|
|
int LocalSock;
|
|
struct in6_addr v6_addr;
|
|
int if_idx;
|
|
char addr6[8][5];
|
|
char buf[65]; // INET6_ADDRSTRLEN
|
|
int ifname_found = 0;
|
|
int valid_addr_found = 0;
|
|
|
|
// Copy interface name, if it was provided.
|
|
if( IfName != NULL ) {
|
|
if( strlen(IfName) > sizeof(gIF_NAME) )
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
|
|
strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
}
|
|
|
|
// Create an unbound datagram socket to do the SIOCGIFADDR ioctl on.
|
|
if( ( LocalSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Can't create addrlist socket\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Get the interface configuration information...
|
|
ifConf.ifc_len = sizeof szBuffer;
|
|
ifConf.ifc_ifcu.ifcu_buf = ( caddr_t ) szBuffer;
|
|
|
|
if( ioctl( LocalSock, SIOCGIFCONF, &ifConf ) < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"DiscoverInterfaces: SIOCGIFCONF returned error\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// Cycle through the list of interfaces looking for IP addresses.
|
|
for( i = 0; i < ifConf.ifc_len ; ) {
|
|
struct ifreq *pifReq =
|
|
( struct ifreq * )( ( caddr_t ) ifConf.ifc_req + i );
|
|
i += sizeof *pifReq;
|
|
|
|
// See if this is the sort of interface we want to deal with.
|
|
strcpy( ifReq.ifr_name, pifReq->ifr_name );
|
|
if( ioctl( LocalSock, SIOCGIFFLAGS, &ifReq ) < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Can't get interface flags for %s:\n",
|
|
ifReq.ifr_name );
|
|
}
|
|
|
|
// Skip LOOPBACK interfaces, DOWN interfaces and interfaces that
|
|
// don't support MULTICAST.
|
|
if( ( ifReq.ifr_flags & IFF_LOOPBACK )
|
|
|| ( !( ifReq.ifr_flags & IFF_UP ) )
|
|
|| ( !( ifReq.ifr_flags & IFF_MULTICAST ) ) ) {
|
|
continue;
|
|
}
|
|
|
|
if( ifname_found == 0 ) {
|
|
// We have found a valid interface name. Keep it.
|
|
strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) );
|
|
ifname_found = 1;
|
|
} else {
|
|
if( strncmp( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ) != 0 ) {
|
|
// This is not the interface we're looking for.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Check address family.
|
|
if( pifReq->ifr_addr.sa_family == AF_INET ) {
|
|
// Copy interface name, IPv4 address and interface index.
|
|
strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) );
|
|
inet_ntop(AF_INET, &((struct sockaddr_in*)&pifReq->ifr_addr)->sin_addr, gIF_IPV4, sizeof(gIF_IPV4));
|
|
gIF_INDEX = if_nametoindex(gIF_NAME);
|
|
|
|
valid_addr_found = 1;
|
|
break;
|
|
} else {
|
|
// Address is not IPv4
|
|
ifname_found = 0;
|
|
}
|
|
}
|
|
close( LocalSock );
|
|
|
|
// Failed to find a valid interface, or valid address.
|
|
if( ifname_found == 0 || valid_addr_found == 0 ) {
|
|
UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"Failed to find an adapter with valid IP addresses for use.\n" );
|
|
return UPNP_E_INVALID_INTERFACE;
|
|
}
|
|
|
|
// Try to get the IPv6 address for the same interface
|
|
// from "/proc/net/if_inet6", if possible.
|
|
inet6_procfd = fopen( "/proc/net/if_inet6", "r" );
|
|
if( inet6_procfd != NULL ) {
|
|
while( fscanf(inet6_procfd,
|
|
"%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*20s\n",
|
|
addr6[0],addr6[1],addr6[2],addr6[3],
|
|
addr6[4],addr6[5],addr6[6],addr6[7], &if_idx) != EOF) {
|
|
// Get same interface as IPv4 address retrieved.
|
|
if( gIF_INDEX == if_idx ) {
|
|
snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s",
|
|
addr6[0],addr6[1],addr6[2],addr6[3],
|
|
addr6[4],addr6[5],addr6[6],addr6[7]);
|
|
// Validate formed address and check for link-local.
|
|
if( inet_pton(AF_INET6, buf, &v6_addr) > 0 &&
|
|
IN6_IS_ADDR_LINKLOCAL(&v6_addr) ) {
|
|
// Got valid IPv6 link-local adddress.
|
|
strncpy( gIF_IPV6, buf, sizeof(gIF_IPV6) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fclose( inet6_procfd );
|
|
}
|
|
#endif
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"Interface name=%s, index=%d, v4=%s, v6=%s\n",
|
|
gIF_NAME, gIF_INDEX, gIF_IPV4, gIF_IPV6 );
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpThreadDistribution
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
* Function to schedule async functions in threadpool.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
#ifdef INCLUDE_CLIENT_APIS
|
|
void
|
|
UpnpThreadDistribution(struct UpnpNonblockParam *Param)
|
|
{
|
|
int errCode = 0;
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside UpnpThreadDistribution \n" );
|
|
|
|
switch ( Param->FunName ) {
|
|
#if EXCLUDE_GENA == 0
|
|
case SUBSCRIBE: {
|
|
UpnpEventSubscribe *evt = UpnpEventSubscribe_new();
|
|
// cast away constness
|
|
UpnpString *sid = (UpnpString *)UpnpEventSubscribe_get_SID(evt);
|
|
UpnpEventSubscribe_strcpy_PublisherUrl(evt, Param->Url);
|
|
errCode = genaSubscribe(
|
|
Param->Handle,
|
|
UpnpEventSubscribe_get_PublisherUrl(evt),
|
|
(int *)&(Param->TimeOut),
|
|
sid);
|
|
UpnpEventSubscribe_set_ErrCode(evt, errCode);
|
|
UpnpEventSubscribe_set_TimeOut(evt, Param->TimeOut);
|
|
Param->Fun(UPNP_EVENT_SUBSCRIBE_COMPLETE, evt, Param->Cookie);
|
|
UpnpEventSubscribe_delete(evt);
|
|
free(Param);
|
|
break;
|
|
}
|
|
case UNSUBSCRIBE: {
|
|
UpnpEventSubscribe *evt = UpnpEventSubscribe_new();
|
|
UpnpEventSubscribe_strcpy_SID(evt, Param->SubsId);
|
|
errCode = genaUnSubscribe(
|
|
Param->Handle,
|
|
UpnpEventSubscribe_get_SID(evt));
|
|
UpnpEventSubscribe_set_ErrCode(evt, errCode);
|
|
UpnpEventSubscribe_strcpy_PublisherUrl(evt, "");
|
|
UpnpEventSubscribe_set_TimeOut(evt, 0);
|
|
Param->Fun(UPNP_EVENT_UNSUBSCRIBE_COMPLETE, evt, Param->Cookie);
|
|
UpnpEventSubscribe_delete(evt);
|
|
free(Param);
|
|
break;
|
|
}
|
|
case RENEW: {
|
|
UpnpEventSubscribe *evt = UpnpEventSubscribe_new();
|
|
UpnpEventSubscribe_strcpy_SID(evt, Param->SubsId);
|
|
errCode = genaRenewSubscription(
|
|
Param->Handle,
|
|
UpnpEventSubscribe_get_SID(evt),
|
|
&(Param->TimeOut));
|
|
UpnpEventSubscribe_set_ErrCode(evt, errCode);
|
|
UpnpEventSubscribe_set_TimeOut(evt, Param->TimeOut);
|
|
Param->Fun(UPNP_EVENT_RENEWAL_COMPLETE, evt, Param->Cookie);
|
|
UpnpEventSubscribe_delete(evt);
|
|
free(Param);
|
|
break;
|
|
}
|
|
#endif // EXCLUDE_GENA == 0
|
|
#if EXCLUDE_SOAP == 0
|
|
case ACTION: {
|
|
UpnpActionComplete *Evt = UpnpActionComplete_new();
|
|
IXML_Document *actionResult = NULL;
|
|
int errCode = SoapSendAction(
|
|
Param->Url, Param->ServiceType, Param->Act, &actionResult );
|
|
UpnpActionComplete_set_ErrCode(Evt, errCode);
|
|
UpnpActionComplete_set_ActionRequest(Evt, Param->Act);
|
|
UpnpActionComplete_set_ActionResult(Evt, actionResult);
|
|
UpnpActionComplete_strcpy_CtrlUrl(Evt, Param->Url );
|
|
Param->Fun( UPNP_CONTROL_ACTION_COMPLETE, Evt, Param->Cookie );
|
|
free(Param);
|
|
UpnpActionComplete_delete(Evt);
|
|
break;
|
|
}
|
|
case STATUS: {
|
|
UpnpStateVarComplete *Evt = UpnpStateVarComplete_new();
|
|
DOMString currentVal = NULL;
|
|
int errCode = SoapGetServiceVarStatus(
|
|
Param->Url, Param->VarName, ¤tVal );
|
|
UpnpStateVarComplete_set_ErrCode(Evt, errCode);
|
|
UpnpStateVarComplete_strcpy_CtrlUrl(Evt, Param->Url);
|
|
UpnpStateVarComplete_strcpy_StateVarName(Evt, Param->VarName);
|
|
UpnpStateVarComplete_set_CurrentVal(Evt, currentVal);
|
|
Param->Fun( UPNP_CONTROL_GET_VAR_COMPLETE, Evt, Param->Cookie );
|
|
free( Param );
|
|
UpnpStateVarComplete_delete(Evt);
|
|
break;
|
|
}
|
|
#endif // EXCLUDE_SOAP == 0
|
|
default:
|
|
break;
|
|
} // end of switch(Param->FunName)
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Exiting UpnpThreadDistribution \n" );
|
|
|
|
} /****************** End of UpnpThreadDistribution *********************/
|
|
#endif // INCLUDE_CLIENT_APIS
|
|
|
|
/**************************************************************************
|
|
* Function: GetCallBackFn
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
* This function is to get callback function ptr from a handle
|
|
*
|
|
* Return Values: Upnp_FunPtr
|
|
*
|
|
***************************************************************************/
|
|
Upnp_FunPtr GetCallBackFn(UpnpClient_Handle Hnd)
|
|
{
|
|
return ((struct Handle_Info *)HandleTable[Hnd])->Callback;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: InitHandleList
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
* This function is to initialize handle table
|
|
*
|
|
* Return Values:
|
|
*
|
|
***************************************************************************/
|
|
void InitHandleList()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NUM_HANDLE; ++i) {
|
|
HandleTable[i] = NULL;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: GetFreeHandle
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Description:
|
|
* This function is to get a free handle
|
|
*
|
|
* Return Values:
|
|
* integer greater than zero
|
|
* UPNP_E_OUTOF_HANDLE
|
|
*
|
|
***************************************************************************/
|
|
int GetFreeHandle()
|
|
{
|
|
/* Handle 0 is not used as NULL translates to 0 when passed as a handle */
|
|
int i = 1;
|
|
|
|
while (i < NUM_HANDLE && HandleTable[i] != NULL) {
|
|
++i;
|
|
}
|
|
|
|
if (i == NUM_HANDLE) {
|
|
return UPNP_E_OUTOF_HANDLE;
|
|
} else {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: GetClientHandleInfo
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle *client_handle_out: client handle pointer ( key
|
|
* for the client handle structure).
|
|
* OUT struct Handle_Info **HndInfo: Client handle structure passed by
|
|
* this function.
|
|
*
|
|
* Description:
|
|
* NOTE: The logic around the use of this function should be revised.
|
|
* This function is to get client handle info
|
|
*
|
|
* Return Values: HND_CLIENT, HND_INVALID
|
|
*
|
|
***************************************************************************/
|
|
//Assumes at most one client
|
|
Upnp_Handle_Type GetClientHandleInfo(
|
|
IN UpnpClient_Handle *client_handle_out,
|
|
OUT struct Handle_Info **HndInfo)
|
|
{
|
|
Upnp_Handle_Type ret = HND_CLIENT;
|
|
UpnpClient_Handle client;
|
|
|
|
if (GetHandleInfo(1, HndInfo) == HND_CLIENT) {
|
|
client = 1;
|
|
} else if (GetHandleInfo(2, HndInfo) == HND_CLIENT) {
|
|
client = 2;
|
|
} else {
|
|
client = -1;
|
|
ret = HND_INVALID;
|
|
}
|
|
|
|
*client_handle_out = client;
|
|
return ret;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: GetDeviceHandleInfo
|
|
* Retrieves the device handle and information of the first device of the
|
|
* address family spcified.
|
|
*
|
|
* Parameters:
|
|
* IN int AddressFamily:
|
|
* OUT UpnpDevice_Handle * device_handle_out: device handle pointer
|
|
* OUT struct Handle_Info **HndInfo:
|
|
* Device handle structure passed by this function.
|
|
*
|
|
* Description:
|
|
* This function is to get device handle info.
|
|
*
|
|
* Return Values: HND_DEVICE or HND_INVALID
|
|
*
|
|
***************************************************************************/
|
|
Upnp_Handle_Type GetDeviceHandleInfo(
|
|
const int AddressFamily,
|
|
UpnpDevice_Handle *device_handle_out,
|
|
struct Handle_Info **HndInfo)
|
|
{
|
|
// Check if we've got a registered device of the address family specified.
|
|
if( (AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 0) ||
|
|
(AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 0) ) {
|
|
*device_handle_out = -1;
|
|
return HND_INVALID;
|
|
}
|
|
|
|
// Find it.
|
|
for( *device_handle_out=1; *device_handle_out < NUM_HANDLE; (*device_handle_out)++ ) {
|
|
if( GetHandleInfo( *device_handle_out, HndInfo ) == HND_DEVICE ) {
|
|
if( (*HndInfo)->DeviceAf == AddressFamily ) {
|
|
return HND_DEVICE;
|
|
}
|
|
}
|
|
}
|
|
|
|
*device_handle_out = -1;
|
|
return HND_INVALID;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: GetDeviceHandleInfo
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle * device_handle_out: handle pointer
|
|
* (key for the client handle structure).
|
|
* OUT struct Handle_Info **HndInfo: handle structure passed by
|
|
* this function.
|
|
*
|
|
* Description:
|
|
* This function is to get handle info.
|
|
*
|
|
* Return Values: HND_DEVICE, UPNP_E_INVALID_HANDLE
|
|
*
|
|
***************************************************************************/
|
|
Upnp_Handle_Type GetHandleInfo(
|
|
UpnpClient_Handle Hnd,
|
|
struct Handle_Info **HndInfo)
|
|
{
|
|
Upnp_Handle_Type ret = UPNP_E_INVALID_HANDLE;
|
|
|
|
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
|
|
"GetHandleInfo: entering, Handle is %d\n", Hnd);
|
|
|
|
if (Hnd < 1 || Hnd >= NUM_HANDLE) {
|
|
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
|
|
"GetHandleInfo: Handle out of range\n");
|
|
} else if (HandleTable[Hnd] == NULL) {
|
|
UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"GetHandleInfo: HandleTable[%d] is NULL\n",
|
|
Hnd);
|
|
} else if (HandleTable[Hnd] != NULL) {
|
|
*HndInfo = (struct Handle_Info *)HandleTable[Hnd];
|
|
ret = ((struct Handle_Info *)*HndInfo)->HType;
|
|
}
|
|
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "GetHandleInfo: exiting\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: FreeHandle
|
|
*
|
|
* Parameters:
|
|
* IN int Upnp_Handle: handle index
|
|
*
|
|
* Description:
|
|
* This function is to to free handle info.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful
|
|
* UPNP_E_INVALID_HANDLE if not.
|
|
***************************************************************************/
|
|
int FreeHandle(int Upnp_Handle)
|
|
{
|
|
int ret = UPNP_E_INVALID_HANDLE;
|
|
|
|
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
|
|
"FreeHandleInfo: entering, Handle is %d\n", Upnp_Handle);
|
|
|
|
if (Upnp_Handle < 1 || Upnp_Handle >= NUM_HANDLE) {
|
|
UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"FreeHandleInfo: Handle %d is out of range\n",
|
|
Upnp_Handle);
|
|
} else if (HandleTable[Upnp_Handle] == NULL) {
|
|
UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
|
|
"FreeHandleInfo: HandleTable[%d] is NULL\n",
|
|
Upnp_Handle);
|
|
} else {
|
|
free( HandleTable[Upnp_Handle] );
|
|
HandleTable[Upnp_Handle] = NULL;
|
|
ret = UPNP_E_SUCCESS;
|
|
}
|
|
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "FreeHandleInfo: exiting\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: PrintHandleInfo
|
|
*
|
|
* Parameters:
|
|
* IN UpnpClient_Handle Hnd: handle index
|
|
*
|
|
* Description:
|
|
* This function is to print handle info.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else return appropriate error
|
|
***************************************************************************/
|
|
int PrintHandleInfo( IN UpnpClient_Handle Hnd )
|
|
{
|
|
struct Handle_Info * HndInfo;
|
|
if (HandleTable[Hnd] != NULL) {
|
|
HndInfo = HandleTable[Hnd];
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Printing information for Handle_%d\n", Hnd);
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"HType_%d\n", HndInfo->HType);
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
if(HndInfo->HType != HND_CLIENT)
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"DescURL_%s\n", HndInfo->DescURL );
|
|
#endif
|
|
} else {
|
|
return UPNP_E_INVALID_HANDLE;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
|
|
void printNodes( IXML_Node * tmpRoot, int depth )
|
|
{
|
|
int i;
|
|
IXML_NodeList *NodeList1;
|
|
IXML_Node *ChildNode1;
|
|
unsigned short NodeType;
|
|
const DOMString NodeValue;
|
|
const DOMString NodeName;
|
|
NodeList1 = ixmlNode_getChildNodes(tmpRoot);
|
|
for (i = 0; i < 100; ++i) {
|
|
ChildNode1 = ixmlNodeList_item(NodeList1, i);
|
|
if (ChildNode1 == NULL) {
|
|
break;
|
|
}
|
|
|
|
printNodes(ChildNode1, depth+1);
|
|
NodeType = ixmlNode_getNodeType(ChildNode1);
|
|
NodeValue = ixmlNode_getNodeValue(ChildNode1);
|
|
NodeName = ixmlNode_getNodeName(ChildNode1);
|
|
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
|
|
"DEPTH-%2d-IXML_Node Type %d, "
|
|
"IXML_Node Name: %s, IXML_Node Value: %s\n",
|
|
depth, NodeType, NodeName, NodeValue);
|
|
}
|
|
}
|
|
|
|
/****************** End of printNodes *********************/
|
|
|
|
//********************************************************
|
|
//* Name: getlocalhostname
|
|
//* Description: Function to get local IP address
|
|
//* Gets the ip address for the DEFAULT_INTERFACE
|
|
//* interface which is up and not a loopback
|
|
//* assumes at most MAX_INTERFACES interfaces
|
|
//* Called by: UpnpInit
|
|
//* In: char *out
|
|
//* Out: Ip address
|
|
//* Return codes: UPNP_E_SUCCESS
|
|
//* Error codes: UPNP_E_INIT
|
|
//********************************************************
|
|
|
|
/**************************************************************************
|
|
* Function: getlocalhostname
|
|
*
|
|
* Parameters:
|
|
* OUT char *out: IP address of the interface.
|
|
* IN int out_len: Length of the output buffer.
|
|
*
|
|
* Description:
|
|
* This function is to get local IP address. It gets the ip address for
|
|
* the DEFAULT_INTERFACE interface which is up and not a loopback
|
|
* assumes at most MAX_INTERFACES interfaces
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else return appropriate error
|
|
***************************************************************************/
|
|
int getlocalhostname(OUT char *out, IN const int out_len)
|
|
{
|
|
#ifdef WIN32
|
|
struct hostent *h=NULL;
|
|
struct sockaddr_in LocalAddr;
|
|
|
|
gethostname(out, out_len);
|
|
h=gethostbyname(out);
|
|
if (h!=NULL){
|
|
memcpy(&LocalAddr.sin_addr,h->h_addr_list[0],4);
|
|
strncpy(out, inet_ntoa(LocalAddr.sin_addr), out_len);
|
|
}
|
|
return UPNP_E_SUCCESS;
|
|
#elif (defined(BSD) && BSD >= 199306)
|
|
struct ifaddrs *ifap, *ifa;
|
|
|
|
if (getifaddrs(&ifap) != 0) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"DiscoverInterfaces: getifaddrs() returned error\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
|
|
// cycle through available interfaces
|
|
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
|
|
// Skip loopback, point-to-point and down interfaces,
|
|
// except don't skip down interfaces
|
|
// if we're trying to get a list of configurable interfaces.
|
|
if( ( ifa->ifa_flags & IFF_LOOPBACK )
|
|
|| ( !( ifa->ifa_flags & IFF_UP ) ) ) {
|
|
continue;
|
|
}
|
|
if( ifa->ifa_addr->sa_family == AF_INET ) {
|
|
// We don't want the loopback interface.
|
|
if( ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr ==
|
|
htonl( INADDR_LOOPBACK ) ) {
|
|
continue;
|
|
}
|
|
|
|
strncpy( out, inet_ntoa( ((struct sockaddr_in *)(ifa->ifa_addr))->
|
|
sin_addr ), out_len );
|
|
out[LINE_SIZE-1] = '\0';
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside getlocalhostname : after strncpy %s\n",
|
|
out );
|
|
break;
|
|
}
|
|
}
|
|
freeifaddrs(ifap);
|
|
|
|
return ifa ? UPNP_E_SUCCESS : UPNP_E_INIT;
|
|
#else
|
|
char szBuffer[MAX_INTERFACES * sizeof( struct ifreq )];
|
|
struct ifconf ifConf;
|
|
struct ifreq ifReq;
|
|
int nResult;
|
|
int i;
|
|
int LocalSock;
|
|
struct sockaddr_in LocalAddr;
|
|
int j = 0;
|
|
|
|
// Create an unbound datagram socket to do the SIOCGIFADDR ioctl on.
|
|
if( ( LocalSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Can't create addrlist socket\n" );
|
|
return UPNP_E_INIT;
|
|
}
|
|
// Get the interface configuration information...
|
|
ifConf.ifc_len = sizeof szBuffer;
|
|
ifConf.ifc_ifcu.ifcu_buf = ( caddr_t ) szBuffer;
|
|
nResult = ioctl( LocalSock, SIOCGIFCONF, &ifConf );
|
|
|
|
if( nResult < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"DiscoverInterfaces: SIOCGIFCONF returned error\n" );
|
|
|
|
return UPNP_E_INIT;
|
|
}
|
|
// Cycle through the list of interfaces looking for IP addresses.
|
|
|
|
for( i = 0; ( ( i < ifConf.ifc_len ) && ( j < DEFAULT_INTERFACE ) ); ) {
|
|
struct ifreq *pifReq =
|
|
( struct ifreq * )( ( caddr_t ) ifConf.ifc_req + i );
|
|
i += sizeof *pifReq;
|
|
|
|
// See if this is the sort of interface we want to deal with.
|
|
strcpy( ifReq.ifr_name, pifReq->ifr_name );
|
|
if( ioctl( LocalSock, SIOCGIFFLAGS, &ifReq ) < 0 ) {
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Can't get interface flags for %s:\n",
|
|
ifReq.ifr_name );
|
|
}
|
|
// Skip loopback, point-to-point and down interfaces,
|
|
// except don't skip down interfaces
|
|
// if we're trying to get a list of configurable interfaces.
|
|
if( ( ifReq.ifr_flags & IFF_LOOPBACK )
|
|
|| ( !( ifReq.ifr_flags & IFF_UP ) ) ) {
|
|
continue;
|
|
}
|
|
if( pifReq->ifr_addr.sa_family == AF_INET ) {
|
|
// Get a pointer to the address...
|
|
memcpy( &LocalAddr, &pifReq->ifr_addr,
|
|
sizeof pifReq->ifr_addr );
|
|
|
|
// We don't want the loopback interface.
|
|
if( LocalAddr.sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) {
|
|
continue;
|
|
}
|
|
|
|
}
|
|
//increment j if we found an address which is not loopback
|
|
//and is up
|
|
j++;
|
|
|
|
}
|
|
close( LocalSock );
|
|
|
|
strncpy( out, inet_ntoa( LocalAddr.sin_addr ), out_len );
|
|
|
|
UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__,
|
|
"Inside getlocalhostname : after strncpy %s\n",
|
|
out );
|
|
return UPNP_E_SUCCESS;
|
|
#endif
|
|
}
|
|
|
|
#ifdef INCLUDE_DEVICE_APIS
|
|
#if EXCLUDE_SSDP == 0
|
|
|
|
/**************************************************************************
|
|
* Function: AutoAdvertise
|
|
*
|
|
* Parameters:
|
|
* IN void *input: information provided to the thread.
|
|
*
|
|
* Description:
|
|
* This function is a timer thread scheduled by UpnpSendAdvertisement
|
|
* to the send advetisement again.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
void
|
|
AutoAdvertise( void *input )
|
|
{
|
|
upnp_timeout *event = ( upnp_timeout * ) input;
|
|
|
|
UpnpSendAdvertisement( event->handle, *( ( int * )event->Event ) );
|
|
free_upnp_timeout( event );
|
|
}
|
|
#endif //INCLUDE_DEVICE_APIS
|
|
#endif
|
|
|
|
/*
|
|
**************************** */
|
|
#ifdef INTERNAL_WEB_SERVER
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSetWebServerRootDir
|
|
*
|
|
* Parameters:
|
|
* IN const char* rootDir:Path of the root directory of the web server.
|
|
*
|
|
* Description:
|
|
* This function sets the document root directory for
|
|
* the internal web server. This directory is considered the
|
|
* root directory (i.e. "/") of the web server.
|
|
* This function also activates or deactivates the web server.
|
|
* To disable the web server, pass NULL for rootDir to
|
|
* activate, pass a valid directory string.
|
|
*
|
|
* Note that this function is not available when the web server is not
|
|
* compiled into the UPnP Library.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else returns appropriate error
|
|
***************************************************************************/
|
|
int
|
|
UpnpSetWebServerRootDir( IN const char *rootDir )
|
|
{
|
|
if( UpnpSdkInit == 0 )
|
|
return UPNP_E_FINISH;
|
|
if( ( rootDir == NULL ) || ( strlen( rootDir ) == 0 ) ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
membuffer_destroy( &gDocumentRootDir );
|
|
|
|
return ( web_server_set_root_dir( rootDir ) );
|
|
}
|
|
#endif // INTERNAL_WEB_SERVER
|
|
/*
|
|
*************************** */
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpAddVirtualDir
|
|
*
|
|
* Parameters:
|
|
* IN const char *newDirName:The name of the new directory mapping to add.
|
|
*
|
|
* Description:
|
|
* This function adds a virtual directory mapping.
|
|
*
|
|
* All webserver requests containing the given directory are read using
|
|
* functions contained in a VirtualDirCallbacks structure registered
|
|
* via UpnpSetVirtualDirCallbacks.
|
|
*
|
|
* Note that this function is not available when the web server is not
|
|
* compiled into the UPnP Library.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else returns appropriate error
|
|
***************************************************************************/
|
|
int
|
|
UpnpAddVirtualDir( IN const char *newDirName )
|
|
{
|
|
|
|
virtualDirList *pNewVirtualDir,
|
|
*pLast;
|
|
virtualDirList *pCurVirtualDir;
|
|
char dirName[NAME_SIZE];
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
// SDK is not initialized
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
if( ( newDirName == NULL ) || ( strlen( newDirName ) == 0 ) ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( *newDirName != '/' ) {
|
|
dirName[0] = '/';
|
|
strcpy( dirName + 1, newDirName );
|
|
} else {
|
|
strcpy( dirName, newDirName );
|
|
}
|
|
|
|
pCurVirtualDir = pVirtualDirList;
|
|
while( pCurVirtualDir != NULL ) {
|
|
// already has this entry
|
|
if( strcmp( pCurVirtualDir->dirName, dirName ) == 0 ) {
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
pCurVirtualDir = pCurVirtualDir->next;
|
|
}
|
|
|
|
pNewVirtualDir =
|
|
( virtualDirList * ) malloc( sizeof( virtualDirList ) );
|
|
if( pNewVirtualDir == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
pNewVirtualDir->next = NULL;
|
|
strcpy( pNewVirtualDir->dirName, dirName );
|
|
*( pNewVirtualDir->dirName + strlen( dirName ) ) = 0;
|
|
|
|
if( pVirtualDirList == NULL ) { // first virtual dir
|
|
pVirtualDirList = pNewVirtualDir;
|
|
} else {
|
|
pLast = pVirtualDirList;
|
|
while( pLast->next != NULL ) {
|
|
pLast = pLast->next;
|
|
}
|
|
pLast->next = pNewVirtualDir;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpRemoveVirtualDir
|
|
*
|
|
* Parameters:
|
|
* IN const char *newDirName:The name of the directory mapping to remove.
|
|
*
|
|
* Description:
|
|
* This function removes a virtual directory mapping.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else returns appropriate error
|
|
***************************************************************************/
|
|
int
|
|
UpnpRemoveVirtualDir( IN const char *dirName )
|
|
{
|
|
|
|
virtualDirList *pPrev;
|
|
virtualDirList *pCur;
|
|
int found = 0;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
if( dirName == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
if( pVirtualDirList == NULL ) {
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
//
|
|
// Handle the special case where the directory that we are
|
|
// removing is the first and only one in the list.
|
|
//
|
|
|
|
if( ( pVirtualDirList->next == NULL ) &&
|
|
( strcmp( pVirtualDirList->dirName, dirName ) == 0 ) ) {
|
|
free( pVirtualDirList );
|
|
pVirtualDirList = NULL;
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
pCur = pVirtualDirList;
|
|
pPrev = pCur;
|
|
|
|
while( pCur != NULL ) {
|
|
if( strcmp( pCur->dirName, dirName ) == 0 ) {
|
|
pPrev->next = pCur->next;
|
|
free( pCur );
|
|
found = 1;
|
|
break;
|
|
} else {
|
|
pPrev = pCur;
|
|
pCur = pCur->next;
|
|
}
|
|
}
|
|
|
|
if( found == 1 )
|
|
return UPNP_E_SUCCESS;
|
|
else
|
|
return UPNP_E_INVALID_PARAM;
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpRemoveAllVirtualDirs
|
|
*
|
|
* Parameters: VOID
|
|
*
|
|
* Description:
|
|
* This function removes all the virtual directory mappings.
|
|
*
|
|
* Return Values: VOID
|
|
*
|
|
***************************************************************************/
|
|
void
|
|
UpnpRemoveAllVirtualDirs()
|
|
{
|
|
|
|
virtualDirList *pCur;
|
|
virtualDirList *pNext;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return;
|
|
}
|
|
|
|
pCur = pVirtualDirList;
|
|
|
|
while( pCur != NULL ) {
|
|
pNext = pCur->next;
|
|
free( pCur );
|
|
|
|
pCur = pNext;
|
|
}
|
|
|
|
pVirtualDirList = NULL;
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpEnableWebserver
|
|
*
|
|
* Parameters:
|
|
* IN int enable: TRUE to enable, FALSE to disable.
|
|
*
|
|
* Description:
|
|
* This function enables or disables the webserver. A value of
|
|
* TRUE enables the webserver, FALSE disables it.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS if successful else returns appropriate error
|
|
***************************************************************************/
|
|
int
|
|
UpnpEnableWebserver( IN int enable )
|
|
{
|
|
int retVal;
|
|
|
|
if( UpnpSdkInit != 1 ) {
|
|
return UPNP_E_FINISH;
|
|
}
|
|
|
|
switch ( enable ) {
|
|
#ifdef INTERNAL_WEB_SERVER
|
|
case TRUE:
|
|
if( ( retVal = web_server_init() ) != UPNP_E_SUCCESS ) {
|
|
return retVal;
|
|
}
|
|
bWebServerState = WEB_SERVER_ENABLED;
|
|
SetHTTPGetCallback( web_server_callback );
|
|
break;
|
|
|
|
case FALSE:
|
|
web_server_destroy();
|
|
bWebServerState = WEB_SERVER_DISABLED;
|
|
SetHTTPGetCallback( NULL );
|
|
break;
|
|
#endif
|
|
default:
|
|
return UPNP_E_INVALID_PARAM;
|
|
}
|
|
|
|
return UPNP_E_SUCCESS;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpIsWebserverEnabled
|
|
*
|
|
* Parameters: VOID
|
|
*
|
|
* Description:
|
|
* This function checks if the webserver is enabled or disabled.
|
|
*
|
|
* Return Values: int
|
|
* 1, if webserver enabled
|
|
* 0, if webserver disabled
|
|
***************************************************************************/
|
|
int
|
|
UpnpIsWebserverEnabled()
|
|
{
|
|
if( UpnpSdkInit != 1 ) {
|
|
return 0;
|
|
}
|
|
|
|
return ( bWebServerState == WEB_SERVER_ENABLED );
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_GetInfoCallback(VDCallback_GetInfo callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.get_info = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_OpenCallback(VDCallback_Open callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.open = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_ReadCallback(VDCallback_Read callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.read = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_WriteCallback(VDCallback_Write callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.write = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_SeekCallback(VDCallback_Seek callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.seek = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int UpnpVirtualDir_set_CloseCallback(VDCallback_Close callback)
|
|
{
|
|
int ret = UPNP_E_SUCCESS;
|
|
if (!callback) {
|
|
ret = UPNP_E_INVALID_PARAM;
|
|
} else {
|
|
virtualDirCallback.close = callback;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpFree
|
|
*
|
|
* Parameters:
|
|
* IN void *item:The item to free.
|
|
*
|
|
* Description:
|
|
* This function free the memory allocated by tbe UPnP library
|
|
*
|
|
* Return Values: void
|
|
***************************************************************************/
|
|
void
|
|
UpnpFree( IN void *item )
|
|
{
|
|
if( item )
|
|
free( item );
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSetContentLength
|
|
* OBSOLETE METHOD: use UpnpSetMaxContentLength() instead.
|
|
***************************************************************************/
|
|
int UpnpSetContentLength(
|
|
IN UpnpClient_Handle Hnd,
|
|
IN int contentLength)
|
|
{
|
|
int errCode = UPNP_E_SUCCESS;
|
|
struct Handle_Info *HInfo = NULL;
|
|
|
|
do {
|
|
if( UpnpSdkInit != 1 ) {
|
|
errCode = UPNP_E_FINISH;
|
|
break;
|
|
}
|
|
|
|
HandleLock();
|
|
|
|
errCode = GetHandleInfo( Hnd, &HInfo );
|
|
|
|
if( errCode != HND_DEVICE ) {
|
|
errCode = UPNP_E_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
if( contentLength > MAX_SOAP_CONTENT_LENGTH ) {
|
|
errCode = UPNP_E_OUTOF_BOUNDS;
|
|
break;
|
|
}
|
|
|
|
g_maxContentLength = contentLength;
|
|
|
|
} while( 0 );
|
|
|
|
HandleUnlock();
|
|
return errCode;
|
|
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* Function: UpnpSetMaxContentLength
|
|
*
|
|
* Parameters:
|
|
* IN int contentLength: The maximum size to be set
|
|
*
|
|
* Description:
|
|
* Sets the maximum content-length that the SDK will process on an
|
|
* incoming SOAP requests or responses. This API allows devices that have
|
|
* memory constraints to exhibit consistent behaviour if the size of the
|
|
* incoming SOAP message exceeds the memory that device can allocate.
|
|
* The default maximum content-length is {\tt DEFAULT_SOAP_CONTENT_LENGTH}
|
|
* = 16K bytes.
|
|
*
|
|
* Return Values: int
|
|
* UPNP_E_SUCCESS: The operation completed successfully.
|
|
*
|
|
***************************************************************************/
|
|
int
|
|
UpnpSetMaxContentLength (
|
|
IN size_t contentLength
|
|
/** Permissible content length, in bytes */
|
|
)
|
|
{
|
|
int errCode = UPNP_E_SUCCESS;
|
|
|
|
do {
|
|
if( UpnpSdkInit != 1 ) {
|
|
errCode = UPNP_E_FINISH;
|
|
break;
|
|
}
|
|
|
|
g_maxContentLength = contentLength;
|
|
|
|
} while( 0 );
|
|
|
|
return errCode;
|
|
|
|
}
|
|
|
|
/*********************** END OF FILE upnpapi.c :) ************************/
|