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 //-----------------------------------------------------------------------------
1667 //-----------------------------------------------------------------------------
1669 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
1671 if(stackState == OC_STACK_INITIALIZED)
1673 OC_LOG(INFO, TAG, PCF("Subsequent calls to OCInit() without calling \
1674 OCStop() between them are ignored."));
1680 OCStackResult result = OC_STACK_ERROR;
1681 OC_LOG(INFO, TAG, PCF("Entering OCInit"));
1684 if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
1686 OC_LOG(ERROR, TAG, PCF("Invalid mode"));
1687 return OC_STACK_ERROR;
1691 defaultDeviceHandler = NULL;
1694 result = CAResultToOCResult(CAInitialize());
1695 VERIFY_SUCCESS(result, OC_STACK_OK);
1697 result = CAResultToOCResult(OCSelectNetwork());
1698 VERIFY_SUCCESS(result, OC_STACK_OK);
1700 CARegisterHandler(HandleCARequests, HandleCAResponses);
1701 switch (myStackMode)
1704 result = CAResultToOCResult(CAStartDiscoveryServer());
1705 OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
1708 result = CAResultToOCResult(CAStartListeningServer());
1709 OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
1711 case OC_CLIENT_SERVER:
1712 result = CAResultToOCResult(CAStartListeningServer());
1713 if(result == OC_STACK_OK)
1715 result = CAResultToOCResult(CAStartDiscoveryServer());
1719 VERIFY_SUCCESS(result, OC_STACK_OK);
1721 #if defined(__WITH_DTLS__)
1722 result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ?
1723 OC_STACK_OK : OC_STACK_ERROR;
1724 VERIFY_SUCCESS(result, OC_STACK_OK);
1725 #endif // (__WITH_DTLS__)
1727 #ifdef WITH_PRESENCE
1728 PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
1729 #endif // WITH_PRESENCE
1731 //Update Stack state to initialized
1732 stackState = OC_STACK_INITIALIZED;
1734 // Initialize resource
1735 if(myStackMode != OC_CLIENT)
1737 result = initResources();
1741 if(result != OC_STACK_OK)
1743 OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
1744 deleteAllResources();
1746 stackState = OC_STACK_UNINITIALIZED;
1751 OCStackResult OCStop()
1753 OC_LOG(INFO, TAG, PCF("Entering OCStop"));
1755 if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
1757 OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
1760 else if (stackState != OC_STACK_INITIALIZED)
1762 OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
1763 return OC_STACK_ERROR;
1766 stackState = OC_STACK_UNINIT_IN_PROGRESS;
1768 #ifdef WITH_PRESENCE
1769 // Ensure that the TTL associated with ANY and ALL presence notifications originating from
1770 // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
1771 presenceResource.presenceTTL = 0;
1772 #endif // WITH_PRESENCE
1774 // Free memory dynamically allocated for resources
1775 deleteAllResources();
1778 // Remove all observers
1779 DeleteObserverList();
1780 // Remove all the client callbacks
1781 DeleteClientCBList();
1782 // Deinit security blob
1783 DeinitOCSecurityInfo();
1784 stackState = OC_STACK_UNINITIALIZED;
1788 CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
1793 return CA_MSG_CONFIRM;
1798 return CA_MSG_NONCONFIRM;
1802 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1806 query = strchr (inputUri, '?');
1810 if((query - inputUri) > MAX_URI_LENGTH)
1812 return OC_STACK_INVALID_URI;
1815 if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1817 return OC_STACK_INVALID_QUERY;
1820 else if(uriLen > MAX_URI_LENGTH)
1822 return OC_STACK_INVALID_URI;
1827 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1828 const char *referenceUri, const char *request, OCConnectivityType conType,
1829 OCQualityOfService qos, OCCallbackData *cbData,
1830 OCHeaderOption * options, uint8_t numOptions)
1832 OCStackResult result = OC_STACK_ERROR;
1833 ClientCB *clientCB = NULL;
1834 char * requestUri = NULL;
1835 char * resourceType = NULL;
1836 char * query = NULL;
1837 char * newUri = (char *)requiredUri;
1838 (void) referenceUri;
1839 CARemoteEndpoint_t* endpoint = NULL;
1840 CAResult_t caResult;
1841 CAToken_t token = NULL;
1842 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
1843 OCDoHandle resHandle = NULL;
1844 CAInfo_t requestData ={};
1845 CARequestInfo_t requestInfo ={};
1846 CAGroupEndpoint_t grpEnd = {};
1848 // To track if memory is allocated for additional header options
1850 OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1852 // Validate input parameters
1853 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1854 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1856 //TODO ("Need to form the final query by concatenating require and reference URI's");
1857 VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1859 uint16_t uriLen = strlen(requiredUri);
1861 // ToDo: We should also check if the requiredUri has a mutlicast address,
1862 // then qos has to be OC_Low_QOS
1868 case OC_REST_DELETE:
1869 case OC_REST_OBSERVE:
1870 case OC_REST_OBSERVE_ALL:
1871 case OC_REST_CANCEL_OBSERVE:
1873 #ifdef WITH_PRESENCE
1874 case OC_REST_PRESENCE:
1878 result = OC_STACK_INVALID_METHOD;
1882 if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1887 if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1889 result = OC_STACK_INVALID_PARAM;
1893 #ifdef WITH_PRESENCE
1894 if(method == OC_REST_PRESENCE)
1896 result = getQueryFromUri(requiredUri, &query, &newUri);
1898 if(result != OC_STACK_OK)
1900 OC_LOG_V(ERROR, TAG, "Invalid Param from getQueryFromUri: %d, URI is %s",
1901 result, requiredUri);
1907 result = getResourceType((char *) query, &resourceType);
1911 OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1915 OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
1920 OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
1922 if(result != OC_STACK_OK)
1927 #endif // WITH_PRESENCE
1929 requestUri = (char *) OCMalloc(uriLen + 1);
1932 memcpy(requestUri, newUri, (uriLen + 1));
1936 result = OC_STACK_NO_MEMORY;
1940 resHandle = GenerateInvocationHandle();
1943 result = OC_STACK_NO_MEMORY;
1950 case OC_REST_OBSERVE:
1951 case OC_REST_OBSERVE_ALL:
1952 case OC_REST_CANCEL_OBSERVE:
1954 requestInfo.method = CA_GET;
1959 requestInfo.method = CA_PUT;
1964 requestInfo.method = CA_POST;
1967 case OC_REST_DELETE:
1969 requestInfo.method = CA_DELETE;
1972 #ifdef WITH_PRESENCE
1973 case OC_REST_PRESENCE:
1975 // Replacing method type with GET because "presence"
1976 // is a stack layer only implementation.
1977 requestInfo.method = CA_GET;
1982 result = OC_STACK_INVALID_METHOD;
1987 caResult = CAGenerateToken(&token, tokenLength);
1988 if (caResult != CA_STATUS_OK)
1990 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
1991 CADestroyToken(token);
1992 result = CAResultToOCResult (caResult);
1996 requestData.type = qualityOfServiceToMessageType(qos);
1997 requestData.token = token;
1998 requestData.tokenLength = tokenLength;
1999 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2001 result = CreateObserveHeaderOption (&(requestData.options), options,
2002 numOptions, OC_OBSERVE_REGISTER);
2003 if (result != OC_STACK_OK)
2005 CADestroyToken(token);
2008 requestData.numOptions = numOptions + 1;
2012 requestData.options = (CAHeaderOption_t*)options;
2013 requestData.numOptions = numOptions;
2015 requestData.payload = (char *)request;
2017 requestInfo.info = requestData;
2018 CATransportType_t caConType;
2020 result = OCToCATransportType((OCConnectivityType) conType, &caConType);
2021 if (result != OC_STACK_OK)
2023 OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
2028 if(conType == OC_ALL)
2030 grpEnd.transportType = caConType;
2032 grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
2033 if(!grpEnd.resourceUri)
2035 result = OC_STACK_NO_MEMORY;
2036 CADestroyToken(token);
2039 strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
2041 caResult = CASendRequestToAll(&grpEnd, &requestInfo);
2045 caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
2047 if (caResult != CA_STATUS_OK)
2049 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2050 result = CAResultToOCResult (caResult);
2051 CADestroyToken(token);
2055 caResult = CASendRequest(endpoint, &requestInfo);
2058 if (caResult != CA_STATUS_OK)
2060 OC_LOG(ERROR, TAG, PCF("CASendRequest"));
2061 result = CAResultToOCResult (caResult);
2062 CADestroyToken(token);
2066 result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method,
2067 requestUri, resourceType, conType,
2068 GetTicks(MAX_CB_TIMEOUT_SECONDS * MILLISECONDS_PER_SECOND));
2069 if(result != OC_STACK_OK)
2071 result = OC_STACK_NO_MEMORY;
2077 *handle = resHandle;
2081 if(newUri != requiredUri)
2085 if (result != OC_STACK_OK)
2087 OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
2088 FindAndDeleteClientCB(clientCB);
2091 OCFree(resourceType);
2093 CADestroyRemoteEndpoint(endpoint);
2094 OCFree(grpEnd.resourceUri);
2096 if (requestData.options && requestData.numOptions > 0)
2098 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2100 OCFree(requestData.options);
2106 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
2110 * This ftn is implemented one of two ways in the case of observation:
2112 * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
2113 * Remove the callback associated on client side.
2114 * When the next notification comes in from server,
2115 * reply with RESET message to server.
2116 * Keep in mind that the server will react to RESET only
2117 * if the last notification was sent as CON
2119 * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
2120 * and it is associated with an observe request
2121 * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
2122 * Send CON Observe request to server with
2123 * observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
2124 * Remove the callback associated on client side.
2126 OCStackResult ret = OC_STACK_OK;
2127 CARemoteEndpoint_t* endpoint = NULL;
2128 CAResult_t caResult;
2129 CAInfo_t requestData = {};
2130 CARequestInfo_t requestInfo = {};
2134 return OC_STACK_INVALID_PARAM;
2137 OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
2139 ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL);
2143 switch (clientCB->method)
2145 case OC_REST_OBSERVE:
2146 case OC_REST_OBSERVE_ALL:
2147 OC_LOG(INFO, TAG, PCF("Canceling observation"));
2148 if(qos == OC_HIGH_QOS)
2150 requestData.type = qualityOfServiceToMessageType(qos);
2151 requestData.token = clientCB->token;
2152 requestData.tokenLength = clientCB->tokenLength;
2153 if (CreateObserveHeaderOption (&(requestData.options),
2154 options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
2156 return OC_STACK_ERROR;
2158 requestData.numOptions = numOptions + 1;
2159 requestInfo.method = CA_GET;
2160 requestInfo.info = requestData;
2162 CATransportType_t caConType;
2163 ret = OCToCATransportType(clientCB->conType, &caConType);
2164 if(ret != OC_STACK_OK)
2169 caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri,
2170 caConType, &endpoint);
2171 if (caResult != CA_STATUS_OK)
2173 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2174 ret = OC_STACK_ERROR;
2179 caResult = CASendRequest(endpoint, &requestInfo);
2180 if (caResult != CA_STATUS_OK)
2182 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2183 ret = OC_STACK_ERROR;
2185 ret = CAResultToOCResult (caResult);
2189 FindAndDeleteClientCB(clientCB);
2192 #ifdef WITH_PRESENCE
2193 case OC_REST_PRESENCE:
2194 FindAndDeleteClientCB(clientCB);
2198 ret = OC_STACK_INVALID_METHOD;
2203 CADestroyRemoteEndpoint(endpoint);
2204 if (requestData.numOptions > 0)
2206 OCFree(requestData.options);
2212 #ifdef WITH_PRESENCE
2213 OCStackResult OCProcessPresence()
2215 OCStackResult result = OC_STACK_OK;
2216 uint8_t ipAddr[4] = { 0 };
2219 OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
2220 ClientCB* cbNode = NULL;
2222 OCClientResponse clientResponse ={};
2223 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
2225 LL_FOREACH(cbList, cbNode)
2227 if(OC_REST_PRESENCE == cbNode->method)
2229 if(cbNode->presence)
2231 uint32_t now = GetTicks(0);
2232 OC_LOG_V(DEBUG, TAG, "this TTL level %d",
2233 cbNode->presence->TTLlevel);
2234 OC_LOG_V(DEBUG, TAG, "current ticks %d", now);
2237 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
2242 if(cbNode->presence->TTLlevel < PresenceTimeOutSize)
2244 OC_LOG_V(DEBUG, TAG, "timeout ticks %d",
2245 cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
2248 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
2250 OC_LOG(DEBUG, TAG, PCF("No more timeout ticks"));
2251 if (ParseIPv4Address(cbNode->requestUri, ipAddr, &port))
2253 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
2256 clientResponse.sequenceNumber = 0;
2257 clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
2258 clientResponse.addr = (OCDevAddr *) &dst;
2259 clientResponse.resJSONPayload = NULL;
2261 // Increment the TTLLevel (going to a next state), so we don't keep
2262 // sending presence notification to client.
2263 cbNode->presence->TTLlevel++;
2264 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2265 cbNode->presence->TTLlevel);
2269 result = OC_STACK_INVALID_IP;
2273 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
2274 if (cbResult == OC_STACK_DELETE_TRANSACTION)
2276 FindAndDeleteClientCB(cbNode);
2280 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
2282 CAResult_t caResult = CA_STATUS_OK;
2283 CARemoteEndpoint_t* endpoint = NULL;
2284 CAInfo_t requestData ={};
2285 CARequestInfo_t requestInfo = {};
2287 OC_LOG(DEBUG, TAG, PCF("time to test server presence"));
2290 CATransportType_t caConType;
2291 result = OCToCATransportType(cbNode->conType, &caConType);
2292 caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, caConType,
2294 if (caResult != CA_STATUS_OK || result != OC_STACK_OK)
2296 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2300 requestData.type = CA_MSG_NONCONFIRM;
2301 requestData.token = cbNode->token;
2302 requestData.tokenLength = cbNode->tokenLength;
2303 requestInfo.method = CA_GET;
2304 requestInfo.info = requestData;
2306 caResult = CASendRequest(endpoint, &requestInfo);
2307 CADestroyRemoteEndpoint(endpoint);
2309 if (caResult != CA_STATUS_OK)
2311 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2315 cbNode->presence->TTLlevel++;
2316 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2317 cbNode->presence->TTLlevel);
2323 if (result != OC_STACK_OK)
2325 OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
2329 #endif // WITH_PRESENCE
2331 OCStackResult OCProcess()
2333 #ifdef WITH_PRESENCE
2334 OCProcessPresence();
2336 CAHandleRequestResponse();
2341 #ifdef WITH_PRESENCE
2342 OCStackResult OCStartPresence(const uint32_t ttl)
2344 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
2345 OCChangeResourceProperty(
2346 &(((OCResource *)presenceResource.handle)->resourceProperties),
2349 if (OC_MAX_PRESENCE_TTL_SECONDS < ttl)
2351 presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS;
2352 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to max value"));
2356 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
2357 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to default value"));
2361 presenceResource.presenceTTL = ttl;
2363 OC_LOG_V(DEBUG, TAG, "Presence TTL is %lu seconds", presenceResource.presenceTTL);
2365 if (OC_PRESENCE_UNINITIALIZED == presenceState)
2367 presenceState = OC_PRESENCE_INITIALIZED;
2369 CAAddress_t addressInfo;
2370 strncpy(addressInfo.IP.ipAddress, OC_MULTICAST_IP, CA_IPADDR_SIZE);
2371 addressInfo.IP.port = OC_MULTICAST_PORT;
2373 CAToken_t caToken = NULL;
2374 CAResult_t caResult = CAGenerateToken(&caToken, tokenLength);
2375 if (caResult != CA_STATUS_OK)
2377 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2378 CADestroyToken(caToken);
2379 return OC_STACK_ERROR;
2382 CATransportType_t connType;
2383 OCToCATransportType(OC_ALL, &connType );
2384 AddObserver(OC_PRESENCE_URI, NULL, 0, caToken, tokenLength,
2385 (OCResource *)presenceResource.handle, OC_LOW_QOS,
2386 &addressInfo, connType);
2387 CADestroyToken(caToken);
2390 // Each time OCStartPresence is called
2391 // a different random 32-bit integer number is used
2392 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2394 return SendPresenceNotification(NULL);
2397 OCStackResult OCStopPresence()
2399 OCStackResult result = OC_STACK_ERROR;
2401 if(presenceResource.handle)
2403 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2406 // make resource inactive
2407 result = OCChangeResourceProperty(
2408 &(((OCResource *) presenceResource.handle)->resourceProperties),
2411 if(result != OC_STACK_OK)
2414 PCF("Changing the presence resource properties to ACTIVE not successful"));
2418 return SendStopNotification();
2422 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
2424 defaultDeviceHandler = entityHandler;
2429 OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
2431 OC_LOG(INFO, TAG, PCF("Entering OCSetDeviceInfo"));
2433 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
2435 return SaveDeviceInfo(deviceInfo);
2439 return OC_STACK_ERROR;
2443 OCStackResult OCCreateResource(OCResourceHandle *handle,
2444 const char *resourceTypeName,
2445 const char *resourceInterfaceName,
2446 const char *uri, OCEntityHandler entityHandler,
2447 uint8_t resourceProperties)
2450 OCResource *pointer = NULL;
2453 OCStackResult result = OC_STACK_ERROR;
2455 OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
2457 if(myStackMode == OC_CLIENT)
2459 return OC_STACK_INVALID_PARAM;
2461 // Validate parameters
2462 if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH )
2464 OC_LOG(ERROR, TAG, PCF("URI is invalid"));
2465 return OC_STACK_INVALID_URI;
2467 // Is it presented during resource discovery?
2468 if (!handle || !resourceTypeName)
2470 OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
2471 return OC_STACK_INVALID_PARAM;
2474 if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0)
2476 resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
2479 // Make sure resourceProperties bitmask has allowed properties specified
2480 if (resourceProperties
2481 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE))
2483 OC_LOG(ERROR, TAG, PCF("Invalid property"));
2484 return OC_STACK_INVALID_PARAM;
2487 // If the headResource is NULL, then no resources have been created...
2488 pointer = headResource;
2491 // At least one resources is in the resource list, so we need to search for
2492 // repeated URLs, which are not allowed. If a repeat is found, exit with an error
2495 if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0)
2497 OC_LOG(ERROR, TAG, PCF("URI already in use"));
2498 return OC_STACK_INVALID_PARAM;
2500 pointer = pointer->next;
2503 // Create the pointer and insert it into the resource list
2504 pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
2507 result = OC_STACK_NO_MEMORY;
2510 pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
2512 insertResource(pointer);
2515 size = strlen(uri) + 1;
2516 str = (char *) OCMalloc(size);
2519 result = OC_STACK_NO_MEMORY;
2522 strncpy(str, uri, size);
2525 // Set properties. Set OC_ACTIVE
2526 pointer->resourceProperties = (OCResourceProperty) (resourceProperties
2529 // Add the resourcetype to the resource
2530 result = BindResourceTypeToResource(pointer, resourceTypeName);
2531 if (result != OC_STACK_OK)
2533 OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
2537 // Add the resourceinterface to the resource
2538 result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
2539 if (result != OC_STACK_OK)
2541 OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
2545 // If an entity handler has been passed, attach it to the newly created
2546 // resource. Otherwise, set the default entity handler.
2549 pointer->entityHandler = entityHandler;
2553 pointer->entityHandler = defaultResourceEHandler;
2557 result = OC_STACK_OK;
2559 #ifdef WITH_PRESENCE
2560 if(presenceResource.handle)
2562 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2563 SendPresenceNotification(pointer->rsrcType);
2567 if (result != OC_STACK_OK)
2569 // Deep delete of resource and other dynamic elements that it contains
2570 deleteResource(pointer);
2576 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
2577 const char *resourceTypeName,
2578 const char *resourceInterfaceName,
2581 OCEntityHandler entityHandler,
2582 uint8_t resourceProperties)
2584 OC_LOG(INFO, TAG, PCF("Entering OCCreateResourceWithHost"));
2590 OC_LOG(ERROR, TAG, PCF("Added resource host is NULL."));
2591 return OC_STACK_INVALID_PARAM;
2594 OCStackResult result = OC_STACK_ERROR;
2596 result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
2597 uri, entityHandler, resourceProperties);
2599 if (result == OC_STACK_OK)
2602 size = strlen(host) + 1;
2603 str = (char *) OCMalloc(size);
2606 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated."));
2607 return OC_STACK_NO_MEMORY;
2609 strncpy(str, host, size);
2611 ((OCResource *) *handle)->host = str;
2617 OCStackResult OCBindResource(
2618 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2620 OCResource *resource = NULL;
2623 OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
2625 // Validate parameters
2626 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2627 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2628 // Container cannot contain itself
2629 if (collectionHandle == resourceHandle)
2631 OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
2632 return OC_STACK_INVALID_PARAM;
2635 // Use the handle to find the resource in the resource linked list
2636 resource = findResource((OCResource *) collectionHandle);
2639 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2640 return OC_STACK_INVALID_PARAM;
2643 // Look for an open slot to add add the child resource.
2644 // If found, add it and return success
2645 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2647 if (!resource->rsrcResources[i])
2649 resource->rsrcResources[i] = (OCResource *) resourceHandle;
2650 OC_LOG(INFO, TAG, PCF("resource bound"));
2652 #ifdef WITH_PRESENCE
2653 if(presenceResource.handle)
2655 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2656 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2664 // Unable to add resourceHandle, so return error
2665 return OC_STACK_ERROR;
2668 OCStackResult OCUnBindResource(
2669 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2671 OCResource *resource = NULL;
2674 OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
2676 // Validate parameters
2677 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2678 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2679 // Container cannot contain itself
2680 if (collectionHandle == resourceHandle)
2682 OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
2683 return OC_STACK_INVALID_PARAM;
2686 // Use the handle to find the resource in the resource linked list
2687 resource = findResource((OCResource *) collectionHandle);
2690 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2691 return OC_STACK_INVALID_PARAM;
2694 // Look for an open slot to add add the child resource.
2695 // If found, add it and return success
2696 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2698 if (resourceHandle == resource->rsrcResources[i])
2700 resource->rsrcResources[i] = (OCResource *) NULL;
2701 OC_LOG(INFO, TAG, PCF("resource unbound"));
2703 // Send notification when resource is unbounded successfully.
2704 #ifdef WITH_PRESENCE
2705 if(presenceResource.handle)
2707 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2708 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2715 OC_LOG(INFO, TAG, PCF("resource not found in collection"));
2717 // Unable to add resourceHandle, so return error
2718 return OC_STACK_ERROR;
2721 OCStackResult BindResourceTypeToResource(OCResource* resource,
2722 const char *resourceTypeName)
2724 OCResourceType *pointer = NULL;
2727 OCStackResult result = OC_STACK_ERROR;
2729 OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
2731 // Validate parameters
2732 VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
2733 // TODO: Does resource attribute representation really have to be maintained in stack?
2734 // Is it presented during resource discovery?
2736 // Create the resourcetype and insert it into the resource list
2737 pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
2740 result = OC_STACK_NO_MEMORY;
2744 // Set the resourceTypeName
2745 size = strlen(resourceTypeName) + 1;
2746 str = (char *) OCMalloc(size);
2749 result = OC_STACK_NO_MEMORY;
2752 strncpy(str, resourceTypeName, size);
2753 pointer->resourcetypename = str;
2755 insertResourceType(resource, pointer);
2756 result = OC_STACK_OK;
2759 if (result != OC_STACK_OK)
2768 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
2769 const char *resourceInterfaceName)
2771 OCResourceInterface *pointer = NULL;
2774 OCStackResult result = OC_STACK_ERROR;
2776 OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
2778 // Validate parameters
2779 VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
2781 //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
2783 // Create the resourceinterface and insert it into the resource list
2784 pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
2787 result = OC_STACK_NO_MEMORY;
2791 // Set the resourceinterface name
2792 size = strlen(resourceInterfaceName) + 1;
2793 str = (char *) OCMalloc(size);
2796 result = OC_STACK_NO_MEMORY;
2799 strncpy(str, resourceInterfaceName, size);
2800 pointer->name = str;
2802 // Bind the resourceinterface to the resource
2803 insertResourceInterface(resource, pointer);
2805 result = OC_STACK_OK;
2808 if (result != OC_STACK_OK)
2817 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
2818 const char *resourceTypeName)
2821 OCStackResult result = OC_STACK_ERROR;
2822 OCResource *resource = NULL;
2824 // Make sure resource exists
2825 resource = findResource((OCResource *) handle);
2828 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2829 return OC_STACK_ERROR;
2832 // call internal function
2833 result = BindResourceTypeToResource(resource, resourceTypeName);
2835 #ifdef WITH_PRESENCE
2836 if(presenceResource.handle)
2838 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2839 SendPresenceNotification(resource->rsrcType);
2846 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
2847 const char *resourceInterfaceName)
2850 OCStackResult result = OC_STACK_ERROR;
2851 OCResource *resource = NULL;
2853 // Make sure resource exists
2854 resource = findResource((OCResource *) handle);
2857 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2858 return OC_STACK_ERROR;
2861 // call internal function
2862 result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2864 #ifdef WITH_PRESENCE
2865 if(presenceResource.handle)
2867 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2868 SendPresenceNotification(resource->rsrcType);
2875 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
2877 OCResource *pointer = headResource;
2879 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2880 VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2884 *numResources = *numResources + 1;
2885 pointer = pointer->next;
2890 OCResourceHandle OCGetResourceHandle(uint8_t index)
2892 OCResource *pointer = headResource;
2894 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2896 // Iterate through the list
2897 for( uint8_t i = 0; i < index && pointer; ++i)
2899 pointer = pointer->next;
2901 return (OCResourceHandle) pointer;
2904 OCStackResult OCDeleteResource(OCResourceHandle handle)
2906 OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2910 OC_LOG(ERROR, TAG, PCF("Invalid param"));
2911 return OC_STACK_INVALID_PARAM;
2914 OCResource *resource = findResource((OCResource *) handle);
2915 if (resource == NULL)
2917 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2918 return OC_STACK_NO_RESOURCE;
2921 if (deleteResource((OCResource *) handle) != OC_STACK_OK)
2923 OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2924 return OC_STACK_ERROR;
2930 const char *OCGetResourceUri(OCResourceHandle handle)
2932 OCResource *resource = NULL;
2933 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2935 resource = findResource((OCResource *) handle);
2938 return resource->uri;
2940 return (const char *) NULL;
2943 OCResourceProperty OCGetResourceProperties(OCResourceHandle handle)
2945 OCResource *resource = NULL;
2946 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2948 resource = findResource((OCResource *) handle);
2951 return resource->resourceProperties;
2953 return (OCResourceProperty)-1;
2956 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2957 uint8_t *numResourceTypes)
2959 OCResource *resource = NULL;
2960 OCResourceType *pointer = NULL;
2962 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2963 VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
2964 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2966 *numResourceTypes = 0;
2968 resource = findResource((OCResource *) handle);
2971 pointer = resource->rsrcType;
2974 *numResourceTypes = *numResourceTypes + 1;
2975 pointer = pointer->next;
2981 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index)
2983 OCResourceType *resourceType = NULL;
2985 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
2987 resourceType = findResourceTypeAtIndex(handle, index);
2990 return resourceType->resourcetypename;
2992 return (const char *) NULL;
2995 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
2996 uint8_t *numResourceInterfaces)
2998 OCResourceInterface *pointer = NULL;
2999 OCResource *resource = NULL;
3001 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
3003 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3004 VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
3006 *numResourceInterfaces = 0;
3007 resource = findResource((OCResource *) handle);
3010 pointer = resource->rsrcInterface;
3013 *numResourceInterfaces = *numResourceInterfaces + 1;
3014 pointer = pointer->next;
3020 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index)
3022 OCResourceInterface *resourceInterface = NULL;
3024 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
3026 resourceInterface = findResourceInterfaceAtIndex(handle, index);
3027 if (resourceInterface)
3029 return resourceInterface->name;
3031 return (const char *) NULL;
3034 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
3037 OCResource *resource = NULL;
3039 OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
3041 if (index >= MAX_CONTAINED_RESOURCES)
3046 resource = findResource((OCResource *) collectionHandle);
3052 return resource->rsrcResources[index];
3055 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
3056 OCEntityHandler entityHandler)
3058 OCResource *resource = NULL;
3060 OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
3062 // Validate parameters
3063 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3065 // Use the handle to find the resource in the resource linked list
3066 resource = findResource((OCResource *)handle);
3069 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3070 return OC_STACK_ERROR;
3074 resource->entityHandler = entityHandler;
3076 #ifdef WITH_PRESENCE
3077 if(presenceResource.handle)
3079 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3080 SendPresenceNotification(resource->rsrcType);
3087 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle)
3089 OCResource *resource = NULL;
3091 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
3093 // Use the handle to find the resource in the resource linked list
3094 resource = findResource((OCResource *)handle);
3097 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3102 return resource->entityHandler;
3105 void incrementSequenceNumber(OCResource * resPtr)
3107 // Increment the sequence number
3108 resPtr->sequenceNum += 1;
3109 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
3111 resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
3116 #ifdef WITH_PRESENCE
3117 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
3119 OCResource *resPtr = NULL;
3120 OCStackResult result = OC_STACK_ERROR;
3121 OCMethod method = OC_REST_PRESENCE;
3122 uint32_t maxAge = 0;
3123 resPtr = findResource((OCResource *) presenceResource.handle);
3126 return OC_STACK_NO_RESOURCE;
3129 if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
3131 maxAge = presenceResource.presenceTTL;
3133 result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
3139 OCStackResult SendStopNotification()
3141 OCResource *resPtr = NULL;
3142 OCStackResult result = OC_STACK_ERROR;
3143 OCMethod method = OC_REST_PRESENCE;
3144 resPtr = findResource((OCResource *) presenceResource.handle);
3147 return OC_STACK_NO_RESOURCE;
3150 // maxAge is 0. ResourceType is NULL.
3151 result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
3156 #endif // WITH_PRESENCE
3157 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos)
3160 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3162 OCResource *resPtr = NULL;
3163 OCStackResult result = OC_STACK_ERROR;
3164 OCMethod method = OC_REST_NOMETHOD;
3165 uint32_t maxAge = 0;
3167 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3168 #ifdef WITH_PRESENCE
3169 if(handle == presenceResource.handle)
3173 #endif // WITH_PRESENCE
3174 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3176 // Verify that the resource exists
3177 resPtr = findResource ((OCResource *) handle);
3180 return OC_STACK_NO_RESOURCE;
3184 //only increment in the case of regular observing (not presence)
3185 incrementSequenceNumber(resPtr);
3186 method = OC_REST_OBSERVE;
3187 maxAge = MAX_OBSERVE_AGE;
3188 #ifdef WITH_PRESENCE
3189 result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
3191 result = SendAllObserverNotification (method, resPtr, maxAge, qos);
3198 OCNotifyListOfObservers (OCResourceHandle handle,
3199 OCObservationId *obsIdList,
3200 uint8_t numberOfIds,
3201 const char *notificationJSONPayload,
3202 OCQualityOfService qos)
3204 OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
3206 OCResource *resPtr = NULL;
3207 //TODO: we should allow the server to define this
3208 uint32_t maxAge = MAX_OBSERVE_AGE;
3210 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3211 VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
3212 VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
3214 // Verify that the resource exists
3215 resPtr = findResource ((OCResource *) handle);
3216 if (NULL == resPtr || myStackMode == OC_CLIENT)
3218 return OC_STACK_NO_RESOURCE;
3222 incrementSequenceNumber(resPtr);
3224 return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
3225 notificationJSONPayload, maxAge, qos));
3228 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
3230 OCStackResult result = OC_STACK_ERROR;
3231 OCServerRequest *serverRequest = NULL;
3233 OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
3235 // Validate input parameters
3236 VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
3237 VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
3239 // TODO: Placeholder for creating a response entry when implementing
3240 // block transfer feature
3242 // If a response payload is present, check if block transfer is required
3243 if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
3244 (const char *)ehResponse->payload, ehResponse->payloadSize))
3246 OC_LOG(INFO, TAG, PCF("Block transfer required"));
3248 // Persistent response buffer is needed for block transfer
3249 if (!ehResponse->persistentBufferFlag)
3251 OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
3252 return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
3254 // TODO: Placeholder for block transfer handling
3255 // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
3256 // when implementing the block transfer feature
3261 // Get pointer to request info
3262 serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
3265 result = serverRequest->ehResponseHandler(ehResponse);
3271 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
3273 OCStackResult result = OC_STACK_NOTIMPL;
3275 OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
3277 // TODO: validate response handle
3282 //-----------------------------------------------------------------------------
3283 // Private internal function definitions
3284 //-----------------------------------------------------------------------------
3285 static OCDoHandle GenerateInvocationHandle()
3287 OCDoHandle handle = NULL;
3288 // Generate token here, it will be deleted when the transaction is deleted
3289 handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3292 OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3298 #ifdef WITH_PRESENCE
3299 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
3300 OCResourceProperty resourceProperties, uint8_t enable)
3304 return OC_STACK_INVALID_PARAM;
3306 if (resourceProperties
3307 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW))
3309 OC_LOG(ERROR, TAG, PCF("Invalid property"));
3310 return OC_STACK_INVALID_PARAM;
3314 *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
3318 *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
3324 OCStackResult initResources()
3326 OCStackResult result = OC_STACK_OK;
3327 // Init application resource vars
3328 headResource = NULL;
3329 tailResource = NULL;
3330 // Init Virtual Resources
3331 #ifdef WITH_PRESENCE
3332 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
3333 //presenceResource.token = OCGenerateCoAPToken();
3334 result = OCCreateResource(&presenceResource.handle,
3335 OC_RSRVD_RESOURCE_TYPE_PRESENCE,
3340 //make resource inactive
3341 result = OCChangeResourceProperty(
3342 &(((OCResource *) presenceResource.handle)->resourceProperties),
3348 void insertResource(OCResource *resource)
3352 headResource = resource;
3353 tailResource = resource;
3357 tailResource->next = resource;
3358 tailResource = resource;
3360 resource->next = NULL;
3363 OCResource *findResource(OCResource *resource)
3365 OCResource *pointer = headResource;
3369 if (pointer == resource)
3373 pointer = pointer->next;
3378 void deleteAllResources()
3380 OCResource *pointer = headResource;
3381 OCResource *temp = NULL;
3385 temp = pointer->next;
3386 #ifdef WITH_PRESENCE
3387 if(pointer != (OCResource *) presenceResource.handle)
3389 #endif // WITH_PRESENCE
3390 deleteResource(pointer);
3391 #ifdef WITH_PRESENCE
3393 #endif // WITH_PRESENCE
3397 #ifdef WITH_PRESENCE
3398 // Ensure that the last resource to be deleted is the presence resource. This allows for all
3399 // presence notification attributed to their deletion to be processed.
3400 deleteResource((OCResource *) presenceResource.handle);
3401 #endif // WITH_PRESENCE
3404 OCStackResult deleteResource(OCResource *resource)
3406 OCResource *prev = NULL;
3407 OCResource *temp = NULL;
3409 temp = headResource;
3412 if (temp == resource)
3414 // Invalidate all Resource Properties.
3415 resource->resourceProperties = (OCResourceProperty) 0;
3416 #ifdef WITH_PRESENCE
3417 if(resource != (OCResource *) presenceResource.handle)
3419 #endif // WITH_PRESENCE
3420 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
3421 #ifdef WITH_PRESENCE
3424 if(presenceResource.handle)
3426 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3427 if(resource != (OCResource *) presenceResource.handle)
3429 SendPresenceNotification(resource->rsrcType);
3433 SendPresenceNotification(NULL);
3437 // Only resource in list.
3438 if (temp == headResource && temp == tailResource)
3440 headResource = NULL;
3441 tailResource = NULL;
3444 else if (temp == headResource)
3446 headResource = temp->next;
3449 else if (temp == tailResource)
3451 tailResource = prev;
3452 tailResource->next = NULL;
3456 prev->next = temp->next;
3459 deleteResourceElements(temp);
3470 return OC_STACK_ERROR;
3473 void deleteResourceElements(OCResource *resource)
3481 OCFree(resource->uri);
3483 // Delete resourcetype linked list
3484 deleteResourceType(resource->rsrcType);
3486 // Delete resourceinterface linked list
3487 deleteResourceInterface(resource->rsrcInterface);
3490 void deleteResourceType(OCResourceType *resourceType)
3492 OCResourceType *pointer = resourceType;
3493 OCResourceType *next = NULL;
3497 next = pointer->next;
3498 OCFree(pointer->resourcetypename);
3504 void deleteResourceInterface(OCResourceInterface *resourceInterface)
3506 OCResourceInterface *pointer = resourceInterface;
3507 OCResourceInterface *next = NULL;
3511 next = pointer->next;
3512 OCFree(pointer->name);
3518 void insertResourceType(OCResource *resource, OCResourceType *resourceType)
3520 OCResourceType *pointer = NULL;
3521 OCResourceType *previous = NULL;
3522 if (!resource || !resourceType)
3526 // resource type list is empty.
3527 else if (!resource->rsrcType)
3529 resource->rsrcType = resourceType;
3533 pointer = resource->rsrcType;
3537 // resource type already exists. Free 2nd arg and return.
3538 if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename))
3540 OCFree(resourceType->resourcetypename);
3541 OCFree(resourceType);
3545 pointer = pointer->next;
3547 previous->next = resourceType;
3549 resourceType->next = NULL;
3552 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index)
3554 OCResource *resource = NULL;
3555 OCResourceType *pointer = NULL;
3557 // Find the specified resource
3558 resource = findResource((OCResource *) handle);
3564 // Make sure a resource has a resourcetype
3565 if (!resource->rsrcType)
3570 // Iterate through the list
3571 pointer = resource->rsrcType;
3572 for(uint8_t i = 0; i< index && pointer; ++i)
3574 pointer = pointer->next;
3579 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
3581 if(resourceTypeList && resourceTypeName)
3583 OCResourceType * rtPointer = resourceTypeList;
3584 while(resourceTypeName && rtPointer)
3586 if(rtPointer->resourcetypename &&
3587 strcmp(resourceTypeName, (const char *)
3588 (rtPointer->resourcetypename)) == 0)
3592 rtPointer = rtPointer->next;
3600 * Insert a new interface into interface linked list only if not already present.
3601 * If alredy present, 2nd arg is free'd.
3602 * Default interface will always be first if present.
3604 void insertResourceInterface(OCResource *resource, OCResourceInterface *newInterface)
3606 OCResourceInterface *pointer = NULL;
3607 OCResourceInterface *previous = NULL;
3609 newInterface->next = NULL;
3611 OCResourceInterface **firstInterface = &(resource->rsrcInterface);
3613 if (!*firstInterface)
3615 *firstInterface = newInterface;
3617 else if (strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3619 if (strcmp((*firstInterface)->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3621 OCFree(newInterface->name);
3622 OCFree(newInterface);
3627 newInterface->next = *firstInterface;
3628 *firstInterface = newInterface;
3633 pointer = *firstInterface;
3636 if (strcmp(newInterface->name, pointer->name) == 0)
3638 OCFree(newInterface->name);
3639 OCFree(newInterface);
3643 pointer = pointer->next;
3645 previous->next = newInterface;
3649 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
3652 OCResource *resource = NULL;
3653 OCResourceInterface *pointer = NULL;
3655 // Find the specified resource
3656 resource = findResource((OCResource *) handle);
3662 // Make sure a resource has a resourceinterface
3663 if (!resource->rsrcInterface)
3668 // Iterate through the list
3669 pointer = resource->rsrcInterface;
3671 for (uint8_t i = 0; i < index && pointer; ++i)
3673 pointer = pointer->next;
3678 bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size)
3680 bool result = false;
3682 // Determine if we are checking a request or a response
3685 // If size is greater than 0, use it for the request size value, otherwise
3686 // assume request is null terminated and use strlen for size value
3687 if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
3694 // If size is greater than 0, use it for the response size value, otherwise
3695 // assume response is null terminated and use strlen for size value
3696 if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
3704 OCStackResult getResourceType(const char * query, char** resourceType)
3708 return OC_STACK_INVALID_PARAM;
3711 OCStackResult result = OC_STACK_ERROR;
3713 if(strncmp(query, "rt=", 3) == 0)
3715 *resourceType = (char *) OCMalloc(strlen(query)-3 + 1);
3718 result = OC_STACK_NO_MEMORY;
3722 strcpy((char *)*resourceType, ((const char *)&query[3]));
3723 result = OC_STACK_OK;
3731 * This function splits the uri using the '?' delimiter.
3732 * "uriWithoutQuery" is the block of characters between the beginning
3733 * till the delimiter or '\0' which ever comes first.
3734 * "query" is whatever is to the right of the delimiter if present.
3735 * No delimiter sets the query to NULL.
3736 * If either are present, they will be malloc'ed into the params 2, 3.
3737 * The first param, *uri is left untouched.
3739 * NOTE: This function does not account for whitespace at the end of the uri NOR
3740 * malformed uri's with '??'. Whitespace at the end will be assumed to be
3741 * part of the query.
3743 OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithoutQuery)
3747 return OC_STACK_INVALID_URI;
3749 if(!query || !uriWithoutQuery)
3751 return OC_STACK_INVALID_PARAM;
3755 *uriWithoutQuery = NULL;
3757 size_t uriWithoutQueryLen = 0;
3758 size_t queryLen = 0;
3759 size_t uriLen = strlen(uri);
3761 char *pointerToDelimiter = strstr(uri, "?");
3763 uriWithoutQueryLen = pointerToDelimiter == NULL ? uriLen : pointerToDelimiter - uri;
3764 queryLen = pointerToDelimiter == NULL ? 0 : uriLen - uriWithoutQueryLen - 1;
3766 if (uriWithoutQueryLen)
3768 *uriWithoutQuery = (char *) OCCalloc(uriWithoutQueryLen + 1, 1);
3769 if (!*uriWithoutQuery)
3773 strncpy(*uriWithoutQuery, uri, uriWithoutQueryLen);
3777 return OC_STACK_INVALID_PARAM;
3782 *query = (char *) OCCalloc(queryLen + 1, 1);
3785 OCFree(*uriWithoutQuery);
3786 *uriWithoutQuery = NULL;
3789 strncpy(*query, pointerToDelimiter + 1, queryLen);
3795 return OC_STACK_NO_MEMORY;
3798 const uint8_t* OCGetServerInstanceID(void)
3800 static bool generated = false;
3801 static ServerID sid;
3807 if (OCGenerateUuid(sid) != RAND_UUID_OK)
3809 OC_LOG(FATAL, TAG, PCF("Generate UUID for Server Instance failed!"));
3816 const char* OCGetServerInstanceIDString(void)
3818 static bool generated = false;
3819 static char sidStr[UUID_STRING_SIZE];
3826 const uint8_t* sid = OCGetServerInstanceID();
3828 if(OCConvertUuidToString(sid, sidStr) != RAND_UUID_OK)
3830 OC_LOG(FATAL, TAG, PCF("Generate UUID String for Server Instance failed!"));
3838 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
3839 uint8_t *c, uint8_t *d )
3841 if ( !ipAddr || !a || !b || !c || !d )
3843 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3844 return OC_STACK_INVALID_PARAM;
3847 *a = ipAddr->addr[0];
3848 *b = ipAddr->addr[1];
3849 *c = ipAddr->addr[2];
3850 *d = ipAddr->addr[3];
3855 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
3857 if ( !ipAddr || !port )
3859 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3860 return OC_STACK_INVALID_PARAM;
3863 *port = (ipAddr->addr[5]<< 8) | ipAddr->addr[4];
3868 CAResult_t OCSelectNetwork()
3870 CAResult_t retResult = CA_STATUS_FAILED;
3871 CAResult_t caResult = CA_STATUS_OK;
3873 CATransportType_t connTypes[] = {
3877 int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]);
3879 for(int i = 0; i<numConnTypes; i++)
3881 // Ignore CA_NOT_SUPPORTED error. The CA Layer may have not compiled in the interface.
3882 if(caResult == CA_STATUS_OK || caResult == CA_NOT_SUPPORTED)
3884 caResult = CASelectNetwork(connTypes[i]);
3885 if(caResult == CA_STATUS_OK)
3887 retResult = CA_STATUS_OK;
3892 if(retResult != CA_STATUS_OK)
3894 return caResult; // Returns error of appropriate transport that failed fatally.
3900 OCStackResult CAResultToOCResult(CAResult_t caResult)
3906 case CA_STATUS_INVALID_PARAM:
3907 return OC_STACK_INVALID_PARAM;
3908 case CA_ADAPTER_NOT_ENABLED:
3909 return OC_STACK_ADAPTER_NOT_ENABLED;
3910 case CA_SERVER_STARTED_ALREADY:
3912 case CA_SERVER_NOT_STARTED:
3913 return OC_STACK_ERROR;
3914 case CA_DESTINATION_NOT_REACHABLE:
3915 return OC_STACK_COMM_ERROR;
3916 case CA_SOCKET_OPERATION_FAILED:
3917 return OC_STACK_COMM_ERROR;
3918 case CA_SEND_FAILED:
3919 return OC_STACK_COMM_ERROR;
3920 case CA_RECEIVE_FAILED:
3921 return OC_STACK_COMM_ERROR;
3922 case CA_MEMORY_ALLOC_FAILED:
3923 return OC_STACK_NO_MEMORY;
3924 case CA_REQUEST_TIMEOUT:
3925 return OC_STACK_TIMEOUT;
3926 case CA_DESTINATION_DISCONNECTED:
3927 return OC_STACK_COMM_ERROR;
3928 case CA_STATUS_FAILED:
3929 return OC_STACK_ERROR;
3930 case CA_NOT_SUPPORTED:
3931 return OC_STACK_NOTIMPL;
3933 return OC_STACK_ERROR;