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 CAConnectivityType_t.
351 * @param ocConType OCConnectivityType input.
352 * @param caConType CAConnectivityType_t output.
353 * @return ::OC_STACK_OK on success, some other value upon failure.
355 static OCStackResult OCToCAConnectivityType(OCConnectivityType ocConType,
356 CAConnectivityType_t* caConType);
359 * Convert CAConnectivityType_t to CAConnectivityType_t.
361 * @param caConType CAConnectivityType_t input.
362 * @param ocConType OCConnectivityType output.
363 * @return ::OC_STACK_OK on success, some other value upon failure.
365 static OCStackResult CAToOCConnectivityType(CAConnectivityType_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 OCToCAConnectivityType(OCConnectivityType ocConType, CAConnectivityType_t* caConType)
653 OCStackResult ret = OC_STACK_OK;
658 *caConType = CA_ETHERNET;
661 *caConType = CA_WIFI;
670 // Currently OC_ALL represents WIFI and ETHERNET
671 // Add other connectivity types as they are enabled in future
672 *caConType = (CAConnectivityType_t) (CA_WIFI|CA_ETHERNET);
675 ret = OC_STACK_INVALID_PARAM;
681 OCStackResult CAToOCConnectivityType(CAConnectivityType_t caConType, OCConnectivityType *ocConType)
683 OCStackResult ret = OC_STACK_OK;
688 *ocConType = OC_ETHERNET;
691 *ocConType = OC_WIFI;
700 ret = OC_STACK_INVALID_PARAM;
706 OCStackResult UpdateResponseAddr(OCDevAddr *address, const CARemoteEndpoint_t* endPoint)
708 OCStackResult ret = OC_STACK_ERROR;
710 char * savePtr = NULL;
711 char * cpAddress = (char *) OCMalloc(strlen(endPoint->addressInfo.IP.ipAddress) + 1);
714 ret = OC_STACK_NO_MEMORY;
717 memcpy(cpAddress, endPoint->addressInfo.IP.ipAddress,
718 strlen(endPoint->addressInfo.IP.ipAddress) + 1);
720 // Grabs the first three numbers from the IPv4 address and replaces dots
721 for(int i=0; i<4; i++)
723 tok = strtok_r(i==0 ? cpAddress : NULL, ".", &savePtr);
727 ret = OC_STACK_ERROR;
730 address->addr[i] = atoi(tok);
733 memcpy(&address->addr[4], &endPoint->addressInfo.IP.port, sizeof(uint16_t));
741 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
743 uint32_t lowerBound = 0;
744 uint32_t higherBound = 0;
746 if (!cbNode || !cbNode->presence || !cbNode->presence->timeOut)
748 return OC_STACK_INVALID_PARAM;
751 OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0));
753 cbNode->presence->TTL = maxAgeSeconds;
755 for(int index = 0; index < PresenceTimeOutSize; index++)
757 // Guard against overflow
758 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index]))
761 lowerBound = GetTicks((PresenceTimeOut[index] *
762 cbNode->presence->TTL *
763 MILLISECONDS_PER_SECOND)/100);
767 lowerBound = GetTicks(UINT32_MAX);
770 if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index+1]))
773 higherBound = GetTicks((PresenceTimeOut[index + 1] *
774 cbNode->presence->TTL *
775 MILLISECONDS_PER_SECOND)/100);
779 higherBound = GetTicks(UINT32_MAX);
782 cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
784 OC_LOG_V(DEBUG, TAG, "lowerBound timeout %d", lowerBound);
785 OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound);
786 OC_LOG_V(DEBUG, TAG, "timeOut entry %d", cbNode->presence->timeOut[index]);
789 cbNode->presence->TTLlevel = 0;
791 OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel);
795 void parsePresencePayload(char* payload, uint32_t* seqNum, uint32_t* maxAge, char** resType)
798 char * savePtr = NULL;
799 // The format of the payload is {"oc":[%u:%u:%s]}
800 // %u : sequence number,
802 // %s : Resource Type (Optional)
804 if (!payload || !seqNum || !maxAge || !resType)
808 tok = strtok_r(payload, "[:]}", &savePtr);
809 payload[strlen(payload)] = ':';
811 //Retrieve sequence number
812 tok = strtok_r(NULL, "[:]}", &savePtr);
817 payload[strlen((char *)payload)] = ':';
818 *seqNum = (uint32_t) atoi(tok);
821 tok = strtok_r(NULL, "[:]}", &savePtr);
826 *maxAge = (uint32_t) atoi(tok);
828 //Retrieve ResourceType
829 tok = strtok_r(NULL, "[:]}",&savePtr);
835 *resType = (char *)OCMalloc(strlen(tok) + 1);
840 payload[strlen((char *)payload)] = ':';
841 strcpy(*resType, tok);
842 OC_LOG_V(DEBUG, TAG, "resourceTypeName %s", *resType);
844 payload[strlen((char *)payload)] = ']';
847 static OCStackResult HandlePresenceResponse(const CARemoteEndpoint_t* endPoint,
848 const CAResponseInfo_t* responseInfo)
850 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
851 ClientCB * cbNode = NULL;
852 char *resourceTypeName = NULL;
853 OCClientResponse response = {};
854 OCDevAddr address = {};
855 OCStackResult result = OC_STACK_ERROR;
858 char *fullUri = NULL;
859 char *ipAddress = NULL;
860 int presenceSubscribe = 0;
861 int multicastPresenceSubscribe = 0;
862 size_t addressLen = 0;
864 if (responseInfo->result != CA_SUCCESS)
866 OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
867 return OC_STACK_ERROR;
870 fullUri = (char *) OCMalloc(MAX_URI_LENGTH);
874 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for fullUri"));
875 result = OC_STACK_NO_MEMORY;
879 addressLen = strlen(endPoint->addressInfo.IP.ipAddress);
880 ipAddress = (char *) OCMalloc(addressLen + 1);
884 OC_LOG(ERROR, TAG, PCF("Memory could not be allocated for ipAddress"));
885 result = OC_STACK_NO_MEMORY;
889 strncpy(ipAddress, endPoint->addressInfo.IP.ipAddress, addressLen);
890 ipAddress[addressLen] = '\0';
892 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", ipAddress, endPoint->addressInfo.IP.port,
895 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
899 presenceSubscribe = 1;
903 snprintf(fullUri, MAX_URI_LENGTH, "coap://%s:%u%s", OC_MULTICAST_IP, OC_MULTICAST_PORT,
904 endPoint->resourceUri);
905 cbNode = GetClientCB(NULL, 0, NULL, fullUri);
908 multicastPresenceSubscribe = 1;
912 if(!presenceSubscribe && !multicastPresenceSubscribe)
914 OC_LOG(ERROR, TAG, PCF("Received a presence notification, but no callback, ignoring"));
918 // No payload to the application in case of presence
919 response.resJSONPayload = NULL;
920 response.result = OC_STACK_OK;
922 result = UpdateResponseAddr(&address, endPoint);
923 if(result != OC_STACK_OK)
928 response.addr = &address;
930 result = CAToOCConnectivityType(endPoint->connectivityType, &(response.connType));
931 if(result != OC_STACK_OK)
933 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
937 if(responseInfo->info.payload)
939 parsePresencePayload(responseInfo->info.payload,
940 &(response.sequenceNumber),
945 if(presenceSubscribe)
947 if(cbNode->sequenceNumber == response.sequenceNumber)
949 if (cbNode->presence)
951 OC_LOG(INFO, TAG, PCF("No presence change. Updating TTL."));
953 result = ResetPresenceTTL(cbNode, maxAge);
955 if (result != OC_STACK_OK)
957 OC_LOG_V(ERROR, TAG, "ResetPresenceTTL failed with error: %u", result);
962 OC_LOG(INFO, TAG, PCF("Not subscribed to presence."));
969 OC_LOG(INFO, TAG, PCF("Stopping presence"));
970 response.result = OC_STACK_PRESENCE_STOPPED;
973 OCFree(cbNode->presence->timeOut);
974 OCFree(cbNode->presence);
975 cbNode->presence = NULL;
980 if(!cbNode->presence)
982 cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
983 if(!(cbNode->presence))
985 OC_LOG(ERROR, TAG, PCF("Could not allocate memory for cbNode->presence"));
986 result = OC_STACK_NO_MEMORY;
990 VERIFY_NON_NULL_V(cbNode->presence);
991 cbNode->presence->timeOut = NULL;
992 cbNode->presence->timeOut = (uint32_t *)
993 OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
994 if(!(cbNode->presence->timeOut)){
996 PCF("Could not allocate memory for cbNode->presence->timeOut"));
997 OCFree(cbNode->presence);
998 result = OC_STACK_NO_MEMORY;
1003 ResetPresenceTTL(cbNode, maxAge);
1005 OC_LOG(INFO, TAG, PCF("Presence changed, calling up the stack"));
1006 cbNode->sequenceNumber = response.sequenceNumber;
1008 // Ensure that a filter is actually applied.
1009 if(resourceTypeName && cbNode->filterResourceType)
1011 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1020 // This is the multicast case
1022 OCMulticastNode* mcNode = NULL;
1023 mcNode = GetMCPresenceNode(fullUri);
1027 if(mcNode->nonce == response.sequenceNumber)
1029 OC_LOG(INFO, TAG, PCF("No presence change (Multicast)"));
1032 mcNode->nonce = response.sequenceNumber;
1036 OC_LOG(INFO, TAG, PCF("Stopping presence"));
1037 response.result = OC_STACK_PRESENCE_STOPPED;
1042 uint32_t uriLen = strlen(fullUri);
1043 char* uri = (char *) OCMalloc(uriLen + 1);
1046 memcpy(uri, fullUri, (uriLen + 1));
1051 PCF("No Memory for URI to store in the presence node"));
1052 result = OC_STACK_NO_MEMORY;
1055 result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber);
1056 if(result != OC_STACK_OK)
1059 PCF("Unable to add Multicast Presence Node"));
1065 // Ensure that a filter is actually applied.
1066 if(resourceTypeName && cbNode->filterResourceType)
1068 if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
1075 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &response);
1077 if (cbResult == OC_STACK_DELETE_TRANSACTION)
1079 FindAndDeleteClientCB(cbNode);
1085 OCFree(resourceTypeName);
1089 void HandleCAResponses(const CARemoteEndpoint_t* endPoint, const CAResponseInfo_t* responseInfo)
1091 OC_LOG(INFO, TAG, PCF("Enter HandleCAResponses"));
1093 if(NULL == endPoint)
1095 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1099 if(NULL == responseInfo)
1101 OC_LOG(ERROR, TAG, PCF("responseInfo is NULL"));
1105 if(strcmp(endPoint->resourceUri, OC_PRESENCE_URI) == 0)
1107 HandlePresenceResponse(endPoint, responseInfo);
1111 ClientCB *cbNode = GetClientCB(responseInfo->info.token,
1112 responseInfo->info.tokenLength, NULL, NULL);
1113 OC_LOG_V(DEBUG, TAG, "Response has the token %s", responseInfo->info.token);
1114 ResourceObserver * observer = GetObserverUsingToken (responseInfo->info.token,
1115 responseInfo->info.tokenLength);
1119 OC_LOG(INFO, TAG, PCF("There is a cbNode associated with the response token"));
1120 if(responseInfo->result == CA_EMPTY)
1122 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1123 // We do not have a case for the client to receive a RESET
1124 if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1126 //This is the case of receiving an ACK on a request to a slow resource!
1127 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1128 //TODO: should we inform the client
1129 // app that at least the request was received at the server?
1132 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1134 OC_LOG(INFO, TAG, PCF("Receiving A Timeout for this token"));
1135 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1136 OCClientResponse response = {};
1137 OCDevAddr address = {};
1138 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1139 if(result != OC_STACK_OK)
1141 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1145 result = UpdateResponseAddr(&address, endPoint);
1146 if(result != OC_STACK_OK)
1148 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1151 response.addr = &address;
1153 response.result = CAToOCStackResult(responseInfo->result);
1154 cbNode->callBack(cbNode->context,
1155 cbNode->handle, &response);
1156 FindAndDeleteClientCB(cbNode);
1160 OC_LOG(INFO, TAG, PCF("This is a regular response, A client call back is found"));
1161 OC_LOG(INFO, TAG, PCF("Calling into application address space"));
1162 OCClientResponse response = {};
1163 OCDevAddr address = {};
1165 OCStackResult result = UpdateResponseAddr(&address, endPoint);
1166 if(result != OC_STACK_OK)
1168 OC_LOG(ERROR, TAG, PCF("Error parsing IP address in UpdateResponseAddr"));
1171 response.addr = &address;
1172 // Populate the connectivity type. If this is a discovery response,
1173 // the resource that will be constructed from this response will make
1174 // further API calls from this interface.
1175 result = CAToOCConnectivityType(endPoint->connectivityType,
1176 &(response.connType));
1177 if(result != OC_STACK_OK)
1179 OC_LOG(ERROR, TAG, PCF("Invalid connectivity type in endpoint"));
1183 response.result = CAToOCStackResult(responseInfo->result);
1184 response.resJSONPayload = (const char*)responseInfo->info.payload;
1185 response.numRcvdVendorSpecificHeaderOptions = 0;
1186 if(responseInfo->info.numOptions > 0)
1189 //First option always with option ID is COAP_OPTION_OBSERVE if it is available.
1190 if(responseInfo->info.options[0].optionID == COAP_OPTION_OBSERVE)
1192 memcpy (&(response.sequenceNumber),
1193 &(responseInfo->info.options[0].optionData), sizeof(uint32_t));
1194 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions - 1;
1199 response.numRcvdVendorSpecificHeaderOptions = responseInfo->info.numOptions;
1202 if(response.numRcvdVendorSpecificHeaderOptions > MAX_HEADER_OPTIONS)
1204 OC_LOG(ERROR, TAG, PCF("#header options are more than MAX_HEADER_OPTIONS"));
1208 for (uint8_t i = start; i < responseInfo->info.numOptions; i++)
1210 memcpy (&(response.rcvdVendorSpecificHeaderOptions[i-start]),
1211 &(responseInfo->info.options[i]), sizeof(OCHeaderOption));
1215 if (cbNode->method == OC_REST_OBSERVE &&
1216 response.sequenceNumber > OC_OFFSET_SEQUENCE_NUMBER &&
1217 response.sequenceNumber <= cbNode->sequenceNumber)
1219 OC_LOG_V(INFO, TAG, PCF("Received stale notification. Number :%d"),
1220 response.sequenceNumber);
1224 OCStackApplicationResult appFeedback = cbNode->callBack(cbNode->context,
1227 cbNode->sequenceNumber = response.sequenceNumber;
1229 if (appFeedback == OC_STACK_DELETE_TRANSACTION)
1231 FindAndDeleteClientCB(cbNode);
1235 // To keep discovery callbacks active.
1236 cbNode->TTL = GetTicks(MAX_CB_TIMEOUT_SECONDS *
1237 MILLISECONDS_PER_SECOND);
1241 //Need to send ACK when the response is CON
1242 if(responseInfo->info.type == CA_MSG_CONFIRM)
1244 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1245 CA_MSG_ACKNOWLEDGE, 0, NULL, NULL, 0);
1253 OC_LOG(INFO, TAG, PCF("There is an observer associated with the response token"));
1254 if(responseInfo->result == CA_EMPTY)
1256 OC_LOG(INFO, TAG, PCF("Receiving A ACK/RESET for this token"));
1257 if(responseInfo->info.type == CA_MSG_RESET)
1259 OC_LOG(INFO, TAG, PCF("This is a RESET"));
1260 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1261 OC_OBSERVER_NOT_INTERESTED);
1263 else if(responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1265 OC_LOG(INFO, TAG, PCF("This is a pure ACK"));
1266 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1267 OC_OBSERVER_STILL_INTERESTED);
1270 else if(responseInfo->result == CA_RETRANSMIT_TIMEOUT)
1272 OC_LOG(INFO, TAG, PCF("Receiving Time Out for an observer"));
1273 OCStackFeedBack(responseInfo->info.token, responseInfo->info.tokenLength,
1274 OC_OBSERVER_FAILED_COMM);
1279 if(!cbNode && !observer)
1281 if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER)
1283 OC_LOG(INFO, TAG, PCF("This is a client, but no cbNode was found for token"));
1284 if(responseInfo->result == CA_EMPTY)
1286 OC_LOG(INFO, TAG, PCF("Receiving CA_EMPTY in the ocstack"));
1290 OC_LOG(INFO, TAG, PCF("Received a response or notification,\
1291 but I do not have callback. Sending RESET"));
1292 SendDirectStackResponse(endPoint, responseInfo->info.messageId, CA_EMPTY,
1293 CA_MSG_RESET, 0, NULL, NULL, 0);
1297 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
1299 OC_LOG(INFO, TAG, PCF("This is a server, but no observer was found for token"));
1300 if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
1302 OC_LOG_V(INFO, TAG, PCF("Received ACK at server for messageId : %d"),
1303 responseInfo->info.messageId);
1305 if (responseInfo->info.type == CA_MSG_RESET)
1307 OC_LOG_V(INFO, TAG, PCF("Received RESET at server for messageId : %d"),
1308 responseInfo->info.messageId);
1314 OC_LOG_V(INFO, TAG, PCF("Received payload: %s\n"), (char*)responseInfo->info.payload);
1315 OC_LOG(INFO, TAG, PCF("Exit HandleCAResponses"));
1319 * This function sends out Direct Stack Responses. These are responses that are not coming
1320 * from the application entity handler. These responses have no payload and are usually ACKs,
1321 * RESETs or some error conditions that were caught by the stack.
1323 OCStackResult SendDirectStackResponse(const CARemoteEndpoint_t* endPoint, const uint16_t coapID,
1324 const CAResponseResult_t responseResult, const CAMessageType_t type,
1325 const uint8_t numOptions, const CAHeaderOption_t *options,
1326 CAToken_t token, uint8_t tokenLength)
1328 CAResponseInfo_t respInfo = {};
1329 respInfo.result = responseResult;
1330 respInfo.info.messageId = coapID;
1331 respInfo.info.numOptions = numOptions;
1332 respInfo.info.options = (CAHeaderOption_t*)options;
1333 respInfo.info.payload = NULL;
1334 respInfo.info.token = token;
1335 respInfo.info.tokenLength = tokenLength;
1336 respInfo.info.type = type;
1338 CAResult_t caResult = CASendResponse(endPoint, &respInfo);
1339 if(caResult != CA_STATUS_OK)
1341 OC_LOG(ERROR, TAG, PCF("CASendResponse error"));
1342 return OC_STACK_ERROR;
1347 //This function will be called back by CA layer when a request is received
1348 void HandleCARequests(const CARemoteEndpoint_t* endPoint, const CARequestInfo_t* requestInfo)
1350 OC_LOG(INFO, TAG, PCF("Enter HandleCARequests"));
1353 OC_LOG(ERROR, TAG, PCF("endPoint is NULL"));
1359 OC_LOG(ERROR, TAG, PCF("requestInfo is NULL"));
1363 OCStackResult requestResult = OC_STACK_ERROR;
1365 if(myStackMode == OC_CLIENT)
1367 //TODO: should the client be responding to requests?
1371 OCServerProtocolRequest serverRequest = {};
1373 OC_LOG_V(INFO, TAG, PCF("Endpoint URI : %s\n"), (char*)endPoint->resourceUri);
1375 char * newUri = NULL;
1376 char * query = NULL;
1378 requestResult = getQueryFromUri(endPoint->resourceUri, &query, &newUri);
1380 if (requestResult != OC_STACK_OK)
1382 OC_LOG_V(ERROR, TAG, "getQueryFromUri() failed with OC error code %d\n", requestResult);
1385 OC_LOG_V(INFO, TAG, PCF("URI without query: %s\n"), newUri);
1386 OC_LOG_V(INFO, TAG, PCF("Query : %s\n"), query);
1388 if(strlen(newUri) < MAX_URI_LENGTH)
1391 memcpy (&(serverRequest.resourceUrl), newUri, strlen(newUri));
1396 OC_LOG(ERROR, TAG, PCF("URI length exceeds MAX_URI_LENGTH."));
1404 if(strlen(query) < MAX_QUERY_LENGTH)
1406 memcpy (&(serverRequest.query), query, strlen(query));
1411 OC_LOG(ERROR, TAG, PCF("Query length exceeds MAX_QUERY_LENGTH."));
1416 //copy request payload
1417 if (requestInfo->info.payload)
1419 size_t payloadLen = strlen(requestInfo->info.payload);
1420 serverRequest.reqTotalSize = payloadLen + 1;
1421 memcpy (&(serverRequest.reqJSONPayload), requestInfo->info.payload,
1426 serverRequest.reqTotalSize = 1;
1427 serverRequest.reqJSONPayload[0] = '\0';
1430 switch (requestInfo->method)
1434 serverRequest.method = OC_REST_GET;
1439 serverRequest.method = OC_REST_PUT;
1444 serverRequest.method = OC_REST_POST;
1449 serverRequest.method = OC_REST_DELETE;
1454 OC_LOG(ERROR, TAG, PCF("Received CA method %d not supported"));
1455 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_REQ,
1456 requestInfo->info.type, requestInfo->info.numOptions,
1457 requestInfo->info.options, requestInfo->info.token,
1458 requestInfo->info.tokenLength);
1463 OC_LOG_V(INFO, TAG, "HandleCARequests: CA token length = %d",
1464 requestInfo->info.tokenLength);
1465 OC_LOG_BUFFER(INFO, TAG, (const uint8_t *)requestInfo->info.token,
1466 requestInfo->info.tokenLength);
1467 serverRequest.requestToken = (CAToken_t)OCMalloc(requestInfo->info.tokenLength);
1468 serverRequest.tokenLength = requestInfo->info.tokenLength;
1470 if (!serverRequest.requestToken)
1472 OC_LOG(FATAL, TAG, "Server Request Token is NULL");
1473 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_INTERNAL_SERVER_ERROR,
1474 requestInfo->info.type, requestInfo->info.numOptions,
1475 requestInfo->info.options, requestInfo->info.token,
1476 requestInfo->info.tokenLength);
1479 memcpy(serverRequest.requestToken, requestInfo->info.token, requestInfo->info.tokenLength);
1481 if (requestInfo->info.type == CA_MSG_CONFIRM)
1483 serverRequest.qos = OC_HIGH_QOS;
1487 serverRequest.qos = OC_LOW_QOS;
1489 // CA does not need the following 2 fields
1490 // Are we sure CA does not need them? how is it responding to multicast
1491 serverRequest.delayedResNeeded = 0;
1492 serverRequest.secured = endPoint->isSecured;
1494 serverRequest.coapID = requestInfo->info.messageId;
1497 serverRequest.addressInfo = endPoint->addressInfo;
1498 serverRequest.connectivityType = endPoint->connectivityType;
1500 // copy vendor specific header options
1501 uint8_t tempNum = (requestInfo->info.numOptions);
1502 GetObserveHeaderOption(&serverRequest.observationOption, requestInfo->info.options, &tempNum);
1503 if (requestInfo->info.numOptions > MAX_HEADER_OPTIONS)
1506 PCF("The request info numOptions is greater than MAX_HEADER_OPTIONS"));
1507 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_BAD_OPT,
1508 requestInfo->info.type, requestInfo->info.numOptions,
1509 requestInfo->info.options, requestInfo->info.token,
1510 requestInfo->info.tokenLength);
1513 serverRequest.numRcvdVendorSpecificHeaderOptions = tempNum;
1514 if (serverRequest.numRcvdVendorSpecificHeaderOptions)
1516 memcpy (&(serverRequest.rcvdVendorSpecificHeaderOptions), requestInfo->info.options,
1517 sizeof(CAHeaderOption_t)*tempNum);
1520 requestResult = HandleStackRequests (&serverRequest);
1522 // Send ACK to client as precursor to slow response
1523 if(requestResult == OC_STACK_SLOW_RESOURCE)
1525 SendDirectStackResponse(endPoint, requestInfo->info.messageId, CA_EMPTY,
1526 CA_MSG_ACKNOWLEDGE,0, NULL, NULL, 0);
1528 else if(requestResult != OC_STACK_OK)
1530 OC_LOG_V(ERROR, TAG, PCF("HandleStackRequests failed. error: %d"), requestResult);
1532 CAResponseResult_t stackResponse = OCToCAStackResult(requestResult);
1534 SendDirectStackResponse(endPoint, requestInfo->info.messageId, stackResponse,
1535 requestInfo->info.type, requestInfo->info.numOptions,
1536 requestInfo->info.options, requestInfo->info.token,
1537 requestInfo->info.tokenLength);
1539 // requestToken is fed to HandleStackRequests, which then goes to AddServerRequest.
1540 // The token is copied in there, and is thus still owned by this function.
1541 OCFree(serverRequest.requestToken);
1542 OC_LOG(INFO, TAG, PCF("Exit HandleCARequests"));
1545 OCStackResult HandleStackRequests(OCServerProtocolRequest * protocolRequest)
1547 OC_LOG(INFO, TAG, PCF("Entering HandleStackRequests (OCStack Layer)"));
1548 OCStackResult result = OC_STACK_ERROR;
1549 ResourceHandling resHandling;
1550 OCResource *resource;
1551 if(!protocolRequest)
1553 OC_LOG(ERROR, TAG, PCF("protocolRequest is NULL"));
1554 return OC_STACK_INVALID_PARAM;
1557 OCServerRequest * request = GetServerRequestUsingToken(protocolRequest->requestToken,
1558 protocolRequest->tokenLength);
1561 OC_LOG(INFO, TAG, PCF("This is a new Server Request"));
1562 result = AddServerRequest(&request, protocolRequest->coapID,
1563 protocolRequest->delayedResNeeded, protocolRequest->secured, 0,
1564 protocolRequest->method, protocolRequest->numRcvdVendorSpecificHeaderOptions,
1565 protocolRequest->observationOption, protocolRequest->qos,
1566 protocolRequest->query, protocolRequest->rcvdVendorSpecificHeaderOptions,
1567 protocolRequest->reqJSONPayload, protocolRequest->requestToken,
1568 protocolRequest->tokenLength,
1569 protocolRequest->resourceUrl,protocolRequest->reqTotalSize,
1570 &protocolRequest->addressInfo, protocolRequest->connectivityType);
1571 if (OC_STACK_OK != result)
1573 OC_LOG(ERROR, TAG, PCF("Error adding server request"));
1579 OC_LOG(ERROR, TAG, PCF("Out of Memory"));
1580 return OC_STACK_NO_MEMORY;
1583 if(!protocolRequest->reqMorePacket)
1585 request->requestComplete = 1;
1591 PCF("This is either a repeated or blocked Server Request"));
1594 if(request->requestComplete)
1596 OC_LOG(INFO, TAG, PCF("This Server Request is complete"));
1597 result = DetermineResourceHandling (request, &resHandling, &resource);
1598 if (result == OC_STACK_OK)
1600 result = ProcessRequest(resHandling, resource, request);
1605 OC_LOG(INFO, TAG, PCF("This Server Request is incomplete"));
1606 result = OC_STACK_CONTINUE;
1611 bool ParseIPv4Address(char * ipAddrStr, uint8_t * ipAddr, uint16_t * port)
1615 uint8_t dotCount = 0;
1619 /* search for scheme */
1621 if (!isdigit((char) *ipAddrStr))
1623 coap = OC_COAP_SCHEME;
1624 while (*coap && tolower(*itr) == *coap)
1634 if (isdigit(*ipAddrStr))
1636 ipAddr[index] *= 10;
1637 ipAddr[index] += *ipAddrStr - '0';
1639 else if (*ipAddrStr == '.')
1651 if(*ipAddrStr == ':')
1655 if (isdigit(*ipAddrStr))
1658 *port += *ipAddrStr - '0';
1668 return (3 == dotCount);
1671 //-----------------------------------------------------------------------------
1673 //-----------------------------------------------------------------------------
1675 OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode)
1677 if(stackState == OC_STACK_INITIALIZED)
1679 OC_LOG(INFO, TAG, PCF("Subsequent calls to OCInit() without calling \
1680 OCStop() between them are ignored."));
1686 OCStackResult result = OC_STACK_ERROR;
1687 OC_LOG(INFO, TAG, PCF("Entering OCInit"));
1690 if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
1692 OC_LOG(ERROR, TAG, PCF("Invalid mode"));
1693 return OC_STACK_ERROR;
1697 defaultDeviceHandler = NULL;
1700 result = CAResultToOCResult(CAInitialize());
1701 VERIFY_SUCCESS(result, OC_STACK_OK);
1703 result = CAResultToOCResult(OCSelectNetwork());
1704 VERIFY_SUCCESS(result, OC_STACK_OK);
1706 CARegisterHandler(HandleCARequests, HandleCAResponses);
1707 switch (myStackMode)
1710 result = CAResultToOCResult(CAStartDiscoveryServer());
1711 OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer"));
1714 result = CAResultToOCResult(CAStartListeningServer());
1715 OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer"));
1717 case OC_CLIENT_SERVER:
1718 result = CAResultToOCResult(CAStartListeningServer());
1719 if(result == OC_STACK_OK)
1721 result = CAResultToOCResult(CAStartDiscoveryServer());
1725 VERIFY_SUCCESS(result, OC_STACK_OK);
1727 #if defined(__WITH_DTLS__)
1728 result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ?
1729 OC_STACK_OK : OC_STACK_ERROR;
1730 VERIFY_SUCCESS(result, OC_STACK_OK);
1731 #endif // (__WITH_DTLS__)
1733 #ifdef WITH_PRESENCE
1734 PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1;
1735 #endif // WITH_PRESENCE
1737 //Update Stack state to initialized
1738 stackState = OC_STACK_INITIALIZED;
1740 // Initialize resource
1741 if(myStackMode != OC_CLIENT)
1743 result = initResources();
1747 if(result != OC_STACK_OK)
1749 OC_LOG(ERROR, TAG, PCF("Stack initialization error"));
1750 deleteAllResources();
1752 stackState = OC_STACK_UNINITIALIZED;
1757 OCStackResult OCStop()
1759 OC_LOG(INFO, TAG, PCF("Entering OCStop"));
1761 if (stackState == OC_STACK_UNINIT_IN_PROGRESS)
1763 OC_LOG(DEBUG, TAG, PCF("Stack already stopping, exiting"));
1766 else if (stackState != OC_STACK_INITIALIZED)
1768 OC_LOG(ERROR, TAG, PCF("Stack not initialized"));
1769 return OC_STACK_ERROR;
1772 stackState = OC_STACK_UNINIT_IN_PROGRESS;
1774 #ifdef WITH_PRESENCE
1775 // Ensure that the TTL associated with ANY and ALL presence notifications originating from
1776 // here send with the code "OC_STACK_PRESENCE_STOPPED" result.
1777 presenceResource.presenceTTL = 0;
1778 #endif // WITH_PRESENCE
1780 // Free memory dynamically allocated for resources
1781 deleteAllResources();
1784 // Remove all observers
1785 DeleteObserverList();
1786 // Remove all the client callbacks
1787 DeleteClientCBList();
1788 // Deinit security blob
1789 DeinitOCSecurityInfo();
1790 stackState = OC_STACK_UNINITIALIZED;
1794 CAMessageType_t qualityOfServiceToMessageType(OCQualityOfService qos)
1799 return CA_MSG_CONFIRM;
1804 return CA_MSG_NONCONFIRM;
1808 OCStackResult verifyUriQueryLength(const char *inputUri, uint16_t uriLen)
1812 query = strchr (inputUri, '?');
1816 if((query - inputUri) > MAX_URI_LENGTH)
1818 return OC_STACK_INVALID_URI;
1821 if((inputUri + uriLen - 1 - query) > MAX_QUERY_LENGTH)
1823 return OC_STACK_INVALID_QUERY;
1826 else if(uriLen > MAX_URI_LENGTH)
1828 return OC_STACK_INVALID_URI;
1833 OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requiredUri,
1834 const char *referenceUri, const char *request, OCConnectivityType conType,
1835 OCQualityOfService qos, OCCallbackData *cbData,
1836 OCHeaderOption * options, uint8_t numOptions)
1838 OCStackResult result = OC_STACK_ERROR;
1839 ClientCB *clientCB = NULL;
1840 char * requestUri = NULL;
1841 char * resourceType = NULL;
1842 char * query = NULL;
1843 char * newUri = (char *)requiredUri;
1844 (void) referenceUri;
1845 CARemoteEndpoint_t* endpoint = NULL;
1846 CAResult_t caResult;
1847 CAToken_t token = NULL;
1848 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
1849 OCDoHandle resHandle = NULL;
1850 CAInfo_t requestData ={};
1851 CARequestInfo_t requestInfo ={};
1852 CAGroupEndpoint_t grpEnd = {};
1854 // To track if memory is allocated for additional header options
1856 OC_LOG(INFO, TAG, PCF("Entering OCDoResource"));
1858 // Validate input parameters
1859 VERIFY_NON_NULL(cbData, FATAL, OC_STACK_INVALID_CALLBACK);
1860 VERIFY_NON_NULL(cbData->cb, FATAL, OC_STACK_INVALID_CALLBACK);
1862 //TODO ("Need to form the final query by concatenating require and reference URI's");
1863 VERIFY_NON_NULL(requiredUri, FATAL, OC_STACK_INVALID_URI);
1865 uint16_t uriLen = strlen(requiredUri);
1867 // ToDo: We should also check if the requiredUri has a mutlicast address,
1868 // then qos has to be OC_Low_QOS
1874 case OC_REST_DELETE:
1875 case OC_REST_OBSERVE:
1876 case OC_REST_OBSERVE_ALL:
1877 case OC_REST_CANCEL_OBSERVE:
1879 #ifdef WITH_PRESENCE
1880 case OC_REST_PRESENCE:
1884 result = OC_STACK_INVALID_METHOD;
1888 if((result = verifyUriQueryLength(requiredUri, uriLen)) != OC_STACK_OK)
1893 if((request) && (strlen(request) > MAX_REQUEST_LENGTH))
1895 result = OC_STACK_INVALID_PARAM;
1899 #ifdef WITH_PRESENCE
1900 if(method == OC_REST_PRESENCE)
1902 result = getQueryFromUri(requiredUri, &query, &newUri);
1905 result = getResourceType((char *) query, &resourceType);
1909 OC_LOG_V(DEBUG, TAG, "Got Resource Type: %s", resourceType);
1913 OC_LOG(DEBUG, TAG, PCF("Resource type is NULL."));
1918 OC_LOG(DEBUG, TAG, PCF("Query string is NULL."));
1920 if(result != OC_STACK_OK)
1925 #endif // WITH_PRESENCE
1927 requestUri = (char *) OCMalloc(uriLen + 1);
1930 memcpy(requestUri, newUri, (uriLen + 1));
1934 result = OC_STACK_NO_MEMORY;
1938 resHandle = GenerateInvocationHandle();
1941 result = OC_STACK_NO_MEMORY;
1948 case OC_REST_OBSERVE:
1949 case OC_REST_OBSERVE_ALL:
1950 case OC_REST_CANCEL_OBSERVE:
1952 requestInfo.method = CA_GET;
1957 requestInfo.method = CA_PUT;
1962 requestInfo.method = CA_POST;
1965 case OC_REST_DELETE:
1967 requestInfo.method = CA_DELETE;
1970 #ifdef WITH_PRESENCE
1971 case OC_REST_PRESENCE:
1973 // Replacing method type with GET because "presence"
1974 // is a stack layer only implementation.
1975 requestInfo.method = CA_GET;
1980 result = OC_STACK_INVALID_METHOD;
1985 caResult = CAGenerateToken(&token, tokenLength);
1986 if (caResult != CA_STATUS_OK)
1988 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
1989 CADestroyToken(token);
1990 result = CAResultToOCResult (caResult);
1994 requestData.type = qualityOfServiceToMessageType(qos);
1995 requestData.token = token;
1996 requestData.tokenLength = tokenLength;
1997 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
1999 result = CreateObserveHeaderOption (&(requestData.options), options,
2000 numOptions, OC_OBSERVE_REGISTER);
2001 if (result != OC_STACK_OK)
2005 requestData.numOptions = numOptions + 1;
2009 requestData.options = (CAHeaderOption_t*)options;
2010 requestData.numOptions = numOptions;
2012 requestData.payload = (char *)request;
2014 requestInfo.info = requestData;
2016 CAConnectivityType_t caConType;
2018 result = OCToCAConnectivityType((OCConnectivityType) conType, &caConType);
2019 if (result != OC_STACK_OK)
2021 OC_LOG(ERROR, TAG, PCF("Invalid Connectivity Type"));
2026 if(conType == OC_ALL)
2028 grpEnd.connectivityType = caConType;
2030 grpEnd.resourceUri = (CAURI_t) OCMalloc(uriLen + 1);
2031 if(!grpEnd.resourceUri)
2033 result = OC_STACK_NO_MEMORY;
2036 strncpy(grpEnd.resourceUri, requiredUri, (uriLen + 1));
2038 caResult = CASendRequestToAll(&grpEnd, &requestInfo);
2042 caResult = CACreateRemoteEndpoint(newUri, caConType, &endpoint);
2044 if (caResult != CA_STATUS_OK)
2046 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2047 result = CAResultToOCResult (caResult);
2048 CADestroyToken(token);
2052 caResult = CASendRequest(endpoint, &requestInfo);
2055 if (caResult != CA_STATUS_OK)
2057 OC_LOG(ERROR, TAG, PCF("CASendRequest"));
2058 result = CAResultToOCResult (caResult);
2059 CADestroyToken(token);
2063 result = AddClientCB(&clientCB, cbData, token, tokenLength, &resHandle, method,
2064 requestUri, resourceType, conType,
2065 GetTicks(MAX_CB_TIMEOUT_SECONDS * MILLISECONDS_PER_SECOND));
2066 if(result != OC_STACK_OK)
2068 result = OC_STACK_NO_MEMORY;
2074 *handle = resHandle;
2078 if(newUri != requiredUri)
2082 if (result != OC_STACK_OK)
2084 OC_LOG(ERROR, TAG, PCF("OCDoResource error"));
2085 FindAndDeleteClientCB(clientCB);
2088 OCFree(resourceType);
2090 CADestroyRemoteEndpoint(endpoint);
2091 OCFree(grpEnd.resourceUri);
2092 if (requestData.options && requestData.numOptions > 0)
2094 if ((method == OC_REST_OBSERVE) || (method == OC_REST_OBSERVE_ALL))
2096 OCFree(requestData.options);
2102 OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options,
2106 * This ftn is implemented one of two ways in the case of observation:
2108 * 1. qos == OC_NON_CONFIRMABLE. When observe is unobserved..
2109 * Remove the callback associated on client side.
2110 * When the next notification comes in from server,
2111 * reply with RESET message to server.
2112 * Keep in mind that the server will react to RESET only
2113 * if the last notification was sent as CON
2115 * 2. qos == OC_CONFIRMABLE. When OCCancel is called,
2116 * and it is associated with an observe request
2117 * (i.e. ClientCB->method == OC_REST_OBSERVE || OC_REST_OBSERVE_ALL),
2118 * Send CON Observe request to server with
2119 * observe flag = OC_RESOURCE_OBSERVE_DEREGISTER.
2120 * Remove the callback associated on client side.
2122 OCStackResult ret = OC_STACK_OK;
2123 CARemoteEndpoint_t* endpoint = NULL;
2124 CAResult_t caResult;
2125 CAInfo_t requestData = {};
2126 CARequestInfo_t requestInfo = {};
2130 return OC_STACK_INVALID_PARAM;
2133 OC_LOG(INFO, TAG, PCF("Entering OCCancel"));
2135 ClientCB *clientCB = GetClientCB(NULL, 0, handle, NULL);
2139 switch (clientCB->method)
2141 case OC_REST_OBSERVE:
2142 case OC_REST_OBSERVE_ALL:
2143 OC_LOG(INFO, TAG, PCF("Canceling observation"));
2144 if(qos == OC_HIGH_QOS)
2146 requestData.type = qualityOfServiceToMessageType(qos);
2147 requestData.token = clientCB->token;
2148 requestData.tokenLength = clientCB->tokenLength;
2149 if (CreateObserveHeaderOption (&(requestData.options),
2150 options, numOptions, OC_OBSERVE_DEREGISTER) != OC_STACK_OK)
2152 return OC_STACK_ERROR;
2154 requestData.numOptions = numOptions + 1;
2155 requestInfo.method = CA_GET;
2156 requestInfo.info = requestData;
2158 CAConnectivityType_t caConType;
2159 ret = OCToCAConnectivityType(clientCB->conType, &caConType);
2160 if(ret != OC_STACK_OK)
2165 caResult = CACreateRemoteEndpoint((char *)clientCB->requestUri,
2166 caConType, &endpoint);
2167 if (caResult != CA_STATUS_OK)
2169 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2170 ret = OC_STACK_ERROR;
2175 caResult = CASendRequest(endpoint, &requestInfo);
2176 if (caResult != CA_STATUS_OK)
2178 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2179 ret = OC_STACK_ERROR;
2181 ret = CAResultToOCResult (caResult);
2185 FindAndDeleteClientCB(clientCB);
2188 #ifdef WITH_PRESENCE
2189 case OC_REST_PRESENCE:
2190 FindAndDeleteClientCB(clientCB);
2194 ret = OC_STACK_INVALID_METHOD;
2199 CADestroyRemoteEndpoint(endpoint);
2200 if (requestData.numOptions > 0)
2202 OCFree(requestData.options);
2208 #ifdef WITH_PRESENCE
2209 OCStackResult OCProcessPresence()
2211 OCStackResult result = OC_STACK_OK;
2212 uint8_t ipAddr[4] = { 0 };
2215 OC_LOG(INFO, TAG, PCF("Entering RequestPresence"));
2216 ClientCB* cbNode = NULL;
2218 OCClientResponse clientResponse ={};
2219 OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
2221 LL_FOREACH(cbList, cbNode)
2223 if(OC_REST_PRESENCE == cbNode->method)
2225 if(cbNode->presence)
2227 uint32_t now = GetTicks(0);
2228 OC_LOG_V(DEBUG, TAG, "this TTL level %d",
2229 cbNode->presence->TTLlevel);
2230 OC_LOG_V(DEBUG, TAG, "current ticks %d", now);
2233 if(cbNode->presence->TTLlevel >= (PresenceTimeOutSize + 1))
2238 if(cbNode->presence->TTLlevel < PresenceTimeOutSize)
2240 OC_LOG_V(DEBUG, TAG, "timeout ticks %d",
2241 cbNode->presence->timeOut[cbNode->presence->TTLlevel]);
2244 if(cbNode->presence->TTLlevel >= PresenceTimeOutSize)
2246 OC_LOG(DEBUG, TAG, PCF("No more timeout ticks"));
2247 if (ParseIPv4Address(cbNode->requestUri, ipAddr, &port))
2249 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
2252 clientResponse.sequenceNumber = 0;
2253 clientResponse.result = OC_STACK_PRESENCE_TIMEOUT;
2254 clientResponse.addr = (OCDevAddr *) &dst;
2255 clientResponse.resJSONPayload = NULL;
2257 // Increment the TTLLevel (going to a next state), so we don't keep
2258 // sending presence notification to client.
2259 cbNode->presence->TTLlevel++;
2260 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2261 cbNode->presence->TTLlevel);
2265 result = OC_STACK_INVALID_IP;
2269 cbResult = cbNode->callBack(cbNode->context, cbNode->handle, &clientResponse);
2270 if (cbResult == OC_STACK_DELETE_TRANSACTION)
2272 FindAndDeleteClientCB(cbNode);
2276 if(now >= cbNode->presence->timeOut[cbNode->presence->TTLlevel])
2278 CAResult_t caResult = CA_STATUS_OK;
2279 CARemoteEndpoint_t* endpoint = NULL;
2280 CAInfo_t requestData ={};
2281 CARequestInfo_t requestInfo = {};
2283 OC_LOG(DEBUG, TAG, PCF("time to test server presence"));
2286 CAConnectivityType_t caConType;
2287 result = OCToCAConnectivityType(cbNode->conType, &caConType);
2288 caResult = CACreateRemoteEndpoint((char *)cbNode->requestUri, caConType,
2290 if (caResult != CA_STATUS_OK || result != OC_STACK_OK)
2292 OC_LOG(ERROR, TAG, PCF("CACreateRemoteEndpoint error"));
2296 requestData.type = CA_MSG_NONCONFIRM;
2297 requestData.token = cbNode->token;
2298 requestData.tokenLength = cbNode->tokenLength;
2299 requestInfo.method = CA_GET;
2300 requestInfo.info = requestData;
2302 caResult = CASendRequest(endpoint, &requestInfo);
2303 CADestroyRemoteEndpoint(endpoint);
2305 if (caResult != CA_STATUS_OK)
2307 OC_LOG(ERROR, TAG, PCF("CASendRequest error"));
2311 cbNode->presence->TTLlevel++;
2312 OC_LOG_V(DEBUG, TAG, "moving to TTL level %d",
2313 cbNode->presence->TTLlevel);
2319 if (result != OC_STACK_OK)
2321 OC_LOG(ERROR, TAG, PCF("OCProcessPresence error"));
2325 #endif // WITH_PRESENCE
2327 OCStackResult OCProcess()
2329 #ifdef WITH_PRESENCE
2330 OCProcessPresence();
2332 CAHandleRequestResponse();
2337 #ifdef WITH_PRESENCE
2338 OCStackResult OCStartPresence(const uint32_t ttl)
2340 uint8_t tokenLength = CA_MAX_TOKEN_LEN;
2341 OCChangeResourceProperty(
2342 &(((OCResource *)presenceResource.handle)->resourceProperties),
2345 if (OC_MAX_PRESENCE_TTL_SECONDS < ttl)
2347 presenceResource.presenceTTL = OC_MAX_PRESENCE_TTL_SECONDS;
2348 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to max value"));
2352 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
2353 OC_LOG(INFO, TAG, PCF("Setting Presence TTL to default value"));
2357 presenceResource.presenceTTL = ttl;
2359 OC_LOG_V(DEBUG, TAG, "Presence TTL is %lu seconds", presenceResource.presenceTTL);
2361 if (OC_PRESENCE_UNINITIALIZED == presenceState)
2363 presenceState = OC_PRESENCE_INITIALIZED;
2365 CAAddress_t addressInfo;
2366 strncpy(addressInfo.IP.ipAddress, OC_MULTICAST_IP, CA_IPADDR_SIZE);
2367 addressInfo.IP.port = OC_MULTICAST_PORT;
2369 CAToken_t caToken = NULL;
2370 CAResult_t caResult = CAGenerateToken(&caToken, tokenLength);
2371 if (caResult != CA_STATUS_OK)
2373 OC_LOG(ERROR, TAG, PCF("CAGenerateToken error"));
2374 CADestroyToken(caToken);
2375 return OC_STACK_ERROR;
2378 CAConnectivityType_t connType;
2379 OCToCAConnectivityType(OC_ALL, &connType );
2380 AddObserver(OC_PRESENCE_URI, NULL, 0, caToken, tokenLength,
2381 (OCResource *)presenceResource.handle, OC_LOW_QOS,
2382 &addressInfo, connType);
2383 CADestroyToken(caToken);
2386 // Each time OCStartPresence is called
2387 // a different random 32-bit integer number is used
2388 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2390 return SendPresenceNotification(NULL);
2393 OCStackResult OCStopPresence()
2395 OCStackResult result = OC_STACK_ERROR;
2397 if(presenceResource.handle)
2399 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2402 // make resource inactive
2403 result = OCChangeResourceProperty(
2404 &(((OCResource *) presenceResource.handle)->resourceProperties),
2407 if(result != OC_STACK_OK)
2410 PCF("Changing the presence resource properties to ACTIVE not successful"));
2414 return SendStopNotification();
2418 OCStackResult OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandler entityHandler)
2420 defaultDeviceHandler = entityHandler;
2425 OCStackResult OCSetDeviceInfo(OCDeviceInfo deviceInfo)
2427 OC_LOG(INFO, TAG, PCF("Entering OCSetDeviceInfo"));
2429 if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
2431 return SaveDeviceInfo(deviceInfo);
2435 return OC_STACK_ERROR;
2439 OCStackResult OCCreateResource(OCResourceHandle *handle,
2440 const char *resourceTypeName,
2441 const char *resourceInterfaceName,
2442 const char *uri, OCEntityHandler entityHandler,
2443 uint8_t resourceProperties)
2446 OCResource *pointer = NULL;
2449 OCStackResult result = OC_STACK_ERROR;
2451 OC_LOG(INFO, TAG, PCF("Entering OCCreateResource"));
2453 if(myStackMode == OC_CLIENT)
2455 return OC_STACK_INVALID_PARAM;
2457 // Validate parameters
2458 if(!uri || uri[0]=='\0' || strlen(uri)>=MAX_URI_LENGTH )
2460 OC_LOG(ERROR, TAG, PCF("URI is invalid"));
2461 return OC_STACK_INVALID_URI;
2463 // Is it presented during resource discovery?
2464 if (!handle || !resourceTypeName)
2466 OC_LOG(ERROR, TAG, PCF("Input parameter is NULL"));
2467 return OC_STACK_INVALID_PARAM;
2470 if(!resourceInterfaceName || strlen(resourceInterfaceName) == 0)
2472 resourceInterfaceName = OC_RSRVD_INTERFACE_DEFAULT;
2475 // Make sure resourceProperties bitmask has allowed properties specified
2476 if (resourceProperties
2477 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE))
2479 OC_LOG(ERROR, TAG, PCF("Invalid property"));
2480 return OC_STACK_INVALID_PARAM;
2483 // If the headResource is NULL, then no resources have been created...
2484 pointer = headResource;
2487 // At least one resources is in the resource list, so we need to search for
2488 // repeated URLs, which are not allowed. If a repeat is found, exit with an error
2491 if (strncmp(uri, pointer->uri, MAX_URI_LENGTH) == 0)
2493 OC_LOG(ERROR, TAG, PCF("URI already in use"));
2494 return OC_STACK_INVALID_PARAM;
2496 pointer = pointer->next;
2499 // Create the pointer and insert it into the resource list
2500 pointer = (OCResource *) OCCalloc(1, sizeof(OCResource));
2503 result = OC_STACK_NO_MEMORY;
2506 pointer->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER;
2508 insertResource(pointer);
2511 size = strlen(uri) + 1;
2512 str = (char *) OCMalloc(size);
2515 result = OC_STACK_NO_MEMORY;
2518 strncpy(str, uri, size);
2521 // Set properties. Set OC_ACTIVE
2522 pointer->resourceProperties = (OCResourceProperty) (resourceProperties
2525 // Add the resourcetype to the resource
2526 result = BindResourceTypeToResource(pointer, resourceTypeName);
2527 if (result != OC_STACK_OK)
2529 OC_LOG(ERROR, TAG, PCF("Error adding resourcetype"));
2533 // Add the resourceinterface to the resource
2534 result = BindResourceInterfaceToResource(pointer, resourceInterfaceName);
2535 if (result != OC_STACK_OK)
2537 OC_LOG(ERROR, TAG, PCF("Error adding resourceinterface"));
2541 // If an entity handler has been passed, attach it to the newly created
2542 // resource. Otherwise, set the default entity handler.
2545 pointer->entityHandler = entityHandler;
2549 pointer->entityHandler = defaultResourceEHandler;
2553 result = OC_STACK_OK;
2555 #ifdef WITH_PRESENCE
2556 if(presenceResource.handle)
2558 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2559 SendPresenceNotification(pointer->rsrcType);
2563 if (result != OC_STACK_OK)
2565 // Deep delete of resource and other dynamic elements that it contains
2566 deleteResource(pointer);
2572 OCStackResult OCCreateResourceWithHost(OCResourceHandle *handle,
2573 const char *resourceTypeName,
2574 const char *resourceInterfaceName,
2577 OCEntityHandler entityHandler,
2578 uint8_t resourceProperties)
2585 return OC_STACK_INVALID_PARAM;
2588 OCStackResult result = OC_STACK_ERROR;
2590 result = OCCreateResource(handle, resourceTypeName, resourceInterfaceName,
2591 uri, entityHandler, resourceProperties);
2593 if (result != OC_STACK_ERROR)
2596 size = strlen(host) + 1;
2597 str = (char *) OCMalloc(size);
2600 return OC_STACK_NO_MEMORY;
2602 strncpy(str, host, size);
2603 ((OCResource *) *handle)->host = str;
2609 OCStackResult OCBindResource(
2610 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2612 OCResource *resource = NULL;
2615 OC_LOG(INFO, TAG, PCF("Entering OCBindResource"));
2617 // Validate parameters
2618 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2619 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2620 // Container cannot contain itself
2621 if (collectionHandle == resourceHandle)
2623 OC_LOG(ERROR, TAG, PCF("Added handle equals collection handle"));
2624 return OC_STACK_INVALID_PARAM;
2627 // Use the handle to find the resource in the resource linked list
2628 resource = findResource((OCResource *) collectionHandle);
2631 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2632 return OC_STACK_INVALID_PARAM;
2635 // Look for an open slot to add add the child resource.
2636 // If found, add it and return success
2637 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2639 if (!resource->rsrcResources[i])
2641 resource->rsrcResources[i] = (OCResource *) resourceHandle;
2642 OC_LOG(INFO, TAG, PCF("resource bound"));
2644 #ifdef WITH_PRESENCE
2645 if(presenceResource.handle)
2647 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2648 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2656 // Unable to add resourceHandle, so return error
2657 return OC_STACK_ERROR;
2660 OCStackResult OCUnBindResource(
2661 OCResourceHandle collectionHandle, OCResourceHandle resourceHandle)
2663 OCResource *resource = NULL;
2666 OC_LOG(INFO, TAG, PCF("Entering OCUnBindResource"));
2668 // Validate parameters
2669 VERIFY_NON_NULL(collectionHandle, ERROR, OC_STACK_ERROR);
2670 VERIFY_NON_NULL(resourceHandle, ERROR, OC_STACK_ERROR);
2671 // Container cannot contain itself
2672 if (collectionHandle == resourceHandle)
2674 OC_LOG(ERROR, TAG, PCF("removing handle equals collection handle"));
2675 return OC_STACK_INVALID_PARAM;
2678 // Use the handle to find the resource in the resource linked list
2679 resource = findResource((OCResource *) collectionHandle);
2682 OC_LOG(ERROR, TAG, PCF("Collection handle not found"));
2683 return OC_STACK_INVALID_PARAM;
2686 // Look for an open slot to add add the child resource.
2687 // If found, add it and return success
2688 for (i = 0; i < MAX_CONTAINED_RESOURCES; i++)
2690 if (resourceHandle == resource->rsrcResources[i])
2692 resource->rsrcResources[i] = (OCResource *) NULL;
2693 OC_LOG(INFO, TAG, PCF("resource unbound"));
2695 // Send notification when resource is unbounded successfully.
2696 #ifdef WITH_PRESENCE
2697 if(presenceResource.handle)
2699 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2700 SendPresenceNotification(((OCResource *) resourceHandle)->rsrcType);
2707 OC_LOG(INFO, TAG, PCF("resource not found in collection"));
2709 // Unable to add resourceHandle, so return error
2710 return OC_STACK_ERROR;
2713 OCStackResult BindResourceTypeToResource(OCResource* resource,
2714 const char *resourceTypeName)
2716 OCResourceType *pointer = NULL;
2719 OCStackResult result = OC_STACK_ERROR;
2721 OC_LOG(INFO, TAG, PCF("Entering BindResourceTypeToResource"));
2723 // Validate parameters
2724 VERIFY_NON_NULL(resourceTypeName, ERROR, OC_STACK_INVALID_PARAM);
2725 // TODO: Does resource attribute representation really have to be maintained in stack?
2726 // Is it presented during resource discovery?
2728 // Create the resourcetype and insert it into the resource list
2729 pointer = (OCResourceType *) OCCalloc(1, sizeof(OCResourceType));
2732 result = OC_STACK_NO_MEMORY;
2736 // Set the resourceTypeName
2737 size = strlen(resourceTypeName) + 1;
2738 str = (char *) OCMalloc(size);
2741 result = OC_STACK_NO_MEMORY;
2744 strncpy(str, resourceTypeName, size);
2745 pointer->resourcetypename = str;
2747 insertResourceType(resource, pointer);
2748 result = OC_STACK_OK;
2751 if (result != OC_STACK_OK)
2760 OCStackResult BindResourceInterfaceToResource(OCResource* resource,
2761 const char *resourceInterfaceName)
2763 OCResourceInterface *pointer = NULL;
2766 OCStackResult result = OC_STACK_ERROR;
2768 OC_LOG(INFO, TAG, PCF("Entering BindResourceInterfaceToResource"));
2770 // Validate parameters
2771 VERIFY_NON_NULL(resourceInterfaceName, ERROR, OC_STACK_INVALID_PARAM);
2773 //TODO ("Make sure that the resourceinterface name doesn't already exist in the resource");
2775 // Create the resourceinterface and insert it into the resource list
2776 pointer = (OCResourceInterface *) OCCalloc(1, sizeof(OCResourceInterface));
2779 result = OC_STACK_NO_MEMORY;
2783 // Set the resourceinterface name
2784 size = strlen(resourceInterfaceName) + 1;
2785 str = (char *) OCMalloc(size);
2788 result = OC_STACK_NO_MEMORY;
2791 strncpy(str, resourceInterfaceName, size);
2792 pointer->name = str;
2794 // Bind the resourceinterface to the resource
2795 insertResourceInterface(resource, pointer);
2797 result = OC_STACK_OK;
2800 if (result != OC_STACK_OK)
2809 OCStackResult OCBindResourceTypeToResource(OCResourceHandle handle,
2810 const char *resourceTypeName)
2813 OCStackResult result = OC_STACK_ERROR;
2814 OCResource *resource = NULL;
2816 // Make sure resource exists
2817 resource = findResource((OCResource *) handle);
2820 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2821 return OC_STACK_ERROR;
2824 // call internal function
2825 result = BindResourceTypeToResource(resource, resourceTypeName);
2827 #ifdef WITH_PRESENCE
2828 if(presenceResource.handle)
2830 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2831 SendPresenceNotification(resource->rsrcType);
2838 OCStackResult OCBindResourceInterfaceToResource(OCResourceHandle handle,
2839 const char *resourceInterfaceName)
2842 OCStackResult result = OC_STACK_ERROR;
2843 OCResource *resource = NULL;
2845 // Make sure resource exists
2846 resource = findResource((OCResource *) handle);
2849 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2850 return OC_STACK_ERROR;
2853 // call internal function
2854 result = BindResourceInterfaceToResource(resource, resourceInterfaceName);
2856 #ifdef WITH_PRESENCE
2857 if(presenceResource.handle)
2859 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
2860 SendPresenceNotification(resource->rsrcType);
2867 OCStackResult OCGetNumberOfResources(uint8_t *numResources)
2869 OCResource *pointer = headResource;
2871 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResources"));
2872 VERIFY_NON_NULL(numResources, ERROR, OC_STACK_INVALID_PARAM);
2876 *numResources = *numResources + 1;
2877 pointer = pointer->next;
2882 OCResourceHandle OCGetResourceHandle(uint8_t index)
2884 OCResource *pointer = headResource;
2886 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandle"));
2888 // Iterate through the list
2889 for( uint8_t i = 0; i < index && pointer; ++i)
2891 pointer = pointer->next;
2893 return (OCResourceHandle) pointer;
2896 OCStackResult OCDeleteResource(OCResourceHandle handle)
2898 OC_LOG(INFO, TAG, PCF("Entering OCDeleteResource"));
2902 OC_LOG(ERROR, TAG, PCF("Invalid param"));
2903 return OC_STACK_INVALID_PARAM;
2906 OCResource *resource = findResource((OCResource *) handle);
2907 if (resource == NULL)
2909 OC_LOG(ERROR, TAG, PCF("Resource not found"));
2910 return OC_STACK_NO_RESOURCE;
2913 if (deleteResource((OCResource *) handle) != OC_STACK_OK)
2915 OC_LOG(ERROR, TAG, PCF("Error deleting resource"));
2916 return OC_STACK_ERROR;
2922 const char *OCGetResourceUri(OCResourceHandle handle)
2924 OCResource *resource = NULL;
2925 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceUri"));
2927 resource = findResource((OCResource *) handle);
2930 return resource->uri;
2932 return (const char *) NULL;
2935 OCResourceProperty OCGetResourceProperties(OCResourceHandle handle)
2937 OCResource *resource = NULL;
2938 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceProperties"));
2940 resource = findResource((OCResource *) handle);
2943 return resource->resourceProperties;
2945 return (OCResourceProperty)-1;
2948 OCStackResult OCGetNumberOfResourceTypes(OCResourceHandle handle,
2949 uint8_t *numResourceTypes)
2951 OCResource *resource = NULL;
2952 OCResourceType *pointer = NULL;
2954 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceTypes"));
2955 VERIFY_NON_NULL(numResourceTypes, ERROR, OC_STACK_INVALID_PARAM);
2956 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2958 *numResourceTypes = 0;
2960 resource = findResource((OCResource *) handle);
2963 pointer = resource->rsrcType;
2966 *numResourceTypes = *numResourceTypes + 1;
2967 pointer = pointer->next;
2973 const char *OCGetResourceTypeName(OCResourceHandle handle, uint8_t index)
2975 OCResourceType *resourceType = NULL;
2977 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceTypeName"));
2979 resourceType = findResourceTypeAtIndex(handle, index);
2982 return resourceType->resourcetypename;
2984 return (const char *) NULL;
2987 OCStackResult OCGetNumberOfResourceInterfaces(OCResourceHandle handle,
2988 uint8_t *numResourceInterfaces)
2990 OCResourceInterface *pointer = NULL;
2991 OCResource *resource = NULL;
2993 OC_LOG(INFO, TAG, PCF("Entering OCGetNumberOfResourceInterfaces"));
2995 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
2996 VERIFY_NON_NULL(numResourceInterfaces, ERROR, OC_STACK_INVALID_PARAM);
2998 *numResourceInterfaces = 0;
2999 resource = findResource((OCResource *) handle);
3002 pointer = resource->rsrcInterface;
3005 *numResourceInterfaces = *numResourceInterfaces + 1;
3006 pointer = pointer->next;
3012 const char *OCGetResourceInterfaceName(OCResourceHandle handle, uint8_t index)
3014 OCResourceInterface *resourceInterface = NULL;
3016 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceInterfaceName"));
3018 resourceInterface = findResourceInterfaceAtIndex(handle, index);
3019 if (resourceInterface)
3021 return resourceInterface->name;
3023 return (const char *) NULL;
3026 OCResourceHandle OCGetResourceHandleFromCollection(OCResourceHandle collectionHandle,
3029 OCResource *resource = NULL;
3031 OC_LOG(INFO, TAG, PCF("Entering OCGetContainedResource"));
3033 if (index >= MAX_CONTAINED_RESOURCES)
3038 resource = findResource((OCResource *) collectionHandle);
3044 return resource->rsrcResources[index];
3047 OCStackResult OCBindResourceHandler(OCResourceHandle handle,
3048 OCEntityHandler entityHandler)
3050 OCResource *resource = NULL;
3052 OC_LOG(INFO, TAG, PCF("Entering OCBindResourceHandler"));
3054 // Validate parameters
3055 VERIFY_NON_NULL(handle, ERROR, OC_STACK_INVALID_PARAM);
3057 // Use the handle to find the resource in the resource linked list
3058 resource = findResource((OCResource *)handle);
3061 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3062 return OC_STACK_ERROR;
3066 resource->entityHandler = entityHandler;
3068 #ifdef WITH_PRESENCE
3069 if(presenceResource.handle)
3071 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3072 SendPresenceNotification(resource->rsrcType);
3079 OCEntityHandler OCGetResourceHandler(OCResourceHandle handle)
3081 OCResource *resource = NULL;
3083 OC_LOG(INFO, TAG, PCF("Entering OCGetResourceHandler"));
3085 // Use the handle to find the resource in the resource linked list
3086 resource = findResource((OCResource *)handle);
3089 OC_LOG(ERROR, TAG, PCF("Resource not found"));
3094 return resource->entityHandler;
3097 void incrementSequenceNumber(OCResource * resPtr)
3099 // Increment the sequence number
3100 resPtr->sequenceNum += 1;
3101 if (resPtr->sequenceNum == MAX_SEQUENCE_NUMBER)
3103 resPtr->sequenceNum = OC_OFFSET_SEQUENCE_NUMBER+1;
3108 #ifdef WITH_PRESENCE
3109 OCStackResult SendPresenceNotification(OCResourceType *resourceType)
3111 OCResource *resPtr = NULL;
3112 OCStackResult result = OC_STACK_ERROR;
3113 OCMethod method = OC_REST_PRESENCE;
3114 uint32_t maxAge = 0;
3115 resPtr = findResource((OCResource *) presenceResource.handle);
3118 return OC_STACK_NO_RESOURCE;
3121 if((((OCResource *) presenceResource.handle)->resourceProperties) & OC_ACTIVE)
3123 maxAge = presenceResource.presenceTTL;
3125 result = SendAllObserverNotification(method, resPtr, maxAge, resourceType, OC_LOW_QOS);
3131 OCStackResult SendStopNotification()
3133 OCResource *resPtr = NULL;
3134 OCStackResult result = OC_STACK_ERROR;
3135 OCMethod method = OC_REST_PRESENCE;
3136 resPtr = findResource((OCResource *) presenceResource.handle);
3139 return OC_STACK_NO_RESOURCE;
3142 // maxAge is 0. ResourceType is NULL.
3143 result = SendAllObserverNotification(method, resPtr, 0, NULL, OC_LOW_QOS);
3148 #endif // WITH_PRESENCE
3149 OCStackResult OCNotifyAllObservers(OCResourceHandle handle, OCQualityOfService qos)
3152 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3154 OCResource *resPtr = NULL;
3155 OCStackResult result = OC_STACK_ERROR;
3156 OCMethod method = OC_REST_NOMETHOD;
3157 uint32_t maxAge = 0;
3159 OC_LOG(INFO, TAG, PCF("Entering OCNotifyAllObservers"));
3160 #ifdef WITH_PRESENCE
3161 if(handle == presenceResource.handle)
3165 #endif // WITH_PRESENCE
3166 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3168 // Verify that the resource exists
3169 resPtr = findResource ((OCResource *) handle);
3172 return OC_STACK_NO_RESOURCE;
3176 //only increment in the case of regular observing (not presence)
3177 incrementSequenceNumber(resPtr);
3178 method = OC_REST_OBSERVE;
3179 maxAge = MAX_OBSERVE_AGE;
3180 #ifdef WITH_PRESENCE
3181 result = SendAllObserverNotification (method, resPtr, maxAge, NULL, qos);
3183 result = SendAllObserverNotification (method, resPtr, maxAge, qos);
3190 OCNotifyListOfObservers (OCResourceHandle handle,
3191 OCObservationId *obsIdList,
3192 uint8_t numberOfIds,
3193 const char *notificationJSONPayload,
3194 OCQualityOfService qos)
3196 OC_LOG(INFO, TAG, PCF("Entering OCNotifyListOfObservers"));
3198 OCResource *resPtr = NULL;
3199 //TODO: we should allow the server to define this
3200 uint32_t maxAge = MAX_OBSERVE_AGE;
3202 VERIFY_NON_NULL(handle, ERROR, OC_STACK_ERROR);
3203 VERIFY_NON_NULL(obsIdList, ERROR, OC_STACK_ERROR);
3204 VERIFY_NON_NULL(notificationJSONPayload, ERROR, OC_STACK_ERROR);
3206 // Verify that the resource exists
3207 resPtr = findResource ((OCResource *) handle);
3208 if (NULL == resPtr || myStackMode == OC_CLIENT)
3210 return OC_STACK_NO_RESOURCE;
3214 incrementSequenceNumber(resPtr);
3216 return (SendListObserverNotification(resPtr, obsIdList, numberOfIds,
3217 notificationJSONPayload, maxAge, qos));
3220 OCStackResult OCDoResponse(OCEntityHandlerResponse *ehResponse)
3222 OCStackResult result = OC_STACK_ERROR;
3223 OCServerRequest *serverRequest = NULL;
3225 OC_LOG(INFO, TAG, PCF("Entering OCDoResponse"));
3227 // Validate input parameters
3228 VERIFY_NON_NULL(ehResponse, ERROR, OC_STACK_INVALID_PARAM);
3229 VERIFY_NON_NULL(ehResponse->requestHandle, ERROR, OC_STACK_INVALID_PARAM);
3231 // TODO: Placeholder for creating a response entry when implementing
3232 // block transfer feature
3234 // If a response payload is present, check if block transfer is required
3235 if (ehResponse->payload && OCIsPacketTransferRequired(NULL,
3236 (const char *)ehResponse->payload, ehResponse->payloadSize))
3238 OC_LOG(INFO, TAG, PCF("Block transfer required"));
3240 // Persistent response buffer is needed for block transfer
3241 if (!ehResponse->persistentBufferFlag)
3243 OC_LOG(WARNING, TAG, PCF("Persistent response buffer required"));
3244 return OC_STACK_PERSISTENT_BUFFER_REQUIRED;
3246 // TODO: Placeholder for block transfer handling
3247 // TODO: Placeholder for setting the the response handle in the OCServerResponse struct
3248 // when implementing the block transfer feature
3253 // Get pointer to request info
3254 serverRequest = GetServerRequestUsingHandle((OCServerRequest *)ehResponse->requestHandle);
3257 result = serverRequest->ehResponseHandler(ehResponse);
3263 OCStackResult OCCancelResponse(OCResponseHandle responseHandle)
3265 OCStackResult result = OC_STACK_NOTIMPL;
3267 OC_LOG(INFO, TAG, PCF("Entering OCCancelResponse"));
3269 // TODO: validate response handle
3274 //-----------------------------------------------------------------------------
3275 // Private internal function definitions
3276 //-----------------------------------------------------------------------------
3277 static OCDoHandle GenerateInvocationHandle()
3279 OCDoHandle handle = NULL;
3280 // Generate token here, it will be deleted when the transaction is deleted
3281 handle = (OCDoHandle) OCMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3284 OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
3290 #ifdef WITH_PRESENCE
3291 OCStackResult OCChangeResourceProperty(OCResourceProperty * inputProperty,
3292 OCResourceProperty resourceProperties, uint8_t enable)
3296 return OC_STACK_INVALID_PARAM;
3298 if (resourceProperties
3299 > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW))
3301 OC_LOG(ERROR, TAG, PCF("Invalid property"));
3302 return OC_STACK_INVALID_PARAM;
3306 *inputProperty = (OCResourceProperty) (*inputProperty & ~(resourceProperties));
3310 *inputProperty = (OCResourceProperty) (*inputProperty | resourceProperties);
3316 OCStackResult initResources()
3318 OCStackResult result = OC_STACK_OK;
3319 // Init application resource vars
3320 headResource = NULL;
3321 tailResource = NULL;
3322 // Init Virtual Resources
3323 #ifdef WITH_PRESENCE
3324 presenceResource.presenceTTL = OC_DEFAULT_PRESENCE_TTL_SECONDS;
3325 //presenceResource.token = OCGenerateCoAPToken();
3326 result = OCCreateResource(&presenceResource.handle,
3327 OC_RSRVD_RESOURCE_TYPE_PRESENCE,
3332 //make resource inactive
3333 result = OCChangeResourceProperty(
3334 &(((OCResource *) presenceResource.handle)->resourceProperties),
3340 void insertResource(OCResource *resource)
3344 headResource = resource;
3345 tailResource = resource;
3349 tailResource->next = resource;
3350 tailResource = resource;
3352 resource->next = NULL;
3355 OCResource *findResource(OCResource *resource)
3357 OCResource *pointer = headResource;
3361 if (pointer == resource)
3365 pointer = pointer->next;
3370 void deleteAllResources()
3372 OCResource *pointer = headResource;
3373 OCResource *temp = NULL;
3377 temp = pointer->next;
3378 #ifdef WITH_PRESENCE
3379 if(pointer != (OCResource *) presenceResource.handle)
3381 #endif // WITH_PRESENCE
3382 deleteResource(pointer);
3383 #ifdef WITH_PRESENCE
3385 #endif // WITH_PRESENCE
3389 #ifdef WITH_PRESENCE
3390 // Ensure that the last resource to be deleted is the presence resource. This allows for all
3391 // presence notification attributed to their deletion to be processed.
3392 deleteResource((OCResource *) presenceResource.handle);
3393 #endif // WITH_PRESENCE
3396 OCStackResult deleteResource(OCResource *resource)
3398 OCResource *prev = NULL;
3399 OCResource *temp = NULL;
3401 temp = headResource;
3404 if (temp == resource)
3406 // Invalidate all Resource Properties.
3407 resource->resourceProperties = (OCResourceProperty) 0;
3408 #ifdef WITH_PRESENCE
3409 if(resource != (OCResource *) presenceResource.handle)
3411 #endif // WITH_PRESENCE
3412 OCNotifyAllObservers((OCResourceHandle)resource, OC_HIGH_QOS);
3413 #ifdef WITH_PRESENCE
3416 if(presenceResource.handle)
3418 ((OCResource *)presenceResource.handle)->sequenceNum = OCGetRandom();
3419 if(resource != (OCResource *) presenceResource.handle)
3421 SendPresenceNotification(resource->rsrcType);
3425 SendPresenceNotification(NULL);
3429 // Only resource in list.
3430 if (temp == headResource && temp == tailResource)
3432 headResource = NULL;
3433 tailResource = NULL;
3436 else if (temp == headResource)
3438 headResource = temp->next;
3441 else if (temp == tailResource)
3443 tailResource = prev;
3444 tailResource->next = NULL;
3448 prev->next = temp->next;
3451 deleteResourceElements(temp);
3462 return OC_STACK_ERROR;
3465 void deleteResourceElements(OCResource *resource)
3473 OCFree(resource->uri);
3475 // Delete resourcetype linked list
3476 deleteResourceType(resource->rsrcType);
3478 // Delete resourceinterface linked list
3479 deleteResourceInterface(resource->rsrcInterface);
3482 void deleteResourceType(OCResourceType *resourceType)
3484 OCResourceType *pointer = resourceType;
3485 OCResourceType *next = NULL;
3489 next = pointer->next;
3490 OCFree(pointer->resourcetypename);
3496 void deleteResourceInterface(OCResourceInterface *resourceInterface)
3498 OCResourceInterface *pointer = resourceInterface;
3499 OCResourceInterface *next = NULL;
3503 next = pointer->next;
3504 OCFree(pointer->name);
3510 void insertResourceType(OCResource *resource, OCResourceType *resourceType)
3512 OCResourceType *pointer = NULL;
3513 OCResourceType *previous = NULL;
3514 if (!resource || !resourceType)
3518 // resource type list is empty.
3519 else if (!resource->rsrcType)
3521 resource->rsrcType = resourceType;
3525 pointer = resource->rsrcType;
3529 // resource type already exists. Free 2nd arg and return.
3530 if (!strcmp(resourceType->resourcetypename, pointer->resourcetypename))
3532 OCFree(resourceType->resourcetypename);
3533 OCFree(resourceType);
3537 pointer = pointer->next;
3539 previous->next = resourceType;
3541 resourceType->next = NULL;
3544 OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle, uint8_t index)
3546 OCResource *resource = NULL;
3547 OCResourceType *pointer = NULL;
3549 // Find the specified resource
3550 resource = findResource((OCResource *) handle);
3556 // Make sure a resource has a resourcetype
3557 if (!resource->rsrcType)
3562 // Iterate through the list
3563 pointer = resource->rsrcType;
3564 for(uint8_t i = 0; i< index && pointer; ++i)
3566 pointer = pointer->next;
3571 OCResourceType *findResourceType(OCResourceType * resourceTypeList, const char * resourceTypeName)
3573 if(resourceTypeList && resourceTypeName)
3575 OCResourceType * rtPointer = resourceTypeList;
3576 while(resourceTypeName && rtPointer)
3578 if(rtPointer->resourcetypename &&
3579 strcmp(resourceTypeName, (const char *)
3580 (rtPointer->resourcetypename)) == 0)
3584 rtPointer = rtPointer->next;
3591 void insertResourceInterface(OCResource *resource,
3592 OCResourceInterface *resourceInterface)
3594 OCResourceInterface *pointer = NULL;
3595 OCResourceInterface *previous = NULL;
3597 if (!resource->rsrcInterface)
3599 resource->rsrcInterface = resourceInterface;
3603 pointer = resource->rsrcInterface;
3606 // resource type already exists. Free 2nd arg and return.
3607 if (!strcmp(resourceInterface->name, pointer->name))
3609 OCFree(resourceInterface->name);
3610 OCFree(resourceInterface);
3614 pointer = pointer->next;
3616 previous->next = resourceInterface;
3618 resourceInterface->next = NULL;
3621 OCResourceInterface *findResourceInterfaceAtIndex(OCResourceHandle handle,
3624 OCResource *resource = NULL;
3625 OCResourceInterface *pointer = NULL;
3627 // Find the specified resource
3628 resource = findResource((OCResource *) handle);
3634 // Make sure a resource has a resourceinterface
3635 if (!resource->rsrcInterface)
3640 // Iterate through the list
3641 pointer = resource->rsrcInterface;
3643 for (uint8_t i = 0; i < index && pointer; ++i)
3645 pointer = pointer->next;
3650 bool OCIsPacketTransferRequired(const char *request, const char *response, size_t size)
3652 bool result = false;
3654 // Determine if we are checking a request or a response
3657 // If size is greater than 0, use it for the request size value, otherwise
3658 // assume request is null terminated and use strlen for size value
3659 if ((size > MAX_REQUEST_LENGTH) || (strlen(request) > MAX_REQUEST_LENGTH))
3666 // If size is greater than 0, use it for the response size value, otherwise
3667 // assume response is null terminated and use strlen for size value
3668 if ((size > MAX_RESPONSE_LENGTH) || (strlen(response) > MAX_RESPONSE_LENGTH))
3676 OCStackResult getResourceType(const char * query, char** resourceType)
3680 return OC_STACK_INVALID_PARAM;
3683 OCStackResult result = OC_STACK_ERROR;
3685 if(strncmp(query, "rt=", 3) == 0)
3687 *resourceType = (char *) OCMalloc(strlen(query)-3 + 1);
3690 result = OC_STACK_NO_MEMORY;
3694 strcpy((char *)*resourceType, ((const char *)&query[3]));
3695 result = OC_STACK_OK;
3703 * This function splits the uri using the '?' delimiter.
3704 * "uriWithoutQuery" is the block of characters between the beginning
3705 * till the delimiter or '\0' which ever comes first.
3706 * "query" is whatever is to the right of the delimiter if present.
3707 * No delimiter sets the query to NULL.
3708 * If either are present, they will be malloc'ed into the params 2, 3.
3709 * The first param, *uri is left untouched.
3711 * NOTE: This function does not account for whitespace at the end of the uri NOR
3712 * malformed uri's with '??'. Whitespace at the end will be assumed to be
3713 * part of the query.
3715 OCStackResult getQueryFromUri(const char * uri, char** query, char ** uriWithoutQuery)
3719 return OC_STACK_INVALID_URI;
3721 if(!query || !uriWithoutQuery)
3723 return OC_STACK_INVALID_PARAM;
3727 *uriWithoutQuery = NULL;
3729 size_t uriWithoutQueryLen = 0;
3730 size_t queryLen = 0;
3731 size_t uriLen = strlen(uri);
3733 char *pointerToDelimiter = strstr(uri, "?");
3735 uriWithoutQueryLen = pointerToDelimiter == NULL ? uriLen : pointerToDelimiter - uri;
3736 queryLen = pointerToDelimiter == NULL ? 0 : uriLen - uriWithoutQueryLen - 1;
3738 if (uriWithoutQueryLen)
3740 *uriWithoutQuery = (char *) OCCalloc(uriWithoutQueryLen + 1, 1);
3741 if (!*uriWithoutQuery)
3745 strncpy(*uriWithoutQuery, uri, uriWithoutQueryLen);
3749 *query = (char *) OCCalloc(queryLen + 1, 1);
3752 OCFree(*uriWithoutQuery);
3753 *uriWithoutQuery = NULL;
3756 strncpy(*query, pointerToDelimiter + 1, queryLen);
3762 return OC_STACK_NO_MEMORY;
3765 const ServerID OCGetServerInstanceID(void)
3767 static bool generated = false;
3768 static ServerID sid;
3774 sid = OCGetRandom();
3779 const char* OCGetServerInstanceIDString(void)
3781 // max printed length of a base 10
3782 // uint32 is 10 characters, so 11 includes null.
3783 // This will change as the representation gets switched
3785 static char buffer[11];
3787 if (snprintf(buffer, sizeof(buffer),"%u", OCGetServerInstanceID()) < 0)
3795 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
3796 uint8_t *c, uint8_t *d )
3798 if ( !ipAddr || !a || !b || !c || !d )
3800 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3801 return OC_STACK_INVALID_PARAM;
3804 *a = ipAddr->addr[0];
3805 *b = ipAddr->addr[1];
3806 *c = ipAddr->addr[2];
3807 *d = ipAddr->addr[3];
3812 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
3814 if ( !ipAddr || !port )
3816 OC_LOG(FATAL, TAG, PCF("Invalid argument"));
3817 return OC_STACK_INVALID_PARAM;
3820 *port = (ipAddr->addr[5]<< 8) | ipAddr->addr[4];
3825 CAResult_t OCSelectNetwork()
3827 CAResult_t retResult = CA_STATUS_FAILED;
3828 CAResult_t caResult = CA_STATUS_OK;
3830 CAConnectivityType_t connTypes[] = {CA_ETHERNET, CA_WIFI, CA_EDR, CA_LE};
3832 int numConnTypes = sizeof(connTypes)/sizeof(connTypes[0]);
3834 for(int i = 0; i<numConnTypes; i++)
3836 // Ignore CA_NOT_SUPPORTED error. The CA Layer may have not compiled in the interface.
3837 if(caResult == CA_STATUS_OK || caResult == CA_NOT_SUPPORTED)
3839 caResult = CASelectNetwork(connTypes[i]);
3840 if(caResult == CA_STATUS_OK)
3842 retResult = CA_STATUS_OK;
3847 if(retResult != CA_STATUS_OK)
3849 return caResult; // Returns error of appropriate transport that failed fatally.
3855 OCStackResult CAResultToOCResult(CAResult_t caResult)
3861 case CA_STATUS_INVALID_PARAM:
3862 return OC_STACK_INVALID_PARAM;
3863 case CA_ADAPTER_NOT_ENABLED:
3864 return OC_STACK_ADAPTER_NOT_ENABLED;
3865 case CA_SERVER_STARTED_ALREADY:
3867 case CA_SERVER_NOT_STARTED:
3868 return OC_STACK_ERROR;
3869 case CA_DESTINATION_NOT_REACHABLE:
3870 return OC_STACK_COMM_ERROR;
3871 case CA_SOCKET_OPERATION_FAILED:
3872 return OC_STACK_COMM_ERROR;
3873 case CA_SEND_FAILED:
3874 return OC_STACK_COMM_ERROR;
3875 case CA_RECEIVE_FAILED:
3876 return OC_STACK_COMM_ERROR;
3877 case CA_MEMORY_ALLOC_FAILED:
3878 return OC_STACK_NO_MEMORY;
3879 case CA_REQUEST_TIMEOUT:
3880 return OC_STACK_TIMEOUT;
3881 case CA_DESTINATION_DISCONNECTED:
3882 return OC_STACK_COMM_ERROR;
3883 case CA_STATUS_FAILED:
3884 return OC_STACK_ERROR;
3885 case CA_NOT_SUPPORTED:
3886 return OC_STACK_NOTIMPL;
3888 return OC_STACK_ERROR;