Commit 32e5429b authored by George Nash's avatar George Nash Committed by Rick Bell

Handle the pluginAdd request

Patch Set 3 -- added processGetRequest()
Patch Set 4 -- added processPutRequest()
Patch Set 5 -- added gupnp library calls
Patch Set 6 -- added dimming service
Patch Set 7 -- added observer notification
Patch Set 8 -- refactor observer notification

Change-Id: I0381b03063fb79c823888fd7a257c5684dbf281d
Signed-off-by: George Nash's avatarGeorge Nash <george.nash@intel.com>
Signed-off-by: Larry Sachs's avatarLarry Sachs <larry.j.sachs@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/18143Tested-by: default avatarjenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: default avatarRick Bell <richard.s.bell@intel.com>
parent 2b6c7c8d
......@@ -98,6 +98,7 @@ upnp_src = [
'upnp_plugin.cpp',
'UpnpConnector.cpp',
'UpnpDevice.cpp',
'UpnpDimmingService.cpp',
'UpnpException.cpp',
'UpnpManager.cpp',
'UpnpPowerSwitchService.cpp',
......
......@@ -35,8 +35,17 @@
#include "UpnpInternal.h"
#include "UpnpRequest.h"
#include <octypes.h>
#include <ocstack.h>
#include <oic_malloc.h>
#include <oic_string.h>
#include <mpmErrorCode.h>
#include <pluginServer.h>
#include <ConcurrentIotivityUtils.h>
using namespace std;
using namespace boost;
using namespace OC::Bridging;
static const string MODULE = "UpnpConnector";
......@@ -53,6 +62,9 @@ static map <gulong, GUPnPControlPoint *> s_signalMap;
static bool isRootDiscovery[] = {false, true};
const uint BINARY_SWITCH_CALLBACK = 0;
const uint BRIGHTNESS_CALLBACK = 1;
UpnpConnector::UpnpConnector(DiscoveryCallback discoveryCallback, LostCallback lostCallback)
{
DEBUG_PRINT("");
......@@ -502,3 +514,185 @@ void UpnpConnector::onScan()
s_manager->onScan();
}
}
/*******************************************
* callbacks for handling the pluginAdd
*******************************************/
bool isSecureEnvironmentSet()
{
char *non_secure_env = getenv("NONSECURE");
if (non_secure_env != NULL && (strcmp(non_secure_env, "true") == 0))
{
DEBUG_PRINT("Creating NON SECURE resources");
return false;
}
DEBUG_PRINT("Creating SECURE resources");
return true;
}
OCRepPayload* OCRepPayloadCreate()
{
OCRepPayload* payload = (OCRepPayload*)OICCalloc(1, sizeof(OCRepPayload));
if (!payload)
{
return NULL;
}
payload->base.type = PAYLOAD_TYPE_REPRESENTATION;
return payload;
}
OCRepPayload* getCommonPayload(const char *uri, char *interfaceQuery, string resourceType,
OCRepPayload *payload)
{
if (!OCRepPayloadSetUri(payload, uri))
{
throw "Failed to set uri in the payload";
}
if (!OCRepPayloadAddResourceType(payload, resourceType.c_str()))
{
throw "Failed to set resource type in the payload" ;
}
DEBUG_PRINT("Checking against if: " << interfaceQuery);
// If the interface filter is explicitly oic.if.baseline, include all properties.
if (interfaceQuery && string(interfaceQuery) == string(OC_RSRVD_INTERFACE_DEFAULT))
{
if (!OCRepPayloadAddInterface(payload, OC_RSRVD_INTERFACE_ACTUATOR))
{
throw "Failed to set actuator interface";
}
if (!OCRepPayloadAddInterface(payload, OC_RSRVD_INTERFACE_DEFAULT))
{
throw "Failed to set baseline interface" ;
}
}
return payload;
}
OCEntityHandlerResult handleEntityHandlerRequests( OCEntityHandlerRequest *entityHandlerRequest,
std::string resourceType)
{
OCEntityHandlerResult ehResult = OC_EH_ERROR;
OCRepPayload *responsePayload = NULL;
OCRepPayload *payload = OCRepPayloadCreate();
try
{
if ((entityHandlerRequest == NULL))
{
throw "Entity handler received a null entity request context" ;
}
std::string uri = OCGetResourceUri(entityHandlerRequest->resource);
DEBUG_PRINT("URI from resource " << uri);
bool notifyObservers = false;
char *interfaceQuery = NULL;
char *resourceTypeQuery = NULL;
char *dupQuery = OICStrdup(entityHandlerRequest->query);
if (dupQuery)
{
MPMExtractFiltersFromQuery(dupQuery, &interfaceQuery, &resourceTypeQuery);
}
for (const auto& service : s_manager->m_services) {
if (service.second->m_uri == uri) {
switch (entityHandlerRequest->method)
{
case OC_REST_GET:
DEBUG_PRINT(" GET Request for: " << uri);
ehResult = service.second->processGetRequest(payload);
break;
case OC_REST_PUT:
case OC_REST_POST:
DEBUG_PRINT("PUT / POST Request on " << uri);
ehResult = service.second->processPutRequest(entityHandlerRequest, uri, resourceType, payload);
notifyObservers = (ehResult == OC_EH_OK);
break;
default:
DEBUG_PRINT("UnSupported Method [" << entityHandlerRequest->method << "] Received");
ConcurrentIotivityUtils::respondToRequestWithError(entityHandlerRequest, " Unsupported Method", OC_EH_METHOD_NOT_ALLOWED);
return OC_EH_ERROR;
}
}
}
responsePayload = getCommonPayload(uri.c_str(), interfaceQuery, resourceType, payload);
ConcurrentIotivityUtils::respondToRequest(entityHandlerRequest, responsePayload, ehResult);
OICFree(dupQuery);
if (notifyObservers)
{
ConcurrentIotivityUtils::queueNotifyObservers(uri);
}
}
catch (const char *errorMessage)
{
DEBUG_PRINT("Error - " << errorMessage);
ConcurrentIotivityUtils::respondToRequestWithError(entityHandlerRequest, errorMessage, OC_EH_ERROR);
ehResult = OC_EH_ERROR;
}
OCRepPayloadDestroy(responsePayload);
return ehResult;
}
OCEntityHandlerResult resourceEntityHandler(OCEntityHandlerFlag,
OCEntityHandlerRequest *entityHandlerRequest,
void *callback)
{
DEBUG_PRINT("");
uintptr_t callbackParamResourceType = (uintptr_t)callback;
std::string resourceType;
if (callbackParamResourceType == BINARY_SWITCH_CALLBACK)
{
return handleEntityHandlerRequests(entityHandlerRequest, UPNP_OIC_TYPE_POWER_SWITCH);
}
else if (callbackParamResourceType == BRIGHTNESS_CALLBACK)
{
return handleEntityHandlerRequests(entityHandlerRequest, UPNP_OIC_TYPE_BRIGHTNESS);
}
return OC_EH_ERROR;
}
void UpnpConnector::onAdd(std::string uri)
{
DEBUG_PRINT("Adding " << uri);
uint8_t resourceProperties = (OC_OBSERVABLE | OC_DISCOVERABLE);
if (isSecureEnvironmentSet())
{
resourceProperties |= OC_SECURE;
}
for (const auto& service : s_manager->m_services) {
if (service.second->m_uri == uri) {
if (service.second->m_resourceType == UPNP_OIC_TYPE_POWER_SWITCH) {
DEBUG_PRINT("Adding binary switch resource");
ConcurrentIotivityUtils::queueCreateResource(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) {
DEBUG_PRINT("Adding brightness resource");
ConcurrentIotivityUtils::queueCreateResource(uri, UPNP_OIC_TYPE_BRIGHTNESS, OC_RSRVD_INTERFACE_ACTUATOR,
resourceEntityHandler,
(void *) BRIGHTNESS_CALLBACK, resourceProperties);
}
else
{
DEBUG_PRINT("No resource added for " << service.second->m_resourceType);
}
}
}
}
......@@ -35,8 +35,6 @@
#include "UpnpManager.h"
#include "UpnpResource.h"
using namespace OIC::Service;
class UpnpConnector
{
public:
......@@ -48,6 +46,7 @@ class UpnpConnector
void connect();
void disconnect();
void onScan();
void onAdd(std::string uri);
private:
DiscoveryCallback m_discoveryCallback;
......
//******************************************************************
//
// Copyright 2017 Intel Corporation All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "UpnpDimmingService.h"
static const string MODULE = "UpnpDimmingService";
// Service specific attribute initialization
// Brightness service
// TODO the following actions are not yet mapped: (note all unmapped actions are optional)
// SetOnEffectLevel
// SetOnEffect
// GetOnEffectParameters
// StepUp
// StepDown
// StartRampUp
// StartRampDown
// StopRamp
// StartRampToLevel
// SetStepDelta
// GetStepDelta
// SetRampRate
// GetRampRate
// PauseRamp
// ResumeRamp
// GetRampPaused
// GetRampTime
// GetIsRamping
// Organization:
// Attribute Name,
// State Variable Name (can be empty string), State variable type, "evented" flag
// Actions:
// 0: "GET" action name, action type, optional out parameters: var_name,var_type
// 1: "SET" action name, action type, optional in parameters: var_name,var_type
// Vector of embedded attributes (if present)
vector <UpnpAttributeInfo> UpnpDimming::Attributes =
{
{
"brightness",
"LoadLevelStatus", G_TYPE_UINT, true,
{ {"GetLoadLevelStatus", UPNP_ACTION_GET, "retLoadlevelStatus", G_TYPE_UINT},
{"SetLoadLevelTarget", UPNP_ACTION_POST, "newLoadlevelTarget", G_TYPE_UINT}
},
{}
}
};
static const char* brightnessLevelName = "brightness";
OCEntityHandlerResult UpnpDimming::processGetRequest(OCRepPayload *payload)
{
if (payload == NULL)
{
throw "payload is null";
}
//TODO use async version with callback
int64_t brightnessLevelValue = 0;
GError *error = NULL;
if (! gupnp_service_proxy_send_action(m_proxy, "GetLoadLevelStatus", &error,
// IN args (none)
NULL,
// OUT args
"retLoadlevelStatus", G_TYPE_UINT, &brightnessLevelValue,
NULL))
{
ERROR_PRINT("GetLoadLevelStatus action failed");
if (error)
{
DEBUG_PRINT("Error message: " << error->message);
g_error_free(error);
}
return OC_EH_ERROR;
}
if (!OCRepPayloadSetPropInt(payload, brightnessLevelName, brightnessLevelValue))
{
throw "Failed to set brightness value in payload";
}
DEBUG_PRINT(brightnessLevelName << ": " << brightnessLevelValue);
return OC_EH_OK;
}
OCEntityHandlerResult UpnpDimming::processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload)
{
if (!ehRequest || !ehRequest->payload ||
ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
{
throw "Incoming payload is NULL or not a representation";
}
OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
if (!input)
{
throw "PUT payload is null";
}
if (UPNP_OIC_TYPE_BRIGHTNESS == resourceType)
{
int64_t brightnessLevelValue = 0;
if (!OCRepPayloadGetPropInt(input, brightnessLevelName, &brightnessLevelValue))
{
throw "No brightness value in request payload";
}
DEBUG_PRINT("New " << brightnessLevelName << ": " << brightnessLevelValue);
//TODO use async version with callback
GError *error = NULL;
if (! gupnp_service_proxy_send_action(m_proxy, "SetLoadLevelTarget", &error,
// IN args
"newLoadlevelTarget", G_TYPE_UINT, brightnessLevelValue,
NULL,
// OUT args (none)
NULL))
{
ERROR_PRINT("SetLoadLevelTarget action failed");
if (error)
{
DEBUG_PRINT("Error message: " << error->message);
g_error_free(error);
}
return OC_EH_ERROR;
}
if (!OCRepPayloadSetPropInt(payload, brightnessLevelName, brightnessLevelValue))
{
throw "Failed to set brightness value in payload";
}
DEBUG_PRINT(brightnessLevelName << ": " << brightnessLevelValue);
}
else
{
throw "Failed due to unknown resource type";
}
return OC_EH_OK;
}
//******************************************************************
//
// Copyright 2017 Intel Corporation All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#ifndef UPNP_DIMMING_SERVICE_H_
#define UPNP_DIMMING_SERVICE_H_
#include <string>
#include <map>
#include <gupnp.h>
#include "UpnpResource.h"
#include "UpnpInternal.h"
#include "UpnpService.h"
using namespace std;
class UpnpDimming: public UpnpService
{
friend class UpnpService;
public:
UpnpDimming(GUPnPServiceInfo *serviceInfo,
UpnpRequestState *requestState):
UpnpService(serviceInfo, UPNP_OIC_TYPE_BRIGHTNESS, requestState, &Attributes)
{
}
OCEntityHandlerResult processGetRequest(OCRepPayload *payload);
OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload);
private:
static vector <UpnpAttributeInfo> Attributes;
};
#endif
......@@ -28,7 +28,7 @@
//#include "UpnpAVTransportService.h"
//#include "UpnpConnectionManagerService.h"
//#include "UpnpContentDirectoryService.h"
//#include "UpnpDimmingService.h"
#include "UpnpDimmingService.h"
//#include "UpnpLanHostConfigManagementService.h"
//#include "UpnpLayer3ForwardingService.h"
//#include "UpnpDeviceProtectionService.h"
......@@ -315,7 +315,6 @@ void UpnpManager::onScan()
{
for (const auto& service : m_services) {
MPMSendResponse(service.second->m_uri.c_str(), service.second->m_uri.size(), MPM_SCAN);
}
}
......@@ -407,10 +406,10 @@ std::shared_ptr<UpnpService> UpnpManager::generateService(GUPnPServiceInfo *ser
{
return (std::make_shared < UpnpPowerSwitch > (serviceInfo, requestState));
}
// else if (resourceType == UPNP_OIC_TYPE_BRIGHTNESS)
// {
// return (std::make_shared < UpnpDimming > (serviceInfo, requestState));
// }
else if (resourceType == UPNP_OIC_TYPE_BRIGHTNESS)
{
return (std::make_shared < UpnpDimming > (serviceInfo, requestState));
}
// else if (resourceType == UPNP_OIC_TYPE_CONTENT_DIRECTORY)
// {
// return (std::make_shared < UpnpContentDirectory > (serviceInfo, requestState));
......
......@@ -30,6 +30,7 @@ class UpnpManager
void removeDevice(string udn);
void stop();
void onScan();
UpnpResource::Ptr findResource(GUPnPServiceInfo *info);
......@@ -38,12 +39,14 @@ class UpnpManager
std::shared_ptr<UpnpDevice> findDevice(std::string udn);
std::shared_ptr<UpnpService> findService(std::string serviceKey);
// TODO make this private access it through accessors.
// Service map, keyed off service ID
std::map<std::string, std::shared_ptr<UpnpService> > m_services;
private:
// Device map, keyed off device UDN
std::map<std::string, std::shared_ptr<UpnpDevice> > m_devices;
// Service map, keyed off service ID
std::map<std::string, std::shared_ptr<UpnpService> > m_services;
std::shared_ptr<UpnpDevice> addDevice(GUPnPDeviceInfo *info,
const string parent,
......
......@@ -42,3 +42,96 @@ vector <UpnpAttributeInfo> UpnpPowerSwitch::Attributes =
{}
}
};
static const char* powerSwitchStateName = "value";
OCEntityHandlerResult UpnpPowerSwitch::processGetRequest(OCRepPayload *payload)
{
if (payload == NULL)
{
throw "payload is null";
}
//TODO use async version with callback
bool powerSwitchStateValue = false;
GError *error = NULL;
if (! gupnp_service_proxy_send_action(m_proxy, "GetTarget", &error,
// IN args (none)
NULL,
// OUT args
"RetTargetValue", G_TYPE_BOOLEAN, &powerSwitchStateValue,
NULL))
{
ERROR_PRINT("GetTarget action failed");
if (error)
{
DEBUG_PRINT("Error message: " << error->message);
g_error_free(error);
}
return OC_EH_ERROR;
}
if (!OCRepPayloadSetPropBool(payload, powerSwitchStateName, powerSwitchStateValue))
{
throw "Failed to set power switch value in payload";
}
DEBUG_PRINT(powerSwitchStateName << ": " << (powerSwitchStateValue ? "true" : "false"));
return OC_EH_OK;
}
OCEntityHandlerResult UpnpPowerSwitch::processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload)
{
if (!ehRequest || !ehRequest->payload ||
ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION)
{
throw "Incoming payload is NULL or not a representation";
}
OCRepPayload *input = reinterpret_cast<OCRepPayload *>(ehRequest->payload);
if (!input)
{
throw "PUT payload is null";
}
if (UPNP_OIC_TYPE_POWER_SWITCH == resourceType)
{
bool powerSwitchStateValue = false;
if (!OCRepPayloadGetPropBool(input, powerSwitchStateName, &powerSwitchStateValue))
{
throw "No power switch value in request payload";
}
DEBUG_PRINT("New " << powerSwitchStateName << ": " << (powerSwitchStateValue ? "true" : "false"));
//TODO use async version with callback
GError *error = NULL;
if (! gupnp_service_proxy_send_action(m_proxy, "SetTarget", &error,
// IN args
"newTargetValue", G_TYPE_BOOLEAN, powerSwitchStateValue,
NULL,
// OUT args (none)
NULL))
{
ERROR_PRINT("SetTarget action failed");
if (error)
{
DEBUG_PRINT("Error message: " << error->message);
g_error_free(error);
}
return OC_EH_ERROR;
}
if (!OCRepPayloadSetPropBool(payload, powerSwitchStateName, powerSwitchStateValue))
{
throw "Failed to set power switch value in payload";
}
DEBUG_PRINT(powerSwitchStateName << ": " << (powerSwitchStateValue ? "true" : "false"));
}
else
{
throw "Failed due to unknown resource type";
}
return OC_EH_OK;
}
......@@ -43,6 +43,10 @@ class UpnpPowerSwitch: public UpnpService
{
}
OCEntityHandlerResult processGetRequest(OCRepPayload *payload);
OCEntityHandlerResult processPutRequest(OCEntityHandlerRequest *ehRequest,
string uri, string resourceType, OCRepPayload *payload);
private:
static vector <UpnpAttributeInfo> Attributes;
};
......
......@@ -28,7 +28,6 @@
#include "UpnpService.h"
using namespace std;
using namespace OIC::Service;
static const string MODULE = "UpnpService";
......@@ -144,3 +143,18 @@ string UpnpService::getStringField(function< char *(GUPnPServiceInfo *serviceInf
}
return "";
}
OCEntityHandlerResult UpnpService::processGetRequest(OCRepPayload*)
{
ERROR_PRINT("Service processGetRequest() not implemented!");
throw NotImplementedException("Service processGetRequest() not implemented!");
return OC_EH_ERROR;