RemoveCallbackInfo(cbInfo->mapKey);
}
-void Callback::SetCallback(IPCAStatus status, const OCRepresentation& rep, CallbackInfo::Ptr cbInfo)
+void Callback::SetCallback(
+ IPCAStatus status,
+ const OCRepresentation& rep,
+ CallbackInfo::Ptr cbInfo,
+ std::string newResourcePath)
{
if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
{
cbInfo->createResourceCallback(
status,
const_cast<void*>(cbInfo->callbackContext),
- NULL, /* tbd: no info on new resource URI. */
- /* See https://jira.iotivity.org/browse/IOT-1819 */
+ newResourcePath.c_str(),
(IPCAPropertyBagHandle)&rep);
}
else
// resource->put() callback.
void SetCallback(IPCAStatus status,
const OC::OCRepresentation& rep,
- CallbackInfo::Ptr cbInfo);
+ CallbackInfo::Ptr cbInfo,
+ std::string newResourcePath);
// resource->observe() callback.
void ObserveCallback(IPCAStatus status,
const int eCode,
CallbackInfo::Ptr callbackInfo)
{
- OC_UNUSED(headerOptions);
+ std::string newResourcePath;
+ if (headerOptions.size())
+ {
+ // Pass LOCATION_PATH_OPTION_ID to the app.
+ for (auto header : headerOptions)
+ {
+ if (header.getOptionID() == HeaderOption::LOCATION_PATH_OPTION_ID)
+ {
+ newResourcePath = header.getOptionData();
+ break;
+ }
+ }
+ }
IPCAStatus status = MapOCStackResultToIPCAStatus((OCStackResult)eCode);
for (const auto& callback : callbackSnapshot)
{
- callback->SetCallback(status, rep, callbackInfo);
+ callback->SetCallback(status, rep, callbackInfo, newResourcePath);
}
}
IPCAPropertyBagDestroy(propertyBagHandle);
}
+void IPCAElevatorClient::CreateResourceLongRelativePath()
+{
+ IPCAPropertyBagHandle propertyBagHandle;
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+
+ CreateElevatorResource(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_LONG, propertyBagHandle);
+
+ IPCAPropertyBagDestroy(propertyBagHandle);
+}
+
void IPCAElevatorClient::DeleteResource()
{
DeleteElevatorResource();
void GetTargetFloor(int* targetFloor, bool* result);
void SetTargetFloor(int targetFloor, bool* result);
void CreateResourceRelativePath();
- const char* GetNewResourceURI() { return m_newResourcePath.c_str(); }
+ void CreateResourceLongRelativePath();
+ const char* GetNewResourcePath() { return m_newResourcePath.c_str(); }
void CreateResouceExplicitPath();
void DeleteResource();
#define ELEVATOR_CO_PRIVATE_INTERFACE "my.private.if"\r
\r
#define ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH "/ipca/new/resource/relative"\r
+#define ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_LONG "/ipca/new/resource/relative/long"\r
#define ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_TYPE "x.ipca.test.elevator.create.resource.relative"\r
#define ELEVATOR_RESOURCE_NEW_RESOURCE_PATH "/ipca/new/resource/relative/1"\r
\r
CreateResourceRelativePath();
afterCreateCount = g_testElevator1.GetRelativePathResourceCreateCount();
ASSERT_EQ(beforeCreateCount + 1, afterCreateCount);
- // @todo: when IOT-1819 is resolved.
- // EXPECT_STREQ(ELEVATOR_RESOURCE_NEW_RESOURCE_PATH, GetNewResourceURI());
+ EXPECT_STREQ(ELEVATOR_RESOURCE_NEW_RESOURCE_PATH, GetNewResourcePath());
}
+ // Create new resource that results in resource with long resource path.
+ beforeCreateCount = g_testElevator1.GetRelativePathResourceCreateCount();
+ CreateResourceLongRelativePath();
+ afterCreateCount = g_testElevator1.GetRelativePathResourceCreateCount();
+ ASSERT_EQ(beforeCreateCount, afterCreateCount); // resource should not be created.
+
// Delete resource
size_t beforeDeleteCount, afterDeleteCount;
for (int i = 0 ; i < 3 ; i++)
{\r
ocResult = OC_STACK_OK;\r
}\r
+\r
+ // Add path of new resource in the header option.\r
+ std::string newResourcePath = pResponse->getNewResourceUri();\r
+ if (!newResourcePath.empty())\r
+ {\r
+ // MAX_URI_LENGTH is the URI limit of OCEntityHandlerResponse.resourceUri in\r
+ // inProcServerWrapper.cpp.\r
+ if (newResourcePath.length() > MAX_URI_LENGTH)\r
+ {\r
+ return OC_STACK_ERROR;\r
+ }\r
+\r
+ HeaderOption::OCHeaderOption headerOption(\r
+ HeaderOption::LOCATION_PATH_OPTION_ID,\r
+ newResourcePath);\r
+ serverHeaderOptions.push_back(headerOption);\r
+ }\r
+\r
std::thread postCallbackThread(pendingRequest->postCallback,\r
serverHeaderOptions,\r
ocRep,\r
#include "OCApi.h"
#include "testelevatorserver.h"
#include "ipcatestdata.h"
+#include "OCException.h"
using namespace OC;
using namespace std::placeholders;
ehResult = OC_EH_OK;
}
+ else
if (resourceUri.compare(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH) == 0)
{
m_relativePathResourceCreateCount++;
OCPlatform::sendResponse(pResponse);
ehResult = OC_EH_OK;
}
+ else
+ if (resourceUri.compare(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_LONG) == 0)
+ {
+ // long resource path.
+ char newResourcePath[2048];
+ memset(newResourcePath, 'x', 2047);
+ newResourcePath[2047] = '\0';
+
+ m_relativePathResourceCreateCount++;
+
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setNewResourceUri(newResourcePath);
+ pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
+
+ try
+ {
+ // Send the response.
+ if (OCPlatform::sendResponse(pResponse) != OC_STACK_OK)
+ {
+ m_relativePathResourceCreateCount--;
+ ehResult = OC_EH_INTERNAL_SERVER_ERROR;
+ }
+ else
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ catch(OCException& e)
+ {
+ // The stack returns OC_STACK_INVALID_URI when the new resource path
+ // exceeds MAX_URI_LENGTH.
+ if (e.code() == OC_STACK_INVALID_URI)
+ {
+ // The resource is not created.
+ m_relativePathResourceCreateCount--;
+ ehResult = OC_EH_INTERNAL_SERVER_ERROR;
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ }
}
else if (requestType == OC::PlatformCommands::PUT)
return false;
}
+ std::string createRelativeResourcePathLong(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_LONG);
+ result = OCPlatform::registerResource(
+ m_elevatorCreateRelativeResourceLong,
+ createRelativeResourcePathLong,
+ createRelativeResourceType,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
std::string deleteResourcePath(ELEVATOR_RESOURCE_DELETE_PATH);
std::string deleteResourceType(ELEVATOR_RESOURCE_DELETE_TYPE);
result = OCPlatform::registerResource(
OCPlatform::unregisterResource(m_elevatorCreateRelativeResource);
m_elevatorCreateRelativeResource = nullptr;
+ OCPlatform::unregisterResource(m_elevatorCreateRelativeResourceLong);
+ m_elevatorCreateRelativeResourceLong = nullptr;
+
OCPlatform::unregisterResource(m_elevatorDeleteResource);
m_elevatorDeleteResource = nullptr;
-/* *****************************************************************
- *
- * Copyright 2017 Microsoft
- *
- *
- * 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 _ELEVATOR_SERVER_H
-#define _ELEVATOR_SERVER_H
-
-#include <string>
-#include "OCPlatform.h"
-#include "OCApi.h"
-
-using namespace OC;
-
-typedef enum
-{
- Stopped = 0,
- Up,
- Down
-} ElevatorDirection;
-
-class ElevatorServer
-{
-public:
- ElevatorServer();
- ~ElevatorServer();
-
- // Start stop the thread processing the elevator movement. Also register/unregister the
- // elevator from IoTivity.
- bool Start(std::string& elevatorName);
- void Stop();
-
- // Target floor is set by caller.
- void SetTargetFloor(int floor);
- int GetTargetFloor();
-
- // Current floor is set by elevator.
- int GetCurrentFloor();
- ElevatorDirection GetElevatorDirection();
-
- size_t GetRelativePathResourceCreateCount() { return m_relativePathResourceCreateCount; }
- size_t GetExplicitPathResourceCreateCount() { return m_explicitPathResourceCreateCount; }
- size_t GetDeleteResourceCount() { return m_deleteResourceCount; }
- size_t GetIncorrectInterfaceCount() { return m_IncorrectInterfaceCount; }
-
-private:
- // List of observers, when client app calls resource->Observer().
- ObservationIds m_observers;
-
- // Send notification to observers when property values change.
- void NotifyObservers(std::string propertyName, int value);
-
- // Elevator has one resource.
- OCResourceHandle m_elevatorResourceHandle; // The elevator resource.
- OCResourceHandle m_elevatorCOResourceHandle; // CO resource.
- OCResourceHandle m_elevatorMaintenanceHandle;
- OCResourceHandle m_elevatorCreateRelativeResource; // Resource that handles pretent create.
- OCResourceHandle m_elevatorDeleteResource; // Resource that handles pretend delete.
-
- int m_targetFloor; // where elevator needs to be.
- int m_currentFloor; // where elevator is.
- ElevatorDirection m_direction; // current direction of the elevator.
-
- // Thread moving the elevator.
- std::thread m_engineThread;
- bool m_isRunning;
- static void Engine(ElevatorServer* elevator);
-
- // Move current floor to target floor.
- void MoveElevator();
-
- // Helper function to send response for a request.
- OCStackResult SendResponse(std::shared_ptr<OCResourceRequest> request,
- OCEntityHandlerResult result = OC_EH_OK);
- OCStackResult SendMaintenanceResponse(std::shared_ptr<OCResourceRequest> request);
-
- // OCF callback for this elevator.
- OCEntityHandlerResult ElevatorEntityHandler(std::shared_ptr<OCResourceRequest> request);
-
- // Elevator device details.
- std::string m_name;
-
- // Elevator platform details.
- std::string m_platformID;
- std::string m_modelNumber;
- std::string m_platformVersion;
- std::string m_serialNumber;
- std::string m_specVersion;
- std::string m_defaultLanguage;
- std::string m_manufacturerName;
- std::string m_manufacturerUrl;
- std::string m_dateOfManufacture;
- std::string m_operatingSystemVersion;
- std::string m_hardwareVersion;
- std::string m_firmwareVersion;
- std::string m_supportUrl;
- std::string m_systemTime;
-
- // Elevator new resource request count.
- size_t m_relativePathResourceCreateCount;
- size_t m_explicitPathResourceCreateCount;
-
- // Elevator delete resource count.
- size_t m_deleteResourceCount;
-
- // Number of times entity handler is called with incorrect resource interface.
- size_t m_IncorrectInterfaceCount;
-};
-
-#endif // _ELEVATOR_SERVER_H
+/* *****************************************************************\r
+ *\r
+ * Copyright 2017 Microsoft\r
+ *\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ ******************************************************************/\r
+\r
+#ifndef _ELEVATOR_SERVER_H\r
+#define _ELEVATOR_SERVER_H\r
+\r
+#include <string>\r
+#include "OCPlatform.h"\r
+#include "OCApi.h"\r
+\r
+using namespace OC;\r
+\r
+typedef enum\r
+{\r
+ Stopped = 0,\r
+ Up,\r
+ Down\r
+} ElevatorDirection;\r
+\r
+class ElevatorServer\r
+{\r
+public:\r
+ ElevatorServer();\r
+ ~ElevatorServer();\r
+\r
+ // Start stop the thread processing the elevator movement. Also register/unregister the\r
+ // elevator from IoTivity.\r
+ bool Start(std::string& elevatorName);\r
+ void Stop();\r
+\r
+ // Target floor is set by caller.\r
+ void SetTargetFloor(int floor);\r
+ int GetTargetFloor();\r
+\r
+ // Current floor is set by elevator.\r
+ int GetCurrentFloor();\r
+ ElevatorDirection GetElevatorDirection();\r
+\r
+ size_t GetRelativePathResourceCreateCount() { return m_relativePathResourceCreateCount; }\r
+ size_t GetExplicitPathResourceCreateCount() { return m_explicitPathResourceCreateCount; }\r
+ size_t GetDeleteResourceCount() { return m_deleteResourceCount; }\r
+ size_t GetIncorrectInterfaceCount() { return m_IncorrectInterfaceCount; }\r
+\r
+private:\r
+ // List of observers, when client app calls resource->Observer().\r
+ ObservationIds m_observers;\r
+\r
+ // Send notification to observers when property values change.\r
+ void NotifyObservers(std::string propertyName, int value);\r
+\r
+ // Elevator has one resource.\r
+ OCResourceHandle m_elevatorResourceHandle; // The elevator resource.\r
+ OCResourceHandle m_elevatorCOResourceHandle; // CO resource.\r
+ OCResourceHandle m_elevatorMaintenanceHandle;\r
+ OCResourceHandle m_elevatorCreateRelativeResource; // Resource that handles pretend create.\r
+ OCResourceHandle m_elevatorCreateRelativeResourceLong; // Resource that handles pretend create.\r
+ OCResourceHandle m_elevatorDeleteResource; // Resource that handles pretend delete.\r
+\r
+ int m_targetFloor; // where elevator needs to be.\r
+ int m_currentFloor; // where elevator is.\r
+ ElevatorDirection m_direction; // current direction of the elevator.\r
+\r
+ // Thread moving the elevator.\r
+ std::thread m_engineThread;\r
+ bool m_isRunning;\r
+ static void Engine(ElevatorServer* elevator);\r
+\r
+ // Move current floor to target floor.\r
+ void MoveElevator();\r
+\r
+ // Helper function to send response for a request.\r
+ OCStackResult SendResponse(std::shared_ptr<OCResourceRequest> request,\r
+ OCEntityHandlerResult result = OC_EH_OK);\r
+ OCStackResult SendMaintenanceResponse(std::shared_ptr<OCResourceRequest> request);\r
+\r
+ // OCF callback for this elevator.\r
+ OCEntityHandlerResult ElevatorEntityHandler(std::shared_ptr<OCResourceRequest> request);\r
+\r
+ // Elevator device details.\r
+ std::string m_name;\r
+\r
+ // Elevator platform details.\r
+ std::string m_platformID;\r
+ std::string m_modelNumber;\r
+ std::string m_platformVersion;\r
+ std::string m_serialNumber;\r
+ std::string m_specVersion;\r
+ std::string m_defaultLanguage;\r
+ std::string m_manufacturerName;\r
+ std::string m_manufacturerUrl;\r
+ std::string m_dateOfManufacture;\r
+ std::string m_operatingSystemVersion;\r
+ std::string m_hardwareVersion;\r
+ std::string m_firmwareVersion;\r
+ std::string m_supportUrl;\r
+ std::string m_systemTime;\r
+\r
+ // Elevator new resource request count.\r
+ size_t m_relativePathResourceCreateCount;\r
+ size_t m_explicitPathResourceCreateCount;\r
+\r
+ // Elevator delete resource count.\r
+ size_t m_deleteResourceCount;\r
+\r
+ // Number of times entity handler is called with incorrect resource interface.\r
+ size_t m_IncorrectInterfaceCount;\r
+};\r
+\r
+#endif // _ELEVATOR_SERVER_H\r
#define CA_OPTION_URI_QUERY 15
#define CA_OPTION_ACCEPT 17
#define CA_OPTION_LOCATION_QUERY 20
-
+
/**
* @def UUID_PREFIX
* @brief uuid prefix in certificate subject field
} CAPayloadFormat_t;
/**
+ * Option ID of header option. The values match CoAP option types in pdu.h.
+ */
+typedef enum
+{
+ CA_HEADER_OPTION_ID_LOCATION_PATH = 8,
+ CA_HEADER_OPTION_ID_LOCATION_QUERY = 20
+} CAHeaderOptionId_t;
+
+/**
* Header options structure to be filled.
*
* This structure is used to hold header information.
/** An array of the vendor specific header options the entity handler wishes to use in response.*/
OCHeaderOption sendVendorSpecificHeaderOptions[MAX_HEADER_OPTIONS];
- /** URI of new resource that entity handler might create.*/
+ /** Resource path of new resource that entity handler might create.*/
char resourceUri[MAX_URI_LENGTH];
/** Server sets to true for persistent response buffer,false for non-persistent response buffer*/
responseInfo.info.numOptions = ehResponse->numSendVendorSpecificHeaderOptions;
}
+ // Path of new resource is returned in options as location-path.
+ if (ehResponse->resourceUri[0] != '\0')
+ {
+ responseInfo.info.numOptions++;
+ }
+
if(responseInfo.info.numOptions > 0)
{
responseInfo.info.options = (CAHeaderOption_t *)
memcpy(optionsPointer, ehResponse->sendVendorSpecificHeaderOptions,
sizeof(OCHeaderOption) *
ehResponse->numSendVendorSpecificHeaderOptions);
+
+ // Advance the optionPointer by the number of vendor options.
+ optionsPointer += ehResponse->numSendVendorSpecificHeaderOptions;
+ }
+
+ // Return new resource as location-path option.
+ // https://tools.ietf.org/html/rfc7252#section-5.8.2.
+ if (ehResponse->resourceUri[0] != '\0')
+ {
+ if ((strlen(ehResponse->resourceUri) + 1) > CA_MAX_HEADER_OPTION_DATA_LENGTH)
+ {
+ OIC_LOG(ERROR, TAG,
+ "New resource path must be less than CA_MAX_HEADER_OPTION_DATA_LENGTH");
+ OICFree(responseInfo.info.options);
+ return OC_STACK_INVALID_URI;
+ }
+
+ optionsPointer->protocolID = CA_COAP_ID;
+ optionsPointer->optionID = CA_HEADER_OPTION_ID_LOCATION_PATH;
+ OICStrcpy(
+ optionsPointer->optionData,
+ sizeof(optionsPointer->optionData),
+ ehResponse->resourceUri);
+ optionsPointer->optionLength = (uint16_t)strlen(optionsPointer->optionData) + 1;
}
}
else
else
{
OCEntityHandlerResponse response;
+ memset(&response, 0, sizeof(response));
+
// OCRepPayload* payLoad = pResponse->getPayload();
HeaderOptions serverHeaderOptions = pResponse->getHeaderOptions();
if(OC_EH_RESOURCE_CREATED == response.ehResult)
{
- pResponse->getNewResourceUri().copy(response.resourceUri,
- sizeof (response.resourceUri) - 1);
- response.resourceUri[pResponse->getNewResourceUri().length()] = '\0';
+ // Do not truncate if new resource uri is too long, return failure.
+ if (pResponse->getNewResourceUri().length() > (sizeof(response.resourceUri) - 1))
+ {
+ return OC_STACK_INVALID_URI;
+ }
+ else
+ {
+ pResponse->getNewResourceUri().copy(response.resourceUri,
+ sizeof(response.resourceUri) - 1);
+ response.resourceUri[pResponse->getNewResourceUri().length()] = '\0';
+ }
}
if(cLock)