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 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> 2011-03-08 Iain Denniston <iain.denniston(at)gmail.com>
Fix for memory leak. Fix for memory leak.

View File

@ -128,8 +128,9 @@
#define UPNP_E_BUFFER_TOO_SMALL -106 #define UPNP_E_BUFFER_TOO_SMALL -106
/*! /*!
* \brief The description document passed to \b UpnpRegisterRootDevice or * \brief The description document passed to \b UpnpRegisterRootDevice,
* \b UpnpRegisterRootDevice2 is invalid. * \b UpnpRegisterRootDevice2 \b UpnpRegisterRootDevice3 or
* \b UpnpRegisterRootDevice4 is invalid.
*/ */
#define UPNP_E_INVALID_DESC -107 #define UPNP_E_INVALID_DESC -107
@ -418,7 +419,8 @@ typedef int UpnpClient_Handle;
/*! /*!
* \brief Returned when a device application registers with * \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 * Device handles can only be used with functions that operate with a device
* handle. * handle.
@ -840,8 +842,62 @@ EXPORT_SPEC int UpnpRegisterRootDevice3(
const int AddressFamily); const int AddressFamily);
/*! /*!
* \brief Unregisters a root device registered with \b UpnpRegisterRootDevice or * \brief Registers a device application for a specific address family with
* \b UpnpRegisterRootDevice2. * 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 * 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 * advertisements that have not yet expired, the SDK sends a device unavailable

View File

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

View File

@ -80,6 +80,9 @@ struct Handle_Info
#ifdef INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS
/*! URL for the use of SSDP. */ /*! URL for the use of SSDP. */
char DescURL[LINE_SIZE]; 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. */ /*! XML file path for device description. */
char DescXML[LINE_SIZE]; char DescXML[LINE_SIZE];
/* Advertisement timeout */ /* Advertisement timeout */

View File

@ -366,10 +366,13 @@ static int check_soap_body(
if (actionNode) { if (actionNode) {
ns = ixmlNode_getNamespaceURI(actionNode); ns = ixmlNode_getNamespaceURI(actionNode);
name = ixmlNode_getLocalName(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 && if (name &&
ns && ns &&
!strcmp(actionName, name) && !strcmp(actionName, name) &&
!strcmp(urn, ns)) !strncmp(urn, ns, strlen (urn) - 2))
ret_code = UPNP_E_SUCCESS; ret_code = UPNP_E_SUCCESS;
} }
} }
@ -440,7 +443,9 @@ static int check_soap_action_header(
return ret_code; return ret_code;
} }
snprintf(ns_compare, tempSize, "\"%s", urn); 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; ret_code = UPNP_E_INVALID_ACTION;
else { else {
ret_code = UPNP_E_SUCCESS; ret_code = UPNP_E_SUCCESS;

View File

@ -245,10 +245,18 @@ int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd,
} }
case SSDP_DEVICETYPE: { case SSDP_DEVICETYPE: {
if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - 2)) { if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - 2)) {
if (atoi(&DeviceType[strlen(DeviceType) if (atoi(strrchr(DeviceType, ':') + 1)
- 1]) <= atoi(&devType[strlen(devType) - 1])) { < atoi(&devType[strlen(devType) - 1])) {
/* the requested version is lower than the device version /* 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__, UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n", "DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType); devType, DeviceType);
@ -347,10 +355,18 @@ int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd,
case SSDP_SERVICE: case SSDP_SERVICE:
if (ServiceType) { if (ServiceType) {
if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - 2)) { if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - 2)) {
if (atoi(&ServiceType[strlen(ServiceType) - 1]) <= if (atoi(strrchr(ServiceType, ':') + 1) <
atoi(&servType[strlen(servType) - 1])) { atoi(&servType[strlen(servType) - 1])) {
/* the requested version is lower than the service version /* 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__, UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s MATCH\n", "ServiceType=%s and search servType=%s MATCH\n",
ServiceType, servType); ServiceType, servType);