X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fstack%2Fsrc%2Focstack.c;h=569fd52dcb00f6b03896f23f4886c6323bd45cf6;hb=9722e3eaaf34b990f3305aa706517d62ad1bfda8;hp=3224acea8a7cc628c4f8eb98d674ff72e48bfb9b;hpb=ebd4a420a0836c2968e076c264efb9c9e3953d85;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c old mode 100755 new mode 100644 index 3224ace..8f77cf7 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -30,8 +30,13 @@ // For POSIX.1-2001 base specification, // Refer http://pubs.opengroup.org/onlinepubs/009695399/ #define _POSIX_C_SOURCE 200112L +#ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS +#endif +#ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS +#endif +#include "iotivity_config.h" #include #include #include @@ -45,13 +50,18 @@ #include "oic_malloc.h" #include "oic_string.h" #include "logger.h" +#include "trace.h" #include "ocserverrequest.h" #include "secureresourcemanager.h" +#include "psinterface.h" +#include "psiutils.h" #include "doxmresource.h" #include "cacommon.h" #include "cainterface.h" #include "ocpayload.h" #include "ocpayloadcbor.h" +#include "cautilinterface.h" +#include "oicgroup.h" #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) #include "routingutility.h" @@ -60,16 +70,23 @@ #endif #endif -#ifdef WITH_ARDUINO +#ifdef TCP_ADAPTER +#include "oickeepaliveinternal.h" +#endif + +//#ifdef DIRECT_PAIRING +#include "directpairing.h" +//#endif + +#ifdef HAVE_ARDUINO_TIME_H #include "Time.h" -#else +#endif +#ifdef HAVE_SYS_TIME_H #include #endif -#include "coap_time.h" -#include "utlist.h" -#include "pdu.h" +#include -#ifndef ARDUINO +#ifdef HAVE_ARPA_INET_H #include #endif @@ -95,6 +112,14 @@ typedef enum } OCPresenceState; #endif +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) +typedef struct +{ + OCOtmEventHandler cb; + void *ctx; +} OCOtmEventHandler_t; +#endif + //----------------------------------------------------------------------------- // Private variables //----------------------------------------------------------------------------- @@ -102,9 +127,15 @@ static OCStackState stackState = OC_STACK_UNINITIALIZED; OCResource *headResource = NULL; static OCResource *tailResource = NULL; +static OCResourceHandle platformResource = {0}; +static OCResourceHandle deviceResource = {0}; +#ifdef MQ_BROKER +static OCResourceHandle brokerResource = {0}; +#endif + #ifdef WITH_PRESENCE static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED; -static PresenceResource presenceResource; +static PresenceResource presenceResource = {0}; static uint8_t PresenceTimeOutSize = 0; static uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100}; #endif @@ -116,20 +147,25 @@ static bool gRASetInfo = false; #endif OCDeviceEntityHandler defaultDeviceHandler; void* defaultDeviceHandlerCallbackParameter = NULL; -static const char COAP_TCP[] = "coap+tcp:"; +static const char COAP_TCP_SCHEME[] = "coap+tcp:"; +static const char COAPS_TCP_SCHEME[] = "coaps+tcp:"; +static const char CORESPEC[] = "core"; +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) +static OCOtmEventHandler_t g_otmEventHandler = {NULL, NULL}; +#endif //----------------------------------------------------------------------------- // Macros //----------------------------------------------------------------------------- -#define TAG "OCStack" +#define TAG "OIC_RI_STACK" #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \ - {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} } -#define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \ + {OIC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} } +#define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OIC_LOG((logLevel), \ TAG, #arg " is NULL"); return (retVal); } } -#define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OC_LOG((logLevel), \ +#define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OIC_LOG((logLevel), \ TAG, #arg " is NULL"); return; } } -#define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\ +#define VERIFY_NON_NULL_V(arg) { if (!arg) {OIC_LOG(FATAL, TAG, #arg " is NULL");\ goto exit;} } //TODO: we should allow the server to define this @@ -233,6 +269,13 @@ static void deleteResourceType(OCResourceType *resourceType); static void deleteResourceInterface(OCResourceInterface *resourceInterface); /** + * Unbind all child resources. + * + * @param resourceChild Specified binded resource head is deleted from parent. + */ +static void unbindChildResources(OCChildResource *resourceChild); + +/** * Delete all of the dynamically allocated elements that were created for the resource. * * @param resource Specified resource. @@ -261,34 +304,15 @@ static void deleteAllResources(); */ static void incrementSequenceNumber(OCResource * resPtr); -/** - * Verify the lengths of the URI and the query separately. - * - * @param inputUri Input URI and query. - * @param uriLen The length of the initial URI with query. - * @return ::OC_STACK_OK on success, some other value upon failure. - */ -static OCStackResult verifyUriQueryLength(const char * inputUri, - uint16_t uriLen); - /* * Attempts to initialize every network interface that the CA Layer might have compiled in. * * Note: At least one interface must succeed to initialize. If all calls to @ref CASelectNetwork * return something other than @ref CA_STATUS_OK, then this function fails. - * + * @param transportType OCTransportAdapter value to select. * @return ::CA_STATUS_OK on success, some other value upon failure. */ -static CAResult_t OCSelectNetwork(); - -/** - * Get the CoAP ticks after the specified number of milli-seconds. - * - * @param afterMilliSeconds Milli-seconds. - * @return - * CoAP ticks - */ -static uint32_t GetTicks(uint32_t afterMilliSeconds); +static CAResult_t OCSelectNetwork(OCTransportAdapter transportType); /** * Convert CAResponseResult_t to OCStackResult. @@ -296,16 +320,7 @@ static uint32_t GetTicks(uint32_t afterMilliSeconds); * @param caCode CAResponseResult_t code. * @return ::OC_STACK_OK on success, some other value upon failure. */ -static OCStackResult CAToOCStackResult(CAResponseResult_t caCode); - -/** - * Convert OCStackResult to CAResponseResult_t. - * - * @param caCode OCStackResult code. - * @param method OCMethod method the return code replies to. - * @return ::CA_CONTENT on OK, some other value upon failure. - */ -static CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method); +static OCStackResult CAResponseToOCStackResult(CAResponseResult_t caCode); /** * Convert OCTransportFlags_t to CATransportModifiers_t. @@ -373,6 +388,7 @@ static OCStackResult getQueryFromUri(const char * uri, char** resourceType, char static OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName); +#ifdef WITH_PRESENCE /** * Reset presence TTL for a ClientCB struct. ttlLevel will be set to 0. * TTL will be set to maxAge. @@ -383,6 +399,7 @@ static OCResourceType *findResourceType(OCResourceType * resourceTypeList, * @return ::OC_STACK_OK on success, some other value upon failure. */ static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds); +#endif /** * Ensure the accept header option is set appropriatly before sending the requests and routing @@ -395,20 +412,55 @@ static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds); */ static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *requestInfo); +/** + * default adapter state change callback method + * + * @param adapter CA network adapter type. + * @param enabled current adapter state. + */ +static void OCDefaultAdapterStateChangedHandler(CATransportAdapter_t adapter, bool enabled); + +/** + * default connection state change callback method + * + * @param info CAEndpoint which has address, port and etc. + * @param isConnected current connection state. + */ +static void OCDefaultConnectionStateChangedHandler(const CAEndpoint_t *info, bool isConnected); + //----------------------------------------------------------------------------- // Internal functions //----------------------------------------------------------------------------- -uint32_t GetTicks(uint32_t afterMilliSeconds) +bool checkProxyUri(OCHeaderOption *options, uint8_t numOptions) +{ + if (!options || 0 == numOptions) + { + OIC_LOG (INFO, TAG, "No options present"); + return false; + } + + for (uint8_t i = 0; i < numOptions; i++) + { + if (options[i].protocolID == OC_COAP_ID && options[i].optionID == OC_RSRVD_PROXY_OPTION_ID) + { + OIC_LOG(DEBUG, TAG, "Proxy URI is present"); + return true; + } + } + return false; +} + +uint32_t GetTicks(uint32_t milliSeconds) { coap_tick_t now; coap_ticks(&now); // Guard against overflow of uint32_t - if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) / + if (milliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) / COAP_TICKS_PER_SECOND) { - return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND; + return now + (milliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND; } else { @@ -425,9 +477,13 @@ void CopyEndpointToDevAddr(const CAEndpoint_t *in, OCDevAddr *out) out->flags = CAToOCTransportFlags(in->flags); OICStrcpy(out->addr, sizeof(out->addr), in->addr); out->port = in->port; - out->interface = in->interface; + out->ifindex = in->ifindex; #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) - memcpy(out->routeData, in->routeData, sizeof(out->routeData)); + /* This assert is to prevent accidental mismatch between address size macros defined in + * RI and CA and cause crash here. */ + OC_STATIC_ASSERT(MAX_ADDR_STR_SIZE_CA == MAX_ADDR_STR_SIZE, + "Address size mismatch between RI and CA"); + memcpy(out->routeData, in->routeData, sizeof(in->routeData)); #endif } @@ -439,11 +495,16 @@ void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out) out->adapter = (CATransportAdapter_t)in->adapter; out->flags = OCToCATransportFlags(in->flags); OICStrcpy(out->addr, sizeof(out->addr), in->addr); + OICStrcpy(out->remoteId, sizeof(out->remoteId), in->remoteId); #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) - memcpy(out->routeData, in->routeData, sizeof(out->routeData)); + /* This assert is to prevent accidental mismatch between address size macros defined in + * RI and CA and cause crash here. */ + OC_STATIC_ASSERT(MAX_ADDR_STR_SIZE_CA == MAX_ADDR_STR_SIZE, + "Address size mismatch between RI and CA"); + memcpy(out->routeData, in->routeData, sizeof(in->routeData)); #endif out->port = in->port; - out->interface = in->interface; + out->ifindex = in->ifindex; } void FixUpClientResponse(OCClientResponse *cr) @@ -459,13 +520,14 @@ static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t * { VERIFY_NON_NULL(object, FATAL, OC_STACK_INVALID_PARAM); VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM); + OIC_TRACE_BEGIN(%s:OCSendRequest, TAG); #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) - OCStackResult rmResult = RMAddInfo(object->routeData, &(requestInfo->info.options), - &(requestInfo->info.numOptions)); + OCStackResult rmResult = RMAddInfo(object->routeData, requestInfo, true, NULL); if (OC_STACK_OK != rmResult) { - OC_LOG(ERROR, TAG, "Add destination option failed"); + OIC_LOG(ERROR, TAG, "Add destination option failed"); + OIC_TRACE_END(); return rmResult; } #endif @@ -475,9 +537,12 @@ static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t * CAResult_t result = CASendRequest(object, requestInfo); if(CA_STATUS_OK != result) { - OC_LOG_V(ERROR, TAG, "CASendRequest failed with CA error %u", result); + OIC_LOG_V(ERROR, TAG, "CASendRequest failed with CA error %u", result); + OIC_TRACE_END(); return CAResultToOCResult(result); } + + OIC_TRACE_END(); return OC_STACK_OK; } //----------------------------------------------------------------------------- @@ -495,47 +560,56 @@ OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t stat switch(status) { case OC_OBSERVER_NOT_INTERESTED: - OC_LOG(DEBUG, TAG, "observer not interested in our notifications"); - observer = GetObserverUsingToken (token, tokenLength); - if(observer) + OIC_LOG(DEBUG, TAG, "observer not interested in our notifications"); + observer = GetObserverUsingToken(token, tokenLength); + if (observer) { result = FormOCEntityHandlerRequest(&ehRequest, - (OCRequestHandle)NULL, + 0, OC_REST_NOMETHOD, &observer->devAddr, (OCResourceHandle)NULL, NULL, PAYLOAD_TYPE_REPRESENTATION, NULL, 0, 0, NULL, OC_OBSERVE_DEREGISTER, - observer->observeId); - if(result != OC_STACK_OK) + observer->observeId, + 0); + if (result != OC_STACK_OK) { + FreeObserver(observer); return result; } - observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest, - observer->resource->entityHandlerCallbackParam); + + if (observer->resource && observer->resource->entityHandler) + { + observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest, + observer->resource->entityHandlerCallbackParam); + } + + FreeObserver(observer); } - result = DeleteObserverUsingToken (token, tokenLength); - if(result == OC_STACK_OK) + result = DeleteObserverUsingToken(token, tokenLength); + if (result == OC_STACK_OK) { - OC_LOG(DEBUG, TAG, "Removed observer successfully"); + OIC_LOG(DEBUG, TAG, "Removed observer successfully"); } else { result = OC_STACK_OK; - OC_LOG(DEBUG, TAG, "Observer Removal failed"); + OIC_LOG(DEBUG, TAG, "Observer Removal failed"); } break; case OC_OBSERVER_STILL_INTERESTED: - OC_LOG(DEBUG, TAG, "observer still interested, reset the failedCount"); - observer = GetObserverUsingToken (token, tokenLength); - if(observer) + OIC_LOG(DEBUG, TAG, "observer still interested, reset the failedCount"); + observer = GetObserverUsingToken(token, tokenLength); + if (observer) { observer->forceHighQos = 0; observer->failedCommCount = 0; result = OC_STACK_OK; + FreeObserver(observer); } else { @@ -544,59 +618,68 @@ OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t stat break; case OC_OBSERVER_FAILED_COMM: - OC_LOG(DEBUG, TAG, "observer is unreachable"); + OIC_LOG(DEBUG, TAG, "observer is unreachable"); observer = GetObserverUsingToken (token, tokenLength); - if(observer) + if (observer) { - if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM) + if (observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM) { result = FormOCEntityHandlerRequest(&ehRequest, - (OCRequestHandle)NULL, + 0, OC_REST_NOMETHOD, &observer->devAddr, (OCResourceHandle)NULL, NULL, PAYLOAD_TYPE_REPRESENTATION, NULL, 0, 0, NULL, OC_OBSERVE_DEREGISTER, - observer->observeId); - if(result != OC_STACK_OK) + observer->observeId, + 0); + if (result != OC_STACK_OK) { + FreeObserver(observer); return OC_STACK_ERROR; } - observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest, - observer->resource->entityHandlerCallbackParam); - result = DeleteObserverUsingToken (token, tokenLength); - if(result == OC_STACK_OK) + if (observer->resource && observer->resource->entityHandler) + { + observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest, + observer->resource->entityHandlerCallbackParam); + } + + result = DeleteObserverUsingToken(token, tokenLength); + if (result == OC_STACK_OK) { - OC_LOG(DEBUG, TAG, "Removed observer successfully"); + OIC_LOG(DEBUG, TAG, "Removed observer successfully"); } else { result = OC_STACK_OK; - OC_LOG(DEBUG, TAG, "Observer Removal failed"); + OIC_LOG(DEBUG, TAG, "Observer Removal failed"); } } else { observer->failedCommCount++; + observer->forceHighQos = 1; + OIC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d", + observer->failedCommCount); result = OC_STACK_CONTINUE; } - observer->forceHighQos = 1; - OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount); + + FreeObserver(observer); } break; default: - OC_LOG(ERROR, TAG, "Unknown status"); + OIC_LOG(ERROR, TAG, "Unknown status"); result = OC_STACK_ERROR; break; } return result; } -OCStackResult CAToOCStackResult(CAResponseResult_t caCode) + +OCStackResult CAResponseToOCStackResult(CAResponseResult_t caCode) { OCStackResult ret = OC_STACK_ERROR; - switch(caCode) { case CA_CREATED: @@ -606,7 +689,10 @@ OCStackResult CAToOCStackResult(CAResponseResult_t caCode) ret = OC_STACK_RESOURCE_DELETED; break; case CA_CHANGED: + ret = OC_STACK_RESOURCE_CHANGED; + break; case CA_CONTENT: + case CA_VALID: ret = OC_STACK_OK; break; case CA_BAD_REQ: @@ -621,8 +707,38 @@ OCStackResult CAToOCStackResult(CAResponseResult_t caCode) case CA_NOT_FOUND: ret = OC_STACK_NO_RESOURCE; break; + case CA_REQUEST_ENTITY_TOO_LARGE: + ret = OC_STACK_TOO_LARGE_REQ; + break; + case CA_METHOD_NOT_ALLOWED: + ret = OC_STACK_METHOD_NOT_ALLOWED; + break; + case CA_NOT_ACCEPTABLE: + ret = OC_STACK_NOT_ACCEPTABLE; + break; + case CA_FORBIDDEN_REQ: + ret = OC_STACK_FORBIDDEN_REQ; + break; + case CA_TOO_MANY_REQUESTS: + ret = OC_STACK_TOO_MANY_REQUESTS; + break; + case CA_INTERNAL_SERVER_ERROR: + ret = OC_STACK_INTERNAL_SERVER_ERROR; + break; + case CA_NOT_IMPLEMENTED: + ret = OC_STACK_NOT_IMPLEMENTED; + break; + case CA_BAD_GATEWAY: + ret = OC_STACK_BAD_GATEWAY; + break; + case CA_SERVICE_UNAVAILABLE: + ret = OC_STACK_SERVICE_UNAVAILABLE; + break; case CA_RETRANSMIT_TIMEOUT: - ret = OC_STACK_COMM_ERROR; + ret = OC_STACK_GATEWAY_TIMEOUT; + break; + case CA_PROXY_NOT_SUPPORTED: + ret = OC_STACK_PROXY_NOT_SUPPORTED; break; default: break; @@ -654,7 +770,8 @@ CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method) // This should not happen but, // give it a value just in case but output an error ret = CA_CONTENT; - OC_LOG_V(ERROR, TAG, "Unexpected OC_STACK_OK return code for method [%d].", method); + OIC_LOG_V(ERROR, TAG, "Unexpected OC_STACK_OK return code for method [%d].", + method); } break; case OC_STACK_RESOURCE_CREATED: @@ -663,6 +780,9 @@ CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method) case OC_STACK_RESOURCE_DELETED: ret = CA_DELETED; break; + case OC_STACK_RESOURCE_CHANGED: + ret = CA_CHANGED; + break; case OC_STACK_INVALID_QUERY: ret = CA_BAD_REQ; break; @@ -675,9 +795,39 @@ CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method) case OC_STACK_COMM_ERROR: ret = CA_RETRANSMIT_TIMEOUT; break; + case OC_STACK_METHOD_NOT_ALLOWED: + ret = CA_METHOD_NOT_ALLOWED; + break; + case OC_STACK_NOT_ACCEPTABLE: + ret = CA_NOT_ACCEPTABLE; + break; case OC_STACK_UNAUTHORIZED_REQ: ret = CA_UNAUTHORIZED_REQ; break; + case OC_STACK_FORBIDDEN_REQ: + ret = CA_FORBIDDEN_REQ; + break; + case OC_STACK_TOO_MANY_REQUESTS: + ret = CA_TOO_MANY_REQUESTS; + break; + case OC_STACK_INTERNAL_SERVER_ERROR: + ret = CA_INTERNAL_SERVER_ERROR; + break; + case OC_STACK_NOT_IMPLEMENTED: + ret = CA_NOT_IMPLEMENTED; + break; + case OC_STACK_BAD_GATEWAY: + ret = CA_BAD_GATEWAY; + break; + case OC_STACK_SERVICE_UNAVAILABLE: + ret = CA_SERVICE_UNAVAILABLE; + break; + case OC_STACK_GATEWAY_TIMEOUT: + ret = CA_RETRANSMIT_TIMEOUT; + break; + case OC_STACK_PROXY_NOT_SUPPORTED: + ret = CA_PROXY_NOT_SUPPORTED; + break; default: break; } @@ -705,6 +855,7 @@ OCTransportFlags CAToOCTransportFlags(CATransportFlags_t caFlags) return (OCTransportFlags)caFlags; } +#ifdef WITH_PRESENCE static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds) { uint32_t lowerBound = 0; @@ -715,7 +866,7 @@ static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds) return OC_STACK_INVALID_PARAM; } - OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0)); + OIC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0)); cbNode->presence->TTL = maxAgeSeconds; @@ -748,14 +899,14 @@ static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds) cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound); - OC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound); - OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound); - OC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]); + OIC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound); + OIC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound); + OIC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]); } cbNode->presence->TTLlevel = 0; - OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel); + OIC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel); return OC_STACK_OK; } @@ -794,21 +945,131 @@ OCPresenceTrigger convertTriggerStringToEnum(const char * triggerStr) return OC_PRESENCE_TRIGGER_DELETE; } } +#endif // WITH_PRESENCE + +OCStackResult OCEncodeAddressForRFC6874(char *outputAddress, + size_t outputSize, + const char *inputAddress) +{ + VERIFY_NON_NULL(inputAddress, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(outputAddress, FATAL, OC_STACK_INVALID_PARAM); + + size_t inputLength = strnlen(inputAddress, outputSize); + + // inputSize includes the null terminator + size_t inputSize = inputLength + 1; + + if (inputSize > outputSize) + { + OIC_LOG_V(ERROR, TAG, + "OCEncodeAddressForRFC6874 failed: " + "outputSize (%zu) < inputSize (%zu)", + outputSize, inputSize); + + return OC_STACK_ERROR; + } + + char* percentChar = strchr(inputAddress, '%'); + + // If there is no '%' character, then no change is required to the string. + if (NULL == percentChar) + { + OICStrcpy(outputAddress, outputSize, inputAddress); + return OC_STACK_OK; + } + + const char* addressPart = &inputAddress[0]; + const char* scopeIdPart = percentChar + 1; + + // Sanity check to make sure this string doesn't have more '%' characters + if (NULL != strchr(scopeIdPart, '%')) + { + return OC_STACK_ERROR; + } + + // If no string follows the first '%', then the input was invalid. + if (scopeIdPart[0] == '\0') + { + OIC_LOG(ERROR, TAG, "OCEncodeAddressForRFC6874 failed: Invalid input string: no scope ID!"); + return OC_STACK_ERROR; + } + + // Check to see if the string is already encoded + if ((scopeIdPart[0] == '2') && (scopeIdPart[1] == '5')) + { + OIC_LOG(ERROR, TAG, "OCEncodeAddressForRFC6874 failed: Input string is already encoded"); + return OC_STACK_ERROR; + } + + // Fail if we don't have room for encoded string's two additional chars + if (outputSize < (inputSize + 2)) + { + OIC_LOG(ERROR, TAG, "OCEncodeAddressForRFC6874 failed: encoded output will not fit!"); + return OC_STACK_ERROR; + } + + // Restore the null terminator with an escaped '%' character, per RFC 6874 + OICStrcpy(outputAddress, scopeIdPart - addressPart, addressPart); + OICStrcat(outputAddress, outputSize, "%25"); + OICStrcat(outputAddress, outputSize, scopeIdPart); + + return OC_STACK_OK; +} + +OCStackResult OCDecodeAddressForRFC6874(char *outputAddress, + size_t outputSize, + const char *inputAddress, + const char *end) +{ + VERIFY_NON_NULL(inputAddress, FATAL, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(outputAddress, FATAL, OC_STACK_INVALID_PARAM); + + if (NULL == end) + { + end = inputAddress + strlen(inputAddress); + } + size_t inputLength = end - inputAddress; + + const char *percent = strchr(inputAddress, '%'); + if (!percent || (percent > end)) + { + OICStrcpyPartial(outputAddress, outputSize, inputAddress, inputLength); + } + else + { + if (percent[1] != '2' || percent[2] != '5') + { + return OC_STACK_INVALID_URI; + } + + int addrlen = percent - inputAddress + 1; + OICStrcpyPartial(outputAddress, outputSize, inputAddress, addrlen); + OICStrcpyPartial(outputAddress + addrlen, outputSize - addrlen, + percent + 3, end - percent - 3); + } + + return OC_STACK_OK; +} +#ifdef WITH_PRESENCE /** * The cononical presence allows constructed URIs to be string compared. * * requestUri must be a char array of size CA_MAX_URI_LENGTH */ -static int FormCanonicalPresenceUri(const CAEndpoint_t *endpoint, char *resourceUri, - char *presenceUri) +static int FormCanonicalPresenceUri(const CAEndpoint_t *endpoint, + char *presenceUri, bool isMulticast) { VERIFY_NON_NULL(endpoint , FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(resourceUri, FATAL, OC_STACK_INVALID_PARAM); VERIFY_NON_NULL(presenceUri, FATAL, OC_STACK_INVALID_PARAM); - CAEndpoint_t *ep = (CAEndpoint_t *)endpoint; + if (isMulticast) + { + OIC_LOG(DEBUG, TAG, "Make Multicast Presence URI"); + return snprintf(presenceUri, CA_MAX_URI_LENGTH, "%s", OC_RSRVD_PRESENCE_URI); + } + CAEndpoint_t *ep = (CAEndpoint_t *)endpoint; if (ep->adapter == CA_ADAPTER_IP) { if ((ep->flags & CA_IPV6) && !(ep->flags & CA_IPV4)) @@ -819,8 +1080,19 @@ static int FormCanonicalPresenceUri(const CAEndpoint_t *endpoint, char *resource } else { + char addressEncoded[CA_MAX_URI_LENGTH] = {0}; + + OCStackResult result = OCEncodeAddressForRFC6874(addressEncoded, + sizeof(addressEncoded), + ep->addr); + + if (OC_STACK_OK != result) + { + return -1; + } + return snprintf(presenceUri, CA_MAX_URI_LENGTH, "coap://[%s]:%u%s", - ep->addr, ep->port, OC_RSRVD_PRESENCE_URI); + addressEncoded, ep->port, OC_RSRVD_PRESENCE_URI); } } else @@ -861,43 +1133,10 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, if (responseInfo->result != CA_CONTENT) { - OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result); + OIC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result); return OC_STACK_ERROR; } - // check for unicast presence - uriLen = FormCanonicalPresenceUri(endpoint, OC_RSRVD_PRESENCE_URI, presenceUri); - if (uriLen < 0 || (size_t)uriLen >= sizeof (presenceUri)) - { - return OC_STACK_INVALID_URI; - } - - cbNode = GetClientCB(NULL, 0, NULL, presenceUri); - if (cbNode) - { - presenceSubscribe = 1; - } - else - { - // check for multiicast presence - CAEndpoint_t ep = { .adapter = endpoint->adapter, - .flags = endpoint->flags }; - - uriLen = FormCanonicalPresenceUri(&ep, OC_RSRVD_PRESENCE_URI, presenceUri); - - cbNode = GetClientCB(NULL, 0, NULL, presenceUri); - if (cbNode) - { - multicastPresenceSubscribe = 1; - } - } - - if (!presenceSubscribe && !multicastPresenceSubscribe) - { - OC_LOG(ERROR, TAG, "Received a presence notification, but no callback, ignoring"); - goto exit; - } - response.payload = NULL; response.result = OC_STACK_OK; @@ -913,12 +1152,12 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, if(result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Presence parse failed"); + OIC_LOG(ERROR, TAG, "Presence parse failed"); goto exit; } if(!response.payload || response.payload->type != PAYLOAD_TYPE_PRESENCE) { - OC_LOG(ERROR, TAG, "Presence payload was wrong type"); + OIC_LOG(ERROR, TAG, "Presence payload was wrong type"); result = OC_STACK_ERROR; goto exit; } @@ -927,19 +1166,50 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, maxAge = ((OCPresencePayload*)response.payload)->maxAge; } + // check for unicast presence + uriLen = FormCanonicalPresenceUri(endpoint, presenceUri, + responseInfo->isMulticast); + if (uriLen < 0 || (size_t)uriLen >= sizeof (presenceUri)) + { + return OC_STACK_INVALID_URI; + } + OIC_LOG(INFO, TAG, "check for unicast presence"); + cbNode = GetClientCB(NULL, 0, NULL, presenceUri); + if (cbNode) + { + presenceSubscribe = 1; + } + else + { + // check for multicast presence + OIC_LOG(INFO, TAG, "check for multicast presence"); + cbNode = GetClientCB(NULL, 0, NULL, OC_RSRVD_PRESENCE_URI); + if (cbNode) + { + multicastPresenceSubscribe = 1; + } + } + + if (!presenceSubscribe && !multicastPresenceSubscribe) + { + OIC_LOG(INFO, TAG, "Received a presence notification, " + "but need to register presence callback, ignoring"); + goto exit; + } + if (presenceSubscribe) { if(cbNode->sequenceNumber == response.sequenceNumber) { - OC_LOG(INFO, TAG, "No presence change"); + OIC_LOG(INFO, TAG, "No presence change"); ResetPresenceTTL(cbNode, maxAge); - OC_LOG_V(INFO, TAG, "ResetPresenceTTL - TTLlevel:%d\n", cbNode->presence->TTLlevel); + OIC_LOG_V(INFO, TAG, "ResetPresenceTTL - TTLlevel:%d\n", cbNode->presence->TTLlevel); goto exit; } if(maxAge == 0) { - OC_LOG(INFO, TAG, "Stopping presence"); + OIC_LOG(INFO, TAG, "Stopping presence"); response.result = OC_STACK_PRESENCE_STOPPED; if(cbNode->presence) { @@ -956,7 +1226,7 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, if(!(cbNode->presence)) { - OC_LOG(ERROR, TAG, "Could not allocate memory for cbNode->presence"); + OIC_LOG(ERROR, TAG, "Could not allocate memory for cbNode->presence"); result = OC_STACK_NO_MEMORY; goto exit; } @@ -966,9 +1236,10 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, cbNode->presence->timeOut = (uint32_t *) OICMalloc(PresenceTimeOutSize * sizeof(uint32_t)); if(!(cbNode->presence->timeOut)){ - OC_LOG(ERROR, TAG, + OIC_LOG(ERROR, TAG, "Could not allocate memory for cbNode->presence->timeOut"); OICFree(cbNode->presence); + cbNode->presence = NULL; result = OC_STACK_NO_MEMORY; goto exit; } @@ -977,71 +1248,32 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, ResetPresenceTTL(cbNode, maxAge); cbNode->sequenceNumber = response.sequenceNumber; - - // Ensure that a filter is actually applied. - if( resourceTypeName && cbNode->filterResourceType) - { - if(!findResourceType(cbNode->filterResourceType, resourceTypeName)) - { - goto exit; - } - } } } else { // This is the multicast case - OCMulticastNode* mcNode = NULL; - mcNode = GetMCPresenceNode(presenceUri); - - if(mcNode != NULL) - { - if(mcNode->nonce == response.sequenceNumber) - { - OC_LOG(INFO, TAG, "No presence change (Multicast)"); - goto exit; - } - mcNode->nonce = response.sequenceNumber; - - if(maxAge == 0) - { - OC_LOG(INFO, TAG, "Stopping presence"); - response.result = OC_STACK_PRESENCE_STOPPED; - } - } - else + OIC_LOG(INFO, TAG, "this is the multicast presence"); + if (0 == maxAge) { - char* uri = OICStrdup(presenceUri); - if (!uri) - { - OC_LOG(INFO, TAG, - "No Memory for URI to store in the presence node"); - result = OC_STACK_NO_MEMORY; - goto exit; - } - - result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber); - if(result == OC_STACK_NO_MEMORY) - { - OC_LOG(INFO, TAG, - "No Memory for Multicast Presence Node"); - OICFree(uri); - goto exit; - } - // presence node now owns uri + OIC_LOG(INFO, TAG, "Stopping presence"); + response.result = OC_STACK_PRESENCE_STOPPED; } + } - // Ensure that a filter is actually applied. - if(resourceTypeName && cbNode->filterResourceType) + // Ensure that a filter is actually applied. + if (resourceTypeName && cbNode->filterResourceType) + { + OIC_LOG_V(INFO, TAG, "find resource type : %s", resourceTypeName); + if(!findResourceType(cbNode->filterResourceType, resourceTypeName)) { - if(!findResourceType(cbNode->filterResourceType, resourceTypeName)) - { - goto exit; - } + goto exit; } } + OIC_LOG(INFO, TAG, "Before calling into application address space for presence"); cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response); + OIC_LOG(INFO, TAG, "After calling into application address space for presence"); if (cbResult == OC_STACK_DELETE_TRANSACTION) { @@ -1052,105 +1284,154 @@ exit: OCPayloadDestroy(response.payload); return result; } +#endif // WITH_PRESENCE -void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo) +OCStackResult HandleBatchResponse(char *requestUri, OCRepPayload **payload) { - VERIFY_NON_NULL_NR(endPoint, FATAL); - VERIFY_NON_NULL_NR(responseInfo, FATAL); + if (requestUri && *payload) + { + char *interfaceName = NULL; + char *rtTypeName = NULL; + char *uriQuery = NULL; + char *uriWithoutQuery = NULL; + if (OC_STACK_OK == getQueryFromUri(requestUri, &uriQuery, &uriWithoutQuery)) + { + if (OC_STACK_OK == ExtractFiltersFromQuery(uriQuery, &interfaceName, &rtTypeName)) + { + if (interfaceName && (0 == strcmp(OC_RSRVD_INTERFACE_BATCH, interfaceName))) + { + char *uri = (*payload)->uri; + if (uri && 0 != strcmp(uriWithoutQuery, uri)) + { + OCRepPayload *newPayload = OCRepPayloadCreate(); + if (newPayload) + { + OCRepPayloadSetUri(newPayload, uri); + newPayload->next = *payload; + *payload = newPayload; + } + } + } + } + } - OC_LOG(INFO, TAG, "Enter HandleCAResponses"); + OICFree(interfaceName); + OICFree(rtTypeName); + OICFree(uriQuery); + OICFree(uriWithoutQuery); + return OC_STACK_OK; + } + return OC_STACK_INVALID_PARAM; +} -#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) -#ifdef ROUTING_GATEWAY - bool needRIHandling = false; - /* - * Routing manager is going to update either of endpoint or response or both. - * This typecasting is done to avoid unnecessary duplication of Endpoint and responseInfo - * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper - * destination. - */ - OCStackResult ret = RMHandleResponse((CAResponseInfo_t *)responseInfo, (CAEndpoint_t *)endPoint, - &needRIHandling); - if(ret != OC_STACK_OK || !needRIHandling) - { - OC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret); - return; - } -#endif - - /* - * Put source in sender endpoint so that the next packet from application can be routed to - * proper destination and remove "RM" coap header option before passing request / response to - * RI as this option will make no sense to either RI or application. - */ - RMUpdateInfo((CAHeaderOption_t **) &(responseInfo->info.options), - (uint8_t *) &(responseInfo->info.numOptions), - (CAEndpoint_t *) endPoint); -#endif +void OCHandleResponse(const CAEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo) +{ + OIC_TRACE_MARK(%s:OCHandleResponse:%s, TAG, responseInfo->info.resourceUri); + OIC_LOG(DEBUG, TAG, "Enter OCHandleResponse"); +#ifdef WITH_PRESENCE if(responseInfo->info.resourceUri && strcmp(responseInfo->info.resourceUri, OC_RSRVD_PRESENCE_URI) == 0) { HandlePresenceResponse(endPoint, responseInfo); return; } +#endif ClientCB *cbNode = GetClientCB(responseInfo->info.token, responseInfo->info.tokenLength, NULL, NULL); - ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token, - responseInfo->info.tokenLength); - if(cbNode) { - OC_LOG(INFO, TAG, "There is a cbNode associated with the response token"); + OIC_LOG(INFO, TAG, "There is a cbNode associated with the response token"); +#ifdef __TIZENRT__ + // check obs header option + bool obsHeaderOpt = false; + CAHeaderOption_t *options = responseInfo->info.options; + for (uint8_t i = 0; i< responseInfo->info.numOptions; i++) + { + if (options && options[i].protocolID == CA_COAP_ID && + options[i].optionID == COAP_OPTION_OBSERVE) + { + obsHeaderOpt = true; + break; + } + } +#endif if(responseInfo->result == CA_EMPTY) { - OC_LOG(INFO, TAG, "Receiving A ACK/RESET for this token"); + OIC_LOG(INFO, TAG, "Receiving A ACK/RESET for this token"); // We do not have a case for the client to receive a RESET if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE) { //This is the case of receiving an ACK on a request to a slow resource! - OC_LOG(INFO, TAG, "This is a pure ACK"); + OIC_LOG(INFO, TAG, "This is a pure ACK"); //TODO: should we inform the client // app that at least the request was received at the server? } } else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT) { - OC_LOG(INFO, TAG, "Receiving A Timeout for this token"); - OC_LOG(INFO, TAG, "Calling into application address space"); + OIC_LOG(INFO, TAG, "Receiving A Timeout for this token"); OCClientResponse response = {.devAddr = {.adapter = OC_DEFAULT_ADAPTER}}; CopyEndpointToDevAddr(endPoint, &response.devAddr); FixUpClientResponse(&response); - response.resourceUri = responseInfo->info.resourceUri; + response.resourceUri = OICStrdup(responseInfo->info.resourceUri); memcpy(response.identity.id, responseInfo->info.identity.id, sizeof (response.identity.id)); response.identity.id_length = responseInfo->info.identity.id_length; - response.result = CAToOCStackResult(responseInfo->result); + response.result = CAResponseToOCStackResult(responseInfo->result); + OIC_LOG(INFO, TAG, "Before calling into application address space for reTrans timeout"); cbNode->callBack(cbNode->context, cbNode->handle, &response); + OIC_LOG(INFO, TAG, "After calling into application address space for reTrans timeout"); FindAndDeleteClientCB(cbNode); + OICFree((void *)response.resourceUri); } - else +#ifdef __TIZENRT__ + else if ((cbNode->method == OC_REST_OBSERVE || cbNode->method == OC_REST_OBSERVE_ALL) + && (responseInfo->result == CA_CONTENT) && !obsHeaderOpt) { - OC_LOG(INFO, TAG, "This is a regular response, A client call back is found"); - OC_LOG(INFO, TAG, "Calling into application address space"); - OCClientResponse response = {.devAddr = {.adapter = OC_DEFAULT_ADAPTER}}; - response.sequenceNumber = OC_OBSERVE_NO_OPTION; CopyEndpointToDevAddr(endPoint, &response.devAddr); FixUpClientResponse(&response); - response.resourceUri = responseInfo->info.resourceUri; + response.resourceUri = OICStrdup(responseInfo->info.resourceUri); + memcpy(response.identity.id, responseInfo->info.identity.id, + sizeof (response.identity.id)); + response.identity.id_length = responseInfo->info.identity.id_length; + response.result = OC_STACK_UNAUTHORIZED_REQ; + + OIC_LOG(INFO, TAG, "Before calling into application address space for observe resp"); + cbNode->callBack(cbNode->context, + cbNode->handle, + &response); + OIC_LOG(INFO, TAG, "After calling into application address space for observe resp"); + + FindAndDeleteClientCB(cbNode); + OICFree(response.resourceUri); + } +#endif + else + { + OIC_LOG(INFO, TAG, "This is a regular response, A client call back is found"); + + OCClientResponse response; + memset(&response, 0, sizeof(OCClientResponse)); + response.devAddr.adapter = OC_DEFAULT_ADAPTER; + + response.sequenceNumber = MAX_SEQUENCE_NUMBER + 1; + CopyEndpointToDevAddr(endPoint, &response.devAddr); + FixUpClientResponse(&response); + response.resourceUri = OICStrdup(responseInfo->info.resourceUri); memcpy(response.identity.id, responseInfo->info.identity.id, sizeof (response.identity.id)); response.identity.id_length = responseInfo->info.identity.id_length; - response.result = CAToOCStackResult(responseInfo->result); + response.result = CAResponseToOCStackResult(responseInfo->result); if(responseInfo->info.payload && responseInfo->info.payloadSize) @@ -1168,14 +1449,21 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res { type = PAYLOAD_TYPE_DISCOVERY; } +#ifdef WITH_MQ + else if (strcmp(cbNode->requestUri, OC_RSRVD_WELL_KNOWN_MQ_URI) == 0) + { + type = PAYLOAD_TYPE_DISCOVERY; + } +#endif else if (strcmp(cbNode->requestUri, OC_RSRVD_DEVICE_URI) == 0) { - type = PAYLOAD_TYPE_DEVICE; + type = PAYLOAD_TYPE_REPRESENTATION; } else if (strcmp(cbNode->requestUri, OC_RSRVD_PLATFORM_URI) == 0) { - type = PAYLOAD_TYPE_PLATFORM; + type = PAYLOAD_TYPE_REPRESENTATION; } + #ifdef ROUTING_GATEWAY else if (strcmp(cbNode->requestUri, OC_RSRVD_GATEWAY_URI) == 0) { @@ -1184,12 +1472,19 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res #endif else if (strcmp(cbNode->requestUri, OC_RSRVD_RD_URI) == 0) { - type = PAYLOAD_TYPE_RD; + type = PAYLOAD_TYPE_REPRESENTATION; + } +#ifdef TCP_ADAPTER + else if (strcmp(cbNode->requestUri, OC_RSRVD_KEEPALIVE_URI) == 0) + { + type = PAYLOAD_TYPE_REPRESENTATION; } +#endif else { - OC_LOG_V(ERROR, TAG, "Unknown Payload type in Discovery: %d %s", + OIC_LOG_V(ERROR, TAG, "Unknown Payload type in Discovery: %d %s", cbNode->method, cbNode->requestUri); + OICFree((void *)response.resourceUri); return; } } @@ -1200,35 +1495,55 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res cbNode->method == OC_REST_OBSERVE_ALL || cbNode->method == OC_REST_DELETE) { - char targetUri[MAX_URI_LENGTH]; - snprintf(targetUri, MAX_URI_LENGTH, "%s?rt=%s", - OC_RSRVD_RD_URI, OC_RSRVD_RESOURCE_TYPE_RDPUBLISH); - if (strcmp(targetUri, cbNode->requestUri) == 0) + if (cbNode->requestUri) { - type = PAYLOAD_TYPE_RD; + if (0 == strcmp(OC_RSRVD_PLATFORM_URI, cbNode->requestUri)) + { + type = PAYLOAD_TYPE_REPRESENTATION; + } + else if (0 == strcmp(OC_RSRVD_DEVICE_URI, cbNode->requestUri)) + { + type = PAYLOAD_TYPE_REPRESENTATION; + } + if (type == PAYLOAD_TYPE_INVALID) + { + OIC_LOG_V(INFO, TAG, "Assuming PAYLOAD_TYPE_REPRESENTATION: %d %s", + cbNode->method, cbNode->requestUri); + type = PAYLOAD_TYPE_REPRESENTATION; + } } - if (type == PAYLOAD_TYPE_INVALID) + else { - OC_LOG_V(INFO, TAG, "Assuming PAYLOAD_TYPE_REPRESENTATION: %d %s", - cbNode->method, cbNode->requestUri); + OIC_LOG(INFO, TAG, "No Request URI, PROXY URI"); type = PAYLOAD_TYPE_REPRESENTATION; } } else { - OC_LOG_V(ERROR, TAG, "Unknown Payload type: %d %s", + OIC_LOG_V(ERROR, TAG, "Unknown Payload type: %d %s", cbNode->method, cbNode->requestUri); + OICFree((void *)response.resourceUri); return; } - if(OC_STACK_OK != OCParsePayload(&response.payload, + // In case of error, still want application to receive the error message. + if (OCResultToSuccess(response.result) || PAYLOAD_TYPE_REPRESENTATION == type) + { + if(OC_STACK_OK != OCParsePayload(&response.payload, type, responseInfo->info.payload, responseInfo->info.payloadSize)) + { + OIC_LOG(ERROR, TAG, "Error converting payload"); + OCPayloadDestroy(response.payload); + OICFree((void *)response.resourceUri); + return; + } + } + else { - OC_LOG(ERROR, TAG, "Error converting payload"); - OCPayloadDestroy(response.payload); - return; + OICFree((void *)response.resourceUri); + response.resourceUri = OICStrdup(cbNode->requestUri); } } @@ -1237,7 +1552,8 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res { int start = 0; //First option always with option ID is COAP_OPTION_OBSERVE if it is available. - if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE) + if(responseInfo->info.options + && responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE) { size_t i; uint32_t observationOption; @@ -1250,7 +1566,6 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res (observationOption << 8) | optionData[i]; } response.sequenceNumber = observationOption; - response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1; start = 1; } @@ -1261,30 +1576,92 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS) { - OC_LOG(ERROR, TAG, "#header options are more than MAX_HEADER_OPTIONS"); + OIC_LOG(ERROR, TAG, "#header options are more than MAX_HEADER_OPTIONS"); OCPayloadDestroy(response.payload); + OICFree((void *)response.resourceUri); return; } - for (uint8_t i = start; i < responseInfo->info.numOptions; i++) + if (response.numRcvdVendorSpecificHeaderOptions > 0) { - memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]), - &(responseInfo->info.options[i]), sizeof(OCHeaderOption)); + response.rcvdVendorSpecificHeaderOptions = + (OCHeaderOption *) OICCalloc(response.numRcvdVendorSpecificHeaderOptions, sizeof(OCHeaderOption)); + if (NULL == response.rcvdVendorSpecificHeaderOptions) + { + OIC_LOG(ERROR, TAG, "Failed to allocate memory for vendor header options"); + OCPayloadDestroy(response.payload); + OICFree((void *)response.resourceUri); + return; + } + + memcpy(response.rcvdVendorSpecificHeaderOptions, responseInfo->info.options + start, + response.numRcvdVendorSpecificHeaderOptions*sizeof(OCHeaderOption)); } } if (cbNode->method == OC_REST_OBSERVE && response.sequenceNumber > OC_OFFSET_SEQUENCE_NUMBER && + cbNode->sequenceNumber <= MAX_SEQUENCE_NUMBER && response.sequenceNumber <= cbNode->sequenceNumber) { - OC_LOG_V(INFO, TAG, "Received stale notification. Number :%d", + OIC_LOG_V(INFO, TAG, "Received stale notification. Number :%d", response.sequenceNumber); } else { +#ifdef RD_CLIENT + if (cbNode->requestUri) + { + // if request uri is '/oic/rd', update ins value of resource. + char *targetUri = strstr(cbNode->requestUri, OC_RSRVD_RD_URI); + if (targetUri) + { + OCUpdateResourceInsWithResponse(cbNode->requestUri, &response); + } + } +#endif + // set remoteID(device ID) into OCClientResponse callback parameter + if (OC_REST_DISCOVER == cbNode->method) + { + OIC_LOG(INFO, TAG, "cbNode method is OC_REST_DISCOVER"); + OCDiscoveryPayload *payload = (OCDiscoveryPayload*) response.payload; + // Payload can be empty in case of error message. + if (payload && payload->sid) + { + OICStrcpy(response.devAddr.remoteId, sizeof(response.devAddr.remoteId), + payload->sid); + OIC_LOG_V(INFO_PRIVATE, TAG, "Device ID of response : %s", + response.devAddr.remoteId); + } + + if(NULL == response.resourceUri) + { + response.resourceUri = OICStrdup(cbNode->requestUri); + } + } +#ifdef TCP_ADAPTER + if (cbNode->requestUri) + { + OIC_LOG_V(INFO, TAG, "cbNode requestUri is %s", cbNode->requestUri); + if (cbNode->method == OC_REST_POST && + strcmp(cbNode->requestUri, OC_RSRVD_KEEPALIVE_URI) == 0) + { + OCHandleKeepAliveResponse(endPoint, response.payload); + } + } +#endif + if (response.payload && response.payload->type == PAYLOAD_TYPE_REPRESENTATION) + { + OIC_LOG(INFO, TAG, "Handle batch response"); + HandleBatchResponse(cbNode->requestUri, (OCRepPayload **)&response.payload); + } + + OIC_LOG(INFO, TAG, "Before calling into application address space for handleResponse"); OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context, cbNode->handle, &response); + OIC_LOG(INFO, TAG, "After calling into application address space for handleResponse"); + cbNode->sequenceNumber = response.sequenceNumber; if (appFeedback == OC_STACK_DELETE_TRANSACTION) @@ -1302,40 +1679,51 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res //Need to send ACK when the response is CON if(responseInfo->info.type == CA_MSG_CONFIRM) { - SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY, - CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0, NULL); + if (!(endPoint->adapter & CA_ADAPTER_TCP)) + { + OIC_LOG(INFO, TAG, "Received a confirmable message. Sending EMPTY"); + SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY, + CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0, NULL, CA_RESPONSE_FOR_RES); + } } + OICFree((void *)response.resourceUri); OCPayloadDestroy(response.payload); + OICFree(response.rcvdVendorSpecificHeaderOptions); } return; } + ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token, + responseInfo->info.tokenLength); + if(observer) { - OC_LOG(INFO, TAG, "There is an observer associated with the response token"); + OIC_LOG(INFO, TAG, "There is an observer associated with the response token"); if(responseInfo->result == CA_EMPTY) { - OC_LOG(INFO, TAG, "Receiving A ACK/RESET for this token"); + OIC_LOG(INFO, TAG, "Receiving A ACK/RESET for this token"); if(responseInfo->info.type == CA_MSG_RESET) { - OC_LOG(INFO, TAG, "This is a RESET"); + OIC_LOG(INFO, TAG, "This is a RESET"); OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength, OC_OBSERVER_NOT_INTERESTED); } else if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE) { - OC_LOG(INFO, TAG, "This is a pure ACK"); + OIC_LOG(INFO, TAG, "This is a pure ACK"); OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength, OC_OBSERVER_STILL_INTERESTED); } } else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT) { - OC_LOG(INFO, TAG, "Receiving Time Out for an observer"); + OIC_LOG(INFO, TAG, "Receiving Time Out for an observer"); OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength, OC_OBSERVER_FAILED_COMM); } + + FreeObserver(observer); return; } @@ -1344,61 +1732,130 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER || myStackMode == OC_GATEWAY) { - OC_LOG(INFO, TAG, "This is a client, but no cbNode was found for token"); + OIC_LOG(INFO, TAG, "This is a client, but no cbNode was found for token"); if(responseInfo->result == CA_EMPTY) { - OC_LOG(INFO, TAG, "Receiving CA_EMPTY in the ocstack"); + OIC_LOG(INFO, TAG, "Receiving CA_EMPTY in the ocstack"); } else { - OC_LOG(INFO, TAG, "Received a message without callbacks. Sending RESET"); - SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY, - CA_MSG_RESET, 0, NULL, NULL, 0, NULL); + if (!(endPoint->adapter & CA_ADAPTER_TCP)) + { + OIC_LOG(INFO, TAG, "Received a message without callbacks. Sending RESET"); + SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY, + CA_MSG_RESET, 0, NULL, NULL, 0, NULL, + CA_RESPONSE_FOR_RES); + } } } if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER || myStackMode == OC_GATEWAY) { - OC_LOG(INFO, TAG, "This is a server, but no observer was found for token"); + OIC_LOG(INFO, TAG, "This is a server, but no observer was found for token"); if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE) { - OC_LOG_V(INFO, TAG, "Received ACK at server for messageId : %d", + OIC_LOG_V(INFO, TAG, "Received ACK at server for messageId : %d", responseInfo->info.messageId); } if (responseInfo->info.type == CA_MSG_RESET) { - OC_LOG_V(INFO, TAG, "Received RESET at server for messageId : %d", + OIC_LOG_V(INFO, TAG, "Received RESET at server for messageId : %d", responseInfo->info.messageId); } } return; } +} + +void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo) +{ + VERIFY_NON_NULL_NR(endPoint, FATAL); + VERIFY_NON_NULL_NR(responseInfo, FATAL); + + OIC_LOG(INFO, TAG, "Enter HandleCAResponses"); + OIC_TRACE_BEGIN(%s:HandleCAResponses, TAG); + +#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) +#ifdef ROUTING_GATEWAY + bool needRIHandling = false; + /* + * Routing manager is going to update either of endpoint or response or both. + * This typecasting is done to avoid unnecessary duplication of Endpoint and responseInfo + * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper + * destination. + */ + OCStackResult ret = RMHandleResponse((CAResponseInfo_t *)responseInfo, (CAEndpoint_t *)endPoint, + &needRIHandling); + if(ret != OC_STACK_OK || !needRIHandling) + { + OIC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret); + OIC_TRACE_END(); + return; + } +#endif + + /* + * Put source in sender endpoint so that the next packet from application can be routed to + * proper destination and remove "RM" coap header option before passing request / response to + * RI as this option will make no sense to either RI or application. + */ + RMUpdateInfo((CAHeaderOption_t **) &(responseInfo->info.options), + (uint8_t *) &(responseInfo->info.numOptions), + (CAEndpoint_t *) endPoint); +#endif - OC_LOG(INFO, TAG, "Exit HandleCAResponses"); + OCHandleResponse(endPoint, responseInfo); + OIC_TRACE_END(); + OIC_LOG(INFO, TAG, "Exit HandleCAResponses"); } /* * This function handles error response from CA * code shall be added to handle the errors */ -void HandleCAErrorResponse(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errrorInfo) +void HandleCAErrorResponse(const CAEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo) { - OC_LOG(INFO, TAG, "Enter HandleCAErrorResponse"); + VERIFY_NON_NULL_NR(endPoint, FATAL); + VERIFY_NON_NULL_NR(errorInfo, FATAL); + + OIC_LOG(INFO, TAG, "Enter HandleCAErrorResponse"); + OIC_TRACE_BEGIN(%s:HandleCAErrorResponse, TAG); - if(NULL == endPoint) + ClientCB *cbNode = GetClientCB(errorInfo->info.token, + errorInfo->info.tokenLength, NULL, NULL); + if (cbNode) { - OC_LOG(ERROR, TAG, "endPoint is NULL"); - return; + OCClientResponse response = { .devAddr = { .adapter = OC_DEFAULT_ADAPTER } }; + CopyEndpointToDevAddr(endPoint, &response.devAddr); + FixUpClientResponse(&response); + response.resourceUri = errorInfo->info.resourceUri; + memcpy(response.identity.id, errorInfo->info.identity.id, + sizeof (response.identity.id)); + response.identity.id_length = errorInfo->info.identity.id_length; + response.result = CAResultToOCResult(errorInfo->result); + + OIC_LOG(INFO, TAG, "Before calling into application address space for error response"); + cbNode->callBack(cbNode->context, cbNode->handle, &response); + OIC_LOG(INFO, TAG, "After calling into application address space for error response"); } - if(NULL == errrorInfo) + ResourceObserver *observer = GetObserverUsingToken(errorInfo->info.token, + errorInfo->info.tokenLength); + if (observer) { - OC_LOG(ERROR, TAG, "errrorInfo is NULL"); - return; + OIC_LOG(INFO, TAG, "Receiving communication error for an observer"); + OCStackResult result = CAResultToOCResult(errorInfo->result); + if (OC_STACK_COMM_ERROR == result) + { + OCStackFeedBack(errorInfo->info.token, errorInfo->info.tokenLength, + OC_OBSERVER_FAILED_COMM); + } } - OC_LOG(INFO, TAG, "Exit HandleCAErrorResponse"); + + OIC_LOG(INFO, TAG, "Exit HandleCAErrorResponse"); + OIC_TRACE_END(); } /* @@ -1409,11 +1866,18 @@ void HandleCAErrorResponse(const CAEndpoint_t *endPoint, const CAErrorInfo_t *er OCStackResult SendDirectStackResponse(const CAEndpoint_t* endPoint, const uint16_t coapID, const CAResponseResult_t responseResult, const CAMessageType_t type, const uint8_t numOptions, const CAHeaderOption_t *options, - CAToken_t token, uint8_t tokenLength, const char *resourceUri) + CAToken_t token, uint8_t tokenLength, const char *resourceUri, + CADataType_t dataType) { - CAResponseInfo_t respInfo = { - .result = responseResult - }; + OIC_LOG(DEBUG, TAG, "Entering SendDirectStackResponse"); + + if (endPoint->flags & CA_MULTICAST) + { + OIC_LOG(ERROR, TAG, "It is unnecessary to respond to a multicast request"); + return OC_STACK_OK; + } + + CAResponseInfo_t respInfo = { .result = responseResult }; respInfo.info.messageId = coapID; respInfo.info.numOptions = numOptions; @@ -1432,76 +1896,149 @@ OCStackResult SendDirectStackResponse(const CAEndpoint_t* endPoint, const uint16 respInfo.info.type = type; respInfo.info.resourceUri = OICStrdup (resourceUri); respInfo.info.acceptFormat = CA_FORMAT_UNDEFINED; + respInfo.info.dataType = dataType; #if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) // Add the destination to route option from the endpoint->routeData. - OCStackResult result = RMAddInfo(endPoint->routeData, - &(respInfo.info.options), - &(respInfo.info.numOptions)); + bool doPost = false; + OCStackResult result = RMAddInfo(endPoint->routeData, &respInfo, false, &doPost); if(OC_STACK_OK != result) { - OC_LOG_V(ERROR, TAG, "Add routing option failed [%d]", result); + OIC_LOG_V(ERROR, TAG, "Add routing option failed [%d]", result); + OICFree (respInfo.info.resourceUri); + OICFree (respInfo.info.options); return result; } -#endif - - CAResult_t caResult = CASendResponse(endPoint, &respInfo); + if (doPost) + { + OIC_LOG(DEBUG, TAG, "Sending a POST message for EMPTY ACK in Client Mode"); + CARequestInfo_t reqInfo = {.method = CA_POST }; + /* The following initialization is not done in a single initializer block as in + * arduino, .c file is compiled as .cpp and moves it from C99 to C++11. The latter + * does not have designated initalizers. This is a work-around for now. + */ + reqInfo.info.type = CA_MSG_NONCONFIRM; + reqInfo.info.messageId = coapID; + reqInfo.info.tokenLength = tokenLength; + reqInfo.info.token = token; + reqInfo.info.numOptions = respInfo.info.numOptions; + reqInfo.info.payload = NULL; + reqInfo.info.resourceUri = OICStrdup (OC_RSRVD_GATEWAY_URI); + if (reqInfo.info.numOptions) + { + reqInfo.info.options = + (CAHeaderOption_t *)OICCalloc(reqInfo.info.numOptions, sizeof(CAHeaderOption_t)); + if (NULL == reqInfo.info.options) + { + OIC_LOG(ERROR, TAG, "Calloc failed"); + OICFree (reqInfo.info.resourceUri); + OICFree (respInfo.info.resourceUri); + OICFree (respInfo.info.options); + return OC_STACK_NO_MEMORY; + } + memcpy (reqInfo.info.options, respInfo.info.options, + sizeof(CAHeaderOption_t) * reqInfo.info.numOptions); - // resourceUri in the info field is cloned in the CA layer and - // thus ownership is still here. - OICFree (respInfo.info.resourceUri); - OICFree (respInfo.info.options); - if(CA_STATUS_OK != caResult) + } + CAResult_t caResult = CASendRequest(endPoint, &reqInfo); + OICFree (reqInfo.info.resourceUri); + OICFree (reqInfo.info.options); + OICFree (respInfo.info.resourceUri); + OICFree (respInfo.info.options); + if (CA_STATUS_OK != caResult) + { + OIC_LOG(ERROR, TAG, "CASendRequest error"); + return CAResultToOCResult(caResult); + } + } + else +#endif { - OC_LOG(ERROR, TAG, "CASendResponse error"); - return CAResultToOCResult(caResult); + CAResult_t caResult = CASendResponse(endPoint, &respInfo); + + // resourceUri in the info field is cloned in the CA layer and + // thus ownership is still here. + OICFree (respInfo.info.resourceUri); + OICFree (respInfo.info.options); + if(CA_STATUS_OK != caResult) + { + OIC_LOG(ERROR, TAG, "CASendResponse error"); + return CAResultToOCResult(caResult); + } } + OIC_LOG(DEBUG, TAG, "Exit SendDirectStackResponse"); return OC_STACK_OK; } -//This function will be called back by CA layer when a request is received -void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* requestInfo) +OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest) { - OC_LOG(INFO, TAG, "Enter HandleCARequests"); - if(!endPoint) + OIC_LOG(INFO, TAG, "Entering HandleStackRequests (OCStack Layer)"); + OCStackResult result = OC_STACK_ERROR; + if(!protocolRequest) { - OC_LOG(ERROR, TAG, "endPoint is NULL"); - return; + OIC_LOG(ERROR, TAG, "protocolRequest is NULL"); + return OC_STACK_INVALID_PARAM; } - if(!requestInfo) + OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken, + protocolRequest->tokenLength); + if(!request) { - OC_LOG(ERROR, TAG, "requestInfo is NULL"); - return; + OIC_LOG(INFO, TAG, "This is a new Server Request"); + result = AddServerRequest(&request, protocolRequest->coapID, + protocolRequest->delayedResNeeded, 0, protocolRequest->method, + protocolRequest->numRcvdVendorSpecificHeaderOptions, + protocolRequest->observationOption, protocolRequest->qos, + protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions, + protocolRequest->payload, protocolRequest->requestToken, + protocolRequest->tokenLength, protocolRequest->resourceUrl, + protocolRequest->reqTotalSize, protocolRequest->acceptFormat, + &protocolRequest->devAddr); + if (OC_STACK_OK != result) + { + OIC_LOG(ERROR, TAG, "Error adding server request"); + return result; + } + + if(!request) + { + OIC_LOG(ERROR, TAG, "Out of Memory"); + return OC_STACK_NO_MEMORY; + } + + if(!protocolRequest->reqMorePacket) + { + request->requestComplete = 1; + } + } + else + { + OIC_LOG(INFO, TAG, "This is either a repeated or blocked Server Request"); } -#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) -#ifdef ROUTING_GATEWAY - bool needRIHandling = false; - /* - * Routing manager is going to update either of endpoint or request or both. - * This typecasting is done to avoid unnecessary duplication of Endpoint and requestInfo - * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper - * destination. It can also remove "RM" coap header option before passing request / response to - * RI as this option will make no sense to either RI or application. - */ - OCStackResult ret = RMHandleRequest((CARequestInfo_t *)requestInfo, (CAEndpoint_t *)endPoint, - &needRIHandling); - if(OC_STACK_OK != ret || !needRIHandling) + if(request->requestComplete) { - OC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret); - return; + OIC_LOG(INFO, TAG, "This Server Request is complete"); + ResourceHandling resHandling = OC_RESOURCE_VIRTUAL; + OCResource *resource = NULL; + result = DetermineResourceHandling (request, &resHandling, &resource); + if (result == OC_STACK_OK) + { + result = ProcessRequest(resHandling, resource, request); + } } -#endif + else + { + OIC_LOG(INFO, TAG, "This Server Request is incomplete"); + result = OC_STACK_CONTINUE; + } + return result; +} - /* - * Put source in sender endpoint so that the next packet from application can be routed to - * proper destination and remove RM header option. - */ - RMUpdateInfo((CAHeaderOption_t **) &(requestInfo->info.options), - (uint8_t *) &(requestInfo->info.numOptions), - (CAEndpoint_t *) endPoint); -#endif +void OCHandleRequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* requestInfo) +{ + OIC_TRACE_MARK(%s:OCHandleRequests:%s, TAG, requestInfo->info.resourceUri); + OIC_LOG(DEBUG, TAG, "Enter OCHandleRequests"); OCStackResult requestResult = OC_STACK_ERROR; @@ -1513,7 +2050,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque OCServerProtocolRequest serverRequest = {0}; - OC_LOG_V(INFO, TAG, "Endpoint URI : %s", requestInfo->info.resourceUri); + OIC_LOG_V(INFO, TAG, "Endpoint URI : %s", requestInfo->info.resourceUri); char * uriWithoutQuery = NULL; char * query = NULL; @@ -1522,11 +2059,11 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque if (requestResult != OC_STACK_OK || !uriWithoutQuery) { - OC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult); + OIC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult); return; } - OC_LOG_V(INFO, TAG, "URI without query: %s", uriWithoutQuery); - OC_LOG_V(INFO, TAG, "Query : %s", query); + OIC_LOG_V(INFO, TAG, "URI without query: %s", uriWithoutQuery); + OIC_LOG_V(INFO, TAG, "Query : %s", query); if(strlen(uriWithoutQuery) < MAX_URI_LENGTH) { @@ -1535,7 +2072,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque } else { - OC_LOG(ERROR, TAG, "URI length exceeds MAX_URI_LENGTH."); + OIC_LOG(ERROR, TAG, "URI length exceeds MAX_URI_LENGTH."); OICFree(uriWithoutQuery); OICFree(query); return; @@ -1550,7 +2087,7 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque } else { - OC_LOG(ERROR, TAG, "Query length exceeds MAX_QUERY_LENGTH."); + OIC_LOG(ERROR, TAG, "Query length exceeds MAX_QUERY_LENGTH."); OICFree(query); return; } @@ -1560,6 +2097,11 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque { serverRequest.reqTotalSize = requestInfo->info.payloadSize; serverRequest.payload = (uint8_t *) OICMalloc(requestInfo->info.payloadSize); + if (!serverRequest.payload) + { + OIC_LOG(ERROR, TAG, "Allocation for payload failed."); + return; + } memcpy (serverRequest.payload, requestInfo->info.payload, requestInfo->info.payloadSize); } @@ -1583,33 +2125,39 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque serverRequest.method = OC_REST_DELETE; break; default: - OC_LOG_V(ERROR, TAG, "Received CA method %d not supported", requestInfo->method); + OIC_LOG_V(ERROR, TAG, "Received CA method %d not supported", requestInfo->method); SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_REQ, requestInfo->info.type, requestInfo->info.numOptions, requestInfo->info.options, requestInfo->info.token, - requestInfo->info.tokenLength, requestInfo->info.resourceUri); + requestInfo->info.tokenLength, requestInfo->info.resourceUri, + CA_RESPONSE_DATA); OICFree(serverRequest.payload); return; } - OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token, + OIC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token, requestInfo->info.tokenLength); - serverRequest.requestToken = (CAToken_t)OICMalloc(requestInfo->info.tokenLength); + serverRequest.tokenLength = requestInfo->info.tokenLength; + if (serverRequest.tokenLength) { + // Non empty token + serverRequest.requestToken = (CAToken_t)OICMalloc(requestInfo->info.tokenLength); - if (!serverRequest.requestToken) - { - OC_LOG(FATAL, TAG, "Allocation for token failed."); - SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR, - requestInfo->info.type, requestInfo->info.numOptions, - requestInfo->info.options, requestInfo->info.token, - requestInfo->info.tokenLength, requestInfo->info.resourceUri); - OICFree(serverRequest.payload); - return; - } - memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength); - - switch (requestInfo->info.acceptFormat) + if (!serverRequest.requestToken) + { + OIC_LOG(FATAL, TAG, "Allocation for token failed."); + SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR, + requestInfo->info.type, requestInfo->info.numOptions, + requestInfo->info.options, requestInfo->info.token, + requestInfo->info.tokenLength, requestInfo->info.resourceUri, + CA_RESPONSE_DATA); + OICFree(serverRequest.payload); + return; + } + memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength); + } + + switch (requestInfo->info.acceptFormat) { case CA_FORMAT_APPLICATION_CBOR: serverRequest.acceptFormat = OC_FORMAT_CBOR; @@ -1648,34 +2196,74 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum); if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS) { - OC_LOG(ERROR, TAG, + OIC_LOG(ERROR, TAG, "The request info numOptions is greater than MAX_HEADER_OPTIONS"); SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_OPT, requestInfo->info.type, requestInfo->info.numOptions, requestInfo->info.options, requestInfo->info.token, - requestInfo->info.tokenLength, requestInfo->info.resourceUri); + requestInfo->info.tokenLength, requestInfo->info.resourceUri, + CA_RESPONSE_DATA); OICFree(serverRequest.payload); OICFree(serverRequest.requestToken); return; } + serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum; - if (serverRequest.numRcvdVendorSpecificHeaderOptions) + if (serverRequest.numRcvdVendorSpecificHeaderOptions && requestInfo->info.options) { - memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options, + serverRequest.rcvdVendorSpecificHeaderOptions = (OCHeaderOption*) OICCalloc(tempNum, sizeof(OCHeaderOption)); + if (NULL == serverRequest.rcvdVendorSpecificHeaderOptions) + { + OIC_LOG(ERROR, TAG, "Failed to allocated memory to vnd header options!"); + OICFree(serverRequest.payload); + OICFree(serverRequest.requestToken); + return; + } + + memcpy (serverRequest.rcvdVendorSpecificHeaderOptions, requestInfo->info.options, sizeof(CAHeaderOption_t)*tempNum); } requestResult = HandleStackRequests (&serverRequest); // Send ACK to client as precursor to slow response - if(requestResult == OC_STACK_SLOW_RESOURCE) + if (requestResult == OC_STACK_SLOW_RESOURCE) + { + if (requestInfo->info.type == CA_MSG_CONFIRM) + { + SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_EMPTY, + CA_MSG_ACKNOWLEDGE,0, NULL, NULL, 0, NULL, + CA_RESPONSE_DATA); + } + } +#ifndef __TIZENRT__ + if (requestResult == OC_STACK_RESOURCE_ERROR + && serverRequest.observationOption == OC_OBSERVE_REGISTER) + { + OIC_LOG_V(ERROR, TAG, "Observe Registration failed due to resource error"); + } +#else + if (serverRequest.observationOption == OC_OBSERVE_REGISTER) { - SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_EMPTY, - CA_MSG_ACKNOWLEDGE,0, NULL, NULL, 0, NULL); + if (requestResult == OC_STACK_RESOURCE_ERROR) + { + OIC_LOG_V(ERROR, TAG, "Observe Registration failed due to resource error"); + } + else if (!OCResultToSuccess(requestResult)) + { + DeleteObserverUsingToken(requestInfo->info.token, requestInfo->info.tokenLength); + } } - else if(requestResult != OC_STACK_OK) +#endif + else if(!OCResultToSuccess(requestResult)) { - OC_LOG_V(ERROR, TAG, "HandleStackRequests failed. error: %d", requestResult); + OIC_LOG_V(ERROR, TAG, "HandleStackRequests failed. error: %d", requestResult); + + // Delete observer node if it is OBSERVE failure from app + if (serverRequest.observationOption == OC_OBSERVE_REGISTER) + { + DeleteObserverUsingToken(requestInfo->info.token, requestInfo->info.tokenLength); + } CAResponseResult_t stackResponse = OCToCAStackResult(requestResult, serverRequest.method); @@ -1683,114 +2271,89 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque SendDirectStackResponse(endPoint, requestInfo->info.messageId, stackResponse, requestInfo->info.type, requestInfo->info.numOptions, requestInfo->info.options, requestInfo->info.token, - requestInfo->info.tokenLength, requestInfo->info.resourceUri); + requestInfo->info.tokenLength, requestInfo->info.resourceUri, + CA_RESPONSE_DATA); } // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest. // The token is copied in there, and is thus still owned by this function. OICFree(serverRequest.payload); OICFree(serverRequest.requestToken); - OC_LOG(INFO, TAG, "Exit HandleCARequests"); + OICFree(serverRequest.rcvdVendorSpecificHeaderOptions); + OIC_LOG(INFO, TAG, "Exit OCHandleRequests"); } -OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest) +//This function will be called back by CA layer when a request is received +void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* requestInfo) { - OC_LOG(INFO, TAG, "Entering HandleStackRequests (OCStack Layer)"); - OCStackResult result = OC_STACK_ERROR; - ResourceHandling resHandling; - OCResource *resource; - if(!protocolRequest) - { - OC_LOG(ERROR, TAG, "protocolRequest is NULL"); - return OC_STACK_INVALID_PARAM; - } - - OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken, - protocolRequest->tokenLength); - if(!request) - { - OC_LOG(INFO, TAG, "This is a new Server Request"); - result = AddServerRequest(&request, protocolRequest->coapID, - protocolRequest->delayedResNeeded, 0, protocolRequest->method, - protocolRequest->numRcvdVendorSpecificHeaderOptions, - protocolRequest->observationOption, protocolRequest->qos, - protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions, - protocolRequest->payload, protocolRequest->requestToken, - protocolRequest->tokenLength, protocolRequest->resourceUrl, - protocolRequest->reqTotalSize, protocolRequest->acceptFormat, - &protocolRequest->devAddr); - if (OC_STACK_OK != result) - { - OC_LOG(ERROR, TAG, "Error adding server request"); - return result; - } - - if(!request) - { - OC_LOG(ERROR, TAG, "Out of Memory"); - return OC_STACK_NO_MEMORY; - } - - if(!protocolRequest->reqMorePacket) - { - request->requestComplete = 1; - } - } - else + OIC_LOG(INFO, TAG, "Enter HandleCARequests"); + OIC_TRACE_BEGIN(%s:HandleCARequests, TAG); + if(!endPoint) { - OC_LOG(INFO, TAG, "This is either a repeated or blocked Server Request"); + OIC_LOG(ERROR, TAG, "endPoint is NULL"); + OIC_TRACE_END(); + return; } - if(request->requestComplete) - { - OC_LOG(INFO, TAG, "This Server Request is complete"); - result = DetermineResourceHandling (request, &resHandling, &resource); - if (result == OC_STACK_OK) - { - result = ProcessRequest(resHandling, resource, request); - } - } - else + if(!requestInfo) { - OC_LOG(INFO, TAG, "This Server Request is incomplete"); - result = OC_STACK_CONTINUE; + OIC_LOG(ERROR, TAG, "requestInfo is NULL"); + OIC_TRACE_END(); + return; } - return result; -} - -bool validatePlatformInfo(OCPlatformInfo info) -{ - if (!info.platformID) +#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) +#ifdef ROUTING_GATEWAY + bool needRIHandling = false; + bool isEmptyMsg = false; + /* + * Routing manager is going to update either of endpoint or request or both. + * This typecasting is done to avoid unnecessary duplication of Endpoint and requestInfo + * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper + * destination. It can also remove "RM" coap header option before passing request / response to + * RI as this option will make no sense to either RI or application. + */ + OCStackResult ret = RMHandleRequest((CARequestInfo_t *)requestInfo, (CAEndpoint_t *)endPoint, + &needRIHandling, &isEmptyMsg); + if(OC_STACK_OK != ret || !needRIHandling) { - OC_LOG(ERROR, TAG, "No platform ID found."); - return false; + OIC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret); + OIC_TRACE_END(); + return; } +#endif - if (info.manufacturerName) - { - size_t lenManufacturerName = strlen(info.manufacturerName); + /* + * Put source in sender endpoint so that the next packet from application can be routed to + * proper destination and remove RM header option. + */ + RMUpdateInfo((CAHeaderOption_t **) &(requestInfo->info.options), + (uint8_t *) &(requestInfo->info.numOptions), + (CAEndpoint_t *) endPoint); - if(lenManufacturerName == 0 || lenManufacturerName > MAX_MANUFACTURER_NAME_LENGTH) - { - OC_LOG(ERROR, TAG, "Manufacturer name fails length requirements."); - return false; - } +#ifdef ROUTING_GATEWAY + if (isEmptyMsg) + { + /* + * In Gateways, the MSGType in route option is used to check if the actual + * response is EMPTY message(4 bytes CoAP Header). In case of Client, the + * EMPTY response is sent in the form of POST request which need to be changed + * to a EMPTY response by RM. This translation is done in this part of the code. + */ + OIC_LOG(INFO, TAG, "This is a Empty response from the Client"); + CAResponseInfo_t respInfo = {.result = CA_EMPTY, + .info.messageId = requestInfo->info.messageId, + .info.type = CA_MSG_ACKNOWLEDGE}; + OCHandleResponse(endPoint, &respInfo); } else +#endif +#endif { - OC_LOG(ERROR, TAG, "No manufacturer name present"); - return false; - } - - if (info.manufacturerUrl) - { - if(strlen(info.manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH) - { - OC_LOG(ERROR, TAG, "Manufacturer url fails length requirements."); - return false; - } + // Normal handling of the packet + OCHandleRequests(endPoint, requestInfo); } - return true; + OIC_LOG(INFO, TAG, "Exit HandleCARequests"); + OIC_TRACE_END(); } //----------------------------------------------------------------------------- @@ -1823,9 +2386,19 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlags clientFlags) { + OC_UNUSED(serverFlags); + OC_UNUSED(clientFlags); + + OIC_LOG(DEBUG, TAG, "call OCInit1"); + return OCInit2(mode, OC_DEFAULT_FLAGS, OC_DEFAULT_FLAGS, OC_DEFAULT_ADAPTER); +} + +OCStackResult OCInit2(OCMode mode, OCTransportFlags serverFlags, OCTransportFlags clientFlags, + OCTransportAdapter transportType) +{ if(stackState == OC_STACK_INITIALIZED) { - OC_LOG(INFO, TAG, "Subsequent calls to OCInit() without calling \ + OIC_LOG(INFO, TAG, "Subsequent calls to OCInit() without calling \ OCStop() between them are ignored."); return OC_STACK_OK; } @@ -1833,7 +2406,7 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag #ifndef ROUTING_GATEWAY if (OC_GATEWAY == mode) { - OC_LOG(ERROR, TAG, "Routing Manager not supported"); + OIC_LOG(ERROR, TAG, "Routing Manager not supported"); return OC_STACK_INVALID_PARAM; } #endif @@ -1841,19 +2414,19 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag #ifdef RA_ADAPTER if(!gRASetInfo) { - OC_LOG(ERROR, TAG, "Need to call OCSetRAInfo before calling OCInit"); + OIC_LOG(ERROR, TAG, "Need to call OCSetRAInfo before calling OCInit"); return OC_STACK_ERROR; } #endif OCStackResult result = OC_STACK_ERROR; - OC_LOG(INFO, TAG, "Entering OCInit"); + OIC_LOG(INFO, TAG, "Entering OCInit"); // Validate mode if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER) || (mode == OC_GATEWAY))) { - OC_LOG(ERROR, TAG, "Invalid mode"); + OIC_LOG(ERROR, TAG, "Invalid mode"); return OC_STACK_ERROR; } myStackMode = mode; @@ -1880,12 +2453,18 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag defaultDeviceHandler = NULL; defaultDeviceHandlerCallbackParameter = NULL; - OCSeedRandom(); - result = CAResultToOCResult(CAInitialize()); + result = InitializeScheduleResourceList(); + VERIFY_SUCCESS(result, OC_STACK_OK); + + result = CAResultToOCResult(CAInitialize((CATransportAdapter_t)transportType)); + VERIFY_SUCCESS(result, OC_STACK_OK); + + result = CAResultToOCResult(OCSelectNetwork(transportType)); VERIFY_SUCCESS(result, OC_STACK_OK); - result = CAResultToOCResult(OCSelectNetwork()); + result = CAResultToOCResult(CARegisterNetworkMonitorHandler( + OCDefaultAdapterStateChangedHandler, OCDefaultConnectionStateChangedHandler)); VERIFY_SUCCESS(result, OC_STACK_OK); switch (myStackMode) @@ -1893,12 +2472,12 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag case OC_CLIENT: CARegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); result = CAResultToOCResult(CAStartDiscoveryServer()); - OC_LOG(INFO, TAG, "Client mode: CAStartDiscoveryServer"); + OIC_LOG(INFO, TAG, "Client mode: CAStartDiscoveryServer"); break; case OC_SERVER: SRMRegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); result = CAResultToOCResult(CAStartListeningServer()); - OC_LOG(INFO, TAG, "Server mode: CAStartListeningServer"); + OIC_LOG(INFO, TAG, "Server mode: CAStartListeningServer"); break; case OC_CLIENT_SERVER: case OC_GATEWAY: @@ -1912,6 +2491,10 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag } VERIFY_SUCCESS(result, OC_STACK_OK); +#ifdef TCP_ADAPTER + CARegisterKeepAliveHandler(OCHandleKeepAliveConnCB); +#endif + #ifdef WITH_PRESENCE PresenceTimeOutSize = sizeof (PresenceTimeOut) / sizeof (PresenceTimeOut[0]) - 1; #endif // WITH_PRESENCE @@ -1931,18 +2514,30 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag result = SRMInitPolicyEngine(); // TODO after BeachHead delivery: consolidate into single SRMInit() } - +#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP) + RMSetStackMode(mode); #ifdef ROUTING_GATEWAY if (OC_GATEWAY == myStackMode) { result = RMInitialize(); } #endif +#endif + +#ifdef TCP_ADAPTER + if (result == OC_STACK_OK) + { + result = OCInitializeKeepAlive(myStackMode); + } +#endif + + InitializeObserverList(); exit: if(result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Stack initialization error"); + OIC_LOG(ERROR, TAG, "Stack initialization error"); + TerminateScheduleResourceList(); deleteAllResources(); CATerminate(); stackState = OC_STACK_UNINITIALIZED; @@ -1952,25 +2547,33 @@ exit: OCStackResult OCStop() { - OC_LOG(INFO, TAG, "Entering OCStop"); + OIC_LOG(INFO, TAG, "Entering OCStop"); if (stackState == OC_STACK_UNINIT_IN_PROGRESS) { - OC_LOG(DEBUG, TAG, "Stack already stopping, exiting"); + OIC_LOG(DEBUG, TAG, "Stack already stopping, exiting"); return OC_STACK_OK; } else if (stackState != OC_STACK_INITIALIZED) { - OC_LOG(ERROR, TAG, "Stack not initialized"); + OIC_LOG(INFO, TAG, "Stack not initialized"); return OC_STACK_ERROR; } + // unset cautil config + CAUtilConfig_t configs = {(CATransportBTFlags_t)CA_DEFAULT_BT_FLAGS}; + CAUtilSetBTConfigure(configs); + stackState = OC_STACK_UNINIT_IN_PROGRESS; + CAUnregisterNetworkMonitorHandler(OCDefaultAdapterStateChangedHandler, + OCDefaultConnectionStateChangedHandler); + #ifdef WITH_PRESENCE // Ensure that the TTL associated with ANY and ALL presence notifications originating from // here send with the code "OC_STACK_PRESENCE_STOPPED" result. presenceResource.presenceTTL = 0; + presenceState = OC_PRESENCE_UNINITIALIZED; #endif // WITH_PRESENCE #ifdef ROUTING_GATEWAY @@ -1980,20 +2583,26 @@ OCStackResult OCStop() } #endif - // Free memory dynamically allocated for resources - deleteAllResources(); - DeleteDeviceInfo(); - DeletePlatformInfo(); - CATerminate(); +#ifdef TCP_ADAPTER + OCTerminateKeepAlive(myStackMode); +#endif + + TerminateScheduleResourceList(); // Remove all observers DeleteObserverList(); + // Free memory dynamically allocated for resources + deleteAllResources(); // Remove all the client callbacks DeleteClientCBList(); + // Terminate connectivity-abstraction layer. + CATerminate(); // De-init the SRM Policy Engine // TODO after BeachHead delivery: consolidate into single SRMDeInit() SRMDeInitPolicyEngine(); + // Destroy Observer List Mutex + TerminateObserverList(); stackState = OC_STACK_UNINITIALIZED; return OC_STACK_OK; @@ -2003,13 +2612,13 @@ OCStackResult OCStartMulticastServer() { if(stackState != OC_STACK_INITIALIZED) { - OC_LOG(ERROR, TAG, "OCStack is not initalized. Cannot start multicast server."); + OIC_LOG(ERROR, TAG, "OCStack is not initalized. Cannot start multicast server."); return OC_STACK_ERROR; } CAResult_t ret = CAStartListeningServer(); if (CA_STATUS_OK != ret) { - OC_LOG_V(ERROR, TAG, "Failed starting listening server: %d", ret); + OIC_LOG_V(ERROR, TAG, "Failed starting listening server: %d", ret); return OC_STACK_ERROR; } return OC_STACK_OK; @@ -2020,7 +2629,7 @@ OCStackResult OCStopMulticastServer() CAResult_t ret = CAStopListeningServer(); if (CA_STATUS_OK != ret) { - OC_LOG_V(ERROR, TAG, "Failed stopping listening server: %d", ret); + OIC_LOG_V(ERROR, TAG, "Failed stopping listening server: %d", ret); return OC_STACK_ERROR; } return OC_STACK_OK; @@ -2040,51 +2649,12 @@ CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos) } } -OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen) -{ - char *query; - - query = strchr (inputUri, '?'); - - if (query != NULL) - { - if((query - inputUri) > MAX_URI_LENGTH) - { - return OC_STACK_INVALID_URI; - } - - if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH) - { - return OC_STACK_INVALID_QUERY; - } - } - else if(uriLen > MAX_URI_LENGTH) - { - return OC_STACK_INVALID_URI; - } - return OC_STACK_OK; -} - -/** - * A request uri consists of the following components in order: - * example - * optionally one of - * CoAP over UDP prefix "coap://" - * CoAP over TCP prefix "coap+tcp://" - * optionally one of - * IPv6 address "[1234::5678]" - * IPv4 address "192.168.1.1" - * optional port ":5683" - * resource uri "/oc/core..." - * - * for PRESENCE requests, extract resource type. - */ -static OCStackResult ParseRequestUri(const char *fullUri, - OCTransportAdapter adapter, - OCTransportFlags flags, - OCDevAddr **devAddr, - char **resourceUri, - char **resourceType) +OCStackResult ParseRequestUri(const char *fullUri, + OCTransportAdapter adapter, + OCTransportFlags flags, + OCDevAddr **devAddr, + char **resourceUri, + char **resourceType) { VERIFY_NON_NULL(fullUri, FATAL, OC_STACK_INVALID_CALLBACK); @@ -2125,7 +2695,8 @@ static OCStackResult ParseRequestUri(const char *fullUri, bool istcp = false; if (prefixLen) { - if ((prefixLen == sizeof(COAP_TCP) - 1) && (!strncmp(fullUri, COAP_TCP, prefixLen))) + if (((prefixLen == sizeof(COAP_TCP_SCHEME) - 1) && (!strncmp(fullUri, COAP_TCP_SCHEME, prefixLen))) + || ((prefixLen == sizeof(COAPS_TCP_SCHEME) - 1) && (!strncmp(fullUri, COAPS_TCP_SCHEME, prefixLen)))) { istcp = true; } @@ -2151,7 +2722,15 @@ static OCStackResult ParseRequestUri(const char *fullUri, { colon = close + 1; } - adapter = (OCTransportAdapter)(adapter | OC_ADAPTER_IP); + + if (istcp) + { + adapter = (OCTransportAdapter)(adapter | OC_ADAPTER_TCP); + } + else + { + adapter = (OCTransportAdapter)(adapter | OC_ADAPTER_IP); + } flags = (OCTransportFlags)(flags | OC_IP_USE_V6); } else @@ -2163,14 +2742,15 @@ static OCStackResult ParseRequestUri(const char *fullUri, end = (colon && colon < slash) ? colon : slash; if (istcp) - { // coap over tcp + { + // coap over tcp adapter = (OCTransportAdapter)(adapter | OC_ADAPTER_TCP); } else { adapter = (OCTransportAdapter)(adapter | OC_ADAPTER_IP); - flags = (OCTransportFlags)(flags | OC_IP_USE_V4); } + flags = (OCTransportFlags)(flags | OC_IP_USE_V4); } else { // MAC address @@ -2207,11 +2787,19 @@ static OCStackResult ParseRequestUri(const char *fullUri, { return OC_STACK_NO_MEMORY; } - OICStrcpyPartial(da->addr, sizeof(da->addr), start, len); + + // Decode address per RFC 6874. + result = OCDecodeAddressForRFC6874(da->addr, sizeof(da->addr), start, end); + if (result != OC_STACK_OK) + { + OICFree(*devAddr); + return result; + } + da->port = port; da->adapter = adapter; da->flags = flags; - if (!strncmp(fullUri, "coaps:", 6)) + if (!strncmp(fullUri, "coaps", 5)) { da->flags = (OCTransportFlags)(da->flags|CA_SECURE); } @@ -2241,7 +2829,7 @@ static OCStackResult ParseRequestUri(const char *fullUri, result = OC_STACK_NO_MEMORY; goto error; } - strcpy(*resourceUri, slash); + OICStrcpy(*resourceUri, (ulen + 1), slash); } // resource type if (type && resourceType) @@ -2276,12 +2864,14 @@ error: return result; } +#ifdef WITH_PRESENCE static OCStackResult OCPreparePresence(CAEndpoint_t *endpoint, - char *resourceUri, char **requestUri) + char **requestUri, + bool isMulticast) { char uri[CA_MAX_URI_LENGTH]; - FormCanonicalPresenceUri(endpoint, resourceUri, uri); + FormCanonicalPresenceUri(endpoint, uri, isMulticast); *requestUri = OICStrdup(uri); if (!*requestUri) @@ -2291,6 +2881,7 @@ static OCStackResult OCPreparePresence(CAEndpoint_t *endpoint, return OC_STACK_OK; } +#endif // WITH_PRESENCE /** * Discover or Perform requests on a specified resource @@ -2306,12 +2897,34 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCHeaderOption *options, uint8_t numOptions) { - OC_LOG(INFO, TAG, "Entering OCDoResource"); + OCStackResult ret = OCDoRequest(handle, method, requestUri,destination, payload, + connectivityType, qos, cbData, options, numOptions); + + // This is the owner of the payload object, so we free it + OCPayloadDestroy(payload); + return ret; +} + +/** + * Discover or Perform requests on a specified resource + */ +OCStackResult OCDoRequest(OCDoHandle *handle, + OCMethod method, + const char *requestUri, + const OCDevAddr *destination, + OCPayload* payload, + OCConnectivityType connectivityType, + OCQualityOfService qos, + OCCallbackData *cbData, + OCHeaderOption *options, + uint8_t numOptions) +{ + OIC_LOG(INFO, TAG, "Entering OCDoResource"); + OIC_TRACE_BEGIN(%s:OCDoRequest, TAG); // Validate input parameters VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK); VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK); - VERIFY_NON_NULL(requestUri , FATAL, OC_STACK_INVALID_URI); OCStackResult result = OC_STACK_ERROR; CAResult_t caResult; @@ -2331,24 +2944,24 @@ OCStackResult OCDoResource(OCDoHandle *handle, char *resourceUri = NULL; char *resourceType = NULL; - // This validation is broken, but doesn't cause harm - size_t uriLen = strlen(requestUri ); - if ((result = verifyUriQueryLength(requestUri , uriLen)) != OC_STACK_OK) - { - goto exit; - } - /* * Support original behavior with address on resourceUri argument. */ adapter = (OCTransportAdapter)(connectivityType >> CT_ADAPTER_SHIFT); flags = (OCTransportFlags)(connectivityType & CT_MASK_FLAGS); - result = ParseRequestUri(requestUri, adapter, flags, &devAddr, &resourceUri, &resourceType); - - if (result != OC_STACK_OK) + if (requestUri) + { + result = ParseRequestUri(requestUri, adapter, flags, &devAddr, &resourceUri, &resourceType); + if (result != OC_STACK_OK) + { + OIC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", requestUri); + goto exit; + } + } + else if (!checkProxyUri(options, numOptions)) { - OC_LOG_V(DEBUG, TAG, "Unable to parse uri: %s", requestUri); + OIC_LOG(ERROR, TAG, "Request doesn't contain RequestURI/Proxy URI"); goto exit; } @@ -2357,7 +2970,6 @@ OCStackResult OCDoResource(OCDoHandle *handle, case OC_REST_GET: case OC_REST_OBSERVE: case OC_REST_OBSERVE_ALL: - case OC_REST_CANCEL_OBSERVE: requestInfo.method = CA_GET; break; case OC_REST_PUT: @@ -2370,7 +2982,9 @@ OCStackResult OCDoResource(OCDoHandle *handle, requestInfo.method = CA_DELETE; break; case OC_REST_DISCOVER: - qos = OC_LOW_QOS; +#ifdef WITH_PRESENCE + case OC_REST_PRESENCE: +#endif if (destination || devAddr) { requestInfo.isMulticast = false; @@ -2381,17 +2995,13 @@ OCStackResult OCDoResource(OCDoHandle *handle, tmpDevAddr.flags = flags; destination = &tmpDevAddr; requestInfo.isMulticast = true; + qos = OC_LOW_QOS; } - // CA_DISCOVER will become GET and isMulticast - requestInfo.method = CA_GET; - break; -#ifdef WITH_PRESENCE - case OC_REST_PRESENCE: - // Replacing method type with GET because "presence" - // is a stack layer only implementation. + // OC_REST_DISCOVER: CA_DISCOVER will become GET and isMulticast. + // OC_REST_PRESENCE: Since "presence" is a stack layer only implementation. + // replacing method type with GET. requestInfo.method = CA_GET; break; -#endif default: result = OC_STACK_INVALID_METHOD; goto exit; @@ -2399,7 +3009,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, if (!devAddr && !destination) { - OC_LOG(DEBUG, TAG, "no devAddr and no destination"); + OIC_LOG(DEBUG, TAG, "no devAddr and no destination"); result = OC_STACK_INVALID_PARAM; goto exit; } @@ -2413,9 +3023,20 @@ OCStackResult OCDoResource(OCDoHandle *handle, result = OC_STACK_NO_MEMORY; goto exit; } + OIC_LOG(DEBUG, TAG, "devAddr is set as destination"); *devAddr = *destination; } + if (devAddr) + { + OIC_LOG_V(INFO_PRIVATE, TAG, "remoteId of devAddr : %s", devAddr->remoteId); + if (!requestInfo.isMulticast) + { + OIC_LOG_V(DEBUG, TAG, "remoteAddr of devAddr : [%s]:[%d]", + devAddr->addr, devAddr->port); + } + } + resHandle = GenerateInvocationHandle(); if (!resHandle) { @@ -2426,7 +3047,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, caResult = CAGenerateToken(&token, tokenLength); if (caResult != CA_STATUS_OK) { - OC_LOG(ERROR, TAG, "CAGenerateToken error"); + OIC_LOG(ERROR, TAG, "CAGenerateToken error"); result= OC_STACK_ERROR; goto exit; } @@ -2435,7 +3056,6 @@ OCStackResult OCDoResource(OCDoHandle *handle, requestInfo.info.type = qualityOfServiceToMessageType(qos); requestInfo.info.token = token; requestInfo.info.tokenLength = tokenLength; - requestInfo.info.resourceUri = resourceUri; if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL)) { @@ -2464,7 +3084,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCConvertPayload(payload, &requestInfo.info.payload, &requestInfo.info.payloadSize)) != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Failed to create CBOR Payload"); + OIC_LOG(ERROR, TAG, "Failed to create CBOR Payload"); goto exit; } requestInfo.info.payloadFormat = CA_FORMAT_APPLICATION_CBOR; @@ -2476,18 +3096,13 @@ OCStackResult OCDoResource(OCDoHandle *handle, requestInfo.info.payloadFormat = CA_FORMAT_UNDEFINED; } - if (result != OC_STACK_OK) - { - OC_LOG(ERROR, TAG, "CACreateEndpoint error"); - goto exit; - } - // prepare for response #ifdef WITH_PRESENCE if (method == OC_REST_PRESENCE) { char *presenceUri = NULL; - result = OCPreparePresence(&endpoint, resourceUri, &presenceUri); + result = OCPreparePresence(&endpoint, &presenceUri, + requestInfo.isMulticast); if (OC_STACK_OK != result) { goto exit; @@ -2496,10 +3111,17 @@ OCStackResult OCDoResource(OCDoHandle *handle, // Assign full presence uri as coap://ip:port/oic/ad to add to callback list. // Presence notification will form a canonical uri to // look for callbacks into the application. + if (resourceUri) + { + OICFree(resourceUri); + } resourceUri = presenceUri; } #endif + // update resourceUri onto requestInfo after check presence uri + requestInfo.info.resourceUri = resourceUri; + ttl = GetTicks(MAX_CB_TIMEOUT_SECONDS * MILLISECONDS_PER_SECOND); result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method, devAddr, resourceUri, resourceType, ttl); @@ -2508,10 +3130,26 @@ OCStackResult OCDoResource(OCDoHandle *handle, goto exit; } + cbData = NULL; // Client CB list entry now owns it + token = NULL; // Client CB list entry now owns it devAddr = NULL; // Client CB list entry now owns it resourceUri = NULL; // Client CB list entry now owns it resourceType = NULL; // Client CB list entry now owns it +#ifdef WITH_PRESENCE + if (method == OC_REST_PRESENCE) + { + OIC_LOG(ERROR, TAG, "AddClientCB for presence done."); + + if (handle) + { + *handle = resHandle; + } + + goto exit; + } +#endif + // send request result = OCSendRequest(&endpoint, &requestInfo); if (OC_STACK_OK != result) @@ -2527,8 +3165,12 @@ OCStackResult OCDoResource(OCDoHandle *handle, exit: if (result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "OCDoResource error"); - FindAndDeleteClientCB(clientCB); + OIC_LOG(ERROR, TAG, "OCDoResource error"); + if (NULL != cbData && NULL != cbData->cd) + { + cbData->cd(cbData->context); + } + FindAndDeleteClientCB(clientCB); CADestroyToken(token); if (handle) { @@ -2537,13 +3179,12 @@ exit: OICFree(resHandle); } - // This is the owner of the payload object, so we free it - OCPayloadDestroy(payload); OICFree(requestInfo.info.payload); OICFree(devAddr); OICFree(resourceUri); OICFree(resourceType); OICFree(requestInfo.info.options); + OIC_TRACE_END(); return result; } @@ -2579,7 +3220,7 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL); if (!clientCB) { - OC_LOG(ERROR, TAG, "Callback not found. Called OCCancel on same resource twice?"); + OIC_LOG(ERROR, TAG, "Callback not found. Called OCCancel on same resource twice?"); return OC_STACK_ERROR; } @@ -2588,15 +3229,17 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption case OC_REST_OBSERVE: case OC_REST_OBSERVE_ALL: - OC_LOG_V(INFO, TAG, "Canceling observation for resource %s", - clientCB->requestUri); - if (qos != OC_HIGH_QOS) + OIC_LOG_V(INFO, TAG, "Canceling observation for resource %s", clientCB->requestUri); + + CopyDevAddrToEndpoint(clientCB->devAddr, &endpoint); + + if ((endpoint.adapter & CA_ADAPTER_IP) && qos != OC_HIGH_QOS) { FindAndDeleteClientCB(clientCB); break; } - OC_LOG(INFO, TAG, "Cancelling observation as CONFIRMABLE"); + OIC_LOG(INFO, TAG, "Cancelling observation as CONFIRMABLE"); requestInfo.info.type = qualityOfServiceToMessageType(qos); requestInfo.info.token = clientCB->token; @@ -2610,7 +3253,6 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption requestInfo.info.numOptions = numOptions + 1; requestInfo.info.resourceUri = OICStrdup (clientCB->requestUri); - CopyDevAddrToEndpoint(clientCB->devAddr, &endpoint); ret = OCSendRequest(&endpoint, &requestInfo); @@ -2626,7 +3268,7 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption break; case OC_REST_DISCOVER: - OC_LOG_V(INFO, TAG, "Cancelling discovery callback for resource %s", + OIC_LOG_V(INFO, TAG, "Cancelling discovery callback for resource %s", clientCB->requestUri); FindAndDeleteClientCB(clientCB); break; @@ -2636,6 +3278,14 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption FindAndDeleteClientCB(clientCB); break; #endif + case OC_REST_GET: + case OC_REST_PUT: + case OC_REST_POST: + case OC_REST_DELETE: + OIC_LOG_V(INFO, TAG, "Cancelling request callback for resource %s", + clientCB->requestUri); + FindAndDeleteClientCB(clientCB); + break; default: ret = OC_STACK_INVALID_METHOD; @@ -2654,10 +3304,10 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption */ OCStackResult OCRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler) { - OC_LOG(INFO, TAG, "RegisterPersistentStorageHandler !!"); + OIC_LOG(INFO, TAG, "RegisterPersistentStorageHandler !!"); if(!persistentStorageHandler) { - OC_LOG(ERROR, TAG, "The persistent storage handler is invalid"); + OIC_LOG(ERROR, TAG, "The persistent storage handler is invalid"); return OC_STACK_INVALID_PARAM; } else @@ -2668,7 +3318,7 @@ OCStackResult OCRegisterPersistentStorageHandler(OCPersistentStorage* persistent !persistentStorageHandler->unlink || !persistentStorageHandler->write) { - OC_LOG(ERROR, TAG, "The persistent storage handler is invalid"); + OIC_LOG(ERROR, TAG, "The persistent storage handler is invalid"); return OC_STACK_INVALID_PARAM; } } @@ -2683,12 +3333,13 @@ OCStackResult OCProcessPresence() // the following line floods the log with messages that are irrelevant // to most purposes. Uncomment as needed. - //OC_LOG(INFO, TAG, "Entering RequestPresence"); + //OIC_LOG(INFO, TAG, "Entering RequestPresence"); ClientCB* cbNode = NULL; + ClientCB* tempcbNode = NULL; OCClientResponse clientResponse; OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION; - LL_FOREACH(cbList, cbNode) + LL_FOREACH_SAFE(cbList, cbNode, tempcbNode) { if (OC_REST_PRESENCE != cbNode->method || !cbNode->presence) { @@ -2696,9 +3347,9 @@ OCStackResult OCProcessPresence() } uint32_t now = GetTicks(0); - OC_LOG_V(DEBUG, TAG, "this TTL level %d", + OIC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel); - OC_LOG_V(DEBUG, TAG, "current ticks %d", now); + OIC_LOG_V(DEBUG, TAG, "current ticks %d", now); if (cbNode->presence->TTLlevel > PresenceTimeOutSize) { @@ -2707,12 +3358,12 @@ OCStackResult OCProcessPresence() if (cbNode->presence->TTLlevel < PresenceTimeOutSize) { - OC_LOG_V(DEBUG, TAG, "timeout ticks %d", + OIC_LOG_V(DEBUG, TAG, "timeout ticks %d", cbNode->presence->timeOut[cbNode->presence->TTLlevel]); } if (cbNode->presence->TTLlevel >= PresenceTimeOutSize) { - OC_LOG(DEBUG, TAG, "No more timeout ticks"); + OIC_LOG(DEBUG, TAG, "No more timeout ticks"); clientResponse.sequenceNumber = 0; clientResponse.result = OC_STACK_PRESENCE_TIMEOUT; @@ -2723,14 +3374,18 @@ OCStackResult OCProcessPresence() // Increment the TTLLevel (going to a next state), so we don't keep // sending presence notification to client. cbNode->presence->TTLlevel++; - OC_LOG_V(DEBUG, TAG, "moving to TTL level %d", + OIC_LOG_V(DEBUG, TAG, "moving to TTL level %d", cbNode->presence->TTLlevel); + OIC_LOG(INFO, TAG, "Before calling into application address space for presence timeout"); cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse); + OIC_LOG(INFO, TAG, "After calling into application address space for presence timeout"); + if (cbResult == OC_STACK_DELETE_TRANSACTION) { FindAndDeleteClientCB(cbNode); } + continue; } if (now < cbNode->presence->timeOut[cbNode->presence->TTLlevel]) @@ -2742,7 +3397,7 @@ OCStackResult OCProcessPresence() CAInfo_t requestData = {.type = CA_MSG_CONFIRM}; CARequestInfo_t requestInfo = {.method = CA_GET}; - OC_LOG(DEBUG, TAG, "time to test server presence"); + OIC_LOG(DEBUG, TAG, "time to test server presence"); CopyDevAddrToEndpoint(cbNode->devAddr, &endpoint); @@ -2760,12 +3415,12 @@ OCStackResult OCProcessPresence() } cbNode->presence->TTLlevel++; - OC_LOG_V(DEBUG, TAG, "moving to TTL level %d", cbNode->presence->TTLlevel); + OIC_LOG_V(DEBUG, TAG, "moving to TTL level %d", cbNode->presence->TTLlevel); } exit: if (result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "OCProcessPresence error"); + OIC_LOG(ERROR, TAG, "OCProcessPresence error"); } return result; @@ -2774,6 +3429,11 @@ exit: OCStackResult OCProcess() { + if (stackState == OC_STACK_UNINITIALIZED) + { + OIC_LOG(ERROR, TAG, "OCProcess has failed. ocstack is not initialized"); + return OC_STACK_ERROR; + } #ifdef WITH_PRESENCE OCProcessPresence(); #endif @@ -2782,12 +3442,17 @@ OCStackResult OCProcess() #ifdef ROUTING_GATEWAY RMProcess(); #endif + +#ifdef TCP_ADAPTER + OCProcessKeepAlive(); +#endif return OC_STACK_OK; } #ifdef WITH_PRESENCE OCStackResult OCStartPresence(const uint32_t ttl) { + OIC_LOG(INFO, TAG, "Entering OCStartPresence"); uint8_t tokenLength = CA_MAX_TOKEN_LEN; OCChangeResourceProperty( &(((OCResource *)presenceResource.handle)->resourceProperties), @@ -2796,18 +3461,20 @@ OCStackResult OCStartPresence(const uint32_t ttl) if (OC_MAX_PRESENCE_TTL_SECONDS < ttl) { presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS; - OC_LOG(INFO, TAG, "Setting Presence TTL to max value"); + OIC_LOG(INFO, TAG, "Setting Presence TTL to max value"); } else if (0 == ttl) { presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS; - OC_LOG(INFO, TAG, "Setting Presence TTL to default value"); + OIC_LOG(INFO, TAG, "Setting Presence TTL to default value"); } else { presenceResource.presenceTTL = ttl; } - OC_LOG_V(DEBUG, TAG, "Presence TTL is %" PRIu32 " seconds", presenceResource.presenceTTL); +#ifndef __TIZENRT__ + OIC_LOG_V(DEBUG, TAG, "Presence TTL is %" PRIu32 " seconds", presenceResource.presenceTTL); +#endif if (OC_PRESENCE_UNINITIALIZED == presenceState) { @@ -2819,7 +3486,7 @@ OCStackResult OCStartPresence(const uint32_t ttl) CAResult_t caResult = CAGenerateToken(&caToken, tokenLength); if (caResult != CA_STATUS_OK) { - OC_LOG(ERROR, TAG, "CAGenerateToken error"); + OIC_LOG(ERROR, TAG, "CAGenerateToken error"); CADestroyToken(caToken); return OC_STACK_ERROR; } @@ -2839,6 +3506,7 @@ OCStackResult OCStartPresence(const uint32_t ttl) OCStackResult OCStopPresence() { + OIC_LOG(INFO, TAG, "Entering OCStopPresence"); OCStackResult result = OC_STACK_ERROR; if(presenceResource.handle) @@ -2853,7 +3521,7 @@ OCStackResult OCStopPresence() if(result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, + OIC_LOG(ERROR, TAG, "Changing the presence resource properties to ACTIVE not successful"); return result; } @@ -2871,40 +3539,6 @@ OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandle return OC_STACK_OK; } -OCStackResult OCSetPlatformInfo(OCPlatformInfo platformInfo) -{ - OC_LOG(INFO, TAG, "Entering OCSetPlatformInfo"); - - if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER || myStackMode == OC_GATEWAY) - { - if (validatePlatformInfo(platformInfo)) - { - return SavePlatformInfo(platformInfo); - } - else - { - return OC_STACK_INVALID_PARAM; - } - } - else - { - return OC_STACK_ERROR; - } -} - -OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo) -{ - OC_LOG(INFO, TAG, "Entering OCSetDeviceInfo"); - - if (!deviceInfo.deviceName || deviceInfo.deviceName[0] == '\0') - { - OC_LOG(ERROR, TAG, "Null or empty device name."); - return OC_STACK_INVALID_PARAM; - } - - return SaveDeviceInfo(deviceInfo); -} - OCStackResult OCCreateResource(OCResourceHandle *handle, const char *resourceTypeName, const char *resourceInterfaceName, @@ -2916,7 +3550,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, OCResource *pointer = NULL; OCStackResult result = OC_STACK_ERROR; - OC_LOG(INFO, TAG, "Entering OCCreateResource"); + OIC_LOG(INFO, TAG, "Entering OCCreateResource"); if(myStackMode == OC_CLIENT) { @@ -2925,27 +3559,37 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, // Validate parameters if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH ) { - OC_LOG(ERROR, TAG, "URI is empty or too long"); + OIC_LOG(ERROR, TAG, "URI is empty or too long"); return OC_STACK_INVALID_URI; } // Is it presented during resource discovery? if (!handle || !resourceTypeName || resourceTypeName[0] == '\0' ) { - OC_LOG(ERROR, TAG, "Input parameter is NULL"); + OIC_LOG(ERROR, TAG, "Input parameter is NULL"); return OC_STACK_INVALID_PARAM; } - if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0) + if (!resourceInterfaceName || strlen(resourceInterfaceName) == 0) { resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT; } +#ifdef MQ_PUBLISHER + resourceProperties = resourceProperties | OC_MQ_PUBLISHER; +#endif // Make sure resourceProperties bitmask has allowed properties specified if (resourceProperties > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE | - OC_EXPLICIT_DISCOVERABLE)) + OC_EXPLICIT_DISCOVERABLE +#ifdef MQ_PUBLISHER + | OC_MQ_PUBLISHER +#endif +#ifdef MQ_BROKER + | OC_MQ_BROKER +#endif + )) { - OC_LOG(ERROR, TAG, "Invalid property"); + OIC_LOG(ERROR, TAG, "Invalid property"); return OC_STACK_INVALID_PARAM; } @@ -2959,7 +3603,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, { if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0) { - OC_LOG_V(ERROR, TAG, "Resource %s already exists", uri); + OIC_LOG_V(ERROR, TAG, "Resource %s already exists", uri); return OC_STACK_INVALID_PARAM; } pointer = pointer->next; @@ -2992,7 +3636,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, result = BindResourceTypeToResource(pointer, resourceTypeName); if (result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Error adding resourcetype"); + OIC_LOG(ERROR, TAG, "Error adding resourcetype"); goto exit; } @@ -3000,7 +3644,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, result = BindResourceInterfaceToResource(pointer, resourceInterfaceName); if (result != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Error adding resourceinterface"); + OIC_LOG(ERROR, TAG, "Error adding resourceinterface"); goto exit; } @@ -3017,6 +3661,9 @@ OCStackResult OCCreateResource(OCResourceHandle *handle, pointer->entityHandlerCallbackParam = NULL; } + // Initialize a pointer indicating child resources in case of collection + pointer->rsrcChildResourcesHead = NULL; + *handle = pointer; result = OC_STACK_OK; @@ -3036,14 +3683,14 @@ exit: return result; } - OCStackResult OCBindResource( OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) { OCResource *resource = NULL; - uint8_t i = 0; + OCChildResource *tempChildResource = NULL; + OCChildResource *newChildResource = NULL; - OC_LOG(INFO, TAG, "Entering OCBindResource"); + OIC_LOG(INFO, TAG, "Entering OCBindResource"); // Validate parameters VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR); @@ -3051,7 +3698,7 @@ OCStackResult OCBindResource( // Container cannot contain itself if (collectionHandle == resourceHandle) { - OC_LOG(ERROR, TAG, "Added handle equals collection handle"); + OIC_LOG(ERROR, TAG, "Added handle equals collection handle"); return OC_STACK_INVALID_PARAM; } @@ -3059,43 +3706,62 @@ OCStackResult OCBindResource( resource = findResource((OCResource *) collectionHandle); if (!resource) { - OC_LOG(ERROR, TAG, "Collection handle not found"); + OIC_LOG(ERROR, TAG, "Collection handle not found"); return OC_STACK_INVALID_PARAM; } // Look for an open slot to add add the child resource. // If found, add it and return success - for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) + + tempChildResource = resource->rsrcChildResourcesHead; + + while(resource->rsrcChildResourcesHead && tempChildResource->next) { - if (!resource->rsrcResources[i]) - { - resource->rsrcResources[i] = (OCResource *) resourceHandle; - OC_LOG(INFO, TAG, "resource bound"); + // TODO: what if one of child resource was deregistered without unbinding? + tempChildResource = tempChildResource->next; + } -#ifdef WITH_PRESENCE - if (presenceResource.handle) - { - ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); - SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType, - OC_PRESENCE_TRIGGER_CHANGE); - } -#endif - return OC_STACK_OK; + // Do memory allocation for child resource + newChildResource = (OCChildResource *) OICCalloc(1, sizeof(OCChildResource)); + if(!newChildResource) + { + OIC_LOG(ERROR, TAG, "Adding new child resource is failed due to memory allocation failure"); + return OC_STACK_ERROR; + } - } + newChildResource->rsrcResource = (OCResource *) resourceHandle; + newChildResource->next = NULL; + + if(!resource->rsrcChildResourcesHead) + { + resource->rsrcChildResourcesHead = newChildResource; + } + else { + tempChildResource->next = newChildResource; } - // Unable to add resourceHandle, so return error - return OC_STACK_ERROR; + OIC_LOG(INFO, TAG, "resource bound"); + +#ifdef WITH_PRESENCE + if (presenceResource.handle) + { + ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); + SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType, + OC_PRESENCE_TRIGGER_CHANGE); + } +#endif + + return OC_STACK_OK; } OCStackResult OCUnBindResource( OCResourceHandle collectionHandle, OCResourceHandle resourceHandle) { OCResource *resource = NULL; - uint8_t i = 0; + OCChildResource *tempChildResource = NULL; + OCChildResource *tempLastChildResource = NULL; - OC_LOG(INFO, TAG, "Entering OCUnBindResource"); + OIC_LOG(INFO, TAG, "Entering OCUnBindResource"); // Validate parameters VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR); @@ -3103,7 +3769,7 @@ OCStackResult OCUnBindResource( // Container cannot contain itself if (collectionHandle == resourceHandle) { - OC_LOG(ERROR, TAG, "removing handle equals collection handle"); + OIC_LOG(ERROR, TAG, "removing handle equals collection handle"); return OC_STACK_INVALID_PARAM; } @@ -3111,18 +3777,47 @@ OCStackResult OCUnBindResource( resource = findResource((OCResource *) collectionHandle); if (!resource) { - OC_LOG(ERROR, TAG, "Collection handle not found"); + OIC_LOG(ERROR, TAG, "Collection handle not found"); return OC_STACK_INVALID_PARAM; } // Look for an open slot to add add the child resource. // If found, add it and return success - for (i = 0; i < MAX_CONTAINED_RESOURCES; i++) + if(!resource->rsrcChildResourcesHead) + { + OIC_LOG(INFO, TAG, "resource not found in collection"); + + // Unable to add resourceHandle, so return error + return OC_STACK_ERROR; + + } + + tempChildResource = resource->rsrcChildResourcesHead; + + while (tempChildResource) { - if (resourceHandle == resource->rsrcResources[i]) + if(tempChildResource->rsrcResource == resourceHandle) { - resource->rsrcResources[i] = (OCResource *) NULL; - OC_LOG(INFO, TAG, "resource unbound"); + // if resource going to be unbinded is the head one. + if( tempChildResource == resource->rsrcChildResourcesHead ) + { + OCChildResource *temp = resource->rsrcChildResourcesHead->next; + OICFree(resource->rsrcChildResourcesHead); + resource->rsrcChildResourcesHead = temp; + temp = NULL; + } + else + { + OCChildResource *temp = tempChildResource->next; + OICFree(tempChildResource); + if (tempLastChildResource) + { + tempLastChildResource->next = temp; + temp = NULL; + } + } + + OIC_LOG(INFO, TAG, "resource unbound"); // Send notification when resource is unbounded successfully. #ifdef WITH_PRESENCE @@ -3133,39 +3828,66 @@ OCStackResult OCUnBindResource( OC_PRESENCE_TRIGGER_CHANGE); } #endif + tempChildResource = NULL; + tempLastChildResource = NULL; + return OC_STACK_OK; + } + + tempLastChildResource = tempChildResource; + tempChildResource = tempChildResource->next; } - OC_LOG(INFO, TAG, "resource not found in collection"); + OIC_LOG(INFO, TAG, "resource not found in collection"); + + tempChildResource = NULL; + tempLastChildResource = NULL; // Unable to add resourceHandle, so return error return OC_STACK_ERROR; } -// Precondition is that the parameter has been checked to not equal NULL. static bool ValidateResourceTypeInterface(const char *resourceItemName) { - if (resourceItemName[0] < 'a' || resourceItemName[0] > 'z') + if (!resourceItemName) { return false; } - - size_t index = 1; - while (resourceItemName[index] != '\0') + // Per RFC 6690 only registered values must follow the first rule below. + // At this point in time the only values registered begin with "core", and + // all other values are specified as opaque strings where multiple values + // are separated by a space. + if (strncmp(resourceItemName, CORESPEC, sizeof(CORESPEC) - 1) == 0) { - if (resourceItemName[index] != '.' && - resourceItemName[index] != '-' && - (resourceItemName[index] < 'a' || resourceItemName[index] > 'z') && - (resourceItemName[index] < '0' || resourceItemName[index] > '9')) + for(size_t index = sizeof(CORESPEC) - 1; resourceItemName[index]; ++index) { - return false; + if (resourceItemName[index] != '.' + && resourceItemName[index] != '-' + && (resourceItemName[index] < 'a' || resourceItemName[index] > 'z') + && (resourceItemName[index] < '0' || resourceItemName[index] > '9')) + { + return false; + } + } + } + else + { + for (size_t index = 0; resourceItemName[index]; ++index) + { + if (resourceItemName[index] == ' ' + || resourceItemName[index] == '\t' + || resourceItemName[index] == '\r' + || resourceItemName[index] == '\n') + { + return false; + } } - ++index; } return true; } + OCStackResult BindResourceTypeToResource(OCResource* resource, const char *resourceTypeName) { @@ -3177,7 +3899,7 @@ OCStackResult BindResourceTypeToResource(OCResource* resource, if (!ValidateResourceTypeInterface(resourceTypeName)) { - OC_LOG(ERROR, TAG, "resource type illegal (see RFC 6690)"); + OIC_LOG(ERROR, TAG, "resource type illegal (see RFC 6690)"); return OC_STACK_INVALID_PARAM; } @@ -3195,11 +3917,12 @@ OCStackResult BindResourceTypeToResource(OCResource* resource, goto exit; } pointer->resourcetypename = str; + pointer->next = NULL; insertResourceType(resource, pointer); result = OC_STACK_OK; - exit: +exit: if (result != OC_STACK_OK) { OICFree(pointer); @@ -3220,11 +3943,11 @@ OCStackResult BindResourceInterfaceToResource(OCResource* resource, if (!ValidateResourceTypeInterface(resourceInterfaceName)) { - OC_LOG(ERROR, TAG, "resource /interface illegal (see RFC 6690)"); + OIC_LOG(ERROR, TAG, "resource /interface illegal (see RFC 6690)"); return OC_STACK_INVALID_PARAM; } - OC_LOG_V(INFO, TAG, "Binding %s interface to %s", resourceInterfaceName, resource->uri); + OIC_LOG_V(INFO, TAG, "Binding %s interface to %s", resourceInterfaceName, resource->uri); pointer = (OCResourceInterface *) OICCalloc(1, sizeof(OCResourceInterface)); if (!pointer) @@ -3266,7 +3989,7 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle, resource = findResource((OCResource *) handle); if (!resource) { - OC_LOG(ERROR, TAG, "Resource not found"); + OIC_LOG(ERROR, TAG, "Resource not found"); return OC_STACK_ERROR; } @@ -3283,6 +4006,37 @@ OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle, return result; } +OCStackResult OCResetResourceTypes(OCResourceHandle handle, + const char *newResourceType) +{ + OCStackResult result = OC_STACK_ERROR; + OCResource *resource = NULL; + + resource = findResource((OCResource *) handle); + if (!resource) + { + OIC_LOG(ERROR, TAG, "Resource not found"); + return OC_STACK_ERROR; + } + + // Clear all bound resource types + deleteResourceType(resource->rsrcType); + resource->rsrcType = NULL; + + // Bind new resource type to resource + result = BindResourceTypeToResource(resource, newResourceType); + +#ifdef WITH_PRESENCE + if(presenceResource.handle) + { + ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); + SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE); + } +#endif + + return result; +} + OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle, const char *resourceInterfaceName) { @@ -3293,7 +4047,7 @@ OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle, resource = findResource((OCResource *) handle); if (!resource) { - OC_LOG(ERROR, TAG, "Resource not found"); + OIC_LOG(ERROR, TAG, "Resource not found"); return OC_STACK_ERROR; } @@ -3310,6 +4064,37 @@ OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle, return result; } +OCStackResult OCResetResourceInterfaces(OCResourceHandle handle, + const char *newResourceInterface) +{ + OCStackResult result = OC_STACK_ERROR; + OCResource *resource = NULL; + + resource = findResource((OCResource *) handle); + if (!resource) + { + OIC_LOG(ERROR, TAG, "Resource not found"); + return OC_STACK_ERROR; + } + + // Clear all bound interface + deleteResourceInterface(resource->rsrcInterface); + resource->rsrcInterface = NULL; + + // Bind new interface to resource + result = BindResourceInterfaceToResource(resource, newResourceInterface); + +#ifdef WITH_PRESENCE + if (presenceResource.handle) + { + ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom(); + SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE); + } +#endif + + return result; +} + OCStackResult OCGetNumberOfResources(uint8_t *numResources) { OCResource *pointer = headResource; @@ -3339,20 +4124,20 @@ OCStackResult OCDeleteResource(OCResourceHandle handle) { if (!handle) { - OC_LOG(ERROR, TAG, "Invalid handle for deletion"); + OIC_LOG(ERROR, TAG, "Invalid handle for deletion"); return OC_STACK_INVALID_PARAM; } OCResource *resource = findResource((OCResource *) handle); if (resource == NULL) { - OC_LOG(ERROR, TAG, "Resource not found"); + OIC_LOG(ERROR, TAG, "Resource not found"); return OC_STACK_NO_RESOURCE; } if (deleteResource((OCResource *) handle) != OC_STACK_OK) { - OC_LOG(ERROR, TAG, "Error deleting resource"); + OIC_LOG(ERROR, TAG, "Error deleting resource"); return OC_STACK_ERROR; } @@ -3458,19 +4243,30 @@ OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHa uint8_t index) { OCResource *resource = NULL; + OCChildResource *tempChildResource = NULL; + uint8_t num = 0; - if (index >= MAX_CONTAINED_RESOURCES) + resource = findResource((OCResource *) collectionHandle); + if (!resource) { return NULL; } - resource = findResource((OCResource *) collectionHandle); - if (!resource) + tempChildResource = resource->rsrcChildResourcesHead; + + while(tempChildResource) { - return NULL; + if( num == index ) + { + return tempChildResource->rsrcResource; + } + num++; + tempChildResource = tempChildResource->next; } - return resource->rsrcResources[index]; + // In this case, the number of resource handles in the collection exceeds the index + tempChildResource = NULL; + return NULL; } OCStackResult OCBindResourceHandler(OCResourceHandle handle, @@ -3486,7 +4282,7 @@ OCStackResult OCBindResourceHandler(OCResourceHandle handle, resource = findResource((OCResource *)handle); if (!resource) { - OC_LOG(ERROR, TAG, "Resource not found"); + OIC_LOG(ERROR, TAG, "Resource not found"); return OC_STACK_ERROR; } @@ -3512,7 +4308,7 @@ OCEntityHandler OCGetResourceHandler(OCResourceHandle handle) resource = findResource((OCResource *)handle); if (!resource) { - OC_LOG(ERROR, TAG, "Resource not found"); + OIC_LOG(ERROR, TAG, "Resource not found"); return NULL; } @@ -3535,6 +4331,7 @@ void incrementSequenceNumber(OCResource * resPtr) OCStackResult SendPresenceNotification(OCResourceType *resourceType, OCPresenceTrigger trigger) { + OIC_LOG(INFO, TAG, "SendPresenceNotification"); OCResource *resPtr = NULL; OCStackResult result = OC_STACK_ERROR; OCMethod method = OC_REST_PRESENCE; @@ -3558,6 +4355,7 @@ OCStackResult SendPresenceNotification(OCResourceType *resourceType, OCStackResult SendStopNotification() { + OIC_LOG(INFO, TAG, "SendStopNotification"); OCResource *resPtr = NULL; OCStackResult result = OC_STACK_ERROR; OCMethod method = OC_REST_PRESENCE; @@ -3582,7 +4380,7 @@ OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService q OCMethod method = OC_REST_NOMETHOD; uint32_t maxAge = 0; - OC_LOG(INFO, TAG, "Notifying all observers"); + OIC_LOG(INFO, TAG, "Notifying all observers"); #ifdef WITH_PRESENCE if(handle == presenceResource.handle) { @@ -3620,7 +4418,7 @@ OCNotifyListOfObservers (OCResourceHandle handle, const OCRepPayload *payload, OCQualityOfService qos) { - OC_LOG(INFO, TAG, "Entering OCNotifyListOfObservers"); + OIC_LOG(INFO, TAG, "Entering OCNotifyListOfObservers"); OCResource *resPtr = NULL; //TODO: we should allow the server to define this @@ -3645,10 +4443,11 @@ OCNotifyListOfObservers (OCResourceHandle handle, OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse) { + OIC_TRACE_BEGIN(%s:OCDoResponse, TAG); OCStackResult result = OC_STACK_ERROR; OCServerRequest *serverRequest = NULL; - OC_LOG(INFO, TAG, "Entering OCDoResponse"); + OIC_LOG(INFO, TAG, "Entering OCDoResponse"); // Validate input parameters VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM); @@ -3656,16 +4455,55 @@ OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse) // Normal response // Get pointer to request info - serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle); + serverRequest = GetServerRequestUsingHandle(ehResponse->requestHandle); if(serverRequest) { // response handler in ocserverrequest.c. Usually HandleSingleResponse. result = serverRequest->ehResponseHandler(ehResponse); } + OIC_TRACE_END(); return result; } +//#ifdef DIRECT_PAIRING +const OCDPDev_t* OCDiscoverDirectPairingDevices(unsigned short waittime) +{ + OIC_LOG(INFO, TAG, "Start OCDiscoverDirectPairingDevices"); + if(OC_STACK_OK != DPDeviceDiscovery(waittime)) + { + OIC_LOG(ERROR, TAG, "Fail to discover Direct-Pairing device"); + return NULL; + } + + return (const OCDPDev_t*)DPGetDiscoveredDevices(); +} + +const OCDPDev_t* OCGetDirectPairedDevices() +{ + return (const OCDPDev_t*)DPGetPairedDevices(); +} + +OCStackResult OCDoDirectPairing(void *ctx, OCDPDev_t* peer, OCPrm_t pmSel, char *pinNumber, + OCDirectPairingCB resultCallback) +{ + OIC_LOG(INFO, TAG, "Start OCDoDirectPairing"); + if(NULL == peer || NULL == pinNumber) + { + OIC_LOG(ERROR, TAG, "Invalid parameters"); + return OC_STACK_INVALID_PARAM; + } + if (NULL == resultCallback) + { + OIC_LOG(ERROR, TAG, "Invalid callback"); + return OC_STACK_INVALID_CALLBACK; + } + + return DPDirectPairing(ctx, (OCDirectPairingDev_t*)peer, (OicSecPrm_t)pmSel, + pinNumber, (OCDirectPairingResultCB)resultCallback); +} +//#endif // DIRECT_PAIRING + //----------------------------------------------------------------------------- // Private internal function definitions //----------------------------------------------------------------------------- @@ -3693,7 +4531,7 @@ OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty, if (resourceProperties > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW)) { - OC_LOG(ERROR, TAG, "Invalid property"); + OIC_LOG(ERROR, TAG, "Invalid property"); return OC_STACK_INVALID_PARAM; } if(!enable) @@ -3730,11 +4568,45 @@ OCStackResult initResources() &(((OCResource *) presenceResource.handle)->resourceProperties), OC_ACTIVE, 0); #endif - +#ifndef WITH_ARDUINO if (result == OC_STACK_OK) { result = SRMInitSecureResources(); } +#endif + + if(result == OC_STACK_OK) + { + CreateResetProfile(); + result = OCCreateResource(&deviceResource, + OC_RSRVD_RESOURCE_TYPE_DEVICE, + OC_RSRVD_INTERFACE_DEFAULT, + OC_RSRVD_DEVICE_URI, + NULL, + NULL, + OC_DISCOVERABLE); + if(result == OC_STACK_OK) + { + result = BindResourceInterfaceToResource((OCResource *)deviceResource, + OC_RSRVD_INTERFACE_READ); + } + } + + if(result == OC_STACK_OK) + { + result = OCCreateResource(&platformResource, + OC_RSRVD_RESOURCE_TYPE_PLATFORM, + OC_RSRVD_INTERFACE_DEFAULT, + OC_RSRVD_PLATFORM_URI, + NULL, + NULL, + OC_DISCOVERABLE); + if(result == OC_STACK_OK) + { + result = BindResourceInterfaceToResource((OCResource *)platformResource, + OC_RSRVD_INTERFACE_READ); + } + } return result; } @@ -3787,6 +4659,11 @@ void deleteAllResources() #endif // WITH_PRESENCE pointer = temp; } + memset(&platformResource, 0, sizeof(platformResource)); + memset(&deviceResource, 0, sizeof(deviceResource)); +#ifdef MQ_BROKER + memset(&brokerResource, 0, sizeof(brokerResource)); +#endif SRMDeInitSecureResources(); @@ -3794,6 +4671,7 @@ void deleteAllResources() // Ensure that the last resource to be deleted is the presence resource. This allows for all // presence notification attributed to their deletion to be processed. deleteResource((OCResource *) presenceResource.handle); + memset(&presenceResource, 0, sizeof(presenceResource)); #endif // WITH_PRESENCE } @@ -3803,11 +4681,11 @@ OCStackResult deleteResource(OCResource *resource) OCResource *temp = NULL; if(!resource) { - OC_LOG(DEBUG,TAG,"resource is NULL"); + OIC_LOG(DEBUG,TAG,"resource is NULL"); return OC_STACK_INVALID_PARAM; } - OC_LOG_V (INFO, TAG, "Deleting resource %s", resource->uri); + OIC_LOG_V (INFO, TAG, "Deleting resource %s", resource->uri); temp = headResource; while (temp) @@ -3830,6 +4708,9 @@ OCStackResult deleteResource(OCResource *resource) SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_DELETE); } #endif + // Delete resource's all observers + DeleteObserverUsingResource(resource); + // Only resource in list. if (temp == headResource && temp == tailResource) { @@ -3842,12 +4723,12 @@ OCStackResult deleteResource(OCResource *resource) headResource = temp->next; } // Deleting tail. - else if (temp == tailResource) + else if (temp == tailResource && prev) { tailResource = prev; tailResource->next = NULL; } - else + else if (prev) { prev->next = temp->next; } @@ -3873,36 +4754,99 @@ void deleteResourceElements(OCResource *resource) return; } - OICFree(resource->uri); - deleteResourceType(resource->rsrcType); - deleteResourceInterface(resource->rsrcInterface); + if (resource->uri) + { + OICFree(resource->uri); + resource->uri = NULL; + } + if (resource->rsrcType) + { + deleteResourceType(resource->rsrcType); + resource->rsrcType = NULL; + } + if (resource->rsrcInterface) + { + deleteResourceInterface(resource->rsrcInterface); + resource->rsrcInterface = NULL; + } + if (resource->rsrcChildResourcesHead) + { + unbindChildResources(resource->rsrcChildResourcesHead); + resource->rsrcChildResourcesHead = NULL; + } + if (resource->rsrcAttributes) + { + OCDeleteResourceAttributes(resource->rsrcAttributes); + resource->rsrcAttributes = NULL; + } + + resource->entityHandler = NULL; + resource = NULL; } void deleteResourceType(OCResourceType *resourceType) { - OCResourceType *pointer = resourceType; OCResourceType *next = NULL; - while (pointer) + for (OCResourceType *pointer = resourceType; pointer; pointer = next) { - next = pointer->next; - OICFree(pointer->resourcetypename); + next = pointer->next ? pointer->next : NULL; + if (pointer->resourcetypename) + { + OICFree(pointer->resourcetypename); + pointer->resourcetypename = NULL; + } OICFree(pointer); - pointer = next; } } void deleteResourceInterface(OCResourceInterface *resourceInterface) { - OCResourceInterface *pointer = resourceInterface; OCResourceInterface *next = NULL; + for (OCResourceInterface *pointer = resourceInterface; pointer; pointer = next) + { + next = pointer->next ? pointer->next : NULL; + if (pointer->name) + { + OICFree(pointer->name); + pointer->name = NULL; + } + OICFree(pointer); + } +} - while (pointer) +void unbindChildResources(OCChildResource *head) +{ + OCChildResource *next = NULL; + for (OCChildResource *current = head; current; current = next) + { + next = current->next; + OICFree(current); + } +} + +void OCDeleteResourceAttributes(OCAttribute *rsrcAttributes) +{ + OCAttribute *next = NULL; + for (OCAttribute *pointer = rsrcAttributes; pointer; pointer = next) { - next = pointer->next; - OICFree(pointer->name); + next = pointer->next ? pointer->next : NULL; + if (pointer->attrName && 0 == strcmp(OC_RSRVD_DATA_MODEL_VERSION, pointer->attrName)) + { + OCFreeOCStringLL((OCStringLL *)pointer->attrValue); + pointer->attrValue = NULL; + } + else if (pointer->attrValue) + { + OICFree(pointer->attrValue); + pointer->attrValue = NULL; + } + if (pointer->attrName) + { + OICFree(pointer->attrName); + pointer->attrName = NULL; + } OICFree(pointer); - pointer = next; } } @@ -3927,7 +4871,7 @@ void insertResourceType(OCResource *resource, OCResourceType *resourceType) { if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename)) { - OC_LOG_V(INFO, TAG, "Type %s already exists", resourceType->resourcetypename); + OIC_LOG_V(INFO, TAG, "Type %s already exists", resourceType->resourcetypename); OICFree(resourceType->resourcetypename); OICFree(resourceType); return; @@ -3935,11 +4879,15 @@ void insertResourceType(OCResource *resource, OCResourceType *resourceType) previous = pointer; pointer = pointer->next; } - previous->next = resourceType; + + if (previous) + { + previous->next = resourceType; + } } resourceType->next = NULL; - OC_LOG_V(INFO, TAG, "Added type %s to %s", resourceType->resourcetypename, resource->uri); + OIC_LOG_V(INFO, TAG, "Added type %s to %s", resourceType->resourcetypename, resource->uri); } OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index) @@ -3976,6 +4924,7 @@ OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * OCResourceType * rtPointer = resourceTypeList; while(resourceTypeName && rtPointer) { + OIC_LOG_V(DEBUG, TAG, "current resourceType : %s", rtPointer->resourcetypename); if(rtPointer->resourcetypename && strcmp(resourceTypeName, (const char *) (rtPointer->resourcetypename)) == 0) @@ -4005,19 +4954,40 @@ void insertResourceInterface(OCResource *resource, OCResourceInterface *newInter if (!*firstInterface) { - *firstInterface = newInterface; - } - else if (strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT) == 0) - { - if (strcmp((*firstInterface)->name, OC_RSRVD_INTERFACE_DEFAULT) == 0) + // If first interface is not oic.if.baseline, by default add it as first interface type. + if (0 == strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT)) { - OICFree(newInterface->name); - OICFree(newInterface); - return; + *firstInterface = newInterface; } else { - newInterface->next = *firstInterface; + OCStackResult result = BindResourceInterfaceToResource(resource, + OC_RSRVD_INTERFACE_DEFAULT); + if (result != OC_STACK_OK) + { + OICFree(newInterface->name); + OICFree(newInterface); + return; + } + if (*firstInterface) + { + (*firstInterface)->next = newInterface; + } + } + } + // If once add oic.if.baseline, later too below code take care of freeing memory. + else if (strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT) == 0) + { + if (strcmp((*firstInterface)->name, OC_RSRVD_INTERFACE_DEFAULT) == 0) + { + OICFree(newInterface->name); + OICFree(newInterface); + return; + } + // This code will not hit anymore, keeping + else + { + newInterface->next = *firstInterface; *firstInterface = newInterface; } } @@ -4035,7 +5005,11 @@ void insertResourceInterface(OCResource *resource, OCResourceInterface *newInter previous = pointer; pointer = pointer->next; } - previous->next = newInterface; + + if (previous) + { + previous->next = newInterface; + } } } @@ -4131,56 +5105,36 @@ OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithout return OC_STACK_NO_MEMORY; } -const OicUuid_t* OCGetServerInstanceID(void) -{ - static bool generated = false; - static OicUuid_t sid; - if (generated) - { - return &sid; - } - - if (GetDoxmDeviceID(&sid) != OC_STACK_OK) - { - OC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!"); - return NULL; - } - generated = true; - return &sid; -} - const char* OCGetServerInstanceIDString(void) { - static bool generated = false; static char sidStr[UUID_STRING_SIZE]; - - if(generated) + OicUuid_t sid; + if (OC_STACK_OK != GetDoxmDeviceID(&sid)) { - return sidStr; + OIC_LOG(FATAL, TAG, "GetDoxmDeviceID failed!"); + return NULL; } - const OicUuid_t* sid = OCGetServerInstanceID(); - - if(OCConvertUuidToString(sid->id, sidStr) != RAND_UUID_OK) + if (OCConvertUuidToString(sid.id, sidStr) != RAND_UUID_OK) { - OC_LOG(FATAL, TAG, "Generate UUID String for Server Instance failed!"); + OIC_LOG(FATAL, TAG, "Generate UUID String for Server Instance failed!"); return NULL; } - generated = true; return sidStr; } -CAResult_t OCSelectNetwork() +CAResult_t OCSelectNetwork(OCTransportAdapter transportType) { + OIC_LOG_V(DEBUG, TAG, "OCSelectNetwork [%d]", transportType); CAResult_t retResult = CA_STATUS_FAILED; CAResult_t caResult = CA_STATUS_OK; CATransportAdapter_t connTypes[] = { CA_ADAPTER_IP, CA_ADAPTER_RFCOMM_BTEDR, - CA_ADAPTER_GATT_BTLE - + CA_ADAPTER_GATT_BTLE, + CA_ADAPTER_NFC #ifdef RA_ADAPTER ,CA_ADAPTER_REMOTE_ACCESS #endif @@ -4191,20 +5145,28 @@ CAResult_t OCSelectNetwork() }; int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]); - for(int i = 0; iins = ins; + + return OC_STACK_OK; +} + + +OCStackResult OCUpdateResourceInsWithResponse(const char *requestUri, + const OCClientResponse *response) +{ + // Validate input parameters + VERIFY_NON_NULL(requestUri, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(response, ERROR, OC_STACK_INVALID_PARAM); + + char *targetUri = (char *) OICMalloc(strlen(requestUri) + 1); + if (!targetUri) + { + return OC_STACK_NO_MEMORY; + } + strncpy(targetUri, requestUri, strlen(requestUri) + 1); + + if (response->result == OC_STACK_RESOURCE_CHANGED) // publish message + { + OIC_LOG(DEBUG, TAG, "update the ins of published resource"); + + char rdPubUri[MAX_URI_LENGTH] = { 0 }; + snprintf(rdPubUri, MAX_URI_LENGTH, "%s?rt=%s", OC_RSRVD_RD_URI, + OC_RSRVD_RESOURCE_TYPE_RDPUBLISH); + + if (strcmp(rdPubUri, targetUri) == 0) + { + // Update resource unique id in stack. + if (response) + { + if (response->payload) + { + OCRepPayload *rdPayload = (OCRepPayload *) response->payload; + OCRepPayload **links = NULL; + size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 }; + if (OCRepPayloadGetPropObjectArray(rdPayload, OC_RSRVD_LINKS, + &links, dimensions)) + { + size_t i = 0; + for (; i < dimensions[0]; i++) + { + char *uri = NULL; + if (OCRepPayloadGetPropString(links[i], OC_RSRVD_HREF, &uri)) + { + OCResourceHandle handle = OCGetResourceHandleAtUri(uri); + int64_t ins = 0; + if (OCRepPayloadGetPropInt(links[i], OC_RSRVD_INS, &ins)) + { + OCBindResourceInsToResource(handle, ins); + } + + OICFree(uri); + uri = NULL; + } + } + + // Free links + size_t count = calcDimTotal(dimensions); + for (size_t k = 0; k < count; k++) + { + OCRepPayloadDestroy(links[k]); + } + OICFree(links); + } + } + } + } + } + else if (response->result == OC_STACK_RESOURCE_DELETED) // delete message + { + OIC_LOG(DEBUG, TAG, "update the ins of deleted resource with 0"); + + uint8_t numResources = 0; + OCGetNumberOfResources(&numResources); + + char *ins = strstr(targetUri, OC_RSRVD_INS); + if (!ins) + { + for (uint8_t i = 0; i < numResources; i++) + { + OCResourceHandle resHandle = OCGetResourceHandle(i); + if (resHandle) + { + OCBindResourceInsToResource(resHandle, 0); + } + } + } + else + { + const char *token = "&"; + char *iterTokenPtr = NULL; + char *start = strtok_r(targetUri, token, &iterTokenPtr); + + while (start != NULL) + { + char *query = start; + query = strstr(query, OC_RSRVD_INS); + if (query) + { + int64_t queryIns = atoi(query + 4); + for (uint8_t i = 0; i < numResources; i++) + { + OCResourceHandle resHandle = OCGetResourceHandle(i); + if (resHandle) + { + int64_t resIns = 0; + OCGetResourceIns(resHandle, &resIns); + if (queryIns && queryIns == resIns) + { + OCBindResourceInsToResource(resHandle, 0); + break; + } + } + } + } + start = strtok_r(NULL, token, &iterTokenPtr); + } + } + } + + OICFree(targetUri); + return OC_STACK_OK; +} + +OCResourceHandle OCGetResourceHandleAtUri(const char *uri) +{ + if (!uri) + { + OIC_LOG(ERROR, TAG, "Resource uri is NULL"); + return NULL; + } + + OCResource *pointer = headResource; + + while (pointer) + { + if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0) + { + OIC_LOG_V(DEBUG, TAG, "Found Resource %s", uri); + return pointer; + } + pointer = pointer->next; + } + return NULL; +} + +OCStackResult OCGetResourceIns(OCResourceHandle handle, int64_t *ins) +{ + OCResource *resource = NULL; + + VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(ins, ERROR, OC_STACK_INVALID_PARAM); + + resource = findResource((OCResource *) handle); + if (resource) + { + *ins = resource->ins; + return OC_STACK_OK; + } + return OC_STACK_ERROR; +} +#endif + +OCStackResult OCSetHeaderOption(OCHeaderOption* ocHdrOpt, size_t* numOptions, uint16_t optionID, + const void* optionData, size_t optionDataLength) +{ + if (!ocHdrOpt) + { + OIC_LOG (INFO, TAG, "Header options are NULL"); + return OC_STACK_INVALID_PARAM; + } + + if (!optionData) + { + OIC_LOG (INFO, TAG, "optionData are NULL"); + return OC_STACK_INVALID_PARAM; + } + + if (!numOptions) + { + OIC_LOG (INFO, TAG, "numOptions is NULL"); + return OC_STACK_INVALID_PARAM; + } + + if (*numOptions >= MAX_HEADER_OPTIONS) + { + OIC_LOG (INFO, TAG, "Exceeding MAX_HEADER_OPTIONS"); + return OC_STACK_NO_MEMORY; + } + + ocHdrOpt += *numOptions; + ocHdrOpt->protocolID = OC_COAP_ID; + ocHdrOpt->optionID = optionID; + ocHdrOpt->optionLength = + optionDataLength < MAX_HEADER_OPTION_DATA_LENGTH ? + optionDataLength : MAX_HEADER_OPTION_DATA_LENGTH; + memcpy(ocHdrOpt->optionData, (const void*) optionData, ocHdrOpt->optionLength); + *numOptions += 1; + + return OC_STACK_OK; +} + +OCStackResult OCGetHeaderOption(OCHeaderOption* ocHdrOpt, size_t numOptions, uint16_t optionID, + void* optionData, size_t optionDataLength, uint16_t* receivedDataLength) +{ + if (!ocHdrOpt || !numOptions) + { + OIC_LOG (INFO, TAG, "No options present"); + return OC_STACK_OK; + } + + if (!optionData) + { + OIC_LOG (INFO, TAG, "optionData are NULL"); + return OC_STACK_INVALID_PARAM; + } + + if (!receivedDataLength) + { + OIC_LOG (INFO, TAG, "receivedDataLength is NULL"); + return OC_STACK_INVALID_PARAM; + } + + for (uint8_t i = 0; i < numOptions; i++) + { + if (ocHdrOpt[i].optionID == optionID) + { + if (optionDataLength >= ocHdrOpt->optionLength) + { + memcpy(optionData, ocHdrOpt->optionData, ocHdrOpt->optionLength); + *receivedDataLength = ocHdrOpt->optionLength; + return OC_STACK_OK; + } + else + { + OIC_LOG (ERROR, TAG, "optionDataLength is less than the length of received data"); + return OC_STACK_ERROR; + } + } + } + return OC_STACK_OK; +} + +void OCDefaultAdapterStateChangedHandler(CATransportAdapter_t adapter, bool enabled) +{ + OIC_LOG(DEBUG, TAG, "OCDefaultAdapterStateChangedHandler"); + + OC_UNUSED(adapter); + OC_UNUSED(enabled); +} + +void OCDefaultConnectionStateChangedHandler(const CAEndpoint_t *info, bool isConnected) +{ + OIC_LOG(DEBUG, TAG, "OCDefaultConnectionStateChangedHandler"); + + /* + * If the client observes one or more resources over a reliable connection, + * then the CoAP server (or intermediary in the role of the CoAP server) + * MUST remove all entries associated with the client endpoint from the lists + * of observers when the connection is either closed or times out. + */ + if (!isConnected) + { + OCDevAddr devAddr = { OC_DEFAULT_ADAPTER }; + CopyEndpointToDevAddr(info, &devAddr); + + // remove observer list with remote device address. + DeleteObserverUsingDevAddr(&devAddr); + } +} + +OCStackResult OCGetDeviceId(OCUUIdentity *deviceId) +{ + OicUuid_t oicUuid; + OCStackResult ret = OC_STACK_ERROR; + + ret = GetDoxmDeviceID(&oicUuid); + if (OC_STACK_OK == ret) + { + memcpy(deviceId, &oicUuid, UUID_IDENTITY_SIZE); + } + else + { + OIC_LOG(ERROR, TAG, "Device ID Get error"); + } + return ret; +} + +OCStackResult OCSetDeviceId(const OCUUIdentity *deviceId) +{ + OicUuid_t oicUuid; + OCStackResult ret = OC_STACK_ERROR; + + memcpy(&oicUuid, deviceId, UUID_LENGTH); + for (int i = 0; i < UUID_LENGTH; i++) + { + OIC_LOG_V(INFO, TAG, "Set Device Id %x", oicUuid.id[i]); + } + ret = SetDoxmDeviceID(&oicUuid); + return ret; +} + +OCStackResult OCGetDeviceOwnedState(bool *isOwned) +{ + bool isDeviceOwned = true; + OCStackResult ret = OC_STACK_ERROR; + + ret = GetDoxmIsOwned(&isDeviceOwned); + if (OC_STACK_OK == ret) + { + *isOwned = isDeviceOwned; + } + else + { + OIC_LOG(ERROR, TAG, "Device Owned State Get error"); + } + return ret; +} + +OCStackResult OCGetDeviceOperationalState(bool* isOp) +{ + if(NULL != isOp) + { + *isOp = GetPstatIsop(); + return OC_STACK_OK; + } + + return OC_STACK_ERROR; +} + +void OCClearCallBackList() +{ + DeleteClientCBList(); +} + +void OCClearObserverlist() +{ + DeleteObserverList(); +} + +int OCEncrypt(const unsigned char *pt, size_t pt_len, + unsigned char **ct, size_t *ct_len) +{ +#ifndef __SECURE_PSI__ + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + return 0; +#else + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + return psiEncrypt(pt, pt_len, ct, ct_len); +#endif // __SECURE_PSI__ +} + +int OCDecrypt(const unsigned char *ct, size_t ct_len, + unsigned char **pt, size_t *pt_len) +{ +#ifndef __SECURE_PSI__ + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + return 0; +#else + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + return psiDecrypt(ct, ct_len, pt, pt_len); +#endif // __SECURE_PSI__ +} + +OCStackResult OCSetKey(const unsigned char* key) +{ +#ifndef __SECURE_PSI__ + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + return OC_STACK_OK; +#else + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + return psiSetKey(key); +#endif // __SECURE_PSI__ +} + +OCStackResult OCGetKey(unsigned char* key) +{ +#ifndef __SECURE_PSI__ + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + return OC_STACK_OK; +#else + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + return psiGetKey(key); +#endif // __SECURE_PSI__ +} + +OCStackResult OCSetSecurePSI(const unsigned char *key, const OCPersistentStorage *psPlain, + const OCPersistentStorage *psEnc, const OCPersistentStorage *psRescue) +{ +#ifndef __SECURE_PSI__ + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + return OC_STACK_OK; +#else + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + return setSecurePSI(key, psPlain, psEnc, psRescue); +#endif // __SECURE_PSI__ +} + +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) +static void OtmEventHandler(const char *addr, uint16_t port, const char *uuid, int event) +{ + if (g_otmEventHandler.cb) + { + g_otmEventHandler.cb(g_otmEventHandler.ctx, addr, port, uuid, event); + } +} + +/* TODO Work-around + * It is already declared in srmutility.h. + * We can't include the header file, because of "redefined VERIFY_NON_NULL" + */ +typedef void (*OicSecOtmEventHandler_t)(const char* addr, uint16_t port, + const char* uuid, int event); +void SetOtmEventHandler(OicSecOtmEventHandler_t otmEventHandler); +#endif + +OCStackResult OCSetOtmEventHandler(void *ctx, OCOtmEventHandler cb) +{ +#if defined(__WITH_DTLS__) || defined (__WITH_TLS__) + OIC_LOG_V(DEBUG, TAG, "%s", __func__); + + g_otmEventHandler.cb = cb; + g_otmEventHandler.ctx = ctx; + + if (g_otmEventHandler.cb) + { + OIC_LOG(DEBUG, TAG, "SET OCOtmEventHandler"); + SetOtmEventHandler(OtmEventHandler); + } + else + { + OIC_LOG(DEBUG, TAG, "UNSET OCOtmEventHandler"); + SetOtmEventHandler(NULL); + } +#else + OIC_LOG_V(DEBUG, TAG, "Not Supported : %s", __func__); + OC_UNUSED(ctx); + OC_UNUSED(cb); +#endif + return OC_STACK_OK; +}