Commit bfd5bed0 authored by Larry Sachs's avatar Larry Sachs Committed by Rick Bell

Align Device and Service Attributes with spec

Updated device attributes to match spec, added service
attributes per spec.  Added service links for actions
and state variables. Added resources for actions and
state variables.

This is an interim commit, still need to add resource
attributes for actions and state variables.

Removed 'uuid:' from resource paths.

Change-Id: I25c8903da2ba194fbbe7776be43e11c931e5ab21
Signed-off-by: Larry Sachs's avatarLarry Sachs <larry.j.sachs@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/20849Reviewed-by: George Nash's avatarGeorge Nash <george.nash@intel.com>
Tested-by: default avatarjenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: default avatarRick Bell <richard.s.bell@intel.com>
parent edca1bc6
......@@ -68,6 +68,8 @@ const uint BRIGHTNESS_CALLBACK = 2;
const uint GENERIC_DEVICE_CALLBACK = 1000;
const uint GENERIC_SERVICE_CALLBACK = 1001;
const uint GENERIC_ACTION_CALLBACK = 1002;
const uint GENERIC_STATE_VAR_CALLBACK = 1003;
UpnpConnector::UpnpConnector(DiscoveryCallback discoveryCallback, LostCallback lostCallback)
{
......@@ -624,13 +626,17 @@ OCEntityHandlerResult handleEntityHandlerRequests( OCEntityHandlerRequest *entit
MPMExtractFiltersFromQuery(dupQuery, &interfaceQuery, &resourceTypeQuery);
}
for (const auto& service : s_manager->m_services) {
if (service.second->m_uri == uri) {
for (const auto& service : s_manager->m_services)
{
// service entity handler does all service related resources
// (ie uri starts with service uri)
if (uri.find(service.second->m_uri) == 0)
{
switch (entityHandlerRequest->method)
{
case OC_REST_GET:
DEBUG_PRINT(" GET Request for: " << uri);
ehResult = service.second->processGetRequest(payload, resourceType);
ehResult = service.second->processGetRequest(uri, payload, resourceType);
break;
case OC_REST_PUT:
......@@ -649,7 +655,8 @@ OCEntityHandlerResult handleEntityHandlerRequests( OCEntityHandlerRequest *entit
}
for (const auto& device : s_manager->m_devices) {
if (device.second->m_uri == uri) {
if (device.second->m_uri == uri)
{
switch (entityHandlerRequest->method)
{
case OC_REST_GET:
......@@ -718,6 +725,14 @@ OCEntityHandlerResult resourceEntityHandler(OCEntityHandlerFlag,
{
return handleEntityHandlerRequests(entityHandlerRequest, UPNP_SERVICE_RESOURCE);
}
else if (callbackParamResourceType == GENERIC_ACTION_CALLBACK)
{
return handleEntityHandlerRequests(entityHandlerRequest, UPNP_ACTION_RESOURCE);
}
else if (callbackParamResourceType == GENERIC_STATE_VAR_CALLBACK)
{
return handleEntityHandlerRequests(entityHandlerRequest, UPNP_STATE_VAR_RESOURCE);
}
else
{
DEBUG_PRINT("TODO: Handle callback for " << callbackParamResourceType);
......@@ -737,12 +752,14 @@ void UpnpConnector::onAdd(std::string uri)
for (const auto& service : s_manager->m_services) {
if (service.second->m_uri == uri) {
if (service.second->m_resourceType == UPNP_OIC_TYPE_POWER_SWITCH) {
if (service.second->m_resourceType == UPNP_OIC_TYPE_POWER_SWITCH)
{
DEBUG_PRINT("Adding binary switch resource");
createResource(uri, UPNP_OIC_TYPE_POWER_SWITCH, OC_RSRVD_INTERFACE_ACTUATOR,
resourceEntityHandler, (void *) BINARY_SWITCH_CALLBACK, resourceProperties);
}
else if (service.second->m_resourceType == UPNP_OIC_TYPE_BRIGHTNESS) {
else if (service.second->m_resourceType == UPNP_OIC_TYPE_BRIGHTNESS)
{
DEBUG_PRINT("Adding brightness resource");
createResource(uri, UPNP_OIC_TYPE_BRIGHTNESS, OC_RSRVD_INTERFACE_ACTUATOR,
resourceEntityHandler, (void *) BRIGHTNESS_CALLBACK, resourceProperties);
......@@ -752,13 +769,37 @@ void UpnpConnector::onAdd(std::string uri)
DEBUG_PRINT("Adding generic upnp service");
createResource(uri, UPNP_SERVICE_RESOURCE, OC_RSRVD_INTERFACE_ACTUATOR,
resourceEntityHandler, (void *) GENERIC_SERVICE_CALLBACK, resourceProperties);
// create resources for links
if (!service.second->m_links.empty())
{
DEBUG_PRINT("Creating resources for links");
for (unsigned int i = 0; i < service.second->m_links.size(); ++i) {
string linkUri = service.second->m_links[i].href;
string linkRt = service.second->m_links[i].rt;
if (UPNP_ACTION_RESOURCE == linkRt)
{
createResource(linkUri, linkRt, OC_RSRVD_INTERFACE_ACTUATOR,
resourceEntityHandler, (void *) GENERIC_ACTION_CALLBACK, resourceProperties);
}
else if (UPNP_STATE_VAR_RESOURCE == linkRt)
{
createResource(linkUri, linkRt, OC_RSRVD_INTERFACE_SENSOR,
resourceEntityHandler, (void *) GENERIC_STATE_VAR_CALLBACK, resourceProperties);
}
else
{
ERROR_PRINT("Failed to create resource for unknown type " << linkRt);
}
}
}
}
}
}
for (const auto& device : s_manager->m_devices) {
if (device.second->m_uri == uri) {
if (device.second->m_resourceType == UPNP_OIC_TYPE_DEVICE_LIGHT) {
if (device.second->m_resourceType == UPNP_OIC_TYPE_DEVICE_LIGHT)
{
DEBUG_PRINT("Adding light device");
createResource(uri, UPNP_OIC_TYPE_DEVICE_LIGHT, OC_RSRVD_INTERFACE_READ,
resourceEntityHandler, (void *) LIGHT_CALLBACK, resourceProperties);
......@@ -797,7 +838,8 @@ OCStackResult UpnpConnector::createResource(const string uri, const string resou
// {
// DEBUG_PRINT("Failed to bind virtual resource type to " << uri);
// }
if (UPNP_OIC_TYPE_DEVICE_LIGHT == resourceTypeName || UPNP_DEVICE_RESOURCE == resourceTypeName) {
if (UPNP_OIC_TYPE_DEVICE_LIGHT == resourceTypeName ||
UPNP_DEVICE_RESOURCE == resourceTypeName || UPNP_SERVICE_RESOURCE == resourceTypeName) {
result = OCBindResourceTypeToResource(handle, OC_RSRVD_RESOURCE_TYPE_COLLECTION);
if (result == OC_STACK_OK)
{
......
......@@ -42,12 +42,23 @@ UpnpDevice::UpnpDevice(GUPnPDeviceInfo *deviceInfo,
if (m_resourceType == "")
{
throw logic_error(string("Device type ") + m_deviceType + string(" not implemented!"));
throw logic_error(DEVICE_TYPE + string(": ") + m_deviceType + string(" not implemented!"));
return;
}
m_name = getStringField(gupnp_device_info_get_friendly_name, deviceInfo);
m_uri = UpnpUriPrefixMap[m_resourceType] + gupnp_device_info_get_udn(deviceInfo);
string udnWithoutPrefix;
if (m_udn.find(UPNP_PREFIX_UDN) == 0)
{
udnWithoutPrefix = m_udn.substr(UPNP_PREFIX_UDN.size());
}
else
{
udnWithoutPrefix = m_udn;
}
m_uri = UpnpUriPrefixMap[m_resourceType] + udnWithoutPrefix;
if (m_uri.length() > MAX_URI_LENGTH)
{
ERROR_PRINT("URI too long " << m_uri << "( " << m_uri.length());
......@@ -90,15 +101,15 @@ std::vector<string> &UpnpDevice::getServiceList()
static const map< string, function< char *(GUPnPDeviceInfo *deviceInfo)>> s_deviceInfo2AttributesMap
=
{
{"n", gupnp_device_info_get_friendly_name},
{"friendlyName", gupnp_device_info_get_friendly_name},
{"manufacturer", gupnp_device_info_get_manufacturer},
{"manufacturer_url", gupnp_device_info_get_manufacturer_url},
{"model_number", gupnp_device_info_get_model_number},
{"model_name", gupnp_device_info_get_model_name},
{"model_description", gupnp_device_info_get_model_description},
{"model_url", gupnp_device_info_get_model_url},
{"serial_number", gupnp_device_info_get_serial_number},
{"presentation_url", gupnp_device_info_get_presentation_url},
{"manufacturerUrl", gupnp_device_info_get_manufacturer_url},
{"modelNumber", gupnp_device_info_get_model_number},
{"modelName", gupnp_device_info_get_model_name},
{"modelDescription", gupnp_device_info_get_model_description},
{"modelUrl", gupnp_device_info_get_model_url},
{"serialNumber", gupnp_device_info_get_serial_number},
{"presentationUrl", gupnp_device_info_get_presentation_url},
{"upc", gupnp_device_info_get_upc}
};
......@@ -143,16 +154,25 @@ OCEntityHandlerResult UpnpDevice::processGetRequest(OCRepPayload *payload, strin
throw "payload is null";
}
vector<_iconLink> iconLinks;
if (UPNP_DEVICE_RESOURCE == resourceType)
{
GUPnPDeviceInfo *deviceInfo = GUPNP_DEVICE_INFO(m_proxy);
if (!OCRepPayloadSetPropString(payload, "device_type", m_deviceType.c_str()))
if (!OCRepPayloadSetPropString(payload, DEVICE_TYPE.c_str(), m_deviceType.c_str()))
{
throw "Failed to set device_type value in payload";
string message = "Failed to set " + DEVICE_TYPE + " value in payload";
throw message;
}
DEBUG_PRINT("device_type: " << m_deviceType);
DEBUG_PRINT(DEVICE_TYPE << ": " << m_deviceType);
if (!OCRepPayloadSetPropString(payload, UDN.c_str(), m_udn.c_str()))
{
string message = "Failed to set " + UDN + " value in payload";
throw message;
}
DEBUG_PRINT(UDN << ": " << m_udn);
for (auto const &kv : s_deviceInfo2AttributesMap)
{
......@@ -169,23 +189,71 @@ OCEntityHandlerResult UpnpDevice::processGetRequest(OCRepPayload *payload, strin
}
}
char *iconUrl = gupnp_device_info_get_icon_url(deviceInfo, NULL, -1, -1, -1, false, NULL, NULL, NULL, NULL);
// get the smallest icon first
char *mimeType = NULL;
int width = 0;
int height = 0;
char *iconUrl = gupnp_device_info_get_icon_url(deviceInfo, NULL, -1, -1, -1, false,
&mimeType, NULL, &width, &height);
if (iconUrl != NULL)
{
if (!OCRepPayloadSetPropString(payload, "icon_url", iconUrl))
_iconLink iconLink;
iconLink.href = m_uri;
iconLink.rel = LINK_REL_ICON;
iconLink.rt = OIC_TYPE_ICON;
iconLink.mimetype = mimeType;
iconLink.media = iconUrl;
iconLink.width = width;
iconLink.height = height;
iconLinks.push_back(iconLink);
g_free(iconUrl);
g_free(mimeType);
}
// continue getting larger icons
int nextWidth = 0;
int nextHeight = 0;
bool gettingIcons = true;
while (gettingIcons)
{
iconUrl = gupnp_device_info_get_icon_url(deviceInfo, NULL, -1, width, height, true,
&mimeType, NULL, &nextWidth, &nextHeight);
if (iconUrl != NULL)
{
throw "Failed to set icon_url value in payload";
if (width != nextWidth || height != nextHeight)
{
_iconLink iconLink;
iconLink.href = m_uri;
iconLink.rel = LINK_REL_ICON;
iconLink.rt = OIC_TYPE_ICON;
iconLink.mimetype = mimeType;
iconLink.media = iconUrl;
iconLink.width = nextWidth;
iconLink.height = nextHeight;
iconLinks.push_back(iconLink);
width = nextWidth;
height = nextHeight;
}
else
{
gettingIcons = false;
}
g_free(iconUrl);
g_free(mimeType);
}
else{
gettingIcons = false;
}
DEBUG_PRINT("icon_url: " << iconUrl);
g_free(iconUrl);
}
}
if (!m_links.empty())
if (!m_links.empty() || !iconLinks.empty())
{
DEBUG_PRINT("Setting links");
const OCRepPayload *links[m_links.size()];
size_t dimensions[MAX_REP_ARRAY_DEPTH] = {m_links.size(), 0, 0};
const OCRepPayload *links[m_links.size()+iconLinks.size()];
size_t dimensions[MAX_REP_ARRAY_DEPTH] = {m_links.size()+iconLinks.size(), 0, 0};
for (unsigned int i = 0; i < m_links.size(); ++i) {
DEBUG_PRINT(OC_RSRVD_LINKS << "[" << i << "]");
DEBUG_PRINT("\t" << OC_RSRVD_HREF << "=" << m_links[i].href);
......@@ -197,6 +265,25 @@ OCEntityHandlerResult UpnpDevice::processGetRequest(OCRepPayload *payload, strin
OCRepPayloadSetPropString(linkPayload, OC_RSRVD_RESOURCE_TYPE, m_links[i].rt.c_str());
links[i] = linkPayload;
}
for (unsigned int i = 0; i < iconLinks.size(); ++i) {
DEBUG_PRINT(OC_RSRVD_LINKS << "[" << m_links.size()+i << "]");
DEBUG_PRINT("\t" << OC_RSRVD_HREF << "=" << iconLinks[i].href);
DEBUG_PRINT("\t" << OC_RSRVD_REL << "=" << iconLinks[i].rel);
DEBUG_PRINT("\t" << OC_RSRVD_RESOURCE_TYPE << "=" << iconLinks[i].rt);
DEBUG_PRINT("\t" << MIMETYPE.c_str() << "=" << iconLinks[i].mimetype);
DEBUG_PRINT("\t" << MEDIA.c_str() << "=" << iconLinks[i].media);
DEBUG_PRINT("\t" << ICON_WIDTH.c_str() << "=" << iconLinks[i].width);
DEBUG_PRINT("\t" << ICON_HEIGHT.c_str() << "=" << iconLinks[i].height);
OCRepPayload *linkPayload = OCRepPayloadCreate();
OCRepPayloadSetPropString(linkPayload, OC_RSRVD_HREF, iconLinks[i].href.c_str());
OCRepPayloadSetPropString(linkPayload, OC_RSRVD_REL, iconLinks[i].rel.c_str());
OCRepPayloadSetPropString(linkPayload, OC_RSRVD_RESOURCE_TYPE, iconLinks[i].rt.c_str());
OCRepPayloadSetPropString(linkPayload, MIMETYPE.c_str(), iconLinks[i].mimetype.c_str());
OCRepPayloadSetPropString(linkPayload, MEDIA.c_str(), iconLinks[i].media.c_str());
OCRepPayloadSetPropInt(linkPayload, ICON_WIDTH.c_str(), iconLinks[i].width);
OCRepPayloadSetPropInt(linkPayload, ICON_HEIGHT.c_str(), iconLinks[i].height);
links[m_links.size()+i] = linkPayload;
}
OCRepPayloadSetPropObjectArray(payload, OC_RSRVD_LINKS, links, dimensions);
}
......
......@@ -29,6 +29,26 @@
using namespace std;
static const string DEVICE_TYPE = "deviceType";
static const string UDN = "udn";
// for icons
static const string OIC_TYPE_ICON = "oic.r.icon";
static const string MIMETYPE = "mimetype";
static const string MEDIA = "media";
static const string ICON_WIDTH = "width";
static const string ICON_HEIGHT = "height";
struct _iconLink {
string href;
string rel;
string rt;
string mimetype;
string media;
int width;
int height;
};
class UpnpDevice: public UpnpResource
{
public:
......
......@@ -66,7 +66,7 @@ vector <UpnpAttributeInfo> UpnpDimming::Attributes =
static const char* brightnessLevelName = "brightness";
OCEntityHandlerResult UpnpDimming::processGetRequest(OCRepPayload *payload, string resourceType)
OCEntityHandlerResult UpnpDimming::processGetRequest(string uri, OCRepPayload *payload, string resourceType)
{
if (payload == NULL)
{
......@@ -99,7 +99,7 @@ OCEntityHandlerResult UpnpDimming::processGetRequest(OCRepPayload *payload, stri
}
DEBUG_PRINT(brightnessLevelName << ": " << brightnessLevelValue);
return UpnpService::processGetRequest(payload, resourceType);
return UpnpService::processGetRequest(uri, payload, resourceType);
}
OCEntityHandlerResult UpnpDimming::processPutRequest(OCEntityHandlerRequest *ehRequest,
......
......@@ -43,7 +43,7 @@ class UpnpDimming: public UpnpService
{
}
OCEntityHandlerResult processGetRequest(OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processGetRequest(string uri, OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload);
......
......@@ -26,25 +26,26 @@ vector <UpnpAttributeInfo> UpnpGenericService::Attributes =
{
};
OCEntityHandlerResult UpnpGenericService::processGetRequest(OCRepPayload *payload, string resourceType)
OCEntityHandlerResult UpnpGenericService::processGetRequest(string uri, OCRepPayload *payload, string resourceType)
{
if (payload == NULL)
{
throw "payload is null";
}
(void) resourceType;
//TODO use async version with callback
DEBUG_PRINT("TODO:");
DEBUG_PRINT("TODO: process get request for " << uri << " resource type " << resourceType);
// TODO use introspection to get actions and state variables
// TODO create action resource if it doesn't exist
// TODO create state variable resource if it doesn't exist
// TODO add action and state variable links to payload
return UpnpService::processGetRequest(payload, resourceType);
return UpnpService::processGetRequest(uri, payload, resourceType);
}
OCEntityHandlerResult UpnpGenericService::processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload)
{
(void) uri;
(void) resourceType;
(void) payload;
if (!ehRequest || !ehRequest->payload ||
ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
......@@ -59,7 +60,7 @@ OCEntityHandlerResult UpnpGenericService::processPutRequest(OCEntityHandlerReque
}
//TODO use async version with callback
DEBUG_PRINT("TODO:");
DEBUG_PRINT("TODO: process put request for " << uri << " resource type " << resourceType);
return OC_EH_OK;
}
......@@ -42,7 +42,7 @@ class UpnpGenericService: public UpnpService
{
}
OCEntityHandlerResult processGetRequest(OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processGetRequest(string uri, OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload);
......
......@@ -33,11 +33,13 @@
//IoTivity Link Relationships
static const std::string LINK_REL_CONTAINS = "contains";
static const std::string LINK_REL_HOSTS = "hosts";
static const std::string LINK_REL_ICON = "icon";
//From UPNP spec
static const std::string UPNP_PREFIX_DEVICE = "urn:schemas-upnp-org:device";
static const std::string UPNP_PREFIX_SERVICE = "urn:schemas-upnp-org:service";
static const std::string UPNP_PREFIX_SERVICE_ID = "urn:upnp-org:serviceId:";
static const std::string UPNP_PREFIX_UDN = "uuid:";
// Root device
static const std::string UPNP_ROOT_DEVICE = "upnp:rootdevice";
......
......@@ -481,13 +481,48 @@ std::shared_ptr<UpnpService> UpnpManager::generateService(GUPnPServiceInfo *ser
{
if (! resourceType.empty())
{
DEBUG_PRINT("Service type " << serviceType << " implemented as generic upnp service");
return (std::make_shared < UpnpGenericService > (serviceInfo, requestState, resourceType));
DEBUG_PRINT(SERVICE_TYPE << " " << serviceType << " implemented as generic upnp service");
std::shared_ptr<UpnpService> genericService = std::make_shared < UpnpGenericService > (serviceInfo, requestState, resourceType);
GUPnPServiceIntrospection *introspection = gupnp_service_info_get_introspection(serviceInfo, NULL);
if (introspection != NULL)
{
const GList *actionNameList = gupnp_service_introspection_list_action_names(introspection);
if (actionNameList != NULL)
{
const GList *l;
for (l = actionNameList; l != NULL; l = l->next)
{
const string actionName = string ((char *) l->data);
DEBUG_PRINT(genericService->m_uri << " has action " << actionName);
std::shared_ptr<UpnpResource> upnpActionResource = std::make_shared < UpnpResource > ();
upnpActionResource->m_uri = genericService->m_uri + "/" + actionName;
upnpActionResource->m_resourceType = UPNP_ACTION_RESOURCE;
genericService->addLink(upnpActionResource);
}
}
const GList *stateVarNameList = gupnp_service_introspection_list_state_variable_names(introspection);
if (stateVarNameList != NULL)
{
const GList *l;
for (l = stateVarNameList; l != NULL; l = l->next)
{
const string varName = string ((char *) l->data);
DEBUG_PRINT(genericService->m_uri << " has state variable " << varName);
std::shared_ptr<UpnpResource> upnpStateVarResource = std::make_shared < UpnpResource > ();
upnpStateVarResource->m_uri = genericService->m_uri + "/" + varName;
upnpStateVarResource->m_resourceType = UPNP_STATE_VAR_RESOURCE;
genericService->addLink(upnpStateVarResource);
}
}
g_object_unref(introspection);
}
return genericService;
}
else
{
//throw an exception
ERROR_PRINT("Service type " << serviceType << " not implemented!");
ERROR_PRINT(SERVICE_TYPE << " " << serviceType << " not implemented!");
throw NotImplementedException("UpnpService::ctor: Service " + serviceType + " not implemented!");
return nullptr;
}
......
......@@ -45,7 +45,7 @@ vector <UpnpAttributeInfo> UpnpPowerSwitch::Attributes =
static const char* powerSwitchStateName = "value";
OCEntityHandlerResult UpnpPowerSwitch::processGetRequest(OCRepPayload *payload, string resourceType)
OCEntityHandlerResult UpnpPowerSwitch::processGetRequest(string uri, OCRepPayload *payload, string resourceType)
{
if (payload == NULL)
{
......@@ -78,7 +78,7 @@ OCEntityHandlerResult UpnpPowerSwitch::processGetRequest(OCRepPayload *payload,
}
DEBUG_PRINT(powerSwitchStateName << ": " << (powerSwitchStateValue ? "true" : "false"));
return UpnpService::processGetRequest(payload, resourceType);
return UpnpService::processGetRequest(uri, payload, resourceType);
}
OCEntityHandlerResult UpnpPowerSwitch::processPutRequest(OCEntityHandlerRequest *ehRequest,
......
......@@ -43,7 +43,7 @@ class UpnpPowerSwitch: public UpnpService
{
}
OCEntityHandlerResult processGetRequest(OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processGetRequest(string uri, OCRepPayload *payload, string resourceType);
OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload);
......
......@@ -53,8 +53,13 @@ void UpnpResource::addLink(UpnpResource::Ptr pResource)
singleLink.href = pResource->m_uri;
singleLink.rel = LINK_REL_CONTAINS;
singleLink.rt = pResource->getResourceType();
// Ignore action and state variable resources
if (singleLink.rt == UPNP_ACTION_RESOURCE || singleLink.rt == UPNP_STATE_VAR_RESOURCE)
{
// leave link rt unchanged
}
// Embedded devices are all generic upnp devices for now
if (singleLink.rt.find(UPNP_OIC_TYPE_DEVICE_PREFIX) == 0) {
else if (singleLink.rt.find(UPNP_OIC_TYPE_DEVICE_PREFIX) == 0) {
singleLink.rt = UPNP_DEVICE_RESOURCE;
}
// Non-light services are all generic upnp services for now
......
......@@ -31,6 +31,8 @@ using namespace std;
static const string UPNP_DEVICE_RESOURCE = "oic.r.upnp.device";
static const string UPNP_SERVICE_RESOURCE = "oic.r.upnp.service";
static const string UPNP_ACTION_RESOURCE = "oic.r.upnp.action";
static const string UPNP_STATE_VAR_RESOURCE = "oic.r.upnp.stateVariable";
struct _link {
string href;
......
......@@ -31,6 +31,14 @@ using namespace std;
static const string MODULE = "UpnpService";
static const map< string, function< char *(GUPnPServiceInfo *serviceInfo)>> s_serviceInfo2AttributesMap =
{
{"serviceId", gupnp_service_info_get_id},
{"scpdUrl", gupnp_service_info_get_scpd_url},
{"controlUrl", gupnp_service_info_get_control_url},
{"eventSubUrl", gupnp_service_info_get_event_subscription_url}
};
UpnpService::UpnpService(GUPnPServiceInfo *serviceInfo,
string type,
UpnpRequestState *requestState,
......@@ -76,8 +84,17 @@ UpnpService::UpnpService(GUPnPServiceInfo *serviceInfo,
m_name = m_serviceId.substr(UPNP_PREFIX_SERVICE_ID.size());
//TODO: discuss service URI format. Currently: resource_type/service_id/udn
m_uri = UpnpUriPrefixMap[m_resourceType] + m_name + "/" + m_udn;
// URI format: resource_type/service_id/udn_without_uuid_prefix
string udnWithoutPrefix;
if (m_udn.find(UPNP_PREFIX_UDN) == 0)
{
udnWithoutPrefix = m_udn.substr(UPNP_PREFIX_UDN.size());
}
else
{
udnWithoutPrefix = m_udn;
}
m_uri = UpnpUriPrefixMap[m_resourceType] + m_name + "/" + udnWithoutPrefix;
DEBUG_PRINT("service URI: " << m_uri);
if (m_uri.length() > MAX_URI_LENGTH)
{
......@@ -144,10 +161,64 @@ string UpnpService::getStringField(function< char *(GUPnPServiceInfo *serviceInf
return "";
}
OCEntityHandlerResult UpnpService::processGetRequest(OCRepPayload *payload, string resourceType)
OCEntityHandlerResult UpnpService::processGetRequest(string uri, OCRepPayload *payload, string resourceType)
{
(void) payload;
(void) resourceType;
if (payload == NULL)
{
throw "payload is null";
}
if (UPNP_SERVICE_RESOURCE == resourceType)
{
GUPnPServiceInfo *serviceInfo = GUPNP_SERVICE_INFO(m_proxy);
const char *serviceType = gupnp_service_info_get_service_type(serviceInfo);
if (OCRepPayloadSetPropString(payload, SERVICE_TYPE.c_str(), serviceType))
{
DEBUG_PRINT(SERVICE_TYPE << ": " << serviceType);
}
else
{
ERROR_PRINT("Failed to set " + SERVICE_TYPE << " value in payload");
}
for (auto const &kv : s_serviceInfo2AttributesMap)
{
char *c_field = kv.second(serviceInfo);
if (c_field != NULL)
{
if (OCRepPayloadSetPropString(payload, kv.first.c_str(), c_field))
{
DEBUG_PRINT(kv.first << ": " << c_field);
g_free(c_field);
}
else
{
ERROR_PRINT("Failed to set " << kv.first << " value in payload");
}
}
}
if (!m_links.empty())
{
DEBUG_PRINT("Setting links for " << uri);
const OCRepPayload *links[m_links.size()];
size_t dimensions[MAX_REP_ARRAY_DEPTH] = {m_links.size(), 0, 0};
for (unsigned int i = 0; i < m_links.size(); ++i) {