New UpnpRegisterRootDevice4 for legacy CPs.

Add a new UpnpRegisterRootDevice4 which allow user to specify a
description URL to be returned for legacy CPs (for example, CPs
searching for a v1 when the device is v2). Most of those CPs does not
work if they found a v2 in the XML description, so this new function is
only used to solve interoperability issues.
(cherry picked from commit 11f9a2bafe)
This commit is contained in:
Fabrice Fontaine 2011-03-15 10:27:03 +01:00 committed by Marcelo Roberto Jimenez
parent bbe6d49b46
commit daec6a0321
6 changed files with 143 additions and 21 deletions

View File

@ -255,6 +255,16 @@ Version 1.8.0
Version 1.6.13
*******************************************************************************
2011-03-15 Fabrice Fontaine <fabrice.fontaine(at)orange-ftgroup.com>
New UpnpRegisterRootDevice4 for legacy CPs.
Add a new UpnpRegisterRootDevice4 which allow user to specify a
description URL to be returned for legacy CPs (for example, CPs
searching for a v1 when the device is v2). Most of those CPs does not
work if they found a v2 in the XML description, so this new function is
only used to solve interoperability issues.
2011-03-08 Iain Denniston <iain.denniston(at)gmail.com>
Fix for memory leak.

View File

@ -128,8 +128,9 @@
#define UPNP_E_BUFFER_TOO_SMALL -106
/*!
* \brief The description document passed to \b UpnpRegisterRootDevice or
* \b UpnpRegisterRootDevice2 is invalid.
* \brief The description document passed to \b UpnpRegisterRootDevice,
* \b UpnpRegisterRootDevice2 \b UpnpRegisterRootDevice3 or
* \b UpnpRegisterRootDevice4 is invalid.
*/
#define UPNP_E_INVALID_DESC -107
@ -418,7 +419,8 @@ typedef int UpnpClient_Handle;
/*!
* \brief Returned when a device application registers with
* \b UpnpRegisterRootDevice or \b UpnpRegisterRootDevice2.
* \b UpnpRegisterRootDevice, \b UpnpRegisterRootDevice2,
* \b UpnpRegisterRootDevice3 or \b UpnpRegisterRootDevice4.
*
* Device handles can only be used with functions that operate with a device
* handle.
@ -840,8 +842,62 @@ EXPORT_SPEC int UpnpRegisterRootDevice3(
const int AddressFamily);
/*!
* \brief Unregisters a root device registered with \b UpnpRegisterRootDevice or
* \b UpnpRegisterRootDevice2.
* \brief Registers a device application for a specific address family with
* the UPnP library. This function can also be used to specify a dedicated
* description URL to be returned for legacy CPs.
*
* A device application cannot make any other API calls until it registers
* using this function. Device applications can also register as control
* points (see \b UpnpRegisterClient to get a control point handle to perform
* control point functionality).
*
* This is synchronous and does not generate any callbacks. Callbacks can occur
* as soon as this function returns.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_FINISH: The SDK is already terminated or
* is not initialized.
* \li \c UPNP_E_INVALID_DESC: The description document was not
* a valid device description.
* \li \c UPNP_E_INVALID_URL: The URL for the description document
* is not valid.
* \li \c UPNP_E_INVALID_PARAM: Either \b Callback or \b Hnd
* is not a valid pointer or \b DescURL is \c NULL.
* \li \c UPNP_E_NETWORK_ERROR: A network error occurred.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading
* from a socket.
* \li \c UPNP_E_SOCKET_BIND: An error occurred binding a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting the
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
* \li \c UPNP_E_OUTOF_MEMORY: There are insufficient resources to
* register this root device.
*/
EXPORT_SPEC int UpnpRegisterRootDevice4(
/*! [in] Pointer to a string containing the description URL for this root
* device instance. */
const char *DescUrl,
/*! [in] Pointer to the callback function for receiving asynchronous events. */
Upnp_FunPtr Callback,
/*! [in] Pointer to user data returned with the callback function when invoked. */
const void *Cookie,
/*! [out] Pointer to a variable to store the new device handle. */
UpnpDevice_Handle *Hnd,
/*! [in] Address family of this device. Can be AF_INET for an IPv4 device, or
* AF_INET6 for an IPv6 device. Defaults to AF_INET. */
const int AddressFamily,
/*! [in] Pointer to a string containing the description URL to be returned for
* legacy CPs for this root device instance. */
const char *LowerDescUrl);
/*!
* \brief Unregisters a root device registered with \b UpnpRegisterRootDevice,
* \b UpnpRegisterRootDevice2, \b UpnpRegisterRootDevice3 or
* \b UpnpRegisterRootDevice4.
*
* After this call, the \b UpnpDevice_Handle is no longer valid. For all
* advertisements that have not yet expired, the SDK sends a device unavailable

View File

@ -790,6 +790,10 @@ int UpnpRegisterRootDevice(
HInfo->aliasInstalled = 0;
HInfo->HType = HND_DEVICE;
strcpy(HInfo->DescURL, DescUrl);
strcpy(HInfo->LowerDescURL, DescUrl);
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Following Root Device URL will be used when answering to legacy CPs %s\n",
HInfo->LowerDescURL);
HInfo->Callback = Fun;
HInfo->Cookie = (void *)Cookie;
HInfo->MaxAge = DEFAULT_MAXAGE;
@ -952,6 +956,10 @@ int UpnpRegisterRootDevice2(
goto exit_function;
}
strcpy(HInfo->LowerDescURL, HInfo->DescURL);
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Following Root Device URL will be used when answering to legacy CPs %s\n",
HInfo->LowerDescURL);
HInfo->aliasInstalled = config_baseURL != 0;
HInfo->HType = HND_DEVICE;
HInfo->Callback = Fun;
@ -1034,6 +1042,23 @@ int UpnpRegisterRootDevice3(
const void *Cookie,
UpnpDevice_Handle *Hnd,
const int AddressFamily)
{
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Inside UpnpRegisterRootDevice3\n");
return UpnpRegisterRootDevice4(DescUrl, Fun, Cookie, Hnd,
AddressFamily, NULL);
}
#endif /* INCLUDE_DEVICE_APIS */
#ifdef INCLUDE_DEVICE_APIS
int UpnpRegisterRootDevice4(
const char *DescUrl,
Upnp_FunPtr Fun,
const void *Cookie,
UpnpDevice_Handle *Hnd,
const int AddressFamily,
const char *LowerDescUrl)
{
struct Handle_Info *HInfo;
int retVal = 0;
@ -1043,7 +1068,7 @@ int UpnpRegisterRootDevice3(
HandleLock();
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Inside UpnpRegisterRootDevice3\n");
"Inside UpnpRegisterRootDevice4\n");
if (UpnpSdkInit != 1) {
retVal = UPNP_E_FINISH;
goto exit_function;
@ -1087,6 +1112,13 @@ int UpnpRegisterRootDevice3(
HInfo->aliasInstalled = 0;
HInfo->HType = HND_DEVICE;
strcpy(HInfo->DescURL, DescUrl);
if (LowerDescUrl == NULL)
strcpy(HInfo->LowerDescURL, DescUrl);
else
strcpy(HInfo->LowerDescURL, LowerDescUrl);
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Following Root Device URL will be used when answering to legacy CPs %s\n",
HInfo->LowerDescURL);
HInfo->Callback = Fun;
HInfo->Cookie = (void *)Cookie;
HInfo->MaxAge = DEFAULT_MAXAGE;
@ -1109,8 +1141,8 @@ int UpnpRegisterRootDevice3(
goto exit_function;
}
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"UpnpRegisterRootDevice3: Valid Description\n"
"UpnpRegisterRootDevice3: DescURL : %s\n",
"UpnpRegisterRootDevice4: Valid Description\n"
"UpnpRegisterRootDevice4: DescURL : %s\n",
HInfo->DescURL);
HInfo->DeviceList = ixmlDocument_getElementsByTagName(
@ -1122,7 +1154,7 @@ int UpnpRegisterRootDevice3(
ixmlDocument_free(HInfo->DescDocument);
FreeHandle(*Hnd);
UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
"UpnpRegisterRootDevice3: No devices found for RootDevice\n");
"UpnpRegisterRootDevice4: No devices found for RootDevice\n");
retVal = UPNP_E_INVALID_DESC;
goto exit_function;
}
@ -1131,26 +1163,26 @@ int UpnpRegisterRootDevice3(
HInfo->DescDocument, "serviceList" );
if (!HInfo->ServiceList) {
UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
"UpnpRegisterRootDevice3: No services found for RootDevice\n");
"UpnpRegisterRootDevice4: No services found for RootDevice\n");
}
/*
* GENA SET UP
*/
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"UpnpRegisterRootDevice3: Gena Check\n" );
"UpnpRegisterRootDevice4: Gena Check\n" );
hasServiceTable = getServiceTable(
(IXML_Node *)HInfo->DescDocument,
&HInfo->ServiceTable,
HInfo->DescURL);
if (hasServiceTable) {
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"UpnpRegisterRootDevice3: GENA Service Table \n"
"UpnpRegisterRootDevice4: GENA Service Table \n"
"Here are the known services: \n" );
printServiceTable(&HInfo->ServiceTable, UPNP_ALL, API);
} else {
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"\nUpnpRegisterRootDevice3: Empty service table\n");
"\nUpnpRegisterRootDevice4: Empty service table\n");
}
if (AddressFamily == AF_INET) {
@ -1163,7 +1195,7 @@ int UpnpRegisterRootDevice3(
exit_function:
UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
"Exiting RegisterRootDevice3, return value == %d\n", retVal);
"Exiting RegisterRootDevice4, return value == %d\n", retVal);
HandleUnlock();
return retVal;

