1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 //-----------------------------------------------------------------------------
24 //-----------------------------------------------------------------------------
26 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
27 // causes header files to expose definitions
28 // corresponding to the POSIX.1-2001 base
29 // specification (excluding the XSI extension).
30 // For POSIX.1-2001 base specification,
31 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
32 #define _POSIX_C_SOURCE 200112L
37 #include "ocstackinternal.h"
38 #include "ocresourcehandler.h"
39 #include "occlientcb.h"
40 #include "ocobserve.h"
43 #include "ocserverrequest.h"
44 #include "ocsecurityinternal.h"
47 #include "cainterface.h"
54 #include "coap_time.h"
59 #include <arpa/inet.h>
63 #define UINT32_MAX (0xFFFFFFFFUL)
66 //-----------------------------------------------------------------------------
68 //-----------------------------------------------------------------------------
71 OC_STACK_UNINITIALIZED = 0,
73 OC_STACK_UNINIT_IN_PROGRESS
79 OC_PRESENCE_UNINITIALIZED = 0,
80 OC_PRESENCE_INITIALIZED
84 //-----------------------------------------------------------------------------
86 //-----------------------------------------------------------------------------
87 static OCStackState stackState = OC_STACK_UNINITIALIZED;
89 OCResource *headResource = NULL;
90 static OCResource *tailResource = NULL;
92 static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED;
93 static PresenceResource presenceResource;
94 static uint8_t PresenceTimeOutSize = 0;
95 static uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
98 static OCMode myStackMode;
99 OCDeviceEntityHandler defaultDeviceHandler;
102 //-----------------------------------------------------------------------------
104 //-----------------------------------------------------------------------------
105 #define TAG PCF("OCStack")
106 #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
107 {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
108 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
109 TAG, PCF(#arg " is NULL")); return (retVal); } }
110 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
113 //TODO: we should allow the server to define this
114 #define MAX_OBSERVE_AGE (0x2FFFFUL)
116 #define MILLISECONDS_PER_SECOND (1000)
118 * Parse the presence payload and extract various parameters.
119 * Note: Caller should invoke OCFree after done with resType pointer.
121 * @param payload Presence payload.
122 * @param seqNum Sequence number.
123 * @param maxAge Time To Live (in seconds).
124 * @param resType Resource type.
126 // TODO: Not sure if I agree with this. I think it should be static but it is called in
127 // stack/test/stacktests.cpp, not included via a header file. If we intend to allow it
128 // to be called externally, we should change the name to OCParsePresencePayload and make
129 // it part of the official public API. But can't change now due to current API freeze.
130 // Another option might be to make non-API utility functions for doing stuff like this.
131 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType);
133 //-----------------------------------------------------------------------------
134 // Private internal function prototypes
135 //-----------------------------------------------------------------------------
138 * Generate handle of OCDoResource invocation for callback management.
140 * @return Generated OCDoResource handle.
142 static OCDoHandle GenerateInvocationHandle();
145 * Initialize resource data structures, variables, etc.
147 * @return ::OC_STACK_OK on success, some other value upon failure.
149 static OCStackResult initResources();
152 * Add a resource to the end of the linked list of resources.
154 * @param resource Resource to be added
156 static void insertResource(OCResource *resource);
159 * Find a resource in the linked list of resources.
161 * @param resource Resource to be found.
162 * @return Pointer to resource that was found in the linked list or NULL if the resource was not
165 static OCResource *findResource(OCResource *resource);
168 * Insert a resource type into a resource's resource type linked list.
169 * If resource type already exists, it will not be inserted and the
170 * resourceType will be free'd.
171 * resourceType->next should be null to avoid memory leaks.
172 * Function returns silently for null args.
174 * @param resource Resource where resource type is to be inserted.
175 * @param resourceType Resource type to be inserted.
177 static void insertResourceType(OCResource *resource,
178 OCResourceType *resourceType);
181 * Get a resource type at the specified index within a resource.
183 * @param handle Handle of resource.
184 * @param index Index of resource type.
186 * @return Pointer to resource type if found, NULL otherwise.
188 static OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle,
192 * Insert a resource interface into a resource's resource interface linked list.
193 * If resource interface already exists, it will not be inserted and the
194 * resourceInterface will be free'd.
195 * resourceInterface->next should be null to avoid memory leaks.
197 * @param resource Resource where resource interface is to be inserted.
198 * @param resourceInterface Resource interface to be inserted.
200 static void insertResourceInterface(OCResource *resource,
201 OCResourceInterface *resourceInterface);
204 * Get a resource interface at the specified index within a resource.
206 * @param handle Handle of resource.
207 * @param index Index of resource interface.
209 * @return Pointer to resource interface if found, NULL otherwise.
211 static OCResourceInterface *findResourceInterfaceAtIndex(
212 OCResourceHandle handle, uint8_t index);
215 * Delete all of the dynamically allocated elements that were created for the resource type.
217 * @param resourceType Specified resource type.
219 static void deleteResourceType(OCResourceType *resourceType);
222 * Delete all of the dynamically allocated elements that were created for the resource interface.
224 * @param resourceInterface Specified resource interface.
226 static void deleteResourceInterface(OCResourceInterface *resourceInterface);
229 * Delete all of the dynamically allocated elements that were created for the resource.
231 * @param resource Specified resource.
233 static void deleteResourceElements(OCResource *resource);
236 * Delete resource specified by handle. Deletes resource and all resourcetype and resourceinterface
239 * @param handle Handle of resource to be deleted.
241 * @return ::OC_STACK_OK on success, some other value upon failure.
243 static OCStackResult deleteResource(OCResource *resource);
246 * Delete all of the resources in the resource list.
248 static void deleteAllResources();
251 * Increment resource sequence number. Handles rollover.
253 * @param resPtr Pointer to resource.
255 static void incrementSequenceNumber(OCResource * resPtr);
258 * Verify the lengths of the URI and the query separately.
260 * @param inputUri Input URI and query.
261 * @param uriLen The length of the initial URI with query.
262 * @return ::OC_STACK_OK on success, some other value upon failure.
264 static OCStackResult verifyUriQueryLength(const char * inputUri,
268 * Determine if a request/response must be sent in a block transfer because it is too large to be
269 * sent in a single PDU. This function can be used for either a request or a response.
270 * Note: Either the request or response parameter should be non-NULL (i.e. only one, not both).
272 * @param request NULL or pointer to request.
273 * @param response NULL or pointer to response.
274 * @param size 0 or size of the request/response. If 0, strlen is used for determining
275 * the length of the request/response.
278 * false - packet transfer NOT required (i.e. normal request/response).
279 * true - packet transfer required (i.e. block transfer needed).
281 static bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size);
284 * Retrieves a resource type based upon a query contains only just one
285 * resource attribute (and that has to be of type "rt").
287 * @remark This API malloc's memory for the resource type. Do not malloc resourceType
290 * @param query The query part of the URI.
291 * @param resourceType The resource type to be populated; pass by reference.
293 * @return ::OC_STACK_OK on success, some other value upon failure.
295 static OCStackResult getResourceType(const char * query, char** resourceType);
298 * Attempts to initialize every network interface that the CA Layer might have compiled in.
300 * Note: At least one interface must succeed to initialize. If all calls to @ref CASelectNetwork
301 * return something other than @ref CA_STATUS_OK, then this function fails.
303 * @return ::CA_STATUS_OK on success, some other value upon failure.
305 static CAResult_t OCSelectNetwork();
308 * Get the CoAP ticks after the specified number of milli-seconds.
310 * @param afterMilliSeconds Milli-seconds.
314 static uint32_t GetTicks(uint32_t afterMilliSeconds);
317 * This method is used to create the IPv4 dev_addr structure.
318 * Builds a socket interface address using IP address and port number.
319 * TODO: Remove in future. Temporary helper function.
321 * @param a IPv4 octet 0.
322 * @param b IPv4 octet 1.
323 * @param c IPv4 octet 2.
324 * @param d IPv4 octet 3.
325 * @param port Port number.
326 * @param ipAddr - IPv4 address.
327 * @return ::OC_STACK_OK on success, some other value upon failure.
329 static OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
330 uint16_t port, OCDevAddr *ipAddr);
333 * Convert CAResponseResult_t to OCStackResult.
335 * @param caCode CAResponseResult_t code.
336 * @return ::OC_STACK_OK on success, some other value upon failure.
338 static OCStackResult CAToOCStackResult(CAResponseResult_t caCode);
341 * Convert OCStackResult to CAResponseResult_t.
343 * @param caCode OCStackResult code.
344 * @return ::CA_SUCCESS on success, some other value upon failure.
346 static CAResponseResult_t OCToCAStackResult(OCStackResult ocCode);
349 * Convert OCConnectivityType to CATransportType_t.
351 * @param ocConType OCConnectivityType input.
352 * @param caConType CATransportType_t output.
353 * @return ::OC_STACK_OK on success, some other value upon failure.
355 static OCStackResult OCToCATransportType(OCConnectivityType ocConType,
356 CATransportType_t* caConType);
359 * Convert CATransportType_t to OCConnectivityType.
361 * @param caConType CATransportType_t input.
362 * @param ocConType OCConnectivityType output.
363 * @return ::OC_STACK_OK on success, some other value upon failure.
365 static OCStackResult CAToOCConnectivityType(CATransportType_t caConType,
366 OCConnectivityType *ocConType);
369 * Update response.addr appropriately from endPoint.addressInfo.
371 * @param address OCDevAddr output.
372 * @param endPoint CARemoteEndpoint_t input.
373 * @return ::OC_STACK_OK on success, some other value upon failure.
375 static OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint);
378 * Handle response from presence request.
380 * @param endPoint CA remote endpoint.
381 * @param responseInfo CA response info.
382 * @return ::OC_STACK_OK on success, some other value upon failure.
384 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
385 const CAResponseInfo_t* responseInfo);
388 * This function will be called back by CA layer when a response is received.
390 * @param endPoint CA remote endpoint.
391 * @param responseInfo CA response info.
393 static void HandleCAResponses(const CARemoteEndpoint_t* endPoint,
394 const CAResponseInfo_t* responseInfo);
397 * This function will be called back by CA layer when a request is received.
399 * @param endPoint CA remote endpoint.
400 * @param requestInfo CA request info.
402 static void HandleCARequests(const CARemoteEndpoint_t* endPoint,
403 const CARequestInfo_t* requestInfo);
406 * Extract query from a URI.
408 * @param uri Full URI with query.
409 * @param query Pointer to string that will contain query.
410 * @param newURI Pointer to string that will contain URI.
411 * @return ::OC_STACK_OK on success, some other value upon failure.
413 static OCStackResult getQueryFromUri(const char * uri, char** resourceType, char ** newURI);
416 * Finds a resource type in an OCResourceType link-list.
418 * @param resourceTypeList The link-list to be searched through.
419 * @param resourceTypeName The key to search for.
421 * @return Resource type that matches the key (ie. resourceTypeName) or
422 * NULL if there is either an invalid parameter or this function was unable to find the key.
424 static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
425 const char * resourceTypeName);
428 * Reset presence TTL for a ClientCB struct. ttlLevel will be set to 0.
429 * TTL will be set to maxAge.
431 * @param cbNode Callback Node for which presence ttl is to be reset.
432 * @param maxAge New value of ttl in seconds.
434 * @return ::OC_STACK_OK on success, some other value upon failure.
436 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);
438 //-----------------------------------------------------------------------------
439 // Internal functions
440 //-----------------------------------------------------------------------------
442 uint32_t GetTicks(uint32_t afterMilliSeconds)
447 // Guard against overflow of uint32_t
448 if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
449 COAP_TICKS_PER_SECOND)
451 return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
459 OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
460 uint16_t port, OCDevAddr *ipAddr)
464 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
465 return OC_STACK_INVALID_PARAM;
472 ipAddr->addr[4] = (uint8_t)port;
473 ipAddr->addr[5] = (uint8_t)(port >> 8);
478 //-----------------------------------------------------------------------------
479 // Internal API function
480 //-----------------------------------------------------------------------------
482 // This internal function is called to update the stack with the status of
483 // observers and communication failures
484 OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t status)
486 OCStackResult result = OC_STACK_ERROR;
487 ResourceObserver * observer = NULL;
488 OCEntityHandlerRequest ehRequest = {};
492 case OC_OBSERVER_NOT_INTERESTED:
493 OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
494 observer = GetObserverUsingToken (token, tokenLength);
497 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
498 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
499 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
500 if(result != OC_STACK_OK)
504 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
506 //observer is not observing anymore
507 result = DeleteObserverUsingToken (token, tokenLength);
508 if(result == OC_STACK_OK)
510 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
514 result = OC_STACK_OK;
515 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
518 case OC_OBSERVER_STILL_INTERESTED:
519 //observer is still interested
520 OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
521 notifications, reset the failedCount"));
522 observer = GetObserverUsingToken (token, tokenLength);
525 observer->forceHighQos = 0;
526 observer->failedCommCount = 0;
527 result = OC_STACK_OK;
531 result = OC_STACK_OBSERVER_NOT_FOUND;
534 case OC_OBSERVER_FAILED_COMM:
535 //observer is not reachable
536 OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
537 observer = GetObserverUsingToken (token, tokenLength);
540 if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
542 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
543 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
544 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
545 if(result != OC_STACK_OK)
547 return OC_STACK_ERROR;
549 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
550 //observer is unreachable
551 result = DeleteObserverUsingToken (token, tokenLength);
552 if(result == OC_STACK_OK)
554 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
558 result = OC_STACK_OK;
559 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
564 observer->failedCommCount++;
565 result = OC_STACK_CONTINUE;
567 observer->forceHighQos = 1;
568 OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
572 OC_LOG(ERROR, TAG, PCF("Unknown status"));
573 result = OC_STACK_ERROR;
578 OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
580 OCStackResult ret = OC_STACK_ERROR;
588 ret = OC_STACK_RESOURCE_CREATED;
591 ret = OC_STACK_RESOURCE_DELETED;
594 ret = OC_STACK_INVALID_QUERY;
597 ret = OC_STACK_INVALID_OPTION;
600 ret = OC_STACK_NO_RESOURCE;
602 case CA_RETRANSMIT_TIMEOUT:
603 ret = OC_STACK_COMM_ERROR;
611 CAResponseResult_t OCToCAStackResult(OCStackResult ocCode)
613 CAResponseResult_t ret = CA_INTERNAL_SERVER_ERROR;
620 case OC_STACK_RESOURCE_CREATED:
623 case OC_STACK_RESOURCE_DELETED:
626 case OC_STACK_INVALID_QUERY:
629 case OC_STACK_INVALID_OPTION:
632 case OC_STACK_NO_RESOURCE:
635 case OC_STACK_COMM_ERROR:
636 ret = CA_RETRANSMIT_TIMEOUT;
644 OCStackResult OCToCATransportType(OCConnectivityType ocConType, CATransportType_t* caConType)
646 OCStackResult ret = OC_STACK_OK;
651 *caConType = CA_IPV4;
654 *caConType = CA_IPV6;
663 // Currently OC_ALL represents IPv4
664 // Add other connectivity types as they are enabled in future
665 *caConType = (CATransportType_t) (CA_IPV4);
668 ret = OC_STACK_INVALID_PARAM;
674 OCStackResult CAToOCConnectivityType(CATransportType_t caConType, OCConnectivityType *ocConType)
676 OCStackResult ret = OC_STACK_OK;
681 *ocConType = OC_IPV4;
684 *ocConType = OC_IPV6;
693 ret = OC_STACK_INVALID_PARAM;
699 OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint)
701 OCStackResult ret = OC_STACK_ERROR;
703 char * savePtr = NULL;
704 char * cpAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
707 ret = OC_STACK_NO_MEMORY;
710 memcpy(cpAddress, endPoint->addressInfo.IP.ipAddress,
711 strlen(endPoint->addressInfo.IP.ipAddress) + 1);
713 // Grabs the first three numbers from the IPv4 address and replaces dots
714 for(int i=0; i<4; i++)
716 tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
720 ret = OC_STACK_ERROR;
723 address->addr[i] = atoi(tok);
726 memcpy(&address->addr[4], &endPoint->addressInfo.IP.port, sizeof(uint16_t));
734 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
736 uint32_t lowerBound = 0;
737 uint32_t higherBound = 0;
739 if (!cbNode || !cbNode->presence || !cbNode->presence->timeOut)
741 return OC_STACK_INVALID_PARAM;
744 OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0));
746 cbNode->presence->TTL = maxAgeSeconds;
748 for(int index = 0; index < PresenceTimeOutSize; index++)
750 // Guard against overflow
751 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index]))
754 lowerBound = GetTicks((PresenceTimeOut[index] *
755 cbNode->presence->TTL *
756 MILLISECONDS_PER_SECOND)/100);
760 lowerBound = GetTicks(UINT32_MAX);
763 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index+1]))
766 higherBound = GetTicks((PresenceTimeOut[index + 1] *
767 cbNode->presence->TTL *
768 MILLISECONDS_PER_SECOND)/100);
772 higherBound = GetTicks(UINT32_MAX);
775 cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
777 OC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound);
778 OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound);
779 OC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]);
782 cbNode->presence->TTLlevel = 0;
784 OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel);
788 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
791 char * savePtr = NULL;
792 // The format of the payload is {"oc":[%u:%u:%s]}
793 // %u : sequence number,
795 // %s : Resource Type (Optional)
797 if (!payload || !seqNum || !maxAge || !resType)
801 tok = strtok_r(payload, "[:]}", &savePtr);
802 payload[strlen(payload)] = ':';
804 //Retrieve sequence number
805 tok = strtok_r(NULL, "[:]}", &savePtr);
810 payload[strlen((char *)payload)] = ':';
811 *seqNum = (uint32_t) atoi(tok);
814 tok = strtok_r(NULL, "[:]}", &savePtr);
819 *maxAge = (uint32_t) atoi(tok);
821 //Retrieve ResourceType
822 tok = strtok_r(NULL, "[:]}",&savePtr);
828 *resType = (char *)OCMalloc(strlen(tok) + 1);
833 payload[strlen((char *)payload)] = ':';
834 strcpy(*resType, tok);
835 OC_LOG_V(DEBUG, TAG, "resourceTypeName %s", *resType);
837 payload[strlen((char *)payload)] = ']';
840 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
841 const CAResponseInfo_t* responseInfo)
843 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
844 ClientCB * cbNode = NULL;
845 char *resourceTypeName = NULL;
846 OCClientResponse response = {};
847 OCDevAddr address = {};
848 OCStackResult result = OC_STACK_ERROR;
851 char *fullUri = NULL;
852 char *ipAddress = NULL;
853 int presenceSubscribe = 0;
854 int multicastPresenceSubscribe = 0;
855 size_t addressLen = 0;
857 if (responseInfo->result != CA_SUCCESS)
859 OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
860 return OC_STACK_ERROR;
863 fullUri = (char *) OCMalloc(MAX_URI_LENGTH);
867 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for fullUri"));
868 result = OC_STACK_NO_MEMORY;
872 addressLen = strlen(endPoint->addressInfo.IP.ipAddress);
873 ipAddress = (char *) OCMalloc(addressLen + 1);
877 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for ipAddress"));
878 result = OC_STACK_NO_MEMORY;
882 strncpy(ipAddress, endPoint->addressInfo.IP.ipAddress, addressLen);
883 ipAddress[addressLen] = '\0';
885 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
888 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
892 presenceSubscribe = 1;
896 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", OC_MULTICAST_IP, OC_MULTICAST_PORT,
897 endPoint->resourceUri);
898 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
901 multicastPresenceSubscribe = 1;
905 if(!presenceSubscribe && !multicastPresenceSubscribe)
907 OC_LOG(ERROR, TAG, PCF("Received a presence notification, but no callback, ignoring"));
911 // No payload to the application in case of presence
912 response.resJSONPayload = NULL;
913 response.result = OC_STACK_OK;
915 result = UpdateResponseAddr(&address, endPoint);
916 if(result != OC_STACK_OK)
921 response.addr = &address;
923 result = CAToOCConnectivityType(endPoint->transportType, &(response.connType));
924 if(result != OC_STACK_OK)
926 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
930 if(responseInfo->info.payload)
932 parsePresencePayload(responseInfo->info.payload,
933 &(response.sequenceNumber),
938 if(presenceSubscribe)
940 if(cbNode->sequenceNumber == response.sequenceNumber)
942 if (cbNode->presence)
944 OC_LOG(INFO, TAG, PCF("No presence change. Updating TTL."));
946 result = ResetPresenceTTL(cbNode, maxAge);
948 if (result != OC_STACK_OK)
950 OC_LOG_V(ERROR, TAG, "ResetPresenceTTL failed with error: %u", result);
955 OC_LOG(INFO, TAG, PCF("Not subscribed to presence."));
962 OC_LOG(INFO, TAG, PCF("Stopping presence"));
963 response.result = OC_STACK_PRESENCE_STOPPED;
966 OCFree(cbNode->presence->timeOut);
967 OCFree(cbNode->presence);
968 cbNode->presence = NULL;
973 if(!cbNode->presence)
975 cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
976 if(!(cbNode->presence))
978 OC_LOG(ERROR, TAG, PCF("Could not allocate memory for cbNode->presence"));
979 result = OC_STACK_NO_MEMORY;
983 VERIFY_NON_NULL_V(cbNode->presence);
984 cbNode->presence->timeOut = NULL;
985 cbNode->presence->timeOut = (uint32_t *)
986 OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
987 if(!(cbNode->presence->timeOut)){
989 PCF("Could not allocate memory for cbNode->presence->timeOut"));
990 OCFree(cbNode->presence);
991 result = OC_STACK_NO_MEMORY;
996 ResetPresenceTTL(cbNode, maxAge);
998 OC_LOG(INFO, TAG, PCF("Presence changed, calling up the stack"));
999 cbNode->sequenceNumber = response.sequenceNumber;
1001 // Ensure that a filter is actually applied.
1002 if(resourceTypeName && cbNode->filterResourceType)
1004 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1013 // This is the multicast case
1015 OCMulticastNode* mcNode = NULL;
1016 mcNode = GetMCPresenceNode(fullUri);
1020 if(mcNode->nonce == response.sequenceNumber)
1022 OC_LOG(INFO, TAG, PCF("No presence change (Multicast)"));
1025 mcNode->nonce = response.sequenceNumber;
1029 OC_LOG(INFO, TAG, PCF("Stopping presence"));
1030 response.result = OC_STACK_PRESENCE_STOPPED;
1035 uint32_t uriLen = strlen(fullUri);
1036 char* uri = (char *) OCMalloc(uriLen + 1);
1039 memcpy(uri, fullUri, (uriLen + 1));
1044 PCF("No Memory for URI to store in the presence node"));
1045 result = OC_STACK_NO_MEMORY;
1048 result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber);
1049 if(result != OC_STACK_OK)
1052 PCF("Unable to add Multicast Presence Node"));
1058 // Ensure that a filter is actually applied.
1059 if(resourceTypeName && cbNode->filterResourceType)
1061 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1068 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response);
1070 if (cbResult == OC_STACK_DELETE_TRANSACTION)
1072 FindAndDeleteClientCB(cbNode);
1078 OCFree(resourceTypeName);
1082 void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
1084 OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
1086 if(NULL == endPoint)
1088 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1092 if(NULL == responseInfo)
1094 OC_LOG(ERROR, TAG, PCF("responseInfo is NULL"));
1098 if(strcmp(endPoint->resourceUri, OC_PRESENCE_URI) == 0)
1100 HandlePresenceResponse(endPoint, responseInfo);
1104 ClientCB *cbNode = GetClientCB(responseInfo->info.token,
1105 responseInfo->info.tokenLength, NULL, NULL);
1106 OC_LOG_V(DEBUG, TAG, "Response has the token %s", responseInfo->info.token);
1107 ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token,
1108 responseInfo->info.tokenLength);
1112 OC_LOG(INFO, TAG, PCF("There is a cbNode associated with the response token"));
1113 if(responseInfo->result == CA_EMPTY)
1115 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1116 // We do not have a case for the client to receive a RESET
1117 if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1119 //This is the case of receiving an ACK on a request to a slow resource!
1120 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1121 //TODO: should we inform the client
1122 // app that at least the request was received at the server?
1125 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1127 OC_LOG(INFO, TAG, PCF("Receiving A Timeout for this token"));
1128 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1129 OCClientResponse response = {};
1130 OCDevAddr address = {};
1131 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1132 if(result != OC_STACK_OK)
1134 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1138 result = UpdateResponseAddr(&address, endPoint);
1139 if(result != OC_STACK_OK)
1141 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1144 response.addr = &address;
1146 response.result = CAToOCStackResult(responseInfo->result);
1147 cbNode->callBack(cbNode->context,
1148 cbNode->handle, &response);
1149 FindAndDeleteClientCB(cbNode);
1153 OC_LOG(INFO, TAG, PCF("This is a regular response, A client call back is found"));
1154 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1155 OCClientResponse response = {};
1156 OCDevAddr address = {};
1158 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1159 if(result != OC_STACK_OK)
1161 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1164 response.addr = &address;
1165 // Populate the connectivity type. If this is a discovery response,
1166 // the resource that will be constructed from this response will make
1167 // further API calls from this interface.
1168 result = CAToOCConnectivityType(endPoint->transportType,
1169 &(response.connType));
1170 if(result != OC_STACK_OK)
1172 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1176 response.result = CAToOCStackResult(responseInfo->result);
1177 response.resJSONPayload = (const char*)responseInfo->info.payload;
1178 response.numRcvdVendorSpecificHeaderOptions = 0;
1179 if(responseInfo->info.numOptions > 0)
1182 //First option always with option ID is COAP_OPTION_OBSERVE if it is available.
1183 if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
1185 memcpy (&(response.sequenceNumber),
1186 &(responseInfo->info.options[0].optionData), sizeof(uint32_t));
1187 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1;
1192 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
1195 if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS)
1197 OC_LOG(ERROR, TAG, PCF("#header options are more than MAX_HEADER_OPTIONS"));
1201 for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
1203 memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
1204 &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
1208 if (cbNode->method == OC_REST_OBSERVE &&
1209 response.sequenceNumber > OC_OFFSET_SEQUENCE_NUMBER &&
1210 response.sequenceNumber <= cbNode->sequenceNumber)
1212 OC_LOG_V(INFO, TAG, PCF("Received stale notification. Number :%d"),
1213 response.sequenceNumber);
1217 OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context,
1220 cbNode->sequenceNumber = response.sequenceNumber;
1222 if (appFeedback == OC_STACK_DELETE_TRANSACTION)
1224 FindAndDeleteClientCB(cbNode);
1228 // To keep discovery callbacks active.
1229 cbNode->TTL = GetTicks(MAX_CB_TIMEOUT_SECONDS *
1230 MILLISECONDS_PER_SECOND);
1234 //Need to send ACK when the response is CON
1235 if(responseInfo->info.type == CA_MSG_CONFIRM)
1237 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1238 CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0);
1246 OC_LOG(INFO, TAG, PCF("There is an observer associated with the response token"));
1247 if(responseInfo->result == CA_EMPTY)
1249 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1250 if(responseInfo->info.type == CA_MSG_RESET)
1252 OC_LOG(INFO, TAG, PCF("This is a RESET"));
1253 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1254 OC_OBSERVER_NOT_INTERESTED);
1256 else if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1258 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1259 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1260 OC_OBSERVER_STILL_INTERESTED);
1263 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1265 OC_LOG(INFO, TAG, PCF("Receiving Time Out for an observer"));
1266 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1267 OC_OBSERVER_FAILED_COMM);
1272 if(!cbNode && !observer)
1274 if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER)
1276 OC_LOG(INFO, TAG, PCF("This is a client, but no cbNode was found for token"));
1277 if(responseInfo->result == CA_EMPTY)
1279 OC_LOG(INFO, TAG, PCF("Receiving CA_EMPTY in the ocstack"));
1283 OC_LOG(INFO, TAG, PCF("Received a response or notification,\
1284 but I do not have callback. Sending RESET"));
1285 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1286 CA_MSG_RESET, 0, NULL, NULL, 0);
1290 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
1292 OC_LOG(INFO, TAG, PCF("This is a server, but no observer was found for token"));
1293 if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1295 OC_LOG_V(INFO, TAG, PCF("Received ACK at server for messageId : %d"),
1296 responseInfo->info.messageId);
1298 if (responseInfo->info.type == CA_MSG_RESET)
1300 OC_LOG_V(INFO, TAG, PCF("Received RESET at server for messageId : %d"),
1301 responseInfo->info.messageId);
1307 OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
1308 OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
1312 * This function sends out Direct Stack Responses. These are responses that are not coming
1313 * from the application entity handler. These responses have no payload and are usually ACKs,
1314 * RESETs or some error conditions that were caught by the stack.
1316 OCStackResult SendDirectStackResponse(const CARemoteEndpoint_t* endPoint, const uint16_t coapID,
1317 const CAResponseResult_t responseResult, const CAMessageType_t type,
1318 const uint8_t numOptions, const CAHeaderOption_t *options,
1319 CAToken_t token, uint8_t tokenLength)
1321 CAResponseInfo_t respInfo = {};
1322 respInfo.result = responseResult;
1323 respInfo.info.messageId = coapID;
1324 respInfo.info.numOptions = numOptions;
1325 respInfo.info.options = (CAHeaderOption_t*)options;
1326 respInfo.info.payload = NULL;
1327 respInfo.info.token = token;
1328 respInfo.info.tokenLength = tokenLength;
1329 respInfo.info.type = type;
1331 CAResult_t caResult = CASendResponse(endPoint, &respInfo);
1332 if(caResult != CA_STATUS_OK)
1334 OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
1335 return OC_STACK_ERROR;
1340 //This function will be called back by CA layer when a request is received
1341 void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
1343 OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
1346 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1352 OC_LOG(ERROR, TAG, PCF("requestInfo is NULL"));
1356 OCStackResult requestResult = OC_STACK_ERROR;
1358 if(myStackMode == OC_CLIENT)
1360 //TODO: should the client be responding to requests?
1364 OCServerProtocolRequest serverRequest = {};
1366 OC_LOG_V(INFO, TAG, PCF("Endpoint URI : %s\n"), (char*)endPoint->resourceUri);
1368 char * newUri = NULL;
1369 char * query = NULL;
1371 requestResult = getQueryFromUri(endPoint->resourceUri, &query, &newUri);
1373 if (requestResult != OC_STACK_OK)
1375 OC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult);
1378 OC_LOG_V(INFO, TAG, PCF("URI without query: %s\n"), newUri);
1379 OC_LOG_V(INFO, TAG, PCF("Query : %s\n"), query);
1381 if(strlen(newUri) < MAX_URI_LENGTH)
1384 memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
1389 OC_LOG(ERROR, TAG, PCF("URI length exceeds MAX_URI_LENGTH."));
1397 if(strlen(query) < MAX_QUERY_LENGTH)
1399 memcpy (&(serverRequest.query), query, strlen(query));
1404 OC_LOG(ERROR, TAG, PCF("Query length exceeds MAX_QUERY_LENGTH."));
1409 //copy request payload
1410 if (requestInfo->info.payload)
1412 size_t payloadLen = strlen(requestInfo->info.payload);
1413 serverRequest.reqTotalSize = payloadLen + 1;
1414 memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
1419 serverRequest.reqTotalSize = 1;
1420 serverRequest.reqJSONPayload[0] = '\0';
1423 switch (requestInfo->method)
1427 serverRequest.method = OC_REST_GET;
1432 serverRequest.method = OC_REST_PUT;
1437 serverRequest.method = OC_REST_POST;
1442 serverRequest.method = OC_REST_DELETE;
1447 OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
1448 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_REQ,
1449 requestInfo->info.type, requestInfo->info.numOptions,
1450 requestInfo->info.options, requestInfo->info.token,
1451 requestInfo->info.tokenLength);
1456 OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d",
1457 requestInfo->info.tokenLength);
1458 OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token,
1459 requestInfo->info.tokenLength);
1460 serverRequest.requestToken = (CAToken_t)OCMalloc(requestInfo->info.tokenLength);
1461 serverRequest.tokenLength = requestInfo->info.tokenLength;
1463 if (!serverRequest.requestToken)
1465 OC_LOG(FATAL, TAG, "Server Request Token is NULL");
1466 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR,
1467 requestInfo->info.type, requestInfo->info.numOptions,
1468 requestInfo->info.options, requestInfo->info.token,
1469 requestInfo->info.tokenLength);
1472 memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength);
1474 if (requestInfo->info.type == CA_MSG_CONFIRM)
1476 serverRequest.qos = OC_HIGH_QOS;
1480 serverRequest.qos = OC_LOW_QOS;
1482 // CA does not need the following 2 fields
1483 // Are we sure CA does not need them? how is it responding to multicast
1484 serverRequest.delayedResNeeded = 0;
1485 serverRequest.secured = endPoint->isSecured;
1487 serverRequest.coapID = requestInfo->info.messageId;
1490 serverRequest.addressInfo = endPoint->addressInfo;
1491 serverRequest.connectivityType = endPoint->transportType;
1493 // copy vendor specific header options
1494 uint8_t tempNum = (requestInfo->info.numOptions);
1495 GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum);
1496 if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
1499 PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
1500 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_OPT,
1501 requestInfo->info.type, requestInfo->info.numOptions,
1502 requestInfo->info.options, requestInfo->info.token,
1503 requestInfo->info.tokenLength);
1504 OCFree(serverRequest.requestToken);
1507 serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
1508 if (serverRequest.numRcvdVendorSpecificHeaderOptions)
1510 memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
1511 sizeof(CAHeaderOption_t)*tempNum);
1514 requestResult = HandleStackRequests (&serverRequest);
1516 // Send ACK to client as precursor to slow response
1517 if(requestResult == OC_STACK_SLOW_RESOURCE)
1519 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_EMPTY,
1520 CA_MSG_ACKNOWLEDGE,0, NULL, NULL, 0);
1522 else if(requestResult != OC_STACK_OK)
1524 OC_LOG_V(ERROR, TAG, PCF("HandleStackRequests failed. error: %d"), requestResult);
1526 CAResponseResult_t stackResponse = OCToCAStackResult(requestResult);
1528 SendDirectStackResponse(endPoint, requestInfo->info.messageId, stackResponse,
1529 requestInfo->info.type, requestInfo->info.numOptions,
1530 requestInfo->info.options, requestInfo->info.token,
1531 requestInfo->info.tokenLength);
1533 // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest.
1534 // The token is copied in there, and is thus still owned by this function.
1535 OCFree(serverRequest.requestToken);
1536 OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
1539 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
1541 OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
1542 OCStackResult result = OC_STACK_ERROR;
1543 ResourceHandling resHandling;
1544 OCResource *resource;
1545 if(!protocolRequest)
1547 OC_LOG(ERROR, TAG, PCF("protocolRequest is NULL"));
1548 return OC_STACK_INVALID_PARAM;
1551 OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken,
1552 protocolRequest->tokenLength);
1555 OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
1556 result = AddServerRequest(&request, protocolRequest->coapID,
1557 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
1558 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
1559 protocolRequest->observationOption, protocolRequest->qos,
1560 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
1561 protocolRequest->reqJSONPayload, protocolRequest->requestToken,
1562 protocolRequest->tokenLength,
1563 protocolRequest->resourceUrl,protocolRequest->reqTotalSize,
1564 &protocolRequest->addressInfo, protocolRequest->connectivityType);
1565 if (OC_STACK_OK != result)
1567 OC_LOG(ERROR, TAG, PCF("Error adding server request"));
1573 OC_LOG(ERROR, TAG, PCF("Out of Memory"));
1574 return OC_STACK_NO_MEMORY;
1577 if(!protocolRequest->reqMorePacket)
1579 request->requestComplete = 1;
1585 PCF("This is either a repeated or blocked Server Request"));
1588 if(request->requestComplete)
1590 OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
1591 result = DetermineResourceHandling (request, &resHandling, &resource);
1592 if (result == OC_STACK_OK)
1594 result = ProcessRequest(resHandling, resource, request);
1599 OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
1600 result = OC_STACK_CONTINUE;
1605 bool ParseIPv4Address(char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
1609 uint8_t dotCount = 0;
1613 /* search for scheme */
1615 if (!isdigit((char) *ipAddrStr))
1617 coap = OC_COAP_SCHEME;
1618 while (*coap && tolower(*itr) == *coap)
1628 if (isdigit(*ipAddrStr))
1630 ipAddr[index] *= 10;
1631 ipAddr[index] += *ipAddrStr - '0';
1633 else if (*ipAddrStr == '.')
1645 if(*ipAddrStr == ':')
1649 if (isdigit(*ipAddrStr))
1652 *port += *ipAddrStr - '0';
1662 return (3 == dotCount);
1665 bool validatePlatformInfo(OCPlatformInfo info)
1668 if (!info.platformID)
1670 OC_LOG(ERROR, TAG, PCF("No platform ID found."));
1674 if (info.manufacturerName)
1676 size_t lenManufacturerName = strlen(info.manufacturerName);
1678 if(lenManufacturerName == 0 || lenManufacturerName > MAX_MANUFACTURER_NAME_LENGTH)
1680 OC_LOG(ERROR, TAG, PCF("Manufacturer name fails length requirements."));
1686 OC_LOG(ERROR, TAG, PCF("No manufacturer name present"));
1690 if (info.manufacturerUrl)
1692 if(strlen(info.manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH)
1694 OC_LOG(ERROR, TAG, PCF("Manufacturer url fails length requirements."));
1700 //-----------------------------------------------------------------------------
1702 //-----------------------------------------------------------------------------
1704 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
1706 if(stackState == OC_STACK_INITIALIZED)
1708 OC_LOG(INFO, TAG, PCF("Subsequent calls to OCInit() without calling \
1709 OCStop() between them are ignored."));
1715 OCStackResult result = OC_STACK_ERROR;
1716 OC_LOG(INFO, TAG, PCF("Entering OCInit"));
1719 if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
1721 OC_LOG(ERROR, TAG, PCF("Invalid mode"));
1722 return OC_STACK_ERROR;
1726 defaultDeviceHandler = NULL;
1729 result = CAResultToOCResult(CAInitialize());
1730 VERIFY_SUCCESS(result, OC_STACK_OK);
1732 result = CAResultToOCResult(OCSelectNetwork());
1733 VERIFY_SUCCESS(result, OC_STACK_OK);
1735 CARegisterHandler(HandleCARequests, HandleCAResponses);
1736 switch (myStackMode)
1739 result = CAResultToOCResult(CAStartDiscoveryServer());
1740 OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
1743 result = CAResultToOCResult(CAStartListeningServer());
1744 OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
1746 case OC_CLIENT_SERVER:
1747 result = CAResultToOCResult(CAStartListeningServer());
1748 if(result == OC_STACK_OK)
1750 result = CAResultToOCResult(CAStartDiscoveryServer());
1754 VERIFY_SUCCESS(result, OC_STACK_OK);
1756 #if defined(__WITH_DTLS__)
1757 result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ?
1758 OC_STACK_OK : OC_STACK_ERROR;
1759 VERIFY_SUCCESS(result, OC_STACK_OK);
1760 #endif // (__WITH_DTLS__)
1762 #ifdef WITH_PRESENCE
1763 PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
1764 #endif // WITH_PRESENCE
1766 //Update Stack state to initialized
1767 stackState = OC_STACK_INITIALIZED;
1769 // Initialize resource
1770 if(myStackMode != OC_CLIENT)
1772 result = initResources();
1776 if(result != OC_STACK_OK)
1778 OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
1779 deleteAllResources();
1781 stackState = OC_STACK_UNINITIALIZED;
1786 OCStackResult OCStop()
1788 OC_LOG(INFO, TAG, PCF("Entering OCStop"));
1790 if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
1792 OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
1795 else if (stackState != OC_STACK_INITIALIZED)
1797 OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
1798 return OC_STACK_ERROR;
1801 stackState = OC_STACK_UNINIT_IN_PROGRESS;
1803 #ifdef WITH_PRESENCE
1804 // Ensure that the TTL associated with ANY and ALL presence notifications originating from
1805 // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
1806 presenceResource.presenceTTL = 0;
1807 #endif // WITH_PRESENCE
1809 // Free memory dynamically allocated for resources
1810 deleteAllResources();
1812 DeletePlatformInfo();
1814 // Remove all observers
1815 DeleteObserverList();
1816 // Remove all the client callbacks
1817 DeleteClientCBList();
1818 // Deinit security blob
1819 DeinitOCSecurityInfo();
1820 stackState = OC_STACK_UNINITIALIZED;
1824 CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
1829 return CA_MSG_CONFIRM;
1834 return CA_MSG_NONCONFIRM;
1838 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1842 query = strchr (inputUri, '?');
1846 if((query - inputUri) > MAX_URI_LENGTH)
1848 return OC_STACK_INVALID_URI;
1851 if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1853 return OC_STACK_INVALID_QUERY;
1856 else if(uriLen > MAX_URI_LENGTH)
1858 return OC_STACK_INVALID_URI;
1863 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1864 const char *referenceUri, const char *request, OCConnectivityType conType,
1865 OCQualityOfService qos, OCCallbackData *cbData,
1866 OCHeaderOption * options, uint8_t numOptions)
1868 OCStackResult result = OC_STACK_ERROR;
1869 ClientCB *clientCB = NULL;
1870 char * requestUri = NULL;
1871 char * resourceType = NULL;
1872 char * query = NULL;
1873 char * newUri = (char *)requiredUri;
1874 (void) referenceUri;
1875 CARemoteEndpoint_t* endpoint = NULL;
1876 CAResult_t caResult;
1877 CAToken_t token = NULL;
1878 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
1879 OCDoHandle resHandle = NULL;
1880 CAInfo_t requestData ={};
1881 CARequestInfo_t requestInfo ={};
1882 CAGroupEndpoint_t grpEnd = {};
1884 OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1886 // Validate input parameters
1887 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1888 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1890 //TODO ("Need to form the final query by concatenating require and reference URI's");
1891 VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1893 uint16_t uriLen = strlen(requiredUri);
1895 // ToDo: We should also check if the requiredUri has a mutlicast address,
1896 // then qos has to be OC_Low_QOS
1900 case OC_REST_OBSERVE:
1901 case OC_REST_OBSERVE_ALL:
1902 case OC_REST_CANCEL_OBSERVE:
1903 requestInfo.method = CA_GET;
1907 requestInfo.method = CA_PUT;
1911 requestInfo.method = CA_POST;
1914 case OC_REST_DELETE:
1915 requestInfo.method = CA_DELETE;
1918 #ifdef WITH_PRESENCE
1919 case OC_REST_PRESENCE:
1920 // Replacing method type with GET because "presence"
1921 // is a stack layer only implementation.
1922 requestInfo.method = CA_GET;
1927 result = OC_STACK_INVALID_METHOD;
1931 if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1936 if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1938 result = OC_STACK_INVALID_PARAM;
1942 #ifdef WITH_PRESENCE
1943 if(method == OC_REST_PRESENCE)
1945 result = getQueryFromUri(requiredUri, &query, &newUri);
1947 if(result != OC_STACK_OK)
1949 OC_LOG_V(ERROR, TAG, "Invalid Param from getQueryFromUri: %d, URI is %s",
1950 result, requiredUri);
1956 result = getResourceType((char *) query, &resourceType);
1960 OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1964 OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
1969 OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
1971 if(result != OC_STACK_OK)
1976 #endif // WITH_PRESENCE
1978 requestUri = (char *) OCMalloc(uriLen + 1);
1981 memcpy(requestUri, newUri, (uriLen + 1));
1985 result = OC_STACK_NO_MEMORY;
1989 resHandle = GenerateInvocationHandle();
1992 result = OC_STACK_NO_MEMORY;
1997 caResult = CAGenerateToken(&token, tokenLength);
1998 if (caResult != CA_STATUS_OK)
2000 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2001 CADestroyToken(token);
2002 result = CAResultToOCResult (caResult);
2006 requestData.type = qualityOfServiceToMessageType(qos);
2008 requestData.token = token;
2009 requestData.tokenLength = tokenLength;
2011 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2013 result = CreateObserveHeaderOption (&(requestData.options), options,
2014 numOptions, OC_OBSERVE_REGISTER);
2015 if (result != OC_STACK_OK)
2017 CADestroyToken(token);
2020 requestData.numOptions = numOptions + 1;
2024 requestData.options = (CAHeaderOption_t*)options;
2025 requestData.numOptions = numOptions;
2028 requestData.payload = (char *)request;
2030 requestInfo.info = requestData;
2032 CATransportType_t caConType;
2034 result = OCToCATransportType((OCConnectivityType) conType, &caConType);
2035 if (result != OC_STACK_OK)
2037 OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
2042 if(conType == OC_ALL)
2044 grpEnd.transportType = caConType;
2046 grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
2047 if(!grpEnd.resourceUri)
2049 result = OC_STACK_NO_MEMORY;
2050 CADestroyToken(token);
2053 strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
2055 caResult = CASendRequestToAll(&grpEnd, &requestInfo);
2059 caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
2061 if (caResult != CA_STATUS_OK)
2063 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2064 result = CAResultToOCResult (caResult);
2065 CADestroyToken(token);
2069 caResult = CASendRequest(endpoint, &requestInfo);
2072 if (caResult != CA_STATUS_OK)
2074 OC_LOG(ERROR, TAG, PCF("CASendRequest"));
2075 result = CAResultToOCResult (caResult);
2076 CADestroyToken(token);
2080 result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method,
2081 requestUri, resourceType, conType,
2082 GetTicks(MAX_CB_TIMEOUT_SECONDS * MILLISECONDS_PER_SECOND));
2083 if(result != OC_STACK_OK)
2085 result = OC_STACK_NO_MEMORY;
2091 *handle = resHandle;
2095 if(newUri != requiredUri)
2099 if (result != OC_STACK_OK)
2101 OC_LOG_V(ERROR, TAG, PCF("OCDoResource error no %d"), result);
2102 FindAndDeleteClientCB(clientCB);
2105 OCFree(resourceType);
2107 CADestroyRemoteEndpoint(endpoint);
2108 OCFree(grpEnd.resourceUri);
2110 if (requestData.options && requestData.numOptions > 0)
2112 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2114 OCFree(requestData.options);
2120 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
2124 * This ftn is implemented one of two ways in the case of observation:
2126 * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
2127 * Remove the callback associated on client side.
2128 * When the next notification comes in from server,
2129 * reply with RESET message to server.
2130 * Keep in mind that the server will react to RESET only
2131 * if the last notification was sent as CON
2133 * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
2134 * and it is associated with an observe request
2135 * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
2136 * Send CON Observe request to server with
2137 * observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
2138 * Remove the callback associated on client side.
2140 OCStackResult ret = OC_STACK_OK;
2141 CARemoteEndpoint_t* endpoint = NULL;
2142 CAResult_t caResult;
2143 CAInfo_t requestData = {};
2144 CARequestInfo_t requestInfo = {};
2148 return OC_STACK_INVALID_PARAM;
2151 OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
2153 ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL);
2157 switch (clientCB->method)
2159 case OC_REST_OBSERVE:
2160 case OC_REST_OBSERVE_ALL:
2161 if(qos == OC_HIGH_QOS)
2163 requestData.type = qualityOfServiceToMessageType(qos);
2164 requestData.token = clientCB->token;
2165 requestData.tokenLength = clientCB->tokenLength;
2167 if (CreateObserveHeaderOption (&(requestData.options),
2168 options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
2170 return OC_STACK_ERROR;
2172 requestData.numOptions = numOptions + 1;
2173 requestInfo.method = CA_GET;
2174 requestInfo.info = requestData;
2176 CATransportType_t caConType;
2177 ret = OCToCATransportType(clientCB->conType, &caConType);
2178 if(ret != OC_STACK_OK)
2183 caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri,
2184 caConType, &endpoint);
2185 if (caResult != CA_STATUS_OK)
2187 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2188 ret = OC_STACK_ERROR;
2193 caResult = CASendRequest(endpoint, &requestInfo);
2194 if (caResult != CA_STATUS_OK)
2196 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2197 ret = OC_STACK_ERROR;
2199 ret = CAResultToOCResult (caResult);
2203 FindAndDeleteClientCB(clientCB);
2207 #ifdef WITH_PRESENCE
2208 case OC_REST_PRESENCE:
2209 FindAndDeleteClientCB(clientCB);
2213 ret = OC_STACK_INVALID_METHOD;
2219 OC_LOG(ERROR, TAG, PCF("Client callback not found. Called OCCancel twice?"));
2223 CADestroyRemoteEndpoint(endpoint);
2224 if (requestData.numOptions > 0)
2226 OCFree(requestData.options);
2232 #ifdef WITH_PRESENCE
2233 OCStackResult OCProcessPresence()
2235 OCStackResult result = OC_STACK_OK;
2236 uint8_t ipAddr[4] = { 0 };
2239 OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
2240 ClientCB* cbNode = NULL;
2242 OCClientResponse clientResponse ={};
2243 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
2245 LL_FOREACH(cbList, cbNode)
2247 if(OC_REST_PRESENCE == cbNode->method)
2249 if(cbNode->presence)
2251 uint32_t now = GetTicks(0);
2252 OC_LOG_V(DEBUG, TAG, "this TTL level %d",
2253 cbNode->presence->TTLlevel);
2254 OC_LOG_V(DEBUG, TAG, "current ticks %d", now);
2257 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
2262 if(cbNode->presence->TTLlevel < PresenceTimeOutSize)
2264 OC_LOG_V(DEBUG, TAG, "timeout ticks %d",
2265 cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
2268 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
2270 OC_LOG(DEBUG, TAG, PCF("No more timeout ticks"));
2271 if (ParseIPv4Address(cbNode->requestUri, ipAddr, &port))
2273 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
2276 clientResponse.sequenceNumber = 0;
2277 clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
2278 clientResponse.addr = (OCDevAddr *) &dst;
2279 clientResponse.resJSONPayload = NULL;
2281 // Increment the TTLLevel (going to a next state), so we don't keep
2282 // sending presence notification to client.
2283 cbNode->presence->TTLlevel++;
2284 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2285 cbNode->presence->TTLlevel);
2289 result = OC_STACK_INVALID_IP;
2293 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
2294 if (cbResult == OC_STACK_DELETE_TRANSACTION)
2296 FindAndDeleteClientCB(cbNode);
2300 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
2302 CAResult_t caResult = CA_STATUS_OK;
2303 CARemoteEndpoint_t* endpoint = NULL;
2304 CAInfo_t requestData ={};
2305 CARequestInfo_t requestInfo = {};
2307 OC_LOG(DEBUG, TAG, PCF("time to test server presence"));
2310 CATransportType_t caConType;
2311 result = OCToCATransportType(cbNode->conType, &caConType);
2312 caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, caConType,
2314 if (caResult != CA_STATUS_OK || result != OC_STACK_OK)
2316 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2320 requestData.type = CA_MSG_NONCONFIRM;
2321 requestData.token = cbNode->token;
2322 requestData.tokenLength = cbNode->tokenLength;
2323 requestInfo.method = CA_GET;
2324 requestInfo.info = requestData;
2326 caResult = CASendRequest(endpoint, &requestInfo);
2327 CADestroyRemoteEndpoint(endpoint);
2329 if (caResult != CA_STATUS_OK)
2331 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2335 cbNode->presence->TTLlevel++;
2336 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2337 cbNode->presence->TTLlevel);
2343 if (result != OC_STACK_OK)
2345 OC_LOG_V(ERROR, TAG, PCF("OCProcessPresence error no %d"), result);
2349 #endif // WITH_PRESENCE
2351 OCStackResult OCProcess()
2353 #ifdef WITH_PRESENCE
2354 OCProcessPresence();
2356 CAHandleRequestResponse();
2361 #ifdef WITH_PRESENCE
2362 OCStackResult OCStartPresence(const uint32_t ttl)
2364 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
2365 OCChangeResourceProperty(
2366 &(((OCResource *)presenceResource.handle)->resourceProperties),
2369 if (OC_MAX_PRESENCE_TTL_SECONDS < ttl)
2371 presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS;
2372 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to max value"));
2376 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
2377 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to default value"));
2381 presenceResource.presenceTTL = ttl;
2383 OC_LOG_V(DEBUG, TAG, "Presence TTL is %lu seconds", presenceResource.presenceTTL);
2385 if (OC_PRESENCE_UNINITIALIZED == presenceState)
2387 presenceState = OC_PRESENCE_INITIALIZED;
2389 CAAddress_t addressInfo;
2390 strncpy(addressInfo.IP.ipAddress, OC_MULTICAST_IP, CA_IPADDR_SIZE);
2391 addressInfo.IP.port = OC_MULTICAST_PORT;
2393 CAToken_t caToken = NULL;
2394 CAResult_t caResult = CAGenerateToken(&caToken, tokenLength);
2395 if (caResult != CA_STATUS_OK)
2397 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2398 CADestroyToken(caToken);
2399 return OC_STACK_ERROR;
2402 CATransportType_t connType;
2403 OCToCATransportType(OC_ALL, &connType );
2404 AddObserver(OC_PRESENCE_URI, NULL, 0, caToken, tokenLength,
2405 (OCResource *)presenceResource.handle, OC_LOW_QOS,
2406 &addressInfo, connType);
2407 CADestroyToken(caToken);
2410 // Each time OCStartPresence is called
2411 // a different random 32-bit integer number is used
2412 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2414 return SendPresenceNotification(NULL);
2417 OCStackResult OCStopPresence()
2419 OCStackResult result = OC_STACK_ERROR;
2421 if(presenceResource.handle)
2423 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2426 // make resource inactive
2427 result = OCChangeResourceProperty(
2428 &(((OCResource *) presenceResource.handle)->resourceProperties),
2431 if(result != OC_STACK_OK)
2434 PCF("Changing the presence resource properties to ACTIVE not successful"));
2438 return SendStopNotification();
2442 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
2444 defaultDeviceHandler = entityHandler;
2449 OCStackResult OCSetPlatformInfo(OCPlatformInfo platformInfo)
2451 OC_LOG(INFO, TAG, PCF("Entering OCSetPlatformInfo"));
2453 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
2455 if (validatePlatformInfo(platformInfo))
2457 return SavePlatformInfo(platformInfo);
2461 return OC_STACK_INVALID_PARAM;
2466 return OC_STACK_ERROR;
2470 OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
2472 // TODO: Implement this.
2473 OC_LOG(ERROR, TAG, "Implement OCSetDeviceInfo !!");
2475 // Returning ok to make samples work.
2479 OCStackResult OCCreateResource(OCResourceHandle *handle,
2480 const char *resourceTypeName,
2481 const char *resourceInterfaceName,
2482 const char *uri, OCEntityHandler entityHandler,
2483 uint8_t resourceProperties)
2486 OCResource *pointer = NULL;
2489 OCStackResult result = OC_STACK_ERROR;
2491 OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
2493 if(myStackMode == OC_CLIENT)
2495 return OC_STACK_INVALID_PARAM;
2497 // Validate parameters
2498 if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH )
2500 OC_LOG(ERROR, TAG, PCF("URI is invalid"));
2501 return OC_STACK_INVALID_URI;
2503 // Is it presented during resource discovery?
2504 if (!handle || !resourceTypeName)
2506 OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
2507 return OC_STACK_INVALID_PARAM;
2510 if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0)
2512 resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
2515 // Make sure resourceProperties bitmask has allowed properties specified
2516 if (resourceProperties
2517 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE))
2519 OC_LOG(ERROR, TAG, PCF("Invalid property"));
2520 return OC_STACK_INVALID_PARAM;
2523 // If the headResource is NULL, then no resources have been created...
2524 pointer = headResource;
2527 // At least one resources is in the resource list, so we need to search for
2528 // repeated URLs, which are not allowed. If a repeat is found, exit with an error
2531 if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0)
2533 OC_LOG(ERROR, TAG, PCF("URI already in use"));
2534 return OC_STACK_INVALID_PARAM;
2536 pointer = pointer->next;
2539 // Create the pointer and insert it into the resource list
2540 pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
2543 result = OC_STACK_NO_MEMORY;
2546 pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
2548 insertResource(pointer);
2551 size = strlen(uri) + 1;
2552 str = (char *) OCMalloc(size);
2555 result = OC_STACK_NO_MEMORY;
2558 strncpy(str, uri, size);
2561 // Set properties. Set OC_ACTIVE
2562 pointer->resourceProperties = (OCResourceProperty) (resourceProperties
2565 // Add the resourcetype to the resource
2566 result = BindResourceTypeToResource(pointer, resourceTypeName);
2567 if (result != OC_STACK_OK)
2569 OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
2573 // Add the resourceinterface to the resource
2574 result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
2575 if (result != OC_STACK_OK)
2577 OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
2581 // If an entity handler has been passed, attach it to the newly created
2582 // resource. Otherwise, set the default entity handler.
2585 pointer->entityHandler = entityHandler;
2589 pointer->entityHandler = defaultResourceEHandler;
2593 result = OC_STACK_OK;
2595 #ifdef WITH_PRESENCE
2596 if(presenceResource.handle)
2598 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2599 SendPresenceNotification(pointer->rsrcType);
2603 if (result != OC_STACK_OK)
2605 // Deep delete of resource and other dynamic elements that it contains
2606 deleteResource(pointer);
2612 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
2613 const char *resourceTypeName,
2614 const char *resourceInterfaceName,
2617 OCEntityHandler entityHandler,
2618 uint8_t resourceProperties)
2620 OC_LOG(INFO, TAG, PCF("Entering OCCreateResourceWithHost"));
2626 OC_LOG(ERROR, TAG, PCF("Added resource host is NULL."));
2627 return OC_STACK_INVALID_PARAM;
2630 OCStackResult result = OC_STACK_ERROR;
2632 result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
2633 uri, entityHandler, resourceProperties);
2635 if (result == OC_STACK_OK)
2638 size = strlen(host) + 1;
2639 str = (char *) OCMalloc(size);
2642 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated."));
2643 return OC_STACK_NO_MEMORY;
2645 strncpy(str, host, size);
2647 ((OCResource *) *handle)->host = str;
2653 OCStackResult OCBindResource(
2654 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2656 OCResource *resource = NULL;
2659 OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
2661 // Validate parameters
2662 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2663 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2664 // Container cannot contain itself
2665 if (collectionHandle == resourceHandle)
2667 OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
2668 return OC_STACK_INVALID_PARAM;
2671 // Use the handle to find the resource in the resource linked list
2672 resource = findResource((OCResource *) collectionHandle);
2675 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2676 return OC_STACK_INVALID_PARAM;
2679 // Look for an open slot to add add the child resource.
2680 // If found, add it and return success
2681 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2683 if (!resource->rsrcResources[i])
2685 resource->rsrcResources[i] = (OCResource *) resourceHandle;
2686 OC_LOG(INFO, TAG, PCF("resource bound"));
2688 #ifdef WITH_PRESENCE
2689 if(presenceResource.handle)
2691 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2692 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2700 // Unable to add resourceHandle, so return error
2701 return OC_STACK_ERROR;
2704 OCStackResult OCUnBindResource(
2705 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2707 OCResource *resource = NULL;
2710 OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
2712 // Validate parameters
2713 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2714 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2715 // Container cannot contain itself
2716 if (collectionHandle == resourceHandle)
2718 OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
2719 return OC_STACK_INVALID_PARAM;
2722 // Use the handle to find the resource in the resource linked list
2723 resource = findResource((OCResource *) collectionHandle);
2726 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2727 return OC_STACK_INVALID_PARAM;
2730 // Look for an open slot to add add the child resource.
2731 // If found, add it and return success
2732 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2734 if (resourceHandle == resource->rsrcResources[i])
2736 resource->rsrcResources[i] = (OCResource *) NULL;
2737 OC_LOG(INFO, TAG, PCF("resource unbound"));
2739 // Send notification when resource is unbounded successfully.
2740 #ifdef WITH_PRESENCE
2741 if(presenceResource.handle)
2743 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2744 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2751 OC_LOG(INFO, TAG, PCF("resource not found in collection"));
2753 // Unable to add resourceHandle, so return error
2754 return OC_STACK_ERROR;
2757 OCStackResult BindResourceTypeToResource(OCResource* resource,
2758 const char *resourceTypeName)
2760 OCResourceType *pointer = NULL;
2763 OCStackResult result = OC_STACK_ERROR;
2765 OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
2767 // Validate parameters
2768 VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
2769 // TODO: Does resource attribute representation really have to be maintained in stack?
2770 // Is it presented during resource discovery?
2772 // Create the resourcetype and insert it into the resource list
2773 pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
2776 result = OC_STACK_NO_MEMORY;
2780 // Set the resourceTypeName
2781 size = strlen(resourceTypeName) + 1;
2782 str = (char *) OCMalloc(size);
2785 result = OC_STACK_NO_MEMORY;
2788 strncpy(str, resourceTypeName, size);
2789 pointer->resourcetypename = str;
2791 insertResourceType(resource, pointer);
2792 result = OC_STACK_OK;
2795 if (result != OC_STACK_OK)
2804 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
2805 const char *resourceInterfaceName)
2807 OCResourceInterface *pointer = NULL;
2810 OCStackResult result = OC_STACK_ERROR;
2812 OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
2814 // Validate parameters
2815 VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
2817 //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
2819 // Create the resourceinterface and insert it into the resource list
2820 pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
2823 result = OC_STACK_NO_MEMORY;
2827 // Set the resourceinterface name
2828 size = strlen(resourceInterfaceName) + 1;
2829 str = (char *) OCMalloc(size);
2832 result = OC_STACK_NO_MEMORY;
2835 strncpy(str, resourceInterfaceName, size);
2836 pointer->name = str;
2838 // Bind the resourceinterface to the resource
2839 insertResourceInterface(resource, pointer);
2841 result = OC_STACK_OK;
2844 if (result != OC_STACK_OK)
2853 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
2854 const char *resourceTypeName)
2857 OCStackResult result = OC_STACK_ERROR;
2858 OCResource *resource = NULL;
2860 // Make sure resource exists
2861 resource = findResource((OCResource *) handle);
2864 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2865 return OC_STACK_ERROR;
2868 // call internal function
2869 result = BindResourceTypeToResource(resource, resourceTypeName);
2871 #ifdef WITH_PRESENCE
2872 if(presenceResource.handle)
2874 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2875 SendPresenceNotification(resource->rsrcType);
2882 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
2883 const char *resourceInterfaceName)
2886 OCStackResult result = OC_STACK_ERROR;
2887 OCResource *resource = NULL;
2889 // Make sure resource exists
2890 resource = findResource((OCResource *) handle);
2893 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2894 return OC_STACK_ERROR;
2897 // call internal function
2898 result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2900 #ifdef WITH_PRESENCE
2901 if(presenceResource.handle)
2903 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2904 SendPresenceNotification(resource->rsrcType);
2911 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
2913 OCResource *pointer = headResource;
2915 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2916 VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2920 *numResources = *numResources + 1;
2921 pointer = pointer->next;
2926 OCResourceHandle OCGetResourceHandle(uint8_t index)
2928 OCResource *pointer = headResource;
2930 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2932 // Iterate through the list
2933 for( uint8_t i = 0; i < index && pointer; ++i)
2935 pointer = pointer->next;
2937 return (OCResourceHandle) pointer;
2940 OCStackResult OCDeleteResource(OCResourceHandle handle)
2942 OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2946 OC_LOG(ERROR, TAG, PCF("Invalid param"));
2947 return OC_STACK_INVALID_PARAM;
2950 OCResource *resource = findResource((OCResource *) handle);
2951 if (resource == NULL)
2953 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2954 return OC_STACK_NO_RESOURCE;
2957 if (deleteResource((OCResource *) handle) != OC_STACK_OK)
2959 OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2960 return OC_STACK_ERROR;
2966 const char *OCGetResourceUri(OCResourceHandle handle)
2968 OCResource *resource = NULL;
2969 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2971 resource = findResource((OCResource *) handle);
2974 return resource->uri;
2976 return (const char *) NULL;
2979 OCResourceProperty OCGetResourceProperties(OCResourceHandle handle)
2981 OCResource *resource = NULL;
2982 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2984 resource = findResource((OCResource *) handle);
2987 return resource->resourceProperties;
2989 return (OCResourceProperty)-1;
2992 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2993 uint8_t *numResourceTypes)
2995 OCResource *resource = NULL;
2996 OCResourceType *pointer = NULL;
2998 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2999 VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
3000 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3002 *numResourceTypes = 0;
3004 resource = findResource((OCResource *) handle);
3007 pointer = resource->rsrcType;
3010 *numResourceTypes = *numResourceTypes + 1;
3011 pointer = pointer->next;
3017 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index)
3019 OCResourceType *resourceType = NULL;
3021 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
3023 resourceType = findResourceTypeAtIndex(handle, index);
3026 return resourceType->resourcetypename;
3028 return (const char *) NULL;
3031 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
3032 uint8_t *numResourceInterfaces)
3034 OCResourceInterface *pointer = NULL;
3035 OCResource *resource = NULL;
3037 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
3039 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3040 VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
3042 *numResourceInterfaces = 0;
3043 resource = findResource((OCResource *) handle);
3046 pointer = resource->rsrcInterface;
3049 *numResourceInterfaces = *numResourceInterfaces + 1;
3050 pointer = pointer->next;
3056 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index)
3058 OCResourceInterface *resourceInterface = NULL;
3060 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
3062 resourceInterface = findResourceInterfaceAtIndex(handle, index);
3063 if (resourceInterface)
3065 return resourceInterface->name;
3067 return (const char *) NULL;
3070 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
3073 OCResource *resource = NULL;
3075 OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
3077 if (index >= MAX_CONTAINED_RESOURCES)
3082 resource = findResource((OCResource *) collectionHandle);
3088 return resource->rsrcResources[index];
3091 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
3092 OCEntityHandler entityHandler)
3094 OCResource *resource = NULL;
3096 OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
3098 // Validate parameters
3099 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3101 // Use the handle to find the resource in the resource linked list
3102 resource = findResource((OCResource *)handle);
3105 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3106 return OC_STACK_ERROR;
3110 resource->entityHandler = entityHandler;
3112 #ifdef WITH_PRESENCE
3113 if(presenceResource.handle)
3115 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3116 SendPresenceNotification(resource->rsrcType);
3123 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle)
3125 OCResource *resource = NULL;
3127 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
3129 // Use the handle to find the resource in the resource linked list
3130 resource = findResource((OCResource *)handle);
3133 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3138 return resource->entityHandler;
3141 void incrementSequenceNumber(OCResource * resPtr)
3143 // Increment the sequence number
3144 resPtr->sequenceNum += 1;
3145 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
3147 resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
3152 #ifdef WITH_PRESENCE
3153 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
3155 OCResource *resPtr = NULL;
3156 OCStackResult result = OC_STACK_ERROR;
3157 OCMethod method = OC_REST_PRESENCE;
3158 uint32_t maxAge = 0;
3159 resPtr = findResource((OCResource *) presenceResource.handle);
3162 return OC_STACK_NO_RESOURCE;
3165 if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
3167 maxAge = presenceResource.presenceTTL;
3169 result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
3175 OCStackResult SendStopNotification()
3177 OCResource *resPtr = NULL;
3178 OCStackResult result = OC_STACK_ERROR;
3179 OCMethod method = OC_REST_PRESENCE;
3180 resPtr = findResource((OCResource *) presenceResource.handle);
3183 return OC_STACK_NO_RESOURCE;
3186 // maxAge is 0. ResourceType is NULL.
3187 result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
3192 #endif // WITH_PRESENCE
3193 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos)
3196 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3198 OCResource *resPtr = NULL;
3199 OCStackResult result = OC_STACK_ERROR;
3200 OCMethod method = OC_REST_NOMETHOD;
3201 uint32_t maxAge = 0;
3203 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3204 #ifdef WITH_PRESENCE
3205 if(handle == presenceResource.handle)
3209 #endif // WITH_PRESENCE
3210 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3212 // Verify that the resource exists
3213 resPtr = findResource ((OCResource *) handle);
3216 return OC_STACK_NO_RESOURCE;
3220 //only increment in the case of regular observing (not presence)
3221 incrementSequenceNumber(resPtr);
3222 method = OC_REST_OBSERVE;
3223 maxAge = MAX_OBSERVE_AGE;
3224 #ifdef WITH_PRESENCE
3225 result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
3227 result = SendAllObserverNotification (method, resPtr, maxAge, qos);
3234 OCNotifyListOfObservers (OCResourceHandle handle,
3235 OCObservationId *obsIdList,
3236 uint8_t numberOfIds,
3237 const char *notificationJSONPayload,
3238 OCQualityOfService qos)
3240 OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
3242 OCResource *resPtr = NULL;
3243 //TODO: we should allow the server to define this
3244 uint32_t maxAge = MAX_OBSERVE_AGE;
3246 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3247 VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
3248 VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
3250 // Verify that the resource exists
3251 resPtr = findResource ((OCResource *) handle);
3252 if (NULL == resPtr || myStackMode == OC_CLIENT)
3254 return OC_STACK_NO_RESOURCE;
3258 incrementSequenceNumber(resPtr);
3260 return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
3261 notificationJSONPayload, maxAge, qos));
3264 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
3266 OCStackResult result = OC_STACK_ERROR;
3267 OCServerRequest *serverRequest = NULL;
3269 OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
3271 // Validate input parameters
3272 VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
3273 VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
3275 // TODO: Placeholder for creating a response entry when implementing
3276 // block transfer feature
3278 // If a response payload is present, check if block transfer is required
3279 if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
3280 (const char *)ehResponse->payload, ehResponse->payloadSize))
3282 OC_LOG(INFO, TAG, PCF("Block transfer required"));
3284 // Persistent response buffer is needed for block transfer
3285 if (!ehResponse->persistentBufferFlag)
3287 OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
3288 return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
3290 // TODO: Placeholder for block transfer handling
3291 // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
3292 // when implementing the block transfer feature
3297 // Get pointer to request info
3298 serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
3301 result = serverRequest->ehResponseHandler(ehResponse);
3307 //-----------------------------------------------------------------------------
3308 // Private internal function definitions
3309 //-----------------------------------------------------------------------------
3310 static OCDoHandle GenerateInvocationHandle()
3312 OCDoHandle handle = NULL;
3313 // Generate token here, it will be deleted when the transaction is deleted
3314 handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3317 OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3323 #ifdef WITH_PRESENCE
3324 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
3325 OCResourceProperty resourceProperties, uint8_t enable)
3329 return OC_STACK_INVALID_PARAM;
3331 if (resourceProperties
3332 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW))
3334 OC_LOG(ERROR, TAG, PCF("Invalid property"));
3335 return OC_STACK_INVALID_PARAM;
3339 *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
3343 *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
3349 OCStackResult initResources()
3351 OCStackResult result = OC_STACK_OK;
3352 // Init application resource vars
3353 headResource = NULL;
3354 tailResource = NULL;
3355 // Init Virtual Resources
3356 #ifdef WITH_PRESENCE
3357 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
3358 //presenceResource.token = OCGenerateCoAPToken();
3359 result = OCCreateResource(&presenceResource.handle,
3360 OC_RSRVD_RESOURCE_TYPE_PRESENCE,
3365 //make resource inactive
3366 result = OCChangeResourceProperty(
3367 &(((OCResource *) presenceResource.handle)->resourceProperties),
3373 void insertResource(OCResource *resource)
3377 headResource = resource;
3378 tailResource = resource;
3382 tailResource->next = resource;
3383 tailResource = resource;
3385 resource->next = NULL;
3388 OCResource *findResource(OCResource *resource)
3390 OCResource *pointer = headResource;
3394 if (pointer == resource)
3398 pointer = pointer->next;
3403 void deleteAllResources()
3405 OCResource *pointer = headResource;
3406 OCResource *temp = NULL;
3410 temp = pointer->next;
3411 #ifdef WITH_PRESENCE
3412 if(pointer != (OCResource *) presenceResource.handle)
3414 #endif // WITH_PRESENCE
3415 deleteResource(pointer);
3416 #ifdef WITH_PRESENCE
3418 #endif // WITH_PRESENCE
3422 #ifdef WITH_PRESENCE
3423 // Ensure that the last resource to be deleted is the presence resource. This allows for all
3424 // presence notification attributed to their deletion to be processed.
3425 deleteResource((OCResource *) presenceResource.handle);
3426 #endif // WITH_PRESENCE
3429 OCStackResult deleteResource(OCResource *resource)
3431 OCResource *prev = NULL;
3432 OCResource *temp = NULL;
3434 temp = headResource;
3437 if (temp == resource)
3439 // Invalidate all Resource Properties.
3440 resource->resourceProperties = (OCResourceProperty) 0;
3441 #ifdef WITH_PRESENCE
3442 if(resource != (OCResource *) presenceResource.handle)
3444 #endif // WITH_PRESENCE
3445 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
3446 #ifdef WITH_PRESENCE
3449 if(presenceResource.handle)
3451 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3452 if(resource != (OCResource *) presenceResource.handle)
3454 SendPresenceNotification(resource->rsrcType);
3458 SendPresenceNotification(NULL);
3462 // Only resource in list.
3463 if (temp == headResource && temp == tailResource)
3465 headResource = NULL;
3466 tailResource = NULL;
3469 else if (temp == headResource)
3471 headResource = temp->next;
3474 else if (temp == tailResource)
3476 tailResource = prev;
3477 tailResource->next = NULL;
3481 prev->next = temp->next;
3484 deleteResourceElements(temp);
3495 return OC_STACK_ERROR;
3498 void deleteResourceElements(OCResource *resource)
3506 OCFree(resource->uri);
3508 // Delete resourcetype linked list
3509 deleteResourceType(resource->rsrcType);
3511 // Delete resourceinterface linked list
3512 deleteResourceInterface(resource->rsrcInterface);
3515 void deleteResourceType(OCResourceType *resourceType)
3517 OCResourceType *pointer = resourceType;
3518 OCResourceType *next = NULL;
3522 next = pointer->next;
3523 OCFree(pointer->resourcetypename);
3529 void deleteResourceInterface(OCResourceInterface *resourceInterface)
3531 OCResourceInterface *pointer = resourceInterface;
3532 OCResourceInterface *next = NULL;
3536 next = pointer->next;
3537 OCFree(pointer->name);
3543 void insertResourceType(OCResource *resource, OCResourceType *resourceType)
3545 OCResourceType *pointer = NULL;
3546 OCResourceType *previous = NULL;
3547 if (!resource || !resourceType)
3551 // resource type list is empty.
3552 else if (!resource->rsrcType)
3554 resource->rsrcType = resourceType;
3558 pointer = resource->rsrcType;
3562 // resource type already exists. Free 2nd arg and return.
3563 if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename))
3565 OCFree(resourceType->resourcetypename);
3566 OCFree(resourceType);
3570 pointer = pointer->next;
3572 previous->next = resourceType;
3574 resourceType->next = NULL;
3577 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index)
3579 OCResource *resource = NULL;
3580 OCResourceType *pointer = NULL;
3582 // Find the specified resource
3583 resource = findResource((OCResource *) handle);
3589 // Make sure a resource has a resourcetype
3590 if (!resource->rsrcType)
3595 // Iterate through the list
3596 pointer = resource->rsrcType;
3597 for(uint8_t i = 0; i< index && pointer; ++i)
3599 pointer = pointer->next;
3604 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
3606 if(resourceTypeList && resourceTypeName)
3608 OCResourceType * rtPointer = resourceTypeList;
3609 while(resourceTypeName && rtPointer)
3611 if(rtPointer->resourcetypename &&
3612 strcmp(resourceTypeName, (const char *)
3613 (rtPointer->resourcetypename)) == 0)
3617 rtPointer = rtPointer->next;
3625 * Insert a new interface into interface linked list only if not already present.
3626 * If alredy present, 2nd arg is free'd.
3627 * Default interface will always be first if present.
3629 void insertResourceInterface(OCResource *resource, OCResourceInterface *newInterface)
3631 OCResourceInterface *pointer = NULL;
3632 OCResourceInterface *previous = NULL;
3634 newInterface->next = NULL;
3636 OCResourceInterface **firstInterface = &(resource->rsrcInterface);
3638 if (!*firstInterface)
3640 *firstInterface = newInterface;
3642 else if (strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3644 if (strcmp((*firstInterface)->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3646 OCFree(newInterface->name);
3647 OCFree(newInterface);
3652 newInterface->next = *firstInterface;
3653 *firstInterface = newInterface;
3658 pointer = *firstInterface;
3661 if (strcmp(newInterface->name, pointer->name) == 0)
3663 OCFree(newInterface->name);
3664 OCFree(newInterface);
3668 pointer = pointer->next;
3670 previous->next = newInterface;
3674 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
3677 OCResource *resource = NULL;
3678 OCResourceInterface *pointer = NULL;
3680 // Find the specified resource
3681 resource = findResource((OCResource *) handle);
3687 // Make sure a resource has a resourceinterface
3688 if (!resource->rsrcInterface)
3693 // Iterate through the list
3694 pointer = resource->rsrcInterface;
3696 for (uint8_t i = 0; i < index && pointer; ++i)
3698 pointer = pointer->next;
3703 bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size)
3705 bool result = false;
3707 // Determine if we are checking a request or a response
3710 // If size is greater than 0, use it for the request size value, otherwise
3711 // assume request is null terminated and use strlen for size value
3712 if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
3719 // If size is greater than 0, use it for the response size value, otherwise
3720 // assume response is null terminated and use strlen for size value
3721 if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
3729 OCStackResult getResourceType(const char * query, char** resourceType)
3733 return OC_STACK_INVALID_PARAM;
3736 OCStackResult result = OC_STACK_ERROR;
3738 if(strncmp(query, "rt=", 3) == 0)
3740 *resourceType = (char *) OCMalloc(strlen(query)-3 + 1);
3743 result = OC_STACK_NO_MEMORY;
3747 strcpy((char *)*resourceType, ((const char *)&query[3]));
3748 result = OC_STACK_OK;
3756 * This function splits the uri using the '?' delimiter.
3757 * "uriWithoutQuery" is the block of characters between the beginning
3758 * till the delimiter or '\0' which ever comes first.
3759 * "query" is whatever is to the right of the delimiter if present.
3760 * No delimiter sets the query to NULL.
3761 * If either are present, they will be malloc'ed into the params 2, 3.
3762 * The first param, *uri is left untouched.
3764 * NOTE: This function does not account for whitespace at the end of the uri NOR
3765 * malformed uri's with '??'. Whitespace at the end will be assumed to be
3766 * part of the query.
3768 OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithoutQuery)
3772 return OC_STACK_INVALID_URI;
3774 if(!query || !uriWithoutQuery)
3776 return OC_STACK_INVALID_PARAM;
3780 *uriWithoutQuery = NULL;
3782 size_t uriWithoutQueryLen = 0;
3783 size_t queryLen = 0;
3784 size_t uriLen = strlen(uri);
3786 char *pointerToDelimiter = strstr(uri, "?");
3788 uriWithoutQueryLen = pointerToDelimiter == NULL ? uriLen : pointerToDelimiter - uri;
3789 queryLen = pointerToDelimiter == NULL ? 0 : uriLen - uriWithoutQueryLen - 1;
3791 if (uriWithoutQueryLen)
3793 *uriWithoutQuery = (char *) OCCalloc(uriWithoutQueryLen + 1, 1);
3794 if (!*uriWithoutQuery)
3798 strncpy(*uriWithoutQuery, uri, uriWithoutQueryLen);
3802 return OC_STACK_INVALID_PARAM;
3807 *query = (char *) OCCalloc(queryLen + 1, 1);
3810 OCFree(*uriWithoutQuery);
3811 *uriWithoutQuery = NULL;
3814 strncpy(*query, pointerToDelimiter + 1, queryLen);
3820 return OC_STACK_NO_MEMORY;
3823 const uint8_t* OCGetServerInstanceID(void)
3825 static bool generated = false;
3826 static ServerID sid;
3832 if (OCGenerateUuid(sid) != RAND_UUID_OK)
3834 OC_LOG(FATAL, TAG, PCF("Generate UUID for Server Instance failed!"));
3841 const char* OCGetServerInstanceIDString(void)
3843 static bool generated = false;
3844 static char sidStr[UUID_STRING_SIZE];
3851 const uint8_t* sid = OCGetServerInstanceID();
3853 if(OCConvertUuidToString(sid, sidStr) != RAND_UUID_OK)
3855 OC_LOG(FATAL, TAG, PCF("Generate UUID String for Server Instance failed!"));
3863 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
3864 uint8_t *c, uint8_t *d )
3866 if ( !ipAddr || !a || !b || !c || !d )
3868 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3869 return OC_STACK_INVALID_PARAM;
3872 *a = ipAddr->addr[0];
3873 *b = ipAddr->addr[1];
3874 *c = ipAddr->addr[2];
3875 *d = ipAddr->addr[3];
3880 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
3882 if ( !ipAddr || !port )
3884 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3885 return OC_STACK_INVALID_PARAM;
3888 *port = (ipAddr->addr[5]<< 8) | ipAddr->addr[4];
3893 CAResult_t OCSelectNetwork()
3895 CAResult_t retResult = CA_STATUS_FAILED;
3896 CAResult_t caResult = CA_STATUS_OK;
3898 CATransportType_t connTypes[] = {
3902 int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]);
3904 for(int i = 0; i<numConnTypes; i++)
3906 // Ignore CA_NOT_SUPPORTED error. The CA Layer may have not compiled in the interface.
3907 if(caResult == CA_STATUS_OK || caResult == CA_NOT_SUPPORTED)
3909 caResult = CASelectNetwork(connTypes[i]);
3910 if(caResult == CA_STATUS_OK)
3912 retResult = CA_STATUS_OK;
3917 if(retResult != CA_STATUS_OK)
3919 return caResult; // Returns error of appropriate transport that failed fatally.
3925 OCStackResult CAResultToOCResult(CAResult_t caResult)
3931 case CA_STATUS_INVALID_PARAM:
3932 return OC_STACK_INVALID_PARAM;
3933 case CA_ADAPTER_NOT_ENABLED:
3934 return OC_STACK_ADAPTER_NOT_ENABLED;
3935 case CA_SERVER_STARTED_ALREADY:
3937 case CA_SERVER_NOT_STARTED:
3938 return OC_STACK_ERROR;
3939 case CA_DESTINATION_NOT_REACHABLE:
3940 return OC_STACK_COMM_ERROR;
3941 case CA_SOCKET_OPERATION_FAILED:
3942 return OC_STACK_COMM_ERROR;
3943 case CA_SEND_FAILED:
3944 return OC_STACK_COMM_ERROR;
3945 case CA_RECEIVE_FAILED:
3946 return OC_STACK_COMM_ERROR;
3947 case CA_MEMORY_ALLOC_FAILED:
3948 return OC_STACK_NO_MEMORY;
3949 case CA_REQUEST_TIMEOUT:
3950 return OC_STACK_TIMEOUT;
3951 case CA_DESTINATION_DISCONNECTED:
3952 return OC_STACK_COMM_ERROR;
3953 case CA_STATUS_FAILED:
3954 return OC_STACK_ERROR;
3955 case CA_NOT_SUPPORTED:
3956 return OC_STACK_NOTIMPL;
3958 return OC_STACK_ERROR;