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);
439 * Return a server instance ID.
441 * @return Instance ID of the server.
443 static const ServerID OCGetServerInstanceID(void);
445 //-----------------------------------------------------------------------------
446 // Internal functions
447 //-----------------------------------------------------------------------------
449 uint32_t GetTicks(uint32_t afterMilliSeconds)
454 // Guard against overflow of uint32_t
455 if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
456 COAP_TICKS_PER_SECOND)
458 return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
466 OCStackResult OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
467 uint16_t port, OCDevAddr *ipAddr)
471 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
472 return OC_STACK_INVALID_PARAM;
479 ipAddr->addr[4] = (uint8_t)port;
480 ipAddr->addr[5] = (uint8_t)(port >> 8);
485 //-----------------------------------------------------------------------------
486 // Internal API function
487 //-----------------------------------------------------------------------------
489 // This internal function is called to update the stack with the status of
490 // observers and communication failures
491 OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t status)
493 OCStackResult result = OC_STACK_ERROR;
494 ResourceObserver * observer = NULL;
495 OCEntityHandlerRequest ehRequest = {};
499 case OC_OBSERVER_NOT_INTERESTED:
500 OC_LOG(DEBUG, TAG, PCF("observer is not interested in our notifications anymore"));
501 observer = GetObserverUsingToken (token, tokenLength);
504 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
505 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
506 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
507 if(result != OC_STACK_OK)
511 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
513 //observer is not observing anymore
514 result = DeleteObserverUsingToken (token, tokenLength);
515 if(result == OC_STACK_OK)
517 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
521 result = OC_STACK_OK;
522 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
525 case OC_OBSERVER_STILL_INTERESTED:
526 //observer is still interested
527 OC_LOG(DEBUG, TAG, PCF("observer is interested in our \
528 notifications, reset the failedCount"));
529 observer = GetObserverUsingToken (token, tokenLength);
532 observer->forceHighQos = 0;
533 observer->failedCommCount = 0;
534 result = OC_STACK_OK;
538 result = OC_STACK_OBSERVER_NOT_FOUND;
541 case OC_OBSERVER_FAILED_COMM:
542 //observer is not reachable
543 OC_LOG(DEBUG, TAG, PCF("observer is unreachable"));
544 observer = GetObserverUsingToken (token, tokenLength);
547 if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
549 result = FormOCEntityHandlerRequest(&ehRequest, (OCRequestHandle) NULL,
550 OC_REST_NOMETHOD, (OCResourceHandle) NULL, NULL, NULL, 0,
551 NULL, OC_OBSERVE_DEREGISTER, observer->observeId);
552 if(result != OC_STACK_OK)
554 return OC_STACK_ERROR;
556 observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest);
557 //observer is unreachable
558 result = DeleteObserverUsingToken (token, tokenLength);
559 if(result == OC_STACK_OK)
561 OC_LOG(DEBUG, TAG, PCF("Removed observer successfully"));
565 result = OC_STACK_OK;
566 OC_LOG(DEBUG, TAG, PCF("Observer Removal failed"));
571 observer->failedCommCount++;
572 result = OC_STACK_CONTINUE;
574 observer->forceHighQos = 1;
575 OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
579 OC_LOG(ERROR, TAG, PCF("Unknown status"));
580 result = OC_STACK_ERROR;
585 OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
587 OCStackResult ret = OC_STACK_ERROR;
595 ret = OC_STACK_RESOURCE_CREATED;
598 ret = OC_STACK_RESOURCE_DELETED;
601 ret = OC_STACK_INVALID_QUERY;
604 ret = OC_STACK_INVALID_OPTION;
607 ret = OC_STACK_NO_RESOURCE;
609 case CA_RETRANSMIT_TIMEOUT:
610 ret = OC_STACK_COMM_ERROR;
618 CAResponseResult_t OCToCAStackResult(OCStackResult ocCode)
620 CAResponseResult_t ret = CA_INTERNAL_SERVER_ERROR;
627 case OC_STACK_RESOURCE_CREATED:
630 case OC_STACK_RESOURCE_DELETED:
633 case OC_STACK_INVALID_QUERY:
636 case OC_STACK_INVALID_OPTION:
639 case OC_STACK_NO_RESOURCE:
642 case OC_STACK_COMM_ERROR:
643 ret = CA_RETRANSMIT_TIMEOUT;
651 OCStackResult OCToCATransportType(OCConnectivityType ocConType, CATransportType_t* caConType)
653 OCStackResult ret = OC_STACK_OK;
658 *caConType = CA_IPV4;
661 *caConType = CA_IPV4;
670 // Currently OC_ALL represents WIFI and ETHERNET
671 // Add other connectivity types as they are enabled in future
672 *caConType = (CATransportType_t) (CA_IPV4);
675 ret = OC_STACK_INVALID_PARAM;
681 OCStackResult CAToOCConnectivityType(CATransportType_t caConType, OCConnectivityType *ocConType)
683 OCStackResult ret = OC_STACK_OK;
688 *ocConType = OC_ETHERNET;
697 ret = OC_STACK_INVALID_PARAM;
703 OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint)
705 OCStackResult ret = OC_STACK_ERROR;
707 char * savePtr = NULL;
708 char * cpAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
711 ret = OC_STACK_NO_MEMORY;
714 memcpy(cpAddress, endPoint->addressInfo.IP.ipAddress,
715 strlen(endPoint->addressInfo.IP.ipAddress) + 1);
717 // Grabs the first three numbers from the IPv4 address and replaces dots
718 for(int i=0; i<4; i++)
720 tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
724 ret = OC_STACK_ERROR;
727 address->addr[i] = atoi(tok);
730 memcpy(&address->addr[4], &endPoint->addressInfo.IP.port, sizeof(uint16_t));
738 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
740 uint32_t lowerBound = 0;
741 uint32_t higherBound = 0;
743 if (!cbNode || !cbNode->presence || !cbNode->presence->timeOut)
745 return OC_STACK_INVALID_PARAM;
748 OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0));
750 cbNode->presence->TTL = maxAgeSeconds;
752 for(int index = 0; index < PresenceTimeOutSize; index++)
754 // Guard against overflow
755 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index]))
758 lowerBound = GetTicks((PresenceTimeOut[index] *
759 cbNode->presence->TTL *
760 MILLISECONDS_PER_SECOND)/100);
764 lowerBound = GetTicks(UINT32_MAX);
767 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index+1]))
770 higherBound = GetTicks((PresenceTimeOut[index + 1] *
771 cbNode->presence->TTL *
772 MILLISECONDS_PER_SECOND)/100);
776 higherBound = GetTicks(UINT32_MAX);
779 cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
781 OC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound);
782 OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound);
783 OC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]);
786 cbNode->presence->TTLlevel = 0;
788 OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel);
792 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
795 char * savePtr = NULL;
796 // The format of the payload is {"oc":[%u:%u:%s]}
797 // %u : sequence number,
799 // %s : Resource Type (Optional)
801 if (!payload || !seqNum || !maxAge || !resType)
805 tok = strtok_r(payload, "[:]}", &savePtr);
806 payload[strlen(payload)] = ':';
808 //Retrieve sequence number
809 tok = strtok_r(NULL, "[:]}", &savePtr);
814 payload[strlen((char *)payload)] = ':';
815 *seqNum = (uint32_t) atoi(tok);
818 tok = strtok_r(NULL, "[:]}", &savePtr);
823 *maxAge = (uint32_t) atoi(tok);
825 //Retrieve ResourceType
826 tok = strtok_r(NULL, "[:]}",&savePtr);
832 *resType = (char *)OCMalloc(strlen(tok) + 1);
837 payload[strlen((char *)payload)] = ':';
838 strcpy(*resType, tok);
839 OC_LOG_V(DEBUG, TAG, "resourceTypeName %s", *resType);
841 payload[strlen((char *)payload)] = ']';
844 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
845 const CAResponseInfo_t* responseInfo)
847 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
848 ClientCB * cbNode = NULL;
849 char *resourceTypeName = NULL;
850 OCClientResponse response = {};
851 OCDevAddr address = {};
852 OCStackResult result = OC_STACK_ERROR;
855 char *fullUri = NULL;
856 char *ipAddress = NULL;
857 int presenceSubscribe = 0;
858 int multicastPresenceSubscribe = 0;
859 size_t addressLen = 0;
861 if (responseInfo->result != CA_SUCCESS)
863 OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
864 return OC_STACK_ERROR;
867 fullUri = (char *) OCMalloc(MAX_URI_LENGTH);
871 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for fullUri"));
872 result = OC_STACK_NO_MEMORY;
876 addressLen = strlen(endPoint->addressInfo.IP.ipAddress);
877 ipAddress = (char *) OCMalloc(addressLen + 1);
881 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for ipAddress"));
882 result = OC_STACK_NO_MEMORY;
886 strncpy(ipAddress, endPoint->addressInfo.IP.ipAddress, addressLen);
887 ipAddress[addressLen] = '\0';
889 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
892 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
896 presenceSubscribe = 1;
900 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", OC_MULTICAST_IP, OC_MULTICAST_PORT,
901 endPoint->resourceUri);
902 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
905 multicastPresenceSubscribe = 1;
909 if(!presenceSubscribe && !multicastPresenceSubscribe)
911 OC_LOG(ERROR, TAG, PCF("Received a presence notification, but no callback, ignoring"));
915 // No payload to the application in case of presence
916 response.resJSONPayload = NULL;
917 response.result = OC_STACK_OK;
919 result = UpdateResponseAddr(&address, endPoint);
920 if(result != OC_STACK_OK)
925 response.addr = &address;
927 result = CAToOCConnectivityType(endPoint->transportType, &(response.connType));
928 if(result != OC_STACK_OK)
930 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
934 if(responseInfo->info.payload)
936 parsePresencePayload(responseInfo->info.payload,
937 &(response.sequenceNumber),
942 if(presenceSubscribe)
944 if(cbNode->sequenceNumber == response.sequenceNumber)
946 if (cbNode->presence)
948 OC_LOG(INFO, TAG, PCF("No presence change. Updating TTL."));
950 result = ResetPresenceTTL(cbNode, maxAge);
952 if (result != OC_STACK_OK)
954 OC_LOG_V(ERROR, TAG, "ResetPresenceTTL failed with error: %u", result);
959 OC_LOG(INFO, TAG, PCF("Not subscribed to presence."));
966 OC_LOG(INFO, TAG, PCF("Stopping presence"));
967 response.result = OC_STACK_PRESENCE_STOPPED;
970 OCFree(cbNode->presence->timeOut);
971 OCFree(cbNode->presence);
972 cbNode->presence = NULL;
977 if(!cbNode->presence)
979 cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
980 if(!(cbNode->presence))
982 OC_LOG(ERROR, TAG, PCF("Could not allocate memory for cbNode->presence"));
983 result = OC_STACK_NO_MEMORY;
987 VERIFY_NON_NULL_V(cbNode->presence);
988 cbNode->presence->timeOut = NULL;
989 cbNode->presence->timeOut = (uint32_t *)
990 OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
991 if(!(cbNode->presence->timeOut)){
993 PCF("Could not allocate memory for cbNode->presence->timeOut"));
994 OCFree(cbNode->presence);
995 result = OC_STACK_NO_MEMORY;
1000 ResetPresenceTTL(cbNode, maxAge);
1002 OC_LOG(INFO, TAG, PCF("Presence changed, calling up the stack"));
1003 cbNode->sequenceNumber = response.sequenceNumber;
1005 // Ensure that a filter is actually applied.
1006 if(resourceTypeName && cbNode->filterResourceType)
1008 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1017 // This is the multicast case
1019 OCMulticastNode* mcNode = NULL;
1020 mcNode = GetMCPresenceNode(fullUri);
1024 if(mcNode->nonce == response.sequenceNumber)
1026 OC_LOG(INFO, TAG, PCF("No presence change (Multicast)"));
1029 mcNode->nonce = response.sequenceNumber;
1033 OC_LOG(INFO, TAG, PCF("Stopping presence"));
1034 response.result = OC_STACK_PRESENCE_STOPPED;
1039 uint32_t uriLen = strlen(fullUri);
1040 char* uri = (char *) OCMalloc(uriLen + 1);
1043 memcpy(uri, fullUri, (uriLen + 1));
1048 PCF("No Memory for URI to store in the presence node"));
1049 result = OC_STACK_NO_MEMORY;
1052 result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber);
1053 if(result != OC_STACK_OK)
1056 PCF("Unable to add Multicast Presence Node"));
1062 // Ensure that a filter is actually applied.
1063 if(resourceTypeName && cbNode->filterResourceType)
1065 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1072 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response);
1074 if (cbResult == OC_STACK_DELETE_TRANSACTION)
1076 FindAndDeleteClientCB(cbNode);
1082 OCFree(resourceTypeName);
1086 void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
1088 OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
1090 if(NULL == endPoint)
1092 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1096 if(NULL == responseInfo)
1098 OC_LOG(ERROR, TAG, PCF("responseInfo is NULL"));
1102 if(strcmp(endPoint->resourceUri, OC_PRESENCE_URI) == 0)
1104 HandlePresenceResponse(endPoint, responseInfo);
1108 ClientCB *cbNode = GetClientCB(responseInfo->info.token,
1109 responseInfo->info.tokenLength, NULL, NULL);
1110 OC_LOG_V(DEBUG, TAG, "Response has the token %s", responseInfo->info.token);
1111 ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token,
1112 responseInfo->info.tokenLength);
1116 OC_LOG(INFO, TAG, PCF("There is a cbNode associated with the response token"));
1117 if(responseInfo->result == CA_EMPTY)
1119 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1120 // We do not have a case for the client to receive a RESET
1121 if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1123 //This is the case of receiving an ACK on a request to a slow resource!
1124 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1125 //TODO: should we inform the client
1126 // app that at least the request was received at the server?
1129 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1131 OC_LOG(INFO, TAG, PCF("Receiving A Timeout for this token"));
1132 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1133 OCClientResponse response = {};
1134 OCDevAddr address = {};
1135 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1136 if(result != OC_STACK_OK)
1138 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1142 result = UpdateResponseAddr(&address, endPoint);
1143 if(result != OC_STACK_OK)
1145 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1148 response.addr = &address;
1150 response.result = CAToOCStackResult(responseInfo->result);
1151 cbNode->callBack(cbNode->context,
1152 cbNode->handle, &response);
1153 FindAndDeleteClientCB(cbNode);
1157 OC_LOG(INFO, TAG, PCF("This is a regular response, A client call back is found"));
1158 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1159 OCClientResponse response = {};
1160 OCDevAddr address = {};
1162 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1163 if(result != OC_STACK_OK)
1165 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1168 response.addr = &address;
1169 // Populate the connectivity type. If this is a discovery response,
1170 // the resource that will be constructed from this response will make
1171 // further API calls from this interface.
1172 result = CAToOCConnectivityType(endPoint->transportType,
1173 &(response.connType));
1174 if(result != OC_STACK_OK)
1176 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1180 response.result = CAToOCStackResult(responseInfo->result);
1181 response.resJSONPayload = (const char*)responseInfo->info.payload;
1182 response.numRcvdVendorSpecificHeaderOptions = 0;
1183 if(responseInfo->info.numOptions > 0)
1186 //First option always with option ID is COAP_OPTION_OBSERVE if it is available.
1187 if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
1189 memcpy (&(response.sequenceNumber),
1190 &(responseInfo->info.options[0].optionData), sizeof(uint32_t));
1191 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1;
1196 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
1199 if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS)
1201 OC_LOG(ERROR, TAG, PCF("#header options are more than MAX_HEADER_OPTIONS"));
1205 for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
1207 memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
1208 &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
1212 if (cbNode->method == OC_REST_OBSERVE &&
1213 response.sequenceNumber > OC_OFFSET_SEQUENCE_NUMBER &&
1214 response.sequenceNumber <= cbNode->sequenceNumber)
1216 OC_LOG_V(INFO, TAG, PCF("Received stale notification. Number :%d"),
1217 response.sequenceNumber);
1221 OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context,
1224 cbNode->sequenceNumber = response.sequenceNumber;
1226 if (appFeedback == OC_STACK_DELETE_TRANSACTION)
1228 FindAndDeleteClientCB(cbNode);
1232 // To keep discovery callbacks active.
1233 cbNode->TTL = GetTicks(MAX_CB_TIMEOUT_SECONDS *
1234 MILLISECONDS_PER_SECOND);
1238 //Need to send ACK when the response is CON
1239 if(responseInfo->info.type == CA_MSG_CONFIRM)
1241 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1242 CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0);
1250 OC_LOG(INFO, TAG, PCF("There is an observer associated with the response token"));
1251 if(responseInfo->result == CA_EMPTY)
1253 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1254 if(responseInfo->info.type == CA_MSG_RESET)
1256 OC_LOG(INFO, TAG, PCF("This is a RESET"));
1257 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1258 OC_OBSERVER_NOT_INTERESTED);
1260 else if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1262 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1263 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1264 OC_OBSERVER_STILL_INTERESTED);
1267 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1269 OC_LOG(INFO, TAG, PCF("Receiving Time Out for an observer"));
1270 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1271 OC_OBSERVER_FAILED_COMM);
1276 if(!cbNode && !observer)
1278 if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER)
1280 OC_LOG(INFO, TAG, PCF("This is a client, but no cbNode was found for token"));
1281 if(responseInfo->result == CA_EMPTY)
1283 OC_LOG(INFO, TAG, PCF("Receiving CA_EMPTY in the ocstack"));
1287 OC_LOG(INFO, TAG, PCF("Received a response or notification,\
1288 but I do not have callback. Sending RESET"));
1289 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1290 CA_MSG_RESET, 0, NULL, NULL, 0);
1294 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
1296 OC_LOG(INFO, TAG, PCF("This is a server, but no observer was found for token"));
1297 if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1299 OC_LOG_V(INFO, TAG, PCF("Received ACK at server for messageId : %d"),
1300 responseInfo->info.messageId);
1302 if (responseInfo->info.type == CA_MSG_RESET)
1304 OC_LOG_V(INFO, TAG, PCF("Received RESET at server for messageId : %d"),
1305 responseInfo->info.messageId);
1311 OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
1312 OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
1316 * This function sends out Direct Stack Responses. These are responses that are not coming
1317 * from the application entity handler. These responses have no payload and are usually ACKs,
1318 * RESETs or some error conditions that were caught by the stack.
1320 OCStackResult SendDirectStackResponse(const CARemoteEndpoint_t* endPoint, const uint16_t coapID,
1321 const CAResponseResult_t responseResult, const CAMessageType_t type,
1322 const uint8_t numOptions, const CAHeaderOption_t *options,
1323 CAToken_t token, uint8_t tokenLength)
1325 CAResponseInfo_t respInfo = {};
1326 respInfo.result = responseResult;
1327 respInfo.info.messageId = coapID;
1328 respInfo.info.numOptions = numOptions;
1329 respInfo.info.options = (CAHeaderOption_t*)options;
1330 respInfo.info.payload = NULL;
1331 respInfo.info.token = token;
1332 respInfo.info.tokenLength = tokenLength;
1333 respInfo.info.type = type;
1335 CAResult_t caResult = CASendResponse(endPoint, &respInfo);
1336 if(caResult != CA_STATUS_OK)
1338 OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
1339 return OC_STACK_ERROR;
1344 //This function will be called back by CA layer when a request is received
1345 void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
1347 OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
1350 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1356 OC_LOG(ERROR, TAG, PCF("requestInfo is NULL"));
1360 OCStackResult requestResult = OC_STACK_ERROR;
1362 if(myStackMode == OC_CLIENT)
1364 //TODO: should the client be responding to requests?
1368 OCServerProtocolRequest serverRequest = {};
1370 OC_LOG_V(INFO, TAG, PCF("Endpoint URI : %s\n"), (char*)endPoint->resourceUri);
1372 char * newUri = NULL;
1373 char * query = NULL;
1375 requestResult = getQueryFromUri(endPoint->resourceUri, &query, &newUri);
1377 if (requestResult != OC_STACK_OK)
1379 OC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult);
1382 OC_LOG_V(INFO, TAG, PCF("URI without query: %s\n"), newUri);
1383 OC_LOG_V(INFO, TAG, PCF("Query : %s\n"), query);
1385 if(strlen(newUri) < MAX_URI_LENGTH)
1388 memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
1393 OC_LOG(ERROR, TAG, PCF("URI length exceeds MAX_URI_LENGTH."));
1401 if(strlen(query) < MAX_QUERY_LENGTH)
1403 memcpy (&(serverRequest.query), query, strlen(query));
1408 OC_LOG(ERROR, TAG, PCF("Query length exceeds MAX_QUERY_LENGTH."));
1413 //copy request payload
1414 if (requestInfo->info.payload)
1416 size_t payloadLen = strlen(requestInfo->info.payload);
1417 serverRequest.reqTotalSize = payloadLen + 1;
1418 memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
1423 serverRequest.reqTotalSize = 1;
1424 serverRequest.reqJSONPayload[0] = '\0';
1427 switch (requestInfo->method)
1431 serverRequest.method = OC_REST_GET;
1436 serverRequest.method = OC_REST_PUT;
1441 serverRequest.method = OC_REST_POST;
1446 serverRequest.method = OC_REST_DELETE;
1451 OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
1452 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_REQ,
1453 requestInfo->info.type, requestInfo->info.numOptions,
1454 requestInfo->info.options, requestInfo->info.token,
1455 requestInfo->info.tokenLength);
1460 OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d",
1461 requestInfo->info.tokenLength);
1462 OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token,
1463 requestInfo->info.tokenLength);
1464 serverRequest.requestToken = (CAToken_t)OCMalloc(requestInfo->info.tokenLength);
1465 serverRequest.tokenLength = requestInfo->info.tokenLength;
1467 if (!serverRequest.requestToken)
1469 OC_LOG(FATAL, TAG, "Server Request Token is NULL");
1470 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR,
1471 requestInfo->info.type, requestInfo->info.numOptions,
1472 requestInfo->info.options, requestInfo->info.token,
1473 requestInfo->info.tokenLength);
1476 memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength);
1478 if (requestInfo->info.type == CA_MSG_CONFIRM)
1480 serverRequest.qos = OC_HIGH_QOS;
1484 serverRequest.qos = OC_LOW_QOS;
1486 // CA does not need the following 2 fields
1487 // Are we sure CA does not need them? how is it responding to multicast
1488 serverRequest.delayedResNeeded = 0;
1489 serverRequest.secured = endPoint->isSecured;
1491 serverRequest.coapID = requestInfo->info.messageId;
1494 serverRequest.addressInfo = endPoint->addressInfo;
1495 serverRequest.connectivityType = endPoint->transportType;
1497 // copy vendor specific header options
1498 uint8_t tempNum = (requestInfo->info.numOptions);
1499 GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum);
1500 if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
1503 PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
1504 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_OPT,
1505 requestInfo->info.type, requestInfo->info.numOptions,
1506 requestInfo->info.options, requestInfo->info.token,
1507 requestInfo->info.tokenLength);
1508 OCFree(serverRequest.requestToken);
1511 serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
1512 if (serverRequest.numRcvdVendorSpecificHeaderOptions)
1514 memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
1515 sizeof(CAHeaderOption_t)*tempNum);
1518 requestResult = HandleStackRequests (&serverRequest);
1520 // Send ACK to client as precursor to slow response
1521 if(requestResult == OC_STACK_SLOW_RESOURCE)
1523 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_EMPTY,
1524 CA_MSG_ACKNOWLEDGE,0, NULL, NULL, 0);
1526 else if(requestResult != OC_STACK_OK)
1528 OC_LOG_V(ERROR, TAG, PCF("HandleStackRequests failed. error: %d"), requestResult);
1530 CAResponseResult_t stackResponse = OCToCAStackResult(requestResult);
1532 SendDirectStackResponse(endPoint, requestInfo->info.messageId, stackResponse,
1533 requestInfo->info.type, requestInfo->info.numOptions,
1534 requestInfo->info.options, requestInfo->info.token,
1535 requestInfo->info.tokenLength);
1537 // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest.
1538 // The token is copied in there, and is thus still owned by this function.
1539 OCFree(serverRequest.requestToken);
1540 OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
1543 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
1545 OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
1546 OCStackResult result = OC_STACK_ERROR;
1547 ResourceHandling resHandling;
1548 OCResource *resource;
1549 if(!protocolRequest)
1551 OC_LOG(ERROR, TAG, PCF("protocolRequest is NULL"));
1552 return OC_STACK_INVALID_PARAM;
1555 OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken,
1556 protocolRequest->tokenLength);
1559 OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
1560 result = AddServerRequest(&request, protocolRequest->coapID,
1561 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
1562 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
1563 protocolRequest->observationOption, protocolRequest->qos,
1564 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
1565 protocolRequest->reqJSONPayload, protocolRequest->requestToken,
1566 protocolRequest->tokenLength,
1567 protocolRequest->resourceUrl,protocolRequest->reqTotalSize,
1568 &protocolRequest->addressInfo, protocolRequest->connectivityType);
1569 if (OC_STACK_OK != result)
1571 OC_LOG(ERROR, TAG, PCF("Error adding server request"));
1577 OC_LOG(ERROR, TAG, PCF("Out of Memory"));
1578 return OC_STACK_NO_MEMORY;
1581 if(!protocolRequest->reqMorePacket)
1583 request->requestComplete = 1;
1589 PCF("This is either a repeated or blocked Server Request"));
1592 if(request->requestComplete)
1594 OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
1595 result = DetermineResourceHandling (request, &resHandling, &resource);
1596 if (result == OC_STACK_OK)
1598 result = ProcessRequest(resHandling, resource, request);
1603 OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
1604 result = OC_STACK_CONTINUE;
1609 bool ParseIPv4Address(char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
1613 uint8_t dotCount = 0;
1617 /* search for scheme */
1619 if (!isdigit((char) *ipAddrStr))
1621 coap = OC_COAP_SCHEME;
1622 while (*coap && tolower(*itr) == *coap)
1632 if (isdigit(*ipAddrStr))
1634 ipAddr[index] *= 10;
1635 ipAddr[index] += *ipAddrStr - '0';
1637 else if (*ipAddrStr == '.')
1649 if(*ipAddrStr == ':')
1653 if (isdigit(*ipAddrStr))
1656 *port += *ipAddrStr - '0';
1666 return (3 == dotCount);
1669 //-----------------------------------------------------------------------------
1671 //-----------------------------------------------------------------------------
1673 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
1675 if(stackState == OC_STACK_INITIALIZED)
1677 OC_LOG(INFO, TAG, PCF("Subsequent calls to OCInit() without calling \
1678 OCStop() between them are ignored."));
1684 OCStackResult result = OC_STACK_ERROR;
1685 OC_LOG(INFO, TAG, PCF("Entering OCInit"));
1688 if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
1690 OC_LOG(ERROR, TAG, PCF("Invalid mode"));
1691 return OC_STACK_ERROR;
1695 defaultDeviceHandler = NULL;
1698 result = CAResultToOCResult(CAInitialize());
1699 VERIFY_SUCCESS(result, OC_STACK_OK);
1701 result = CAResultToOCResult(OCSelectNetwork());
1702 VERIFY_SUCCESS(result, OC_STACK_OK);
1704 CARegisterHandler(HandleCARequests, HandleCAResponses);
1705 switch (myStackMode)
1708 result = CAResultToOCResult(CAStartDiscoveryServer());
1709 OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
1712 result = CAResultToOCResult(CAStartListeningServer());
1713 OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
1715 case OC_CLIENT_SERVER:
1716 result = CAResultToOCResult(CAStartListeningServer());
1717 if(result == OC_STACK_OK)
1719 result = CAResultToOCResult(CAStartDiscoveryServer());
1723 VERIFY_SUCCESS(result, OC_STACK_OK);
1725 #if defined(__WITH_DTLS__)
1726 result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ?
1727 OC_STACK_OK : OC_STACK_ERROR;
1728 VERIFY_SUCCESS(result, OC_STACK_OK);
1729 #endif // (__WITH_DTLS__)
1731 #ifdef WITH_PRESENCE
1732 PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
1733 #endif // WITH_PRESENCE
1735 //Update Stack state to initialized
1736 stackState = OC_STACK_INITIALIZED;
1738 // Initialize resource
1739 if(myStackMode != OC_CLIENT)
1741 result = initResources();
1745 if(result != OC_STACK_OK)
1747 OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
1748 deleteAllResources();
1750 stackState = OC_STACK_UNINITIALIZED;
1755 OCStackResult OCStop()
1757 OC_LOG(INFO, TAG, PCF("Entering OCStop"));
1759 if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
1761 OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
1764 else if (stackState != OC_STACK_INITIALIZED)
1766 OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
1767 return OC_STACK_ERROR;
1770 stackState = OC_STACK_UNINIT_IN_PROGRESS;
1772 #ifdef WITH_PRESENCE
1773 // Ensure that the TTL associated with ANY and ALL presence notifications originating from
1774 // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
1775 presenceResource.presenceTTL = 0;
1776 #endif // WITH_PRESENCE
1778 // Free memory dynamically allocated for resources
1779 deleteAllResources();
1782 // Remove all observers
1783 DeleteObserverList();
1784 // Remove all the client callbacks
1785 DeleteClientCBList();
1786 // Deinit security blob
1787 DeinitOCSecurityInfo();
1788 stackState = OC_STACK_UNINITIALIZED;
1792 CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
1797 return CA_MSG_CONFIRM;
1802 return CA_MSG_NONCONFIRM;
1806 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1810 query = strchr (inputUri, '?');
1814 if((query - inputUri) > MAX_URI_LENGTH)
1816 return OC_STACK_INVALID_URI;
1819 if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1821 return OC_STACK_INVALID_QUERY;
1824 else if(uriLen > MAX_URI_LENGTH)
1826 return OC_STACK_INVALID_URI;
1831 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1832 const char *referenceUri, const char *request, OCConnectivityType conType,
1833 OCQualityOfService qos, OCCallbackData *cbData,
1834 OCHeaderOption * options, uint8_t numOptions)
1836 OCStackResult result = OC_STACK_ERROR;
1837 ClientCB *clientCB = NULL;
1838 char * requestUri = NULL;
1839 char * resourceType = NULL;
1840 char * query = NULL;
1841 char * newUri = (char *)requiredUri;
1842 (void) referenceUri;
1843 CARemoteEndpoint_t* endpoint = NULL;
1844 CAResult_t caResult;
1845 CAToken_t token = NULL;
1846 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
1847 OCDoHandle resHandle = NULL;
1848 CAInfo_t requestData ={};
1849 CARequestInfo_t requestInfo ={};
1850 CAGroupEndpoint_t grpEnd = {};
1852 // To track if memory is allocated for additional header options
1854 OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1856 // Validate input parameters
1857 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1858 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1860 //TODO ("Need to form the final query by concatenating require and reference URI's");
1861 VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1863 uint16_t uriLen = strlen(requiredUri);
1865 // ToDo: We should also check if the requiredUri has a mutlicast address,
1866 // then qos has to be OC_Low_QOS
1872 case OC_REST_DELETE:
1873 case OC_REST_OBSERVE:
1874 case OC_REST_OBSERVE_ALL:
1875 case OC_REST_CANCEL_OBSERVE:
1877 #ifdef WITH_PRESENCE
1878 case OC_REST_PRESENCE:
1882 result = OC_STACK_INVALID_METHOD;
1886 if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1891 if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1893 result = OC_STACK_INVALID_PARAM;
1897 #ifdef WITH_PRESENCE
1898 if(method == OC_REST_PRESENCE)
1900 result = getQueryFromUri(requiredUri, &query, &newUri);
1902 if(result != OC_STACK_OK)
1904 OC_LOG_V(ERROR, TAG, "Invalid Param from getQueryFromUri: %d, URI is %s",
1905 result, requiredUri);
1911 result = getResourceType((char *) query, &resourceType);
1915 OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1919 OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
1924 OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
1926 if(result != OC_STACK_OK)
1931 #endif // WITH_PRESENCE
1933 requestUri = (char *) OCMalloc(uriLen + 1);
1936 memcpy(requestUri, newUri, (uriLen + 1));
1940 result = OC_STACK_NO_MEMORY;
1944 resHandle = GenerateInvocationHandle();
1947 result = OC_STACK_NO_MEMORY;
1954 case OC_REST_OBSERVE:
1955 case OC_REST_OBSERVE_ALL:
1956 case OC_REST_CANCEL_OBSERVE:
1958 requestInfo.method = CA_GET;
1963 requestInfo.method = CA_PUT;
1968 requestInfo.method = CA_POST;
1971 case OC_REST_DELETE:
1973 requestInfo.method = CA_DELETE;
1976 #ifdef WITH_PRESENCE
1977 case OC_REST_PRESENCE:
1979 // Replacing method type with GET because "presence"
1980 // is a stack layer only implementation.
1981 requestInfo.method = CA_GET;
1986 result = OC_STACK_INVALID_METHOD;
1991 caResult = CAGenerateToken(&token, tokenLength);
1992 if (caResult != CA_STATUS_OK)
1994 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
1995 CADestroyToken(token);
1996 result = CAResultToOCResult (caResult);
2000 requestData.type = qualityOfServiceToMessageType(qos);
2001 requestData.token = token;
2002 requestData.tokenLength = tokenLength;
2003 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2005 result = CreateObserveHeaderOption (&(requestData.options), options,
2006 numOptions, OC_OBSERVE_REGISTER);
2007 if (result != OC_STACK_OK)
2009 CADestroyToken(token);
2012 requestData.numOptions = numOptions + 1;
2016 requestData.options = (CAHeaderOption_t*)options;
2017 requestData.numOptions = numOptions;
2019 requestData.payload = (char *)request;
2021 requestInfo.info = requestData;
2022 CATransportType_t caConType;
2024 result = OCToCATransportType((OCConnectivityType) conType, &caConType);
2025 if (result != OC_STACK_OK)
2027 OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
2032 if(conType == OC_ALL)
2034 grpEnd.transportType = caConType;
2036 grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
2037 if(!grpEnd.resourceUri)
2039 result = OC_STACK_NO_MEMORY;
2040 CADestroyToken(token);
2043 strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
2045 caResult = CASendRequestToAll(&grpEnd, &requestInfo);
2049 caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
2051 if (caResult != CA_STATUS_OK)
2053 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2054 result = CAResultToOCResult (caResult);
2055 CADestroyToken(token);
2059 caResult = CASendRequest(endpoint, &requestInfo);
2062 if (caResult != CA_STATUS_OK)
2064 OC_LOG(ERROR, TAG, PCF("CASendRequest"));
2065 result = CAResultToOCResult (caResult);
2066 CADestroyToken(token);
2070 result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method,
2071 requestUri, resourceType, conType,
2072 GetTicks(MAX_CB_TIMEOUT_SECONDS * MILLISECONDS_PER_SECOND));
2073 if(result != OC_STACK_OK)
2075 result = OC_STACK_NO_MEMORY;
2081 *handle = resHandle;
2085 if(newUri != requiredUri)
2089 if (result != OC_STACK_OK)
2091 OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
2092 FindAndDeleteClientCB(clientCB);
2095 OCFree(resourceType);
2097 CADestroyRemoteEndpoint(endpoint);
2098 OCFree(grpEnd.resourceUri);
2100 if (requestData.options && requestData.numOptions > 0)
2102 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2104 OCFree(requestData.options);
2110 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
2114 * This ftn is implemented one of two ways in the case of observation:
2116 * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
2117 * Remove the callback associated on client side.
2118 * When the next notification comes in from server,
2119 * reply with RESET message to server.
2120 * Keep in mind that the server will react to RESET only
2121 * if the last notification was sent as CON
2123 * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
2124 * and it is associated with an observe request
2125 * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
2126 * Send CON Observe request to server with
2127 * observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
2128 * Remove the callback associated on client side.
2130 OCStackResult ret = OC_STACK_OK;
2131 CARemoteEndpoint_t* endpoint = NULL;
2132 CAResult_t caResult;
2133 CAInfo_t requestData = {};
2134 CARequestInfo_t requestInfo = {};
2138 return OC_STACK_INVALID_PARAM;
2141 OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
2143 ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL);
2147 switch (clientCB->method)
2149 case OC_REST_OBSERVE:
2150 case OC_REST_OBSERVE_ALL:
2151 OC_LOG(INFO, TAG, PCF("Canceling observation"));
2152 if(qos == OC_HIGH_QOS)
2154 requestData.type = qualityOfServiceToMessageType(qos);
2155 requestData.token = clientCB->token;
2156 requestData.tokenLength = clientCB->tokenLength;
2157 if (CreateObserveHeaderOption (&(requestData.options),
2158 options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
2160 return OC_STACK_ERROR;
2162 requestData.numOptions = numOptions + 1;
2163 requestInfo.method = CA_GET;
2164 requestInfo.info = requestData;
2166 CATransportType_t caConType;
2167 ret = OCToCATransportType(clientCB->conType, &caConType);
2168 if(ret != OC_STACK_OK)
2173 caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri,
2174 caConType, &endpoint);
2175 if (caResult != CA_STATUS_OK)
2177 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2178 ret = OC_STACK_ERROR;
2183 caResult = CASendRequest(endpoint, &requestInfo);
2184 if (caResult != CA_STATUS_OK)
2186 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2187 ret = OC_STACK_ERROR;
2189 ret = CAResultToOCResult (caResult);
2193 FindAndDeleteClientCB(clientCB);
2196 #ifdef WITH_PRESENCE
2197 case OC_REST_PRESENCE:
2198 FindAndDeleteClientCB(clientCB);
2202 ret = OC_STACK_INVALID_METHOD;
2207 CADestroyRemoteEndpoint(endpoint);
2208 if (requestData.numOptions > 0)
2210 OCFree(requestData.options);
2216 #ifdef WITH_PRESENCE
2217 OCStackResult OCProcessPresence()
2219 OCStackResult result = OC_STACK_OK;
2220 uint8_t ipAddr[4] = { 0 };
2223 OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
2224 ClientCB* cbNode = NULL;
2226 OCClientResponse clientResponse ={};
2227 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
2229 LL_FOREACH(cbList, cbNode)
2231 if(OC_REST_PRESENCE == cbNode->method)
2233 if(cbNode->presence)
2235 uint32_t now = GetTicks(0);
2236 OC_LOG_V(DEBUG, TAG, "this TTL level %d",
2237 cbNode->presence->TTLlevel);
2238 OC_LOG_V(DEBUG, TAG, "current ticks %d", now);
2241 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
2246 if(cbNode->presence->TTLlevel < PresenceTimeOutSize)
2248 OC_LOG_V(DEBUG, TAG, "timeout ticks %d",
2249 cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
2252 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
2254 OC_LOG(DEBUG, TAG, PCF("No more timeout ticks"));
2255 if (ParseIPv4Address(cbNode->requestUri, ipAddr, &port))
2257 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
2260 clientResponse.sequenceNumber = 0;
2261 clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
2262 clientResponse.addr = (OCDevAddr *) &dst;
2263 clientResponse.resJSONPayload = NULL;
2265 // Increment the TTLLevel (going to a next state), so we don't keep
2266 // sending presence notification to client.
2267 cbNode->presence->TTLlevel++;
2268 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2269 cbNode->presence->TTLlevel);
2273 result = OC_STACK_INVALID_IP;
2277 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
2278 if (cbResult == OC_STACK_DELETE_TRANSACTION)
2280 FindAndDeleteClientCB(cbNode);
2284 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
2286 CAResult_t caResult = CA_STATUS_OK;
2287 CARemoteEndpoint_t* endpoint = NULL;
2288 CAInfo_t requestData ={};
2289 CARequestInfo_t requestInfo = {};
2291 OC_LOG(DEBUG, TAG, PCF("time to test server presence"));
2294 CATransportType_t caConType;
2295 result = OCToCATransportType(cbNode->conType, &caConType);
2296 caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, caConType,
2298 if (caResult != CA_STATUS_OK || result != OC_STACK_OK)
2300 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2304 requestData.type = CA_MSG_NONCONFIRM;
2305 requestData.token = cbNode->token;
2306 requestData.tokenLength = cbNode->tokenLength;
2307 requestInfo.method = CA_GET;
2308 requestInfo.info = requestData;
2310 caResult = CASendRequest(endpoint, &requestInfo);
2311 CADestroyRemoteEndpoint(endpoint);
2313 if (caResult != CA_STATUS_OK)
2315 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2319 cbNode->presence->TTLlevel++;
2320 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2321 cbNode->presence->TTLlevel);
2327 if (result != OC_STACK_OK)
2329 OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
2333 #endif // WITH_PRESENCE
2335 OCStackResult OCProcess()
2337 #ifdef WITH_PRESENCE
2338 OCProcessPresence();
2340 CAHandleRequestResponse();
2345 #ifdef WITH_PRESENCE
2346 OCStackResult OCStartPresence(const uint32_t ttl)
2348 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
2349 OCChangeResourceProperty(
2350 &(((OCResource *)presenceResource.handle)->resourceProperties),
2353 if (OC_MAX_PRESENCE_TTL_SECONDS < ttl)
2355 presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS;
2356 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to max value"));
2360 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
2361 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to default value"));
2365 presenceResource.presenceTTL = ttl;
2367 OC_LOG_V(DEBUG, TAG, "Presence TTL is %lu seconds", presenceResource.presenceTTL);
2369 if (OC_PRESENCE_UNINITIALIZED == presenceState)
2371 presenceState = OC_PRESENCE_INITIALIZED;
2373 CAAddress_t addressInfo;
2374 strncpy(addressInfo.IP.ipAddress, OC_MULTICAST_IP, CA_IPADDR_SIZE);
2375 addressInfo.IP.port = OC_MULTICAST_PORT;
2377 CAToken_t caToken = NULL;
2378 CAResult_t caResult = CAGenerateToken(&caToken, tokenLength);
2379 if (caResult != CA_STATUS_OK)
2381 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2382 CADestroyToken(caToken);
2383 return OC_STACK_ERROR;
2386 CATransportType_t connType;
2387 OCToCATransportType(OC_ALL, &connType );
2388 AddObserver(OC_PRESENCE_URI, NULL, 0, caToken, tokenLength,
2389 (OCResource *)presenceResource.handle, OC_LOW_QOS,
2390 &addressInfo, connType);
2391 CADestroyToken(caToken);
2394 // Each time OCStartPresence is called
2395 // a different random 32-bit integer number is used
2396 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2398 return SendPresenceNotification(NULL);
2401 OCStackResult OCStopPresence()
2403 OCStackResult result = OC_STACK_ERROR;
2405 if(presenceResource.handle)
2407 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2410 // make resource inactive
2411 result = OCChangeResourceProperty(
2412 &(((OCResource *) presenceResource.handle)->resourceProperties),
2415 if(result != OC_STACK_OK)
2418 PCF("Changing the presence resource properties to ACTIVE not successful"));
2422 return SendStopNotification();
2426 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
2428 defaultDeviceHandler = entityHandler;
2433 OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
2435 OC_LOG(INFO, TAG, PCF("Entering OCSetDeviceInfo"));
2437 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
2439 return SaveDeviceInfo(deviceInfo);
2443 return OC_STACK_ERROR;
2447 OCStackResult OCCreateResource(OCResourceHandle *handle,
2448 const char *resourceTypeName,
2449 const char *resourceInterfaceName,
2450 const char *uri, OCEntityHandler entityHandler,
2451 uint8_t resourceProperties)
2454 OCResource *pointer = NULL;
2457 OCStackResult result = OC_STACK_ERROR;
2459 OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
2461 if(myStackMode == OC_CLIENT)
2463 return OC_STACK_INVALID_PARAM;
2465 // Validate parameters
2466 if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH )
2468 OC_LOG(ERROR, TAG, PCF("URI is invalid"));
2469 return OC_STACK_INVALID_URI;
2471 // Is it presented during resource discovery?
2472 if (!handle || !resourceTypeName)
2474 OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
2475 return OC_STACK_INVALID_PARAM;
2478 if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0)
2480 resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
2483 // Make sure resourceProperties bitmask has allowed properties specified
2484 if (resourceProperties
2485 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE))
2487 OC_LOG(ERROR, TAG, PCF("Invalid property"));
2488 return OC_STACK_INVALID_PARAM;
2491 // If the headResource is NULL, then no resources have been created...
2492 pointer = headResource;
2495 // At least one resources is in the resource list, so we need to search for
2496 // repeated URLs, which are not allowed. If a repeat is found, exit with an error
2499 if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0)
2501 OC_LOG(ERROR, TAG, PCF("URI already in use"));
2502 return OC_STACK_INVALID_PARAM;
2504 pointer = pointer->next;
2507 // Create the pointer and insert it into the resource list
2508 pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
2511 result = OC_STACK_NO_MEMORY;
2514 pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
2516 insertResource(pointer);
2519 size = strlen(uri) + 1;
2520 str = (char *) OCMalloc(size);
2523 result = OC_STACK_NO_MEMORY;
2526 strncpy(str, uri, size);
2529 // Set properties. Set OC_ACTIVE
2530 pointer->resourceProperties = (OCResourceProperty) (resourceProperties
2533 // Add the resourcetype to the resource
2534 result = BindResourceTypeToResource(pointer, resourceTypeName);
2535 if (result != OC_STACK_OK)
2537 OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
2541 // Add the resourceinterface to the resource
2542 result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
2543 if (result != OC_STACK_OK)
2545 OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
2549 // If an entity handler has been passed, attach it to the newly created
2550 // resource. Otherwise, set the default entity handler.
2553 pointer->entityHandler = entityHandler;
2557 pointer->entityHandler = defaultResourceEHandler;
2561 result = OC_STACK_OK;
2563 #ifdef WITH_PRESENCE
2564 if(presenceResource.handle)
2566 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2567 SendPresenceNotification(pointer->rsrcType);
2571 if (result != OC_STACK_OK)
2573 // Deep delete of resource and other dynamic elements that it contains
2574 deleteResource(pointer);
2580 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
2581 const char *resourceTypeName,
2582 const char *resourceInterfaceName,
2585 OCEntityHandler entityHandler,
2586 uint8_t resourceProperties)
2588 OC_LOG(INFO, TAG, PCF("Entering OCCreateResourceWithHost"));
2594 OC_LOG(ERROR, TAG, PCF("Added resource host is NULL."));
2595 return OC_STACK_INVALID_PARAM;
2598 OCStackResult result = OC_STACK_ERROR;
2600 result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
2601 uri, entityHandler, resourceProperties);
2603 if (result == OC_STACK_OK)
2606 size = strlen(host) + 1;
2607 str = (char *) OCMalloc(size);
2610 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated."));
2611 return OC_STACK_NO_MEMORY;
2613 strncpy(str, host, size);
2615 ((OCResource *) *handle)->host = str;
2621 OCStackResult OCBindResource(
2622 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2624 OCResource *resource = NULL;
2627 OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
2629 // Validate parameters
2630 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2631 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2632 // Container cannot contain itself
2633 if (collectionHandle == resourceHandle)
2635 OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
2636 return OC_STACK_INVALID_PARAM;
2639 // Use the handle to find the resource in the resource linked list
2640 resource = findResource((OCResource *) collectionHandle);
2643 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2644 return OC_STACK_INVALID_PARAM;
2647 // Look for an open slot to add add the child resource.
2648 // If found, add it and return success
2649 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2651 if (!resource->rsrcResources[i])
2653 resource->rsrcResources[i] = (OCResource *) resourceHandle;
2654 OC_LOG(INFO, TAG, PCF("resource bound"));
2656 #ifdef WITH_PRESENCE
2657 if(presenceResource.handle)
2659 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2660 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2668 // Unable to add resourceHandle, so return error
2669 return OC_STACK_ERROR;
2672 OCStackResult OCUnBindResource(
2673 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2675 OCResource *resource = NULL;
2678 OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
2680 // Validate parameters
2681 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2682 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2683 // Container cannot contain itself
2684 if (collectionHandle == resourceHandle)
2686 OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
2687 return OC_STACK_INVALID_PARAM;
2690 // Use the handle to find the resource in the resource linked list
2691 resource = findResource((OCResource *) collectionHandle);
2694 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2695 return OC_STACK_INVALID_PARAM;
2698 // Look for an open slot to add add the child resource.
2699 // If found, add it and return success
2700 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2702 if (resourceHandle == resource->rsrcResources[i])
2704 resource->rsrcResources[i] = (OCResource *) NULL;
2705 OC_LOG(INFO, TAG, PCF("resource unbound"));
2707 // Send notification when resource is unbounded successfully.
2708 #ifdef WITH_PRESENCE
2709 if(presenceResource.handle)
2711 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2712 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2719 OC_LOG(INFO, TAG, PCF("resource not found in collection"));
2721 // Unable to add resourceHandle, so return error
2722 return OC_STACK_ERROR;
2725 OCStackResult BindResourceTypeToResource(OCResource* resource,
2726 const char *resourceTypeName)
2728 OCResourceType *pointer = NULL;
2731 OCStackResult result = OC_STACK_ERROR;
2733 OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
2735 // Validate parameters
2736 VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
2737 // TODO: Does resource attribute representation really have to be maintained in stack?
2738 // Is it presented during resource discovery?
2740 // Create the resourcetype and insert it into the resource list
2741 pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
2744 result = OC_STACK_NO_MEMORY;
2748 // Set the resourceTypeName
2749 size = strlen(resourceTypeName) + 1;
2750 str = (char *) OCMalloc(size);
2753 result = OC_STACK_NO_MEMORY;
2756 strncpy(str, resourceTypeName, size);
2757 pointer->resourcetypename = str;
2759 insertResourceType(resource, pointer);
2760 result = OC_STACK_OK;
2763 if (result != OC_STACK_OK)
2772 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
2773 const char *resourceInterfaceName)
2775 OCResourceInterface *pointer = NULL;
2778 OCStackResult result = OC_STACK_ERROR;
2780 OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
2782 // Validate parameters
2783 VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
2785 //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
2787 // Create the resourceinterface and insert it into the resource list
2788 pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
2791 result = OC_STACK_NO_MEMORY;
2795 // Set the resourceinterface name
2796 size = strlen(resourceInterfaceName) + 1;
2797 str = (char *) OCMalloc(size);
2800 result = OC_STACK_NO_MEMORY;
2803 strncpy(str, resourceInterfaceName, size);
2804 pointer->name = str;
2806 // Bind the resourceinterface to the resource
2807 insertResourceInterface(resource, pointer);
2809 result = OC_STACK_OK;
2812 if (result != OC_STACK_OK)
2821 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
2822 const char *resourceTypeName)
2825 OCStackResult result = OC_STACK_ERROR;
2826 OCResource *resource = NULL;
2828 // Make sure resource exists
2829 resource = findResource((OCResource *) handle);
2832 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2833 return OC_STACK_ERROR;
2836 // call internal function
2837 result = BindResourceTypeToResource(resource, resourceTypeName);
2839 #ifdef WITH_PRESENCE
2840 if(presenceResource.handle)
2842 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2843 SendPresenceNotification(resource->rsrcType);
2850 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
2851 const char *resourceInterfaceName)
2854 OCStackResult result = OC_STACK_ERROR;
2855 OCResource *resource = NULL;
2857 // Make sure resource exists
2858 resource = findResource((OCResource *) handle);
2861 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2862 return OC_STACK_ERROR;
2865 // call internal function
2866 result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2868 #ifdef WITH_PRESENCE
2869 if(presenceResource.handle)
2871 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2872 SendPresenceNotification(resource->rsrcType);
2879 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
2881 OCResource *pointer = headResource;
2883 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2884 VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2888 *numResources = *numResources + 1;
2889 pointer = pointer->next;
2894 OCResourceHandle OCGetResourceHandle(uint8_t index)
2896 OCResource *pointer = headResource;
2898 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2900 // Iterate through the list
2901 for( uint8_t i = 0; i < index && pointer; ++i)
2903 pointer = pointer->next;
2905 return (OCResourceHandle) pointer;
2908 OCStackResult OCDeleteResource(OCResourceHandle handle)
2910 OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2914 OC_LOG(ERROR, TAG, PCF("Invalid param"));
2915 return OC_STACK_INVALID_PARAM;
2918 OCResource *resource = findResource((OCResource *) handle);
2919 if (resource == NULL)
2921 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2922 return OC_STACK_NO_RESOURCE;
2925 if (deleteResource((OCResource *) handle) != OC_STACK_OK)
2927 OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2928 return OC_STACK_ERROR;
2934 const char *OCGetResourceUri(OCResourceHandle handle)
2936 OCResource *resource = NULL;
2937 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2939 resource = findResource((OCResource *) handle);
2942 return resource->uri;
2944 return (const char *) NULL;
2947 OCResourceProperty OCGetResourceProperties(OCResourceHandle handle)
2949 OCResource *resource = NULL;
2950 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2952 resource = findResource((OCResource *) handle);
2955 return resource->resourceProperties;
2957 return (OCResourceProperty)-1;
2960 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2961 uint8_t *numResourceTypes)
2963 OCResource *resource = NULL;
2964 OCResourceType *pointer = NULL;
2966 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2967 VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
2968 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2970 *numResourceTypes = 0;
2972 resource = findResource((OCResource *) handle);
2975 pointer = resource->rsrcType;
2978 *numResourceTypes = *numResourceTypes + 1;
2979 pointer = pointer->next;
2985 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index)
2987 OCResourceType *resourceType = NULL;
2989 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
2991 resourceType = findResourceTypeAtIndex(handle, index);
2994 return resourceType->resourcetypename;
2996 return (const char *) NULL;
2999 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
3000 uint8_t *numResourceInterfaces)
3002 OCResourceInterface *pointer = NULL;
3003 OCResource *resource = NULL;
3005 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
3007 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3008 VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
3010 *numResourceInterfaces = 0;
3011 resource = findResource((OCResource *) handle);
3014 pointer = resource->rsrcInterface;
3017 *numResourceInterfaces = *numResourceInterfaces + 1;
3018 pointer = pointer->next;
3024 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index)
3026 OCResourceInterface *resourceInterface = NULL;
3028 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
3030 resourceInterface = findResourceInterfaceAtIndex(handle, index);
3031 if (resourceInterface)
3033 return resourceInterface->name;
3035 return (const char *) NULL;
3038 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
3041 OCResource *resource = NULL;
3043 OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
3045 if (index >= MAX_CONTAINED_RESOURCES)
3050 resource = findResource((OCResource *) collectionHandle);
3056 return resource->rsrcResources[index];
3059 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
3060 OCEntityHandler entityHandler)
3062 OCResource *resource = NULL;
3064 OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
3066 // Validate parameters
3067 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
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"));
3074 return OC_STACK_ERROR;
3078 resource->entityHandler = entityHandler;
3080 #ifdef WITH_PRESENCE
3081 if(presenceResource.handle)
3083 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3084 SendPresenceNotification(resource->rsrcType);
3091 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle)
3093 OCResource *resource = NULL;
3095 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
3097 // Use the handle to find the resource in the resource linked list
3098 resource = findResource((OCResource *)handle);
3101 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3106 return resource->entityHandler;
3109 void incrementSequenceNumber(OCResource * resPtr)
3111 // Increment the sequence number
3112 resPtr->sequenceNum += 1;
3113 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
3115 resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
3120 #ifdef WITH_PRESENCE
3121 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
3123 OCResource *resPtr = NULL;
3124 OCStackResult result = OC_STACK_ERROR;
3125 OCMethod method = OC_REST_PRESENCE;
3126 uint32_t maxAge = 0;
3127 resPtr = findResource((OCResource *) presenceResource.handle);
3130 return OC_STACK_NO_RESOURCE;
3133 if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
3135 maxAge = presenceResource.presenceTTL;
3137 result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
3143 OCStackResult SendStopNotification()
3145 OCResource *resPtr = NULL;
3146 OCStackResult result = OC_STACK_ERROR;
3147 OCMethod method = OC_REST_PRESENCE;
3148 resPtr = findResource((OCResource *) presenceResource.handle);
3151 return OC_STACK_NO_RESOURCE;
3154 // maxAge is 0. ResourceType is NULL.
3155 result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
3160 #endif // WITH_PRESENCE
3161 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos)
3164 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3166 OCResource *resPtr = NULL;
3167 OCStackResult result = OC_STACK_ERROR;
3168 OCMethod method = OC_REST_NOMETHOD;
3169 uint32_t maxAge = 0;
3171 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3172 #ifdef WITH_PRESENCE
3173 if(handle == presenceResource.handle)
3177 #endif // WITH_PRESENCE
3178 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3180 // Verify that the resource exists
3181 resPtr = findResource ((OCResource *) handle);
3184 return OC_STACK_NO_RESOURCE;
3188 //only increment in the case of regular observing (not presence)
3189 incrementSequenceNumber(resPtr);
3190 method = OC_REST_OBSERVE;
3191 maxAge = MAX_OBSERVE_AGE;
3192 #ifdef WITH_PRESENCE
3193 result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
3195 result = SendAllObserverNotification (method, resPtr, maxAge, qos);
3202 OCNotifyListOfObservers (OCResourceHandle handle,
3203 OCObservationId *obsIdList,
3204 uint8_t numberOfIds,
3205 const char *notificationJSONPayload,
3206 OCQualityOfService qos)
3208 OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
3210 OCResource *resPtr = NULL;
3211 //TODO: we should allow the server to define this
3212 uint32_t maxAge = MAX_OBSERVE_AGE;
3214 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3215 VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
3216 VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
3218 // Verify that the resource exists
3219 resPtr = findResource ((OCResource *) handle);
3220 if (NULL == resPtr || myStackMode == OC_CLIENT)
3222 return OC_STACK_NO_RESOURCE;
3226 incrementSequenceNumber(resPtr);
3228 return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
3229 notificationJSONPayload, maxAge, qos));
3232 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
3234 OCStackResult result = OC_STACK_ERROR;
3235 OCServerRequest *serverRequest = NULL;
3237 OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
3239 // Validate input parameters
3240 VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
3241 VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
3243 // TODO: Placeholder for creating a response entry when implementing
3244 // block transfer feature
3246 // If a response payload is present, check if block transfer is required
3247 if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
3248 (const char *)ehResponse->payload, ehResponse->payloadSize))
3250 OC_LOG(INFO, TAG, PCF("Block transfer required"));
3252 // Persistent response buffer is needed for block transfer
3253 if (!ehResponse->persistentBufferFlag)
3255 OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
3256 return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
3258 // TODO: Placeholder for block transfer handling
3259 // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
3260 // when implementing the block transfer feature
3265 // Get pointer to request info
3266 serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
3269 result = serverRequest->ehResponseHandler(ehResponse);
3275 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
3277 OCStackResult result = OC_STACK_NOTIMPL;
3279 OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
3281 // TODO: validate response handle
3286 //-----------------------------------------------------------------------------
3287 // Private internal function definitions
3288 //-----------------------------------------------------------------------------
3289 static OCDoHandle GenerateInvocationHandle()
3291 OCDoHandle handle = NULL;
3292 // Generate token here, it will be deleted when the transaction is deleted
3293 handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3296 OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3302 #ifdef WITH_PRESENCE
3303 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
3304 OCResourceProperty resourceProperties, uint8_t enable)
3308 return OC_STACK_INVALID_PARAM;
3310 if (resourceProperties
3311 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW))
3313 OC_LOG(ERROR, TAG, PCF("Invalid property"));
3314 return OC_STACK_INVALID_PARAM;
3318 *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
3322 *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
3328 OCStackResult initResources()
3330 OCStackResult result = OC_STACK_OK;
3331 // Init application resource vars
3332 headResource = NULL;
3333 tailResource = NULL;
3334 // Init Virtual Resources
3335 #ifdef WITH_PRESENCE
3336 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
3337 //presenceResource.token = OCGenerateCoAPToken();
3338 result = OCCreateResource(&presenceResource.handle,
3339 OC_RSRVD_RESOURCE_TYPE_PRESENCE,
3344 //make resource inactive
3345 result = OCChangeResourceProperty(
3346 &(((OCResource *) presenceResource.handle)->resourceProperties),
3352 void insertResource(OCResource *resource)
3356 headResource = resource;
3357 tailResource = resource;
3361 tailResource->next = resource;
3362 tailResource = resource;
3364 resource->next = NULL;
3367 OCResource *findResource(OCResource *resource)
3369 OCResource *pointer = headResource;
3373 if (pointer == resource)
3377 pointer = pointer->next;
3382 void deleteAllResources()
3384 OCResource *pointer = headResource;
3385 OCResource *temp = NULL;
3389 temp = pointer->next;
3390 #ifdef WITH_PRESENCE
3391 if(pointer != (OCResource *) presenceResource.handle)
3393 #endif // WITH_PRESENCE
3394 deleteResource(pointer);
3395 #ifdef WITH_PRESENCE
3397 #endif // WITH_PRESENCE
3401 #ifdef WITH_PRESENCE
3402 // Ensure that the last resource to be deleted is the presence resource. This allows for all
3403 // presence notification attributed to their deletion to be processed.
3404 deleteResource((OCResource *) presenceResource.handle);
3405 #endif // WITH_PRESENCE
3408 OCStackResult deleteResource(OCResource *resource)
3410 OCResource *prev = NULL;
3411 OCResource *temp = NULL;
3413 temp = headResource;
3416 if (temp == resource)
3418 // Invalidate all Resource Properties.
3419 resource->resourceProperties = (OCResourceProperty) 0;
3420 #ifdef WITH_PRESENCE
3421 if(resource != (OCResource *) presenceResource.handle)
3423 #endif // WITH_PRESENCE
3424 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
3425 #ifdef WITH_PRESENCE
3428 if(presenceResource.handle)
3430 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3431 if(resource != (OCResource *) presenceResource.handle)
3433 SendPresenceNotification(resource->rsrcType);
3437 SendPresenceNotification(NULL);
3441 // Only resource in list.
3442 if (temp == headResource && temp == tailResource)
3444 headResource = NULL;
3445 tailResource = NULL;
3448 else if (temp == headResource)
3450 headResource = temp->next;
3453 else if (temp == tailResource)
3455 tailResource = prev;
3456 tailResource->next = NULL;
3460 prev->next = temp->next;
3463 deleteResourceElements(temp);
3474 return OC_STACK_ERROR;
3477 void deleteResourceElements(OCResource *resource)
3485 OCFree(resource->uri);
3487 // Delete resourcetype linked list
3488 deleteResourceType(resource->rsrcType);
3490 // Delete resourceinterface linked list
3491 deleteResourceInterface(resource->rsrcInterface);
3494 void deleteResourceType(OCResourceType *resourceType)
3496 OCResourceType *pointer = resourceType;
3497 OCResourceType *next = NULL;
3501 next = pointer->next;
3502 OCFree(pointer->resourcetypename);
3508 void deleteResourceInterface(OCResourceInterface *resourceInterface)
3510 OCResourceInterface *pointer = resourceInterface;
3511 OCResourceInterface *next = NULL;
3515 next = pointer->next;
3516 OCFree(pointer->name);
3522 void insertResourceType(OCResource *resource, OCResourceType *resourceType)
3524 OCResourceType *pointer = NULL;
3525 OCResourceType *previous = NULL;
3526 if (!resource || !resourceType)
3530 // resource type list is empty.
3531 else if (!resource->rsrcType)
3533 resource->rsrcType = resourceType;
3537 pointer = resource->rsrcType;
3541 // resource type already exists. Free 2nd arg and return.
3542 if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename))
3544 OCFree(resourceType->resourcetypename);
3545 OCFree(resourceType);
3549 pointer = pointer->next;
3551 previous->next = resourceType;
3553 resourceType->next = NULL;
3556 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index)
3558 OCResource *resource = NULL;
3559 OCResourceType *pointer = NULL;
3561 // Find the specified resource
3562 resource = findResource((OCResource *) handle);
3568 // Make sure a resource has a resourcetype
3569 if (!resource->rsrcType)
3574 // Iterate through the list
3575 pointer = resource->rsrcType;
3576 for(uint8_t i = 0; i< index && pointer; ++i)
3578 pointer = pointer->next;
3583 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
3585 if(resourceTypeList && resourceTypeName)
3587 OCResourceType * rtPointer = resourceTypeList;
3588 while(resourceTypeName && rtPointer)
3590 if(rtPointer->resourcetypename &&
3591 strcmp(resourceTypeName, (const char *)
3592 (rtPointer->resourcetypename)) == 0)
3596 rtPointer = rtPointer->next;
3604 * Insert a new interface into interface linked list only if not already present.
3605 * If alredy present, 2nd arg is free'd.
3606 * Default interface will always be first if present.
3608 void insertResourceInterface(OCResource *resource, OCResourceInterface *newInterface)
3610 OCResourceInterface *pointer = NULL;
3611 OCResourceInterface *previous = NULL;
3613 newInterface->next = NULL;
3615 OCResourceInterface **firstInterface = &(resource->rsrcInterface);
3617 if (!*firstInterface)
3619 *firstInterface = newInterface;
3621 else if (strcmp(newInterface->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3623 if (strcmp((*firstInterface)->name, OC_RSRVD_INTERFACE_DEFAULT) == 0)
3625 OCFree(newInterface->name);
3626 OCFree(newInterface);
3631 newInterface->next = *firstInterface;
3632 *firstInterface = newInterface;
3637 pointer = *firstInterface;
3640 if (strcmp(newInterface->name, pointer->name) == 0)
3642 OCFree(newInterface->name);
3643 OCFree(newInterface);
3647 pointer = pointer->next;
3649 previous->next = newInterface;
3653 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
3656 OCResource *resource = NULL;
3657 OCResourceInterface *pointer = NULL;
3659 // Find the specified resource
3660 resource = findResource((OCResource *) handle);
3666 // Make sure a resource has a resourceinterface
3667 if (!resource->rsrcInterface)
3672 // Iterate through the list
3673 pointer = resource->rsrcInterface;
3675 for (uint8_t i = 0; i < index && pointer; ++i)
3677 pointer = pointer->next;
3682 bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size)
3684 bool result = false;
3686 // Determine if we are checking a request or a response
3689 // If size is greater than 0, use it for the request size value, otherwise
3690 // assume request is null terminated and use strlen for size value
3691 if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
3698 // If size is greater than 0, use it for the response size value, otherwise
3699 // assume response is null terminated and use strlen for size value
3700 if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
3708 OCStackResult getResourceType(const char * query, char** resourceType)
3712 return OC_STACK_INVALID_PARAM;
3715 OCStackResult result = OC_STACK_ERROR;
3717 if(strncmp(query, "rt=", 3) == 0)
3719 *resourceType = (char *) OCMalloc(strlen(query)-3 + 1);
3722 result = OC_STACK_NO_MEMORY;
3726 strcpy((char *)*resourceType, ((const char *)&query[3]));
3727 result = OC_STACK_OK;
3735 * This function splits the uri using the '?' delimiter.
3736 * "uriWithoutQuery" is the block of characters between the beginning
3737 * till the delimiter or '\0' which ever comes first.
3738 * "query" is whatever is to the right of the delimiter if present.
3739 * No delimiter sets the query to NULL.
3740 * If either are present, they will be malloc'ed into the params 2, 3.
3741 * The first param, *uri is left untouched.
3743 * NOTE: This function does not account for whitespace at the end of the uri NOR
3744 * malformed uri's with '??'. Whitespace at the end will be assumed to be
3745 * part of the query.
3747 OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithoutQuery)
3751 return OC_STACK_INVALID_URI;
3753 if(!query || !uriWithoutQuery)
3755 return OC_STACK_INVALID_PARAM;
3759 *uriWithoutQuery = NULL;
3761 size_t uriWithoutQueryLen = 0;
3762 size_t queryLen = 0;
3763 size_t uriLen = strlen(uri);
3765 char *pointerToDelimiter = strstr(uri, "?");
3767 uriWithoutQueryLen = pointerToDelimiter == NULL ? uriLen : pointerToDelimiter - uri;
3768 queryLen = pointerToDelimiter == NULL ? 0 : uriLen - uriWithoutQueryLen - 1;
3770 if (uriWithoutQueryLen)
3772 *uriWithoutQuery = (char *) OCCalloc(uriWithoutQueryLen + 1, 1);
3773 if (!*uriWithoutQuery)
3777 strncpy(*uriWithoutQuery, uri, uriWithoutQueryLen);
3781 return OC_STACK_INVALID_PARAM;
3786 *query = (char *) OCCalloc(queryLen + 1, 1);
3789 OCFree(*uriWithoutQuery);
3790 *uriWithoutQuery = NULL;
3793 strncpy(*query, pointerToDelimiter + 1, queryLen);
3799 return OC_STACK_NO_MEMORY;
3802 const ServerID OCGetServerInstanceID(void)
3804 static bool generated = false;
3805 static ServerID sid;
3811 sid = OCGetRandom();
3816 const char* OCGetServerInstanceIDString(void)
3818 // max printed length of a base 10
3819 // uint32 is 10 characters, so 11 includes null.
3820 // This will change as the representation gets switched
3822 static char buffer[11];
3824 if (snprintf(buffer, sizeof(buffer),"%u", OCGetServerInstanceID()) < 0)
3832 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
3833 uint8_t *c, uint8_t *d )
3835 if ( !ipAddr || !a || !b || !c || !d )
3837 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3838 return OC_STACK_INVALID_PARAM;
3841 *a = ipAddr->addr[0];
3842 *b = ipAddr->addr[1];
3843 *c = ipAddr->addr[2];
3844 *d = ipAddr->addr[3];
3849 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
3851 if ( !ipAddr || !port )
3853 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3854 return OC_STACK_INVALID_PARAM;
3857 *port = (ipAddr->addr[5]<< 8) | ipAddr->addr[4];
3862 CAResult_t OCSelectNetwork()
3864 CAResult_t retResult = CA_STATUS_FAILED;
3865 CAResult_t caResult = CA_STATUS_OK;
3867 CATransportType_t connTypes[] = {
3871 int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]);
3873 for(int i = 0; i<numConnTypes; i++)
3875 // Ignore CA_NOT_SUPPORTED error. The CA Layer may have not compiled in the interface.
3876 if(caResult == CA_STATUS_OK || caResult == CA_NOT_SUPPORTED)
3878 caResult = CASelectNetwork(connTypes[i]);
3879 if(caResult == CA_STATUS_OK)
3881 retResult = CA_STATUS_OK;
3886 if(retResult != CA_STATUS_OK)
3888 return caResult; // Returns error of appropriate transport that failed fatally.
3894 OCStackResult CAResultToOCResult(CAResult_t caResult)
3900 case CA_STATUS_INVALID_PARAM:
3901 return OC_STACK_INVALID_PARAM;
3902 case CA_ADAPTER_NOT_ENABLED:
3903 return OC_STACK_ADAPTER_NOT_ENABLED;
3904 case CA_SERVER_STARTED_ALREADY:
3906 case CA_SERVER_NOT_STARTED:
3907 return OC_STACK_ERROR;
3908 case CA_DESTINATION_NOT_REACHABLE:
3909 return OC_STACK_COMM_ERROR;
3910 case CA_SOCKET_OPERATION_FAILED:
3911 return OC_STACK_COMM_ERROR;
3912 case CA_SEND_FAILED:
3913 return OC_STACK_COMM_ERROR;
3914 case CA_RECEIVE_FAILED:
3915 return OC_STACK_COMM_ERROR;
3916 case CA_MEMORY_ALLOC_FAILED:
3917 return OC_STACK_NO_MEMORY;
3918 case CA_REQUEST_TIMEOUT:
3919 return OC_STACK_TIMEOUT;
3920 case CA_DESTINATION_DISCONNECTED:
3921 return OC_STACK_COMM_ERROR;
3922 case CA_STATUS_FAILED:
3923 return OC_STACK_ERROR;
3924 case CA_NOT_SUPPORTED:
3925 return OC_STACK_NOTIMPL;
3927 return OC_STACK_ERROR;