View File

@ -80,6 +80,9 @@ struct Handle_Info
#ifdef INCLUDE_DEVICE_APIS
/*! URL for the use of SSDP. */
char DescURL[LINE_SIZE];
/*! URL for the use of SSDP when answering to legacy CPs (CP searching
* for a v1 when the device is v2). */
char LowerDescURL[LINE_SIZE];
/*! XML file path for device description. */
char DescXML[LINE_SIZE];
/* Advertisement timeout */

View File

@ -366,10 +366,13 @@ static int check_soap_body(
if (actionNode) {
ns = ixmlNode_getNamespaceURI(actionNode);
name = ixmlNode_getLocalName(actionNode);
/* Don't check version number, to accept a
* request comming on a v1 service when
* publishing a v2 service */
if (name &&
ns &&
!strcmp(actionName, name) &&
!strcmp(urn, ns))
!strncmp(urn, ns, strlen (urn) - 2))
ret_code = UPNP_E_SUCCESS;
}
}
@ -440,7 +443,9 @@ static int check_soap_action_header(
return ret_code;
}
snprintf(ns_compare, tempSize, "\"%s", urn);
if (strcmp(temp_header_value, ns_compare))
/* Don't check version number, to accept a request comming on a v1
* service when publishing a v2 service */
if (strncmp(temp_header_value, ns_compare, strlen(ns_compare) - 2))
ret_code = UPNP_E_INVALID_ACTION;
else {
ret_code = UPNP_E_SUCCESS;

View File

@ -245,10 +245,18 @@ int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd,
}
case SSDP_DEVICETYPE: {
if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - 2)) {
if (atoi(&DeviceType[strlen(DeviceType)
- 1]) <= atoi(&devType[strlen(devType) - 1])) {
if (atoi(strrchr(DeviceType, ':') + 1)
< atoi(&devType[strlen(devType) - 1])) {
/* the requested version is lower than the device version
* must reply with the lower version number */
* must reply with the lower version number and the lower
* description URL */
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType);
SendReply(DestAddr, DeviceType, 0, UDNstr, SInfo->LowerDescURL,
defaultExp, 1);
} else if (atoi(strrchr(DeviceType, ':') + 1)
== atoi(&devType[strlen(devType) - 1])) {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType);
@ -347,10 +355,18 @@ int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd,
case SSDP_SERVICE:
if (ServiceType) {
if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - 2)) {
if (atoi(&ServiceType[strlen(ServiceType) - 1]) <=
if (atoi(strrchr(ServiceType, ':') + 1) <
atoi(&servType[strlen(servType) - 1])) {
/* the requested version is lower than the service version
* must reply with the lower version number */
* must reply with the lower version number and the lower
* description URL */
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s MATCH\n",
ServiceType, servType);
SendReply(DestAddr, ServiceType, 0, UDNstr, SInfo->LowerDescURL,
defaultExp, 1);
} else if (atoi(strrchr (ServiceType, ':') + 1) ==
atoi(&servType[strlen(servType) - 1])) {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s MATCH\n",
ServiceType, servType);