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 //-----------------------------------------------------------------------------
70 OC_STACK_UNINITIALIZED = 0, OC_STACK_INITIALIZED, OC_STACK_UNINIT_IN_PROGRESS
74 OC_PRESENCE_UNINITIALIZED = 0, OC_PRESENCE_INITIALIZED
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
81 static OCStackState stackState = OC_STACK_UNINITIALIZED;
83 OCResource *headResource = NULL;
84 static OCResource *tailResource = NULL;
86 static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED;
87 static PresenceResource presenceResource;
88 static uint8_t PresenceTimeOutSize = 0;
89 static uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
92 static OCMode myStackMode;
93 OCDeviceEntityHandler defaultDeviceHandler;
96 //-----------------------------------------------------------------------------
98 //-----------------------------------------------------------------------------
99 #define TAG PCF("OCStack")
100 #define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
101 {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
102 #define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
103 TAG, PCF(#arg " is NULL")); return (retVal); } }
104 #define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg);\
107 //TODO: we should allow the server to define this
108 #define MAX_OBSERVE_AGE (0x2FFFFUL)
110 #define MILLISECONDS_PER_SECOND (1000)
112 * Parse the presence payload and extract various parameters.
113 * Note: Caller should invoke OCFree after done with resType pointer.
115 * @param payload Presence payload.
116 * @param seqNum Sequence number.
117 * @param maxAge Time To Live (in seconds).
118 * @param resType Resource type.
120 // TODO: Not sure if I agree with this. I think it should be static but it is called in
121 // stack/test/stacktests.cpp, not included via a header file. If we intend to allow it
122 // to be called externally, we should change the name to OCParsePresencePayload and make
123 // it part of the official public API. But can't change now due to current API freeze.
124 // Another option might be to make non-API utility functions for doing stuff like this.
125 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType);
127 //-----------------------------------------------------------------------------
128 // Private internal function prototypes
129 //-----------------------------------------------------------------------------
132 * Generate handle of OCDoResource invocation for callback management.
134 * @return Generated OCDoResource handle.
136 static OCDoHandle GenerateInvocationHandle();
139 * Initialize resource data structures, variables, etc.
141 * @return ::OC_STACK_OK on success, some other value upon failure.
143 static OCStackResult initResources();
146 * Add a resource to the end of the linked list of resources.
148 * @param resource Resource to be added
150 static void insertResource(OCResource *resource);
153 * Find a resource in the linked list of resources.
155 * @param resource Resource to be found.
156 * @return Pointer to resource that was found in the linked list or NULL if the resource was not
159 static OCResource *findResource(OCResource *resource);
162 * Insert a resource type into a resource's resource type linked list.
163 * If resource type already exists, it will not be inserted and the
164 * resourceType will be free'd.
165 * resourceType->next should be null to avoid memory leaks.
166 * Function returns silently for null args.
168 * @param resource Resource where resource type is to be inserted.
169 * @param resourceType Resource type to be inserted.
171 static void insertResourceType(OCResource *resource,
172 OCResourceType *resourceType);
175 * Get a resource type at the specified index within a resource.
177 * @param handle Handle of resource.
178 * @param index Index of resource type.
180 * @return Pointer to resource type if found, NULL otherwise.
182 static OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle,
186 * Insert a resource interface into a resource's resource interface linked list.
187 * If resource interface already exists, it will not be inserted and the
188 * resourceInterface will be free'd.
189 * resourceInterface->next should be null to avoid memory leaks.
191 * @param resource Resource where resource interface is to be inserted.
192 * @param resourceInterface Resource interface to be inserted.
194 static void insertResourceInterface(OCResource *resource,
195 OCResourceInterface *resourceInterface);
198 * Get a resource interface at the specified index within a resource.
200 * @param handle Handle of resource.
201 * @param index Index of resource interface.
203 * @return Pointer to resource interface if found, NULL otherwise.
205 static OCResourceInterface *findResourceInterfaceAtIndex(
206 OCResourceHandle handle, uint8_t index);
209 * Delete all of the dynamically allocated elements that were created for the resource type.
211 * @param resourceType Specified resource type.
213 static void deleteResourceType(OCResourceType *resourceType);
216 * Delete all of the dynamically allocated elements that were created for the resource interface.
218 * @param resourceInterface Specified resource interface.
220 static void deleteResourceInterface(OCResourceInterface *resourceInterface);
223 * Delete all of the dynamically allocated elements that were created for the resource.
225 * @param resource Specified resource.
227 static void deleteResourceElements(OCResource *resource);
230 * Delete resource specified by handle. Deletes resource and all resourcetype and resourceinterface
233 * @param handle Handle of resource to be deleted.
235 * @return ::OC_STACK_OK on success, some other value upon failure.
237 static OCStackResult deleteResource(OCResource *resource);
240 * Delete all of the resources in the resource list.
242 static void deleteAllResources();
245 * Increment resource sequence number. Handles rollover.
247 * @param resPtr Pointer to resource.
249 static void incrementSequenceNumber(OCResource * resPtr);
252 * Verify the lengths of the URI and the query separately.
254 * @param inputUri Input URI and query.
255 * @param uriLen The length of the initial URI with query.
256 * @return ::OC_STACK_OK on success, some other value upon failure.
258 static OCStackResult verifyUriQueryLength(const char * inputUri,
262 * Determine if a request/response must be sent in a block transfer because it is too large to be
263 * sent in a single PDU. This function can be used for either a request or a response.
264 * Note: Either the request or response parameter should be non-NULL (i.e. only one, not both).
266 * @param request NULL or pointer to request.
267 * @param response NULL or pointer to response.
268 * @param size 0 or size of the request/response. If 0, strlen is used for determining
269 * the length of the request/response.
272 * false - packet transfer NOT required (i.e. normal request/response).
273 * true - packet transfer required (i.e. block transfer needed).
275 static bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size);
278 * Retrieves a resource type based upon a query contains only just one
279 * resource attribute (and that has to be of type "rt").
281 * @remark This API malloc's memory for the resource type. Do not malloc resourceType
284 * @param query The query part of the URI.
285 * @param resourceType The resource type to be populated; pass by reference.
287 * @return ::OC_STACK_OK on success, some other value upon failure.
289 static OCStackResult getResourceType(const char * query, char** resourceType);
292 * Attempts to initialize every network interface that the CA Layer might have compiled in.
294 * Note: At least one interface must succeed to initialize. If all calls to @ref CASelectNetwork
295 * return something other than @ref CA_STATUS_OK, then this function fails.
297 * @return ::CA_STATUS_OK on success, some other value upon failure.
299 static CAResult_t OCSelectNetwork();
302 * Get the CoAP ticks after the specified number of milli-seconds.
304 * @param afterMilliSeconds Milli-seconds.
308 static uint32_t GetTicks(uint32_t afterMilliSeconds);
311 * This method is used to create the IPv4 dev_addr structure.
312 * Builds a socket interface address using IP address and port number.
313 * TODO: Remove in future. Temporary helper function.
315 * @param a IPv4 octet 0.
316 * @param b IPv4 octet 1.
317 * @param c IPv4 octet 2.
318 * @param d IPv4 octet 3.
319 * @param port Port number.
320 * @param ipAddr - IPv4 address.
321 * @return ::OC_STACK_OK on success, some other value upon failure.
323 static OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
324 uint16_t port, OCDevAddr *ipAddr);
327 * Convert CAResponseResult_t to OCStackResult.
329 * @param caCode CAResponseResult_t code.
330 * @return ::OC_STACK_OK on success, some other value upon failure.
332 static OCStackResult CAToOCStackResult(CAResponseResult_t caCode);
335 * Convert OCStackResult to CAResponseResult_t.
337 * @param caCode OCStackResult code.
338 * @return ::CA_SUCCESS on success, some other value upon failure.
340 static CAResponseResult_t OCToCAStackResult(OCStackResult ocCode);
343 * Convert OCConnectivityType to CAConnectivityType_t.
345 * @param ocConType OCConnectivityType input.
346 * @param caConType CAConnectivityType_t output.
347 * @return ::OC_STACK_OK on success, some other value upon failure.
349 static OCStackResult OCToCAConnectivityType(OCConnectivityType ocConType,
350 CAConnectivityType_t* caConType);
353 * Convert CAConnectivityType_t to CAConnectivityType_t.
355 * @param caConType CAConnectivityType_t input.
356 * @param ocConType OCConnectivityType output.
357 * @return ::OC_STACK_OK on success, some other value upon failure.
359 static OCStackResult CAToOCConnectivityType(CAConnectivityType_t caConType,
360 OCConnectivityType *ocConType);
363 * Update response.addr appropriately from endPoint.addressInfo.
365 * @param address OCDevAddr output.
366 * @param endPoint CARemoteEndpoint_t input.
367 * @return ::OC_STACK_OK on success, some other value upon failure.
369 static OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint);
372 * Handle response from presence request.
374 * @param endPoint CA remote endpoint.
375 * @param responseInfo CA response info.
376 * @return ::OC_STACK_OK on success, some other value upon failure.
378 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
379 const CAResponseInfo_t* responseInfo);
382 * This function will be called back by CA layer when a response is received.
384 * @param endPoint CA remote endpoint.
385 * @param responseInfo CA response info.
387 static void HandleCAResponses(const CARemoteEndpoint_t* endPoint,
388 const CAResponseInfo_t* responseInfo);
391 * This function will be called back by CA layer when a request is received.
393 * @param endPoint CA remote endpoint.
394 * @param requestInfo CA request info.
396 static void HandleCARequests(const CARemoteEndpoint_t* endPoint,
397 const CARequestInfo_t* requestInfo);
400 * Extract query from a URI.
402 * @param uri Full URI with query.
403 * @param query Pointer to string that will contain query.
404 * @param newURI Pointer to string that will contain URI.
405 * @return ::OC_STACK_OK on success, some other value upon failure.
407 static OCStackResult getQueryFromUri(const char * uri, char** resourceType, char ** newURI);
410 * Finds a resource type in an OCResourceType link-list.
412 * @param resourceTypeList The link-list to be searched through.
413 * @param resourceTypeName The key to search for.
415 * @return Resource type that matches the key (ie. resourceTypeName) or
416 * NULL if there is either an invalid parameter or this function was unable to find the key.
418 static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
419 const char * resourceTypeName);
422 * Reset presence TTL for a ClientCB struct. ttlLevel will be set to 0.
423 * TTL will be set to maxAge.
425 * @param cbNode Callback Node for which presence ttl is to be reset.
426 * @param maxAge New value of ttl in seconds.
428 * @return ::OC_STACK_OK on success, some other value upon failure.
430 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);
433 * Return a server instance ID.
435 * @return Instance ID of the server.
437 static const ServerID OCGetServerInstanceID(void);
439 //-----------------------------------------------------------------------------
440 // Internal functions
441 //-----------------------------------------------------------------------------
443 uint32_t GetTicks(uint32_t afterMilliSeconds)
448 // Guard against overflow of uint32_t
449 if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
450 COAP_TICKS_PER_SECOND)
452 return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
460 OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
461 uint16_t port, OCDevAddr *ipAddr)
465 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
466 return OC_STACK_INVALID_PARAM;
473 ipAddr->addr[4] = (uint8_t)port;
474 ipAddr->addr[5] = (uint8_t)(port >> 8);
479 //-----------------------------------------------------------------------------
480 // Internal API function
481 //-----------------------------------------------------------------------------
483 // This internal function is called to update the stack with the status of
484 // observers and communication failures
485 OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t status)
487 OCStackResult result = OC_STACK_ERROR;
488 ResourceObserver * observer = NULL;
489 OCEntityHandlerRequest ehRequest = {};
493 case OC_OBSERVER_NOT_INTERESTED:
494 OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
495 observer = GetObserverUsingToken (token, tokenLength);
498 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
499 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
500 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
501 if(result != OC_STACK_OK)
505 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
507 //observer is not observing anymore
508 result = DeleteObserverUsingToken (token, tokenLength);
509 if(result == OC_STACK_OK)
511 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
515 result = OC_STACK_OK;
516 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
519 case OC_OBSERVER_STILL_INTERESTED:
520 //observer is still interested
521 OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
522 notifications, reset the failedCount"));
523 observer = GetObserverUsingToken (token, tokenLength);
526 observer->forceHighQos = 0;
527 observer->failedCommCount = 0;
528 result = OC_STACK_OK;
532 result = OC_STACK_OBSERVER_NOT_FOUND;
535 case OC_OBSERVER_FAILED_COMM:
536 //observer is not reachable
537 OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
538 observer = GetObserverUsingToken (token, tokenLength);
541 if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
543 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
544 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
545 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
546 if(result != OC_STACK_OK)
548 return OC_STACK_ERROR;
550 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
551 //observer is unreachable
552 result = DeleteObserverUsingToken (token, tokenLength);
553 if(result == OC_STACK_OK)
555 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
559 result = OC_STACK_OK;
560 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
565 observer->failedCommCount++;
566 result = OC_STACK_CONTINUE;
568 observer->forceHighQos = 1;
569 OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
573 OC_LOG(ERROR, TAG, PCF("Unknown status"));
574 result = OC_STACK_ERROR;
579 OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
581 OCStackResult ret = OC_STACK_ERROR;
589 ret = OC_STACK_RESOURCE_CREATED;
592 ret = OC_STACK_RESOURCE_DELETED;
595 ret = OC_STACK_INVALID_QUERY;
598 ret = OC_STACK_INVALID_OPTION;
601 ret = OC_STACK_NO_RESOURCE;
603 case CA_RETRANSMIT_TIMEOUT:
604 ret = OC_STACK_COMM_ERROR;
612 CAResponseResult_t OCToCAStackResult(OCStackResult ocCode)
614 CAResponseResult_t ret = CA_INTERNAL_SERVER_ERROR;
621 case OC_STACK_RESOURCE_CREATED:
624 case OC_STACK_RESOURCE_DELETED:
627 case OC_STACK_INVALID_QUERY:
630 case OC_STACK_INVALID_OPTION:
633 case OC_STACK_NO_RESOURCE:
636 case OC_STACK_COMM_ERROR:
637 ret = CA_RETRANSMIT_TIMEOUT;
645 OCStackResult OCToCAConnectivityType(OCConnectivityType ocConType, CAConnectivityType_t* caConType)
647 OCStackResult ret = OC_STACK_OK;
652 *caConType = CA_ETHERNET;
655 *caConType = CA_WIFI;
664 // Currently OC_ALL represents WIFI and ETHERNET
665 // Add other connectivity types as they are enabled in future
666 *caConType = (CAConnectivityType_t) (CA_WIFI|CA_ETHERNET);
669 ret = OC_STACK_INVALID_PARAM;
675 OCStackResult CAToOCConnectivityType(CAConnectivityType_t caConType, OCConnectivityType *ocConType)
677 OCStackResult ret = OC_STACK_OK;
682 *ocConType = OC_ETHERNET;
685 *ocConType = OC_WIFI;
694 ret = OC_STACK_INVALID_PARAM;
700 OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint)
702 OCStackResult ret = OC_STACK_ERROR;
704 char * savePtr = NULL;
705 char * cpAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
708 ret = OC_STACK_NO_MEMORY;
711 memcpy(cpAddress, endPoint->addressInfo.IP.ipAddress,
712 strlen(endPoint->addressInfo.IP.ipAddress) + 1);
714 // Grabs the first three numbers from the IPv4 address and replaces dots
715 for(int i=0; i<4; i++)
717 tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
721 ret = OC_STACK_ERROR;
724 address->addr[i] = atoi(tok);
727 memcpy(&address->addr[4], &endPoint->addressInfo.IP.port, sizeof(uint16_t));
735 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
737 uint32_t lowerBound = 0;
738 uint32_t higherBound = 0;
740 if (!cbNode || !cbNode->presence || !cbNode->presence->timeOut)
742 return OC_STACK_INVALID_PARAM;
745 OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0));
747 cbNode->presence->TTL = maxAgeSeconds;
749 for(int index = 0; index < PresenceTimeOutSize; index++)
751 // Guard against overflow
752 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index]))
755 lowerBound = GetTicks((PresenceTimeOut[index] *
756 cbNode->presence->TTL *
757 MILLISECONDS_PER_SECOND)/100);
761 lowerBound = GetTicks(UINT32_MAX);
764 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index+1]))
767 higherBound = GetTicks((PresenceTimeOut[index + 1] *
768 cbNode->presence->TTL *
769 MILLISECONDS_PER_SECOND)/100);
773 higherBound = GetTicks(UINT32_MAX);
776 cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
778 OC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound);
779 OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound);
780 OC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]);
783 cbNode->presence->TTLlevel = 0;
785 OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel);
789 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
792 char * savePtr = NULL;
793 // The format of the payload is {"oc":[%u:%u:%s]}
794 // %u : sequence number,
796 // %s : Resource Type (Optional)
798 if (!payload || !seqNum || !maxAge || !resType)
802 tok = strtok_r(payload, "[:]}", &savePtr);
803 payload[strlen(payload)] = ':';
805 //Retrieve sequence number
806 tok = strtok_r(NULL, "[:]}", &savePtr);
811 payload[strlen((char *)payload)] = ':';
812 *seqNum = (uint32_t) atoi(tok);
815 tok = strtok_r(NULL, "[:]}", &savePtr);
820 *maxAge = (uint32_t) atoi(tok);
822 //Retrieve ResourceType
823 tok = strtok_r(NULL, "[:]}",&savePtr);
829 *resType = (char *)OCMalloc(strlen(tok) + 1);
834 payload[strlen((char *)payload)] = ':';
835 strcpy(*resType, tok);
836 OC_LOG_V(DEBUG, TAG, "resourceTypeName %s", *resType);
838 payload[strlen((char *)payload)] = ']';
841 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
842 const CAResponseInfo_t* responseInfo)
844 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
845 ClientCB * cbNode = NULL;
846 char *resourceTypeName = NULL;
847 OCClientResponse response = {};
848 OCDevAddr address = {};
849 OCStackResult result = OC_STACK_ERROR;
852 char *fullUri = NULL;
853 char *ipAddress = NULL;
854 int presenceSubscribe = 0;
855 int multicastPresenceSubscribe = 0;
856 size_t addressLen = 0;
858 if (responseInfo->result != CA_SUCCESS)
860 OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
861 return OC_STACK_ERROR;
864 fullUri = (char *) OCMalloc(MAX_URI_LENGTH);
868 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for fullUri"));
869 result = OC_STACK_NO_MEMORY;
873 addressLen = strlen(endPoint->addressInfo.IP.ipAddress);
874 ipAddress = (char *) OCMalloc(addressLen + 1);
878 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for ipAddress"));
879 result = OC_STACK_NO_MEMORY;
883 strncpy(ipAddress, endPoint->addressInfo.IP.ipAddress, addressLen);
884 ipAddress[addressLen] = '\0';
886 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
889 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
893 presenceSubscribe = 1;
897 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", OC_MULTICAST_IP, OC_MULTICAST_PORT,
898 endPoint->resourceUri);
899 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
902 multicastPresenceSubscribe = 1;
906 if(!presenceSubscribe && !multicastPresenceSubscribe)
908 OC_LOG(ERROR, TAG, PCF("Received a presence notification, but no callback, ignoring"));
912 // No payload to the application in case of presence
913 response.resJSONPayload = NULL;
914 response.result = OC_STACK_OK;
916 result = UpdateResponseAddr(&address, endPoint);
917 if(result != OC_STACK_OK)
922 response.addr = &address;
924 result = CAToOCConnectivityType(endPoint->connectivityType, &(response.connType));
925 if(result != OC_STACK_OK)
927 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
931 if(responseInfo->info.payload)
933 parsePresencePayload(responseInfo->info.payload,
934 &(response.sequenceNumber),
939 if(presenceSubscribe)
941 if(cbNode->sequenceNumber == response.sequenceNumber)
943 if (cbNode->presence)
945 OC_LOG(INFO, TAG, PCF("No presence change. Updating TTL."));
947 result = ResetPresenceTTL(cbNode, maxAge);
949 if (result != OC_STACK_OK)
951 OC_LOG_V(ERROR, TAG, "ResetPresenceTTL failed with error: %u", result);
956 OC_LOG(INFO, TAG, PCF("Not subscribed to presence."));
963 OC_LOG(INFO, TAG, PCF("Stopping presence"));
964 response.result = OC_STACK_PRESENCE_STOPPED;
967 OCFree(cbNode->presence->timeOut);
968 OCFree(cbNode->presence);
969 cbNode->presence = NULL;
974 if(!cbNode->presence)
976 cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
977 if(!(cbNode->presence))
979 OC_LOG(ERROR, TAG, PCF("Could not allocate memory for cbNode->presence"));
980 result = OC_STACK_NO_MEMORY;
984 VERIFY_NON_NULL_V(cbNode->presence);
985 cbNode->presence->timeOut = NULL;
986 cbNode->presence->timeOut = (uint32_t *)
987 OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
988 if(!(cbNode->presence->timeOut)){
990 PCF("Could not allocate memory for cbNode->presence->timeOut"));
991 OCFree(cbNode->presence);
992 result = OC_STACK_NO_MEMORY;
997 ResetPresenceTTL(cbNode, maxAge);
999 OC_LOG(INFO, TAG, PCF("Presence changed, calling up the stack"));
1000 cbNode->sequenceNumber = response.sequenceNumber;
1002 // Ensure that a filter is actually applied.
1003 if(resourceTypeName && cbNode->filterResourceType)
1005 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1014 // This is the multicast case
1016 OCMulticastNode* mcNode = NULL;
1017 mcNode = GetMCPresenceNode(fullUri);
1021 if(mcNode->nonce == response.sequenceNumber)
1023 OC_LOG(INFO, TAG, PCF("No presence change (Multicast)"));
1026 mcNode->nonce = response.sequenceNumber;
1030 OC_LOG(INFO, TAG, PCF("Stopping presence"));
1031 response.result = OC_STACK_PRESENCE_STOPPED;
1036 uint32_t uriLen = strlen(fullUri);
1037 char* uri = (char *) OCMalloc(uriLen + 1);
1040 memcpy(uri, fullUri, (uriLen + 1));
1045 PCF("No Memory for URI to store in the presence node"));
1046 result = OC_STACK_NO_MEMORY;
1049 result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber);
1050 if(result != OC_STACK_OK)
1053 PCF("Unable to add Multicast Presence Node"));
1059 // Ensure that a filter is actually applied.
1060 if(resourceTypeName && cbNode->filterResourceType)
1062 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1069 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response);
1071 if (cbResult == OC_STACK_DELETE_TRANSACTION)
1073 FindAndDeleteClientCB(cbNode);
1079 OCFree(resourceTypeName);
1083 void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
1085 OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
1087 if(NULL == endPoint)
1089 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1093 if(NULL == responseInfo)
1095 OC_LOG(ERROR, TAG, PCF("responseInfo is NULL"));
1099 if(strcmp(endPoint->resourceUri, OC_PRESENCE_URI) == 0)
1101 HandlePresenceResponse(endPoint, responseInfo);
1105 ClientCB *cbNode = GetClientCB(responseInfo->info.token,
1106 responseInfo->info.tokenLength, NULL, NULL);
1107 OC_LOG_V(DEBUG, TAG, "Response has the token %s", responseInfo->info.token);
1108 ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token,
1109 responseInfo->info.tokenLength);
1113 OC_LOG(INFO, TAG, PCF("There is a cbNode associated with the response token"));
1114 if(responseInfo->result == CA_EMPTY)
1116 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1117 // We do not have a case for the client to receive a RESET
1118 if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1120 //This is the case of receiving an ACK on a request to a slow resource!
1121 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1122 //TODO: should we inform the client
1123 // app that at least the request was received at the server?
1126 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1128 OC_LOG(INFO, TAG, PCF("Receiving A Timeout for this token"));
1129 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1130 OCClientResponse response = {};
1131 OCDevAddr address = {};
1132 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1133 if(result != OC_STACK_OK)
1135 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1139 result = UpdateResponseAddr(&address, endPoint);
1140 if(result != OC_STACK_OK)
1142 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1145 response.addr = &address;
1147 response.result = CAToOCStackResult(responseInfo->result);
1148 cbNode->callBack(cbNode->context,
1149 cbNode->handle, &response);
1150 FindAndDeleteClientCB(cbNode);
1154 OC_LOG(INFO, TAG, PCF("This is a regular response, A client call back is found"));
1155 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1156 OCClientResponse response = {};
1157 OCDevAddr address = {};
1159 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1160 if(result != OC_STACK_OK)
1162 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1165 response.addr = &address;
1166 // Populate the connectivity type. If this is a discovery response,
1167 // the resource that will be constructed from this response will make
1168 // further API calls from this interface.
1169 result = CAToOCConnectivityType(endPoint->connectivityType,
1170 &(response.connType));
1171 if(result != OC_STACK_OK)
1173 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1177 response.result = CAToOCStackResult(responseInfo->result);
1178 response.resJSONPayload = (const char*)responseInfo->info.payload;
1179 response.numRcvdVendorSpecificHeaderOptions = 0;
1180 if(responseInfo->info.numOptions > 0)
1183 //First option always with option ID is COAP_OPTION_OBSERVE if it is available.
1184 if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
1186 memcpy (&(response.sequenceNumber),
1187 &(responseInfo->info.options[0].optionData), sizeof(uint32_t));
1188 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1;
1193 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
1196 if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS)
1198 OC_LOG(ERROR, TAG, PCF("#header options are more than MAX_HEADER_OPTIONS"));
1202 for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
1204 memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
1205 &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
1209 if (cbNode->method == OC_REST_OBSERVE &&
1210 response.sequenceNumber > OC_OFFSET_SEQUENCE_NUMBER &&
1211 response.sequenceNumber <= cbNode->sequenceNumber)
1213 OC_LOG_V(INFO, TAG, PCF("Received stale notification. Number :%d"),
1214 response.sequenceNumber);
1218 OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context,
1221 cbNode->sequenceNumber = response.sequenceNumber;
1223 if (appFeedback == OC_STACK_DELETE_TRANSACTION)
1225 FindAndDeleteClientCB(cbNode);
1229 //Need to send ACK when the response is CON
1230 if(responseInfo->info.type == CA_MSG_CONFIRM)
1232 SendResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1233 CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0);
1241 OC_LOG(INFO, TAG, PCF("There is an observer associated with the response token"));
1242 if(responseInfo->result == CA_EMPTY)
1244 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1245 if(responseInfo->info.type == CA_MSG_RESET)
1247 OC_LOG(INFO, TAG, PCF("This is a RESET"));
1248 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1249 OC_OBSERVER_NOT_INTERESTED);
1251 else if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1253 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1254 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1255 OC_OBSERVER_STILL_INTERESTED);
1258 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1260 OC_LOG(INFO, TAG, PCF("Receiving Time Out for an observer"));
1261 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1262 OC_OBSERVER_FAILED_COMM);
1267 if(!cbNode && !observer)
1269 if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER)
1271 OC_LOG(INFO, TAG, PCF("This is a client, but no cbNode was found for token"));
1272 if(responseInfo->result == CA_EMPTY)
1274 OC_LOG(INFO, TAG, PCF("Receiving CA_EMPTY in the ocstack"));
1278 OC_LOG(INFO, TAG, PCF("Received a response or notification,\
1279 but I do not have callback. Sending RESET"));
1280 SendResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1281 CA_MSG_RESET, 0, NULL, NULL, 0);
1285 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
1287 OC_LOG(INFO, TAG, PCF("This is a server, but no observer was found for token"));
1288 if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1290 OC_LOG_V(INFO, TAG, PCF("Received ACK at server for messageId : %d"),
1291 responseInfo->info.messageId);
1293 if (responseInfo->info.type == CA_MSG_RESET)
1295 OC_LOG_V(INFO, TAG, PCF("Received RESET at server for messageId : %d"),
1296 responseInfo->info.messageId);
1302 OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
1303 OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
1307 OCStackResult SendResponse(const CARemoteEndpoint_t* endPoint, const uint16_t coapID,
1308 const CAResponseResult_t responseResult, const CAMessageType_t type,
1309 const uint8_t numOptions, const CAHeaderOption_t *options,
1310 CAToken_t token, uint8_t tokenLength)
1312 CAResponseInfo_t respInfo = {};
1313 respInfo.result = responseResult;
1314 respInfo.info.messageId = coapID;
1315 respInfo.info.numOptions = numOptions;
1316 respInfo.info.options = (CAHeaderOption_t*)options;
1317 respInfo.info.payload = NULL;
1318 respInfo.info.token = token;
1319 respInfo.info.tokenLength = tokenLength;
1320 respInfo.info.type = type;
1322 CAResult_t caResult = CASendResponse(endPoint, &respInfo);
1323 if(caResult != CA_STATUS_OK)
1325 OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
1326 return OC_STACK_ERROR;
1331 //This function will be called back by CA layer when a request is received
1332 void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
1334 OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
1337 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1343 OC_LOG(ERROR, TAG, PCF("requestInfo is NULL"));
1347 OCStackResult requestResult = OC_STACK_ERROR;
1349 if(myStackMode == OC_CLIENT)
1351 //TODO: should the client be responding to requests?
1355 OCServerProtocolRequest serverRequest = {};
1357 OC_LOG_V(INFO, TAG, PCF("Endpoint URI : %s\n"), (char*)endPoint->resourceUri);
1359 char * newUri = NULL;
1360 char * query = NULL;
1362 requestResult = getQueryFromUri(endPoint->resourceUri, &query, &newUri);
1364 if (requestResult != OC_STACK_OK)
1366 OC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult);
1369 OC_LOG_V(INFO, TAG, PCF("URI without query: %s\n"), newUri);
1370 OC_LOG_V(INFO, TAG, PCF("Query : %s\n"), query);
1372 if(strlen(newUri) < MAX_URI_LENGTH)
1375 memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
1380 OC_LOG(ERROR, TAG, PCF("URI length exceeds MAX_URI_LENGTH."));
1388 if(strlen(query) < MAX_QUERY_LENGTH)
1390 memcpy (&(serverRequest.query), query, strlen(query));
1395 OC_LOG(ERROR, TAG, PCF("Query length exceeds MAX_QUERY_LENGTH."));
1400 //copy request payload
1401 if (requestInfo->info.payload)
1403 size_t payloadLen = strlen(requestInfo->info.payload);
1404 serverRequest.reqTotalSize = payloadLen + 1;
1405 memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
1410 serverRequest.reqTotalSize = 1;
1411 serverRequest.reqJSONPayload[0] = '\0';
1414 switch (requestInfo->method)
1418 serverRequest.method = OC_REST_GET;
1423 serverRequest.method = OC_REST_PUT;
1428 serverRequest.method = OC_REST_POST;
1433 serverRequest.method = OC_REST_DELETE;
1438 OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
1439 SendResponse(endPoint, requestInfo->info.messageId, CA_BAD_REQ,
1440 requestInfo->info.type, requestInfo->info.numOptions,
1441 requestInfo->info.options, requestInfo->info.token,
1442 requestInfo->info.tokenLength);
1447 OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d",
1448 requestInfo->info.tokenLength);
1449 OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token,
1450 requestInfo->info.tokenLength);
1451 serverRequest.requestToken = (CAToken_t)OCMalloc(requestInfo->info.tokenLength);
1452 serverRequest.tokenLength = requestInfo->info.tokenLength;
1454 if (!serverRequest.requestToken)
1456 OC_LOG(FATAL, TAG, "Server Request Token is NULL");
1457 SendResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR,
1458 requestInfo->info.type, requestInfo->info.numOptions,
1459 requestInfo->info.options, requestInfo->info.token,
1460 requestInfo->info.tokenLength);
1463 memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength);
1465 if (requestInfo->info.type == CA_MSG_CONFIRM)
1467 serverRequest.qos = OC_HIGH_QOS;
1471 serverRequest.qos = OC_LOW_QOS;
1473 // CA does not need the following 2 fields
1474 // Are we sure CA does not need them? how is it responding to multicast
1475 serverRequest.delayedResNeeded = 0;
1476 serverRequest.secured = endPoint->isSecured;
1478 serverRequest.coapID = requestInfo->info.messageId;
1481 serverRequest.addressInfo = endPoint->addressInfo;
1482 serverRequest.connectivityType = endPoint->connectivityType;
1484 // copy vendor specific header options
1485 uint8_t tempNum = (requestInfo->info.numOptions);
1486 GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum);
1487 if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
1490 PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
1491 SendResponse(endPoint, requestInfo->info.messageId, CA_BAD_OPT,
1492 requestInfo->info.type, requestInfo->info.numOptions,
1493 requestInfo->info.options, requestInfo->info.token,
1494 requestInfo->info.tokenLength);
1497 serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
1498 if (serverRequest.numRcvdVendorSpecificHeaderOptions)
1500 memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
1501 sizeof(CAHeaderOption_t)*tempNum);
1504 requestResult = HandleStackRequests (&serverRequest);
1506 // Send ACK to client as precursor to slow response
1507 if(requestResult == OC_STACK_SLOW_RESOURCE)
1509 SendResponse(endPoint, requestInfo->info.messageId, CA_EMPTY,
1516 else if(requestResult != OC_STACK_OK)
1518 OC_LOG_V(ERROR, TAG, PCF("HandleStackRequests failed. error: %d"), requestResult);
1520 CAResponseResult_t stackResponse = OCToCAStackResult(requestResult);
1522 SendResponse(endPoint, requestInfo->info.messageId, stackResponse,
1523 requestInfo->info.type, requestInfo->info.numOptions,
1524 requestInfo->info.options, requestInfo->info.token,
1525 requestInfo->info.tokenLength);
1527 // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest.
1528 // The token is copied in there, and is thus still owned by this function.
1529 OCFree(serverRequest.requestToken);
1530 OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
1533 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
1535 OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
1536 OCStackResult result = OC_STACK_ERROR;
1537 ResourceHandling resHandling;
1538 OCResource *resource;
1539 if(!protocolRequest)
1541 OC_LOG(ERROR, TAG, PCF("protocolRequest is NULL"));
1542 return OC_STACK_INVALID_PARAM;
1545 OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken,
1546 protocolRequest->tokenLength);
1549 OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
1550 result = AddServerRequest(&request, protocolRequest->coapID,
1551 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
1552 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
1553 protocolRequest->observationOption, protocolRequest->qos,
1554 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
1555 protocolRequest->reqJSONPayload, protocolRequest->requestToken,
1556 protocolRequest->tokenLength,
1557 protocolRequest->resourceUrl,protocolRequest->reqTotalSize,
1558 &protocolRequest->addressInfo, protocolRequest->connectivityType);
1559 if (OC_STACK_OK != result)
1561 OC_LOG(ERROR, TAG, PCF("Error adding server request"));
1567 OC_LOG(ERROR, TAG, PCF("Out of Memory"));
1568 return OC_STACK_NO_MEMORY;
1571 if(!protocolRequest->reqMorePacket)
1573 request->requestComplete = 1;
1579 PCF("This is either a repeated or blocked Server Request"));
1582 if(request->requestComplete)
1584 OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
1585 result = DetermineResourceHandling (request, &resHandling, &resource);
1586 if (result == OC_STACK_OK)
1588 result = ProcessRequest(resHandling, resource, request);
1593 OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
1594 result = OC_STACK_CONTINUE;
1599 bool ParseIPv4Address(char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
1603 uint8_t dotCount = 0;
1607 /* search for scheme */
1609 if (!isdigit((char) *ipAddrStr))
1611 coap = OC_COAP_SCHEME;
1612 while (*coap && tolower(*itr) == *coap)
1620 while (*ipAddrStr) {
1621 if (isdigit(*ipAddrStr))
1623 ipAddr[index] *= 10;
1624 ipAddr[index] += *ipAddrStr - '0';
1626 else if (*ipAddrStr == '.')
1638 if(*ipAddrStr == ':')
1642 if (isdigit(*ipAddrStr))
1645 *port += *ipAddrStr - '0';
1655 return (3 == dotCount);
1658 //-----------------------------------------------------------------------------
1660 //-----------------------------------------------------------------------------
1662 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
1664 if(stackState == OC_STACK_INITIALIZED)
1666 OC_LOG(INFO, TAG, PCF("Subsequent calls to OCInit() without calling \
1667 OCStop() between them are ignored."));
1673 OCStackResult result = OC_STACK_ERROR;
1674 OC_LOG(INFO, TAG, PCF("Entering OCInit"));
1677 if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
1679 OC_LOG(ERROR, TAG, PCF("Invalid mode"));
1680 return OC_STACK_ERROR;
1684 defaultDeviceHandler = NULL;
1687 result = CAResultToOCResult(CAInitialize());
1688 VERIFY_SUCCESS(result, OC_STACK_OK);
1690 result = CAResultToOCResult(OCSelectNetwork());
1691 VERIFY_SUCCESS(result, OC_STACK_OK);
1693 CARegisterHandler(HandleCARequests, HandleCAResponses);
1694 switch (myStackMode)
1697 result = CAResultToOCResult(CAStartDiscoveryServer());
1698 OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
1701 result = CAResultToOCResult(CAStartListeningServer());
1702 OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
1704 case OC_CLIENT_SERVER:
1705 result = CAResultToOCResult(CAStartListeningServer());
1706 if(result == OC_STACK_OK)
1708 result = CAResultToOCResult(CAStartDiscoveryServer());
1712 VERIFY_SUCCESS(result, OC_STACK_OK);
1714 #if defined(__WITH_DTLS__)
1715 result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ?
1716 OC_STACK_OK : OC_STACK_ERROR;
1717 VERIFY_SUCCESS(result, OC_STACK_OK);
1718 #endif // (__WITH_DTLS__)
1720 #ifdef WITH_PRESENCE
1721 PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
1722 #endif // WITH_PRESENCE
1724 //Update Stack state to initialized
1725 stackState = OC_STACK_INITIALIZED;
1727 // Initialize resource
1728 if(myStackMode != OC_CLIENT)
1730 result = initResources();
1734 if(result != OC_STACK_OK)
1736 OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
1737 deleteAllResources();
1739 stackState = OC_STACK_UNINITIALIZED;
1744 OCStackResult OCStop()
1746 OC_LOG(INFO, TAG, PCF("Entering OCStop"));
1748 if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
1750 OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
1753 else if (stackState != OC_STACK_INITIALIZED)
1755 OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
1756 return OC_STACK_ERROR;
1759 stackState = OC_STACK_UNINIT_IN_PROGRESS;
1761 #ifdef WITH_PRESENCE
1762 // Ensure that the TTL associated with ANY and ALL presence notifications originating from
1763 // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
1764 presenceResource.presenceTTL = 0;
1765 #endif // WITH_PRESENCE
1767 // Free memory dynamically allocated for resources
1768 deleteAllResources();
1771 // Remove all observers
1772 DeleteObserverList();
1773 // Remove all the client callbacks
1774 DeleteClientCBList();
1775 // Deinit security blob
1776 DeinitOCSecurityInfo();
1777 stackState = OC_STACK_UNINITIALIZED;
1781 CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
1786 return CA_MSG_CONFIRM;
1791 return CA_MSG_NONCONFIRM;
1795 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1799 query = strchr (inputUri, '?');
1803 if((query - inputUri) > MAX_URI_LENGTH)
1805 return OC_STACK_INVALID_URI;
1808 if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1810 return OC_STACK_INVALID_QUERY;
1813 else if(uriLen > MAX_URI_LENGTH)
1815 return OC_STACK_INVALID_URI;
1820 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1821 const char *referenceUri, const char *request, OCConnectivityType conType,
1822 OCQualityOfService qos, OCCallbackData *cbData,
1823 OCHeaderOption * options, uint8_t numOptions)
1825 OCStackResult result = OC_STACK_ERROR;
1826 ClientCB *clientCB = NULL;
1827 char * requestUri = NULL;
1828 char * resourceType = NULL;
1829 char * query = NULL;
1830 char * newUri = (char *)requiredUri;
1831 (void) referenceUri;
1832 CARemoteEndpoint_t* endpoint = NULL;
1833 CAResult_t caResult;
1834 CAToken_t token = NULL;
1835 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
1836 OCDoHandle resHandle = NULL;
1837 CAInfo_t requestData ={};
1838 CARequestInfo_t requestInfo ={};
1839 CAGroupEndpoint_t grpEnd = {};
1841 // To track if memory is allocated for additional header options
1843 OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1845 // Validate input parameters
1846 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1847 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1849 //TODO ("Need to form the final query by concatenating require and reference URI's");
1850 VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1852 uint16_t uriLen = strlen(requiredUri);
1854 // ToDo: We should also check if the requiredUri has a mutlicast address,
1855 // then qos has to be OC_Low_QOS
1861 case OC_REST_DELETE:
1862 case OC_REST_OBSERVE:
1863 case OC_REST_OBSERVE_ALL:
1864 case OC_REST_CANCEL_OBSERVE:
1866 #ifdef WITH_PRESENCE
1867 case OC_REST_PRESENCE:
1871 result = OC_STACK_INVALID_METHOD;
1875 if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1880 if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1882 result = OC_STACK_INVALID_PARAM;
1886 #ifdef WITH_PRESENCE
1887 if(method == OC_REST_PRESENCE)
1889 result = getQueryFromUri(requiredUri, &query, &newUri);
1892 result = getResourceType((char *) query, &resourceType);
1896 OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1900 OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
1905 OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
1907 if(result != OC_STACK_OK)
1912 #endif // WITH_PRESENCE
1914 requestUri = (char *) OCMalloc(uriLen + 1);
1917 memcpy(requestUri, newUri, (uriLen + 1));
1921 result = OC_STACK_NO_MEMORY;
1925 resHandle = GenerateInvocationHandle();
1928 result = OC_STACK_NO_MEMORY;
1935 case OC_REST_OBSERVE:
1936 case OC_REST_OBSERVE_ALL:
1937 case OC_REST_CANCEL_OBSERVE:
1939 requestInfo.method = CA_GET;
1944 requestInfo.method = CA_PUT;
1949 requestInfo.method = CA_POST;
1952 case OC_REST_DELETE:
1954 requestInfo.method = CA_DELETE;
1957 #ifdef WITH_PRESENCE
1958 case OC_REST_PRESENCE:
1960 // Replacing method type with GET because "presence"
1961 // is a stack layer only implementation.
1962 requestInfo.method = CA_GET;
1967 result = OC_STACK_INVALID_METHOD;
1972 caResult = CAGenerateToken(&token, tokenLength);
1973 if (caResult != CA_STATUS_OK)
1975 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
1976 CADestroyToken(token);
1977 result = CAResultToOCResult (caResult);
1981 requestData.type = qualityOfServiceToMessageType(qos);
1982 requestData.token = token;
1983 requestData.tokenLength = tokenLength;
1984 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
1986 result = CreateObserveHeaderOption (&(requestData.options), options,
1987 numOptions, OC_OBSERVE_REGISTER);
1988 if (result != OC_STACK_OK)
1992 requestData.numOptions = numOptions + 1;
1996 requestData.options = (CAHeaderOption_t*)options;
1997 requestData.numOptions = numOptions;
1999 requestData.payload = (char *)request;
2001 requestInfo.info = requestData;
2003 CAConnectivityType_t caConType;
2005 result = OCToCAConnectivityType((OCConnectivityType) conType, &caConType);
2006 if (result != OC_STACK_OK)
2008 OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
2013 if(conType == OC_ALL)
2015 grpEnd.connectivityType = caConType;
2017 grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
2018 if(!grpEnd.resourceUri)
2020 result = OC_STACK_NO_MEMORY;
2023 strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
2025 caResult = CASendRequestToAll(&grpEnd, &requestInfo);
2029 caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
2031 if (caResult != CA_STATUS_OK)
2033 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2034 result = CAResultToOCResult (caResult);
2035 CADestroyToken(token);
2039 caResult = CASendRequest(endpoint, &requestInfo);
2042 if (caResult != CA_STATUS_OK)
2044 OC_LOG(ERROR, TAG, PCF("CASendRequest"));
2045 result = CAResultToOCResult (caResult);
2046 CADestroyToken(token);
2050 if((result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method,
2051 requestUri, resourceType, conType)) != OC_STACK_OK)
2053 result = OC_STACK_NO_MEMORY;
2059 *handle = resHandle;
2063 if(newUri != requiredUri)
2067 if (result != OC_STACK_OK)
2069 OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
2070 FindAndDeleteClientCB(clientCB);
2073 OCFree(resourceType);
2075 CADestroyRemoteEndpoint(endpoint);
2076 OCFree(grpEnd.resourceUri);
2077 if (requestData.options && requestData.numOptions > 0)
2079 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2081 OCFree(requestData.options);
2087 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
2091 * This ftn is implemented one of two ways in the case of observation:
2093 * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
2094 * Remove the callback associated on client side.
2095 * When the next notification comes in from server,
2096 * reply with RESET message to server.
2097 * Keep in mind that the server will react to RESET only
2098 * if the last notification was sent as CON
2100 * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
2101 * and it is associated with an observe request
2102 * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
2103 * Send CON Observe request to server with
2104 * observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
2105 * Remove the callback associated on client side.
2107 OCStackResult ret = OC_STACK_OK;
2108 CARemoteEndpoint_t* endpoint = NULL;
2109 CAResult_t caResult;
2110 CAInfo_t requestData = {};
2111 CARequestInfo_t requestInfo = {};
2115 return OC_STACK_INVALID_PARAM;
2118 OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
2120 ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL);
2124 switch (clientCB->method)
2126 case OC_REST_OBSERVE:
2127 case OC_REST_OBSERVE_ALL:
2128 OC_LOG(INFO, TAG, PCF("Canceling observation"));
2129 if(qos == OC_HIGH_QOS)
2131 requestData.type = qualityOfServiceToMessageType(qos);
2132 requestData.token = clientCB->token;
2133 requestData.tokenLength = clientCB->tokenLength;
2134 if (CreateObserveHeaderOption (&(requestData.options),
2135 options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
2137 return OC_STACK_ERROR;
2139 requestData.numOptions = numOptions + 1;
2140 requestInfo.method = CA_GET;
2141 requestInfo.info = requestData;
2143 CAConnectivityType_t caConType;
2144 ret = OCToCAConnectivityType(clientCB->conType, &caConType);
2145 if(ret != OC_STACK_OK)
2150 caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri,
2151 caConType, &endpoint);
2152 if (caResult != CA_STATUS_OK)
2154 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2155 ret = OC_STACK_ERROR;
2160 caResult = CASendRequest(endpoint, &requestInfo);
2161 if (caResult != CA_STATUS_OK)
2163 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2164 ret = OC_STACK_ERROR;
2166 ret = CAResultToOCResult (caResult);
2170 FindAndDeleteClientCB(clientCB);
2173 #ifdef WITH_PRESENCE
2174 case OC_REST_PRESENCE:
2175 FindAndDeleteClientCB(clientCB);
2179 ret = OC_STACK_INVALID_METHOD;
2184 CADestroyRemoteEndpoint(endpoint);
2185 if (requestData.numOptions > 0)
2187 OCFree(requestData.options);
2193 #ifdef WITH_PRESENCE
2194 OCStackResult OCProcessPresence()
2196 OCStackResult result = OC_STACK_OK;
2197 uint8_t ipAddr[4] = { 0 };
2200 OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
2201 ClientCB* cbNode = NULL;
2203 OCClientResponse clientResponse ={};
2204 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
2206 LL_FOREACH(cbList, cbNode)
2208 if(OC_REST_PRESENCE == cbNode->method)
2210 if(cbNode->presence)
2212 uint32_t now = GetTicks(0);
2213 OC_LOG_V(DEBUG, TAG, "this TTL level %d",
2214 cbNode->presence->TTLlevel);
2215 OC_LOG_V(DEBUG, TAG, "current ticks %d", now);
2218 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
2223 if(cbNode->presence->TTLlevel < PresenceTimeOutSize)
2225 OC_LOG_V(DEBUG, TAG, "timeout ticks %d",
2226 cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
2229 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
2231 OC_LOG(DEBUG, TAG, PCF("No more timeout ticks"));
2232 if (ParseIPv4Address(cbNode->requestUri, ipAddr, &port))
2234 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
2237 clientResponse.sequenceNumber = 0;
2238 clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
2239 clientResponse.addr = (OCDevAddr *) &dst;
2240 clientResponse.resJSONPayload = NULL;
2242 // Increment the TTLLevel (going to a next state), so we don't keep
2243 // sending presence notification to client.
2244 cbNode->presence->TTLlevel++;
2245 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2246 cbNode->presence->TTLlevel);
2250 result = OC_STACK_INVALID_IP;
2254 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
2255 if (cbResult == OC_STACK_DELETE_TRANSACTION)
2257 FindAndDeleteClientCB(cbNode);
2261 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
2263 CAResult_t caResult = CA_STATUS_OK;
2264 CARemoteEndpoint_t* endpoint = NULL;
2265 CAInfo_t requestData ={};
2266 CARequestInfo_t requestInfo = {};
2268 OC_LOG(DEBUG, TAG, PCF("time to test server presence"));
2271 CAConnectivityType_t caConType;
2272 result = OCToCAConnectivityType(cbNode->conType, &caConType);
2273 caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, caConType,
2275 if (caResult != CA_STATUS_OK || result != OC_STACK_OK)
2277 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2281 requestData.type = CA_MSG_NONCONFIRM;
2282 requestData.token = cbNode->token;
2283 requestData.tokenLength = cbNode->tokenLength;
2284 requestInfo.method = CA_GET;
2285 requestInfo.info = requestData;
2287 caResult = CASendRequest(endpoint, &requestInfo);
2288 CADestroyRemoteEndpoint(endpoint);
2290 if (caResult != CA_STATUS_OK)
2292 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2296 cbNode->presence->TTLlevel++;
2297 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2298 cbNode->presence->TTLlevel);
2304 if (result != OC_STACK_OK)
2306 OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
2310 #endif // WITH_PRESENCE
2312 OCStackResult OCProcess()
2314 #ifdef WITH_PRESENCE
2315 OCProcessPresence();
2317 CAHandleRequestResponse();
2322 #ifdef WITH_PRESENCE
2323 OCStackResult OCStartPresence(const uint32_t ttl)
2325 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
2326 OCChangeResourceProperty(
2327 &(((OCResource *)presenceResource.handle)->resourceProperties),
2330 if (OC_MAX_PRESENCE_TTL_SECONDS < ttl)
2332 presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS;
2333 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to max value"));
2337 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
2338 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to default value"));
2342 presenceResource.presenceTTL = ttl;
2344 OC_LOG_V(DEBUG, TAG, "Presence TTL is %lu seconds", presenceResource.presenceTTL);
2346 if (OC_PRESENCE_UNINITIALIZED == presenceState)
2348 presenceState = OC_PRESENCE_INITIALIZED;
2350 CAAddress_t addressInfo;
2351 strncpy(addressInfo.IP.ipAddress, OC_MULTICAST_IP, CA_IPADDR_SIZE);
2352 addressInfo.IP.port = OC_MULTICAST_PORT;
2354 CAToken_t caToken = NULL;
2355 CAResult_t caResult = CAGenerateToken(&caToken, tokenLength);
2356 if (caResult != CA_STATUS_OK)
2358 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2359 CADestroyToken(caToken);
2360 return OC_STACK_ERROR;
2363 CAConnectivityType_t connType;
2364 OCToCAConnectivityType(OC_ALL, &connType );
2365 AddObserver(OC_PRESENCE_URI, NULL, 0, caToken, tokenLength,
2366 (OCResource *)presenceResource.handle, OC_LOW_QOS,
2367 &addressInfo, connType);
2368 CADestroyToken(caToken);
2371 // Each time OCStartPresence is called
2372 // a different random 32-bit integer number is used
2373 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2375 return SendPresenceNotification(NULL);
2378 OCStackResult OCStopPresence()
2380 OCStackResult result = OC_STACK_ERROR;
2382 if(presenceResource.handle)
2384 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2387 // make resource inactive
2388 result = OCChangeResourceProperty(
2389 &(((OCResource *) presenceResource.handle)->resourceProperties),
2392 if(result != OC_STACK_OK)
2395 PCF("Changing the presence resource properties to ACTIVE not successful"));
2399 return SendStopNotification();
2403 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
2405 defaultDeviceHandler = entityHandler;
2410 OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
2412 OC_LOG(INFO, TAG, PCF("Entering OCSetDeviceInfo"));
2414 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
2416 return SaveDeviceInfo(deviceInfo);
2420 return OC_STACK_ERROR;
2424 OCStackResult OCCreateResource(OCResourceHandle *handle,
2425 const char *resourceTypeName,
2426 const char *resourceInterfaceName,
2427 const char *uri, OCEntityHandler entityHandler,
2428 uint8_t resourceProperties)
2431 OCResource *pointer = NULL;
2434 OCStackResult result = OC_STACK_ERROR;
2436 OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
2438 if(myStackMode == OC_CLIENT)
2440 return OC_STACK_INVALID_PARAM;
2442 // Validate parameters
2443 if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH )
2445 OC_LOG(ERROR, TAG, PCF("URI is invalid"));
2446 return OC_STACK_INVALID_URI;
2448 // Is it presented during resource discovery?
2449 if (!handle || !resourceTypeName)
2451 OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
2452 return OC_STACK_INVALID_PARAM;
2455 if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0)
2457 resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
2460 // Make sure resourceProperties bitmask has allowed properties specified
2461 if (resourceProperties
2462 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE)) {
2463 OC_LOG(ERROR, TAG, PCF("Invalid property"));
2464 return OC_STACK_INVALID_PARAM;
2467 // If the headResource is NULL, then no resources have been created...
2468 pointer = headResource;
2471 // At least one resources is in the resource list, so we need to search for
2472 // repeated URLs, which are not allowed. If a repeat is found, exit with an error
2475 if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0)
2477 OC_LOG(ERROR, TAG, PCF("URI already in use"));
2478 return OC_STACK_INVALID_PARAM;
2480 pointer = pointer->next;
2483 // Create the pointer and insert it into the resource list
2484 pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
2487 result = OC_STACK_NO_MEMORY;
2490 pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
2492 insertResource(pointer);
2495 size = strlen(uri) + 1;
2496 str = (char *) OCMalloc(size);
2499 result = OC_STACK_NO_MEMORY;
2502 strncpy(str, uri, size);
2505 // Set properties. Set OC_ACTIVE
2506 pointer->resourceProperties = (OCResourceProperty) (resourceProperties
2509 // Add the resourcetype to the resource
2510 result = BindResourceTypeToResource(pointer, resourceTypeName);
2511 if (result != OC_STACK_OK)
2513 OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
2517 // Add the resourceinterface to the resource
2518 result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
2519 if (result != OC_STACK_OK)
2521 OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
2525 // If an entity handler has been passed, attach it to the newly created
2526 // resource. Otherwise, set the default entity handler.
2529 pointer->entityHandler = entityHandler;
2533 pointer->entityHandler = defaultResourceEHandler;
2537 result = OC_STACK_OK;
2539 #ifdef WITH_PRESENCE
2540 if(presenceResource.handle)
2542 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2543 SendPresenceNotification(pointer->rsrcType);
2547 if (result != OC_STACK_OK)
2549 // Deep delete of resource and other dynamic elements that it contains
2550 deleteResource(pointer);
2556 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
2557 const char *resourceTypeName,
2558 const char *resourceInterfaceName,
2561 OCEntityHandler entityHandler,
2562 uint8_t resourceProperties)
2569 return OC_STACK_INVALID_PARAM;
2572 OCStackResult result = OC_STACK_ERROR;
2574 result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
2575 uri, entityHandler, resourceProperties);
2577 if (result != OC_STACK_ERROR)
2580 size = strlen(host) + 1;
2581 str = (char *) OCMalloc(size);
2584 return OC_STACK_NO_MEMORY;
2586 strncpy(str, host, size);
2587 ((OCResource *) *handle)->host = str;
2593 OCStackResult OCBindResource(
2594 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2596 OCResource *resource = NULL;
2599 OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
2601 // Validate parameters
2602 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2603 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2604 // Container cannot contain itself
2605 if (collectionHandle == resourceHandle)
2607 OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
2608 return OC_STACK_INVALID_PARAM;
2611 // Use the handle to find the resource in the resource linked list
2612 resource = findResource((OCResource *) collectionHandle);
2615 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2616 return OC_STACK_INVALID_PARAM;
2619 // Look for an open slot to add add the child resource.
2620 // If found, add it and return success
2621 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2623 if (!resource->rsrcResources[i])
2625 resource->rsrcResources[i] = (OCResource *) resourceHandle;
2626 OC_LOG(INFO, TAG, PCF("resource bound"));
2628 #ifdef WITH_PRESENCE
2629 if(presenceResource.handle)
2631 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2632 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2640 // Unable to add resourceHandle, so return error
2641 return OC_STACK_ERROR;
2644 OCStackResult OCUnBindResource(
2645 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2647 OCResource *resource = NULL;
2650 OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
2652 // Validate parameters
2653 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2654 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2655 // Container cannot contain itself
2656 if (collectionHandle == resourceHandle)
2658 OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
2659 return OC_STACK_INVALID_PARAM;
2662 // Use the handle to find the resource in the resource linked list
2663 resource = findResource((OCResource *) collectionHandle);
2666 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2667 return OC_STACK_INVALID_PARAM;
2670 // Look for an open slot to add add the child resource.
2671 // If found, add it and return success
2672 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2674 if (resourceHandle == resource->rsrcResources[i])
2676 resource->rsrcResources[i] = (OCResource *) NULL;
2677 OC_LOG(INFO, TAG, PCF("resource unbound"));
2679 // Send notification when resource is unbounded successfully.
2680 #ifdef WITH_PRESENCE
2681 if(presenceResource.handle)
2683 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2684 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2691 OC_LOG(INFO, TAG, PCF("resource not found in collection"));
2693 // Unable to add resourceHandle, so return error
2694 return OC_STACK_ERROR;
2697 OCStackResult BindResourceTypeToResource(OCResource* resource,
2698 const char *resourceTypeName)
2700 OCResourceType *pointer = NULL;
2703 OCStackResult result = OC_STACK_ERROR;
2705 OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
2707 // Validate parameters
2708 VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
2709 // TODO: Does resource attribute representation really have to be maintained in stack?
2710 // Is it presented during resource discovery?
2712 // Create the resourcetype and insert it into the resource list
2713 pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
2716 result = OC_STACK_NO_MEMORY;
2720 // Set the resourceTypeName
2721 size = strlen(resourceTypeName) + 1;
2722 str = (char *) OCMalloc(size);
2725 result = OC_STACK_NO_MEMORY;
2728 strncpy(str, resourceTypeName, size);
2729 pointer->resourcetypename = str;
2731 insertResourceType(resource, pointer);
2732 result = OC_STACK_OK;
2735 if (result != OC_STACK_OK)
2744 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
2745 const char *resourceInterfaceName)
2747 OCResourceInterface *pointer = NULL;
2750 OCStackResult result = OC_STACK_ERROR;
2752 OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
2754 // Validate parameters
2755 VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
2757 //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
2759 // Create the resourceinterface and insert it into the resource list
2760 pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
2763 result = OC_STACK_NO_MEMORY;
2767 // Set the resourceinterface name
2768 size = strlen(resourceInterfaceName) + 1;
2769 str = (char *) OCMalloc(size);
2772 result = OC_STACK_NO_MEMORY;
2775 strncpy(str, resourceInterfaceName, size);
2776 pointer->name = str;
2778 // Bind the resourceinterface to the resource
2779 insertResourceInterface(resource, pointer);
2781 result = OC_STACK_OK;
2784 if (result != OC_STACK_OK)
2793 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
2794 const char *resourceTypeName)
2797 OCStackResult result = OC_STACK_ERROR;
2798 OCResource *resource = NULL;
2800 // Make sure resource exists
2801 resource = findResource((OCResource *) handle);
2804 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2805 return OC_STACK_ERROR;
2808 // call internal function
2809 result = BindResourceTypeToResource(resource, resourceTypeName);
2811 #ifdef WITH_PRESENCE
2812 if(presenceResource.handle)
2814 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2815 SendPresenceNotification(resource->rsrcType);
2822 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
2823 const char *resourceInterfaceName)
2826 OCStackResult result = OC_STACK_ERROR;
2827 OCResource *resource = NULL;
2829 // Make sure resource exists
2830 resource = findResource((OCResource *) handle);
2833 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2834 return OC_STACK_ERROR;
2837 // call internal function
2838 result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2840 #ifdef WITH_PRESENCE
2841 if(presenceResource.handle)
2843 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2844 SendPresenceNotification(resource->rsrcType);
2851 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
2853 OCResource *pointer = headResource;
2855 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2856 VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2860 *numResources = *numResources + 1;
2861 pointer = pointer->next;
2866 OCResourceHandle OCGetResourceHandle(uint8_t index)
2868 OCResource *pointer = headResource;
2870 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2872 // Iterate through the list
2873 for( uint8_t i = 0; i < index && pointer; ++i)
2875 pointer = pointer->next;
2877 return (OCResourceHandle) pointer;
2880 OCStackResult OCDeleteResource(OCResourceHandle handle)
2882 OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2886 OC_LOG(ERROR, TAG, PCF("Invalid param"));
2887 return OC_STACK_INVALID_PARAM;
2890 OCResource *resource = findResource((OCResource *) handle);
2891 if (resource == NULL)
2893 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2894 return OC_STACK_NO_RESOURCE;
2897 if (deleteResource((OCResource *) handle) != OC_STACK_OK)
2899 OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2900 return OC_STACK_ERROR;
2906 const char *OCGetResourceUri(OCResourceHandle handle)
2908 OCResource *resource = NULL;
2909 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2911 resource = findResource((OCResource *) handle);
2914 return resource->uri;
2916 return (const char *) NULL;
2919 OCResourceProperty OCGetResourceProperties(OCResourceHandle handle)
2921 OCResource *resource = NULL;
2922 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2924 resource = findResource((OCResource *) handle);
2927 return resource->resourceProperties;
2929 return (OCResourceProperty)-1;
2932 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2933 uint8_t *numResourceTypes)
2935 OCResource *resource = NULL;
2936 OCResourceType *pointer = NULL;
2938 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2939 VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
2940 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2942 *numResourceTypes = 0;
2944 resource = findResource((OCResource *) handle);
2947 pointer = resource->rsrcType;
2950 *numResourceTypes = *numResourceTypes + 1;
2951 pointer = pointer->next;
2957 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index)
2959 OCResourceType *resourceType = NULL;
2961 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
2963 resourceType = findResourceTypeAtIndex(handle, index);
2966 return resourceType->resourcetypename;
2968 return (const char *) NULL;
2971 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
2972 uint8_t *numResourceInterfaces)
2974 OCResourceInterface *pointer = NULL;
2975 OCResource *resource = NULL;
2977 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
2979 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2980 VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
2982 *numResourceInterfaces = 0;
2983 resource = findResource((OCResource *) handle);
2986 pointer = resource->rsrcInterface;
2989 *numResourceInterfaces = *numResourceInterfaces + 1;
2990 pointer = pointer->next;
2996 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index)
2998 OCResourceInterface *resourceInterface = NULL;
3000 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
3002 resourceInterface = findResourceInterfaceAtIndex(handle, index);
3003 if (resourceInterface)
3005 return resourceInterface->name;
3007 return (const char *) NULL;
3010 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
3013 OCResource *resource = NULL;
3015 OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
3017 if (index >= MAX_CONTAINED_RESOURCES)
3022 resource = findResource((OCResource *) collectionHandle);
3028 return resource->rsrcResources[index];
3031 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
3032 OCEntityHandler entityHandler)
3034 OCResource *resource = NULL;
3036 OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
3038 // Validate parameters
3039 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3041 // Use the handle to find the resource in the resource linked list
3042 resource = findResource((OCResource *)handle);
3045 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3046 return OC_STACK_ERROR;
3050 resource->entityHandler = entityHandler;
3052 #ifdef WITH_PRESENCE
3053 if(presenceResource.handle)
3055 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3056 SendPresenceNotification(resource->rsrcType);
3063 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle)
3065 OCResource *resource = NULL;
3067 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
3069 // Use the handle to find the resource in the resource linked list
3070 resource = findResource((OCResource *)handle);
3073 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3078 return resource->entityHandler;
3081 void incrementSequenceNumber(OCResource * resPtr)
3083 // Increment the sequence number
3084 resPtr->sequenceNum += 1;
3085 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
3087 resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
3092 #ifdef WITH_PRESENCE
3093 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
3095 OCResource *resPtr = NULL;
3096 OCStackResult result = OC_STACK_ERROR;
3097 OCMethod method = OC_REST_PRESENCE;
3098 uint32_t maxAge = 0;
3099 resPtr = findResource((OCResource *) presenceResource.handle);
3102 return OC_STACK_NO_RESOURCE;
3105 if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
3107 maxAge = presenceResource.presenceTTL;
3109 result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
3115 OCStackResult SendStopNotification()
3117 OCResource *resPtr = NULL;
3118 OCStackResult result = OC_STACK_ERROR;
3119 OCMethod method = OC_REST_PRESENCE;
3120 resPtr = findResource((OCResource *) presenceResource.handle);
3123 return OC_STACK_NO_RESOURCE;
3126 // maxAge is 0. ResourceType is NULL.
3127 result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
3132 #endif // WITH_PRESENCE
3133 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos)
3136 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3138 OCResource *resPtr = NULL;
3139 OCStackResult result = OC_STACK_ERROR;
3140 OCMethod method = OC_REST_NOMETHOD;
3141 uint32_t maxAge = 0;
3143 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3144 #ifdef WITH_PRESENCE
3145 if(handle == presenceResource.handle)
3149 #endif // WITH_PRESENCE
3150 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3152 // Verify that the resource exists
3153 resPtr = findResource ((OCResource *) handle);
3156 return OC_STACK_NO_RESOURCE;
3160 //only increment in the case of regular observing (not presence)
3161 incrementSequenceNumber(resPtr);
3162 method = OC_REST_OBSERVE;
3163 maxAge = MAX_OBSERVE_AGE;
3164 #ifdef WITH_PRESENCE
3165 result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
3167 result = SendAllObserverNotification (method, resPtr, maxAge, qos);
3174 OCNotifyListOfObservers (OCResourceHandle handle,
3175 OCObservationId *obsIdList,
3176 uint8_t numberOfIds,
3177 const char *notificationJSONPayload,
3178 OCQualityOfService qos)
3180 OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
3182 OCResource *resPtr = NULL;
3183 //TODO: we should allow the server to define this
3184 uint32_t maxAge = MAX_OBSERVE_AGE;
3186 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3187 VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
3188 VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
3190 // Verify that the resource exists
3191 resPtr = findResource ((OCResource *) handle);
3192 if (NULL == resPtr || myStackMode == OC_CLIENT)
3194 return OC_STACK_NO_RESOURCE;
3198 incrementSequenceNumber(resPtr);
3200 return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
3201 notificationJSONPayload, maxAge, qos));
3204 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
3206 OCStackResult result = OC_STACK_ERROR;
3207 OCServerRequest *serverRequest = NULL;
3209 OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
3211 // Validate input parameters
3212 VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
3213 VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
3215 // TODO: Placeholder for creating a response entry when implementing
3216 // block transfer feature
3218 // If a response payload is present, check if block transfer is required
3219 if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
3220 (const char *)ehResponse->payload, ehResponse->payloadSize))
3222 OC_LOG(INFO, TAG, PCF("Block transfer required"));
3224 // Persistent response buffer is needed for block transfer
3225 if (!ehResponse->persistentBufferFlag)
3227 OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
3228 return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
3230 // TODO: Placeholder for block transfer handling
3231 // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
3232 // when implementing the block transfer feature
3237 // Get pointer to request info
3238 serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
3241 result = serverRequest->ehResponseHandler(ehResponse);
3247 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
3249 OCStackResult result = OC_STACK_NOTIMPL;
3251 OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
3253 // TODO: validate response handle
3258 //-----------------------------------------------------------------------------
3259 // Private internal function definitions
3260 //-----------------------------------------------------------------------------
3261 static OCDoHandle GenerateInvocationHandle()
3263 OCDoHandle handle = NULL;
3264 // Generate token here, it will be deleted when the transaction is deleted
3265 handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3268 OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3274 #ifdef WITH_PRESENCE
3275 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
3276 OCResourceProperty resourceProperties, uint8_t enable)
3280 return OC_STACK_INVALID_PARAM;
3282 if (resourceProperties
3283 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW))
3285 OC_LOG(ERROR, TAG, PCF("Invalid property"));
3286 return OC_STACK_INVALID_PARAM;
3290 *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
3294 *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
3300 OCStackResult initResources()
3302 OCStackResult result = OC_STACK_OK;
3303 // Init application resource vars
3304 headResource = NULL;
3305 tailResource = NULL;
3306 // Init Virtual Resources
3307 #ifdef WITH_PRESENCE
3308 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
3309 //presenceResource.token = OCGenerateCoAPToken();
3310 result = OCCreateResource(&presenceResource.handle,
3311 OC_RSRVD_RESOURCE_TYPE_PRESENCE,
3316 //make resource inactive
3317 result = OCChangeResourceProperty(
3318 &(((OCResource *) presenceResource.handle)->resourceProperties),
3324 void insertResource(OCResource *resource)
3326 if (!headResource) {
3327 headResource = resource;
3328 tailResource = resource;
3332 tailResource->next = resource;
3333 tailResource = resource;
3335 resource->next = NULL;
3338 OCResource *findResource(OCResource *resource)
3340 OCResource *pointer = headResource;
3344 if (pointer == resource)
3348 pointer = pointer->next;
3353 void deleteAllResources()
3355 OCResource *pointer = headResource;
3356 OCResource *temp = NULL;
3360 temp = pointer->next;
3361 #ifdef WITH_PRESENCE
3362 if(pointer != (OCResource *) presenceResource.handle)
3364 #endif // WITH_PRESENCE
3365 deleteResource(pointer);
3366 #ifdef WITH_PRESENCE
3368 #endif // WITH_PRESENCE
3372 #ifdef WITH_PRESENCE
3373 // Ensure that the last resource to be deleted is the presence resource. This allows for all
3374 // presence notification attributed to their deletion to be processed.
3375 deleteResource((OCResource *) presenceResource.handle);
3376 #endif // WITH_PRESENCE
3379 OCStackResult deleteResource(OCResource *resource)
3381 OCResource *prev = NULL;
3382 OCResource *temp = NULL;
3384 temp = headResource;
3387 if (temp == resource)
3389 // Invalidate all Resource Properties.
3390 resource->resourceProperties = (OCResourceProperty) 0;
3391 #ifdef WITH_PRESENCE
3392 if(resource != (OCResource *) presenceResource.handle)
3394 #endif // WITH_PRESENCE
3395 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
3396 #ifdef WITH_PRESENCE
3399 if(presenceResource.handle)
3401 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3402 if(resource != (OCResource *) presenceResource.handle)
3404 SendPresenceNotification(resource->rsrcType);
3408 SendPresenceNotification(NULL);
3412 // Only resource in list.
3413 if (temp == headResource && temp == tailResource)
3415 headResource = NULL;
3416 tailResource = NULL;
3419 else if (temp == headResource)
3421 headResource = temp->next;
3424 else if (temp == tailResource)
3426 tailResource = prev;
3427 tailResource->next = NULL;
3431 prev->next = temp->next;
3434 deleteResourceElements(temp);
3445 return OC_STACK_ERROR;
3448 void deleteResourceElements(OCResource *resource)
3456 OCFree(resource->uri);
3458 // Delete resourcetype linked list
3459 deleteResourceType(resource->rsrcType);
3461 // Delete resourceinterface linked list
3462 deleteResourceInterface(resource->rsrcInterface);
3465 void deleteResourceType(OCResourceType *resourceType)
3467 OCResourceType *pointer = resourceType;
3468 OCResourceType *next = NULL;
3472 next = pointer->next;
3473 OCFree(pointer->resourcetypename);
3479 void deleteResourceInterface(OCResourceInterface *resourceInterface)
3481 OCResourceInterface *pointer = resourceInterface;
3482 OCResourceInterface *next = NULL;
3486 next = pointer->next;
3487 OCFree(pointer->name);
3493 void insertResourceType(OCResource *resource, OCResourceType *resourceType)
3495 OCResourceType *pointer = NULL;
3496 OCResourceType *previous = NULL;
3497 if (!resource || !resourceType)
3501 // resource type list is empty.
3502 else if (!resource->rsrcType)
3504 resource->rsrcType = resourceType;
3508 pointer = resource->rsrcType;
3512 // resource type already exists. Free 2nd arg and return.
3513 if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename))
3515 OCFree(resourceType->resourcetypename);
3516 OCFree(resourceType);
3520 pointer = pointer->next;
3522 previous->next = resourceType;
3524 resourceType->next = NULL;
3527 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index)
3529 OCResource *resource = NULL;
3530 OCResourceType *pointer = NULL;
3532 // Find the specified resource
3533 resource = findResource((OCResource *) handle);
3539 // Make sure a resource has a resourcetype
3540 if (!resource->rsrcType)
3545 // Iterate through the list
3546 pointer = resource->rsrcType;
3547 for(uint8_t i = 0; i< index && pointer; ++i)
3549 pointer = pointer->next;
3554 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
3556 if(resourceTypeList && resourceTypeName)
3558 OCResourceType * rtPointer = resourceTypeList;
3559 while(resourceTypeName && rtPointer)
3561 if(rtPointer->resourcetypename &&
3562 strcmp(resourceTypeName, (const char *)
3563 (rtPointer->resourcetypename)) == 0)
3567 rtPointer = rtPointer->next;
3574 void insertResourceInterface(OCResource *resource,
3575 OCResourceInterface *resourceInterface)
3577 OCResourceInterface *pointer = NULL;
3578 OCResourceInterface *previous = NULL;
3580 if (!resource->rsrcInterface)
3582 resource->rsrcInterface = resourceInterface;
3586 pointer = resource->rsrcInterface;
3589 // resource type already exists. Free 2nd arg and return.
3590 if (!strcmp(resourceInterface->name, pointer->name))
3592 OCFree(resourceInterface->name);
3593 OCFree(resourceInterface);
3597 pointer = pointer->next;
3599 previous->next = resourceInterface;
3601 resourceInterface->next = NULL;
3604 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
3607 OCResource *resource = NULL;
3608 OCResourceInterface *pointer = NULL;
3610 // Find the specified resource
3611 resource = findResource((OCResource *) handle);
3617 // Make sure a resource has a resourceinterface
3618 if (!resource->rsrcInterface)
3623 // Iterate through the list
3624 pointer = resource->rsrcInterface;
3626 for (uint8_t i = 0; i < index && pointer; ++i)
3628 pointer = pointer->next;
3633 bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size)
3635 bool result = false;
3637 // Determine if we are checking a request or a response
3640 // If size is greater than 0, use it for the request size value, otherwise
3641 // assume request is null terminated and use strlen for size value
3642 if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
3649 // If size is greater than 0, use it for the response size value, otherwise
3650 // assume response is null terminated and use strlen for size value
3651 if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
3659 OCStackResult getResourceType(const char * query, char** resourceType)
3663 return OC_STACK_INVALID_PARAM;
3666 OCStackResult result = OC_STACK_ERROR;
3668 if(strncmp(query, "rt=", 3) == 0)
3670 *resourceType = (char *) OCMalloc(strlen(query)-3 + 1);
3673 result = OC_STACK_NO_MEMORY;
3677 strcpy((char *)*resourceType, ((const char *)&query[3]));
3678 result = OC_STACK_OK;
3685 OCStackResult getQueryFromUri(const char * uri, char** query, char ** newURI)
3689 return OC_STACK_INVALID_URI;
3691 if(!query || !newURI)
3693 return OC_STACK_INVALID_PARAM;
3695 char* strTokPtr = NULL;
3696 char * leftToken = NULL;
3697 char * tempURI = (char *) OCMalloc(strlen(uri) + 1);
3702 strcpy(tempURI, uri);
3704 leftToken = strtok_r(tempURI, "?", &strTokPtr);
3706 //TODO-CA: This could be simplified. Clean up required.
3707 while(leftToken != NULL)
3709 if(strncmp(leftToken, "rt=", 3) == 0 || strncmp(leftToken, "if=", 3) == 0)
3711 *query = (char *) OCMalloc(strlen(leftToken) + 1);
3717 strcpy(*query, leftToken);
3720 leftToken = strtok_r(NULL, "?", &strTokPtr);
3728 return OC_STACK_NO_MEMORY;
3731 const ServerID OCGetServerInstanceID(void)
3733 static bool generated = false;
3734 static ServerID sid;
3740 sid = OCGetRandom();
3745 const char* OCGetServerInstanceIDString(void)
3747 // max printed length of a base 10
3748 // uint32 is 10 characters, so 11 includes null.
3749 // This will change as the representation gets switched
3751 static char buffer[11];
3753 if (snprintf(buffer, sizeof(buffer),"%u", OCGetServerInstanceID()) < 0)
3761 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
3762 uint8_t *c, uint8_t *d )
3764 if ( !ipAddr || !a || !b || !c || !d )
3766 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3767 return OC_STACK_INVALID_PARAM;
3770 *a = ipAddr->addr[0];
3771 *b = ipAddr->addr[1];
3772 *c = ipAddr->addr[2];
3773 *d = ipAddr->addr[3];
3778 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
3780 if ( !ipAddr || !port )
3782 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3783 return OC_STACK_INVALID_PARAM;
3786 *port = (ipAddr->addr[5]<< 8) | ipAddr->addr[4];
3791 CAResult_t OCSelectNetwork()
3793 CAResult_t retResult = CA_STATUS_FAILED;
3794 CAResult_t caResult = CA_STATUS_OK;
3796 CAConnectivityType_t connTypes[] = {
3801 int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]);
3803 for(int i = 0; i<numConnTypes; i++)
3805 // Ignore CA_NOT_SUPPORTED error. The CA Layer may have not compiled in the interface.
3806 if(caResult == CA_STATUS_OK || caResult == CA_NOT_SUPPORTED)
3808 caResult = CASelectNetwork(connTypes[i]);
3809 if(caResult == CA_STATUS_OK)
3811 retResult = CA_STATUS_OK;
3816 if(retResult != CA_STATUS_OK)
3818 return caResult; // Returns error of appropriate transport that failed fatally.
3824 OCStackResult CAResultToOCResult(CAResult_t caResult)
3830 case CA_STATUS_INVALID_PARAM:
3831 return OC_STACK_INVALID_PARAM;
3832 case CA_ADAPTER_NOT_ENABLED:
3833 return OC_STACK_ADAPTER_NOT_ENABLED;
3834 case CA_SERVER_STARTED_ALREADY:
3836 case CA_SERVER_NOT_STARTED:
3837 return OC_STACK_ERROR;
3838 case CA_DESTINATION_NOT_REACHABLE:
3839 return OC_STACK_COMM_ERROR;
3840 case CA_SOCKET_OPERATION_FAILED:
3841 return OC_STACK_COMM_ERROR;
3842 case CA_SEND_FAILED:
3843 return OC_STACK_COMM_ERROR;
3844 case CA_RECEIVE_FAILED:
3845 return OC_STACK_COMM_ERROR;
3846 case CA_MEMORY_ALLOC_FAILED:
3847 return OC_STACK_NO_MEMORY;
3848 case CA_REQUEST_TIMEOUT:
3849 return OC_STACK_TIMEOUT;
3850 case CA_DESTINATION_DISCONNECTED:
3851 return OC_STACK_COMM_ERROR;
3852 case CA_STATUS_FAILED:
3853 return OC_STACK_ERROR;
3854 case CA_NOT_SUPPORTED:
3855 return OC_STACK_NOTIMPL;
3857 return OC_STACK_ERROR;