ocstack.c 128 KB
Newer Older
1 2
//******************************************************************
//
3
// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
19 20 21 22 23 24
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
Sudarshan Prasad's avatar
Sudarshan Prasad committed
25 26 27 28 29 30 31

// Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
// causes header files to expose definitions
// corresponding to the POSIX.1-2001 base
// specification (excluding the XSI extension).
// For POSIX.1-2001 base specification,
// Refer http://pubs.opengroup.org/onlinepubs/009695399/
32 33
#define _POSIX_C_SOURCE 200112L
#include <string.h>
Yuliya Kamatkova's avatar
Yuliya Kamatkova committed
34
#include <ctype.h>
35

36 37
#include "ocstack.h"
#include "ocstackinternal.h"
38
#include "ocresourcehandler.h"
39
#include "occlientcb.h"
40
#include "ocobserve.h"
41
#include "ocrandom.h"
42
#include "oic_malloc.h"
43
#include "oic_string.h"
44
#include "logger.h"
Doug Hudson's avatar
Doug Hudson committed
45
#include "ocserverrequest.h"
Sachin Agrawal's avatar
Sachin Agrawal committed
46
#include "secureresourcemanager.h"
47
#include "doxmresource.h"
48 49
#include "cacommon.h"
#include "cainterface.h"
50 51
#include "ocpayload.h"
#include "ocpayloadcbor.h"
52

53 54 55 56 57 58 59
#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
#include "routingutility.h"
#ifdef ROUTING_GATEWAY
#include "routingmanager.h"
#endif
#endif

Yuliya Kamatkova's avatar
Yuliya Kamatkova committed
60 61 62 63 64 65 66 67 68
#ifdef WITH_ARDUINO
#include "Time.h"
#else
#include <sys/time.h>
#endif
#include "coap_time.h"
#include "utlist.h"
#include "pdu.h"

69 70 71
#ifndef ARDUINO
#include <arpa/inet.h>
#endif
72

73 74 75 76
#ifndef UINT32_MAX
#define UINT32_MAX   (0xFFFFFFFFUL)
#endif

77 78 79
//-----------------------------------------------------------------------------
// Typedefs
//-----------------------------------------------------------------------------
80 81 82 83 84
typedef enum
{
    OC_STACK_UNINITIALIZED = 0,
    OC_STACK_INITIALIZED,
    OC_STACK_UNINIT_IN_PROGRESS
85
} OCStackState;
86

87
#ifdef WITH_PRESENCE
88 89 90 91
typedef enum
{
    OC_PRESENCE_UNINITIALIZED = 0,
    OC_PRESENCE_INITIALIZED
92 93 94
} OCPresenceState;
#endif

95 96 97 98
//-----------------------------------------------------------------------------
// Private variables
//-----------------------------------------------------------------------------
static OCStackState stackState = OC_STACK_UNINITIALIZED;
99

100
OCResource *headResource = NULL;
101
static OCResource *tailResource = NULL;
102 103
static OCResourceHandle platformResource = {0};
static OCResourceHandle deviceResource = {0};
104
#ifdef WITH_PRESENCE
105
static OCPresenceState presenceState = OC_PRESENCE_UNINITIALIZED;
106
static PresenceResource presenceResource;
107 108
static uint8_t PresenceTimeOutSize = 0;
static uint32_t PresenceTimeOut[] = {50, 75, 85, 95, 100};
109
#endif
110

111
static OCMode myStackMode;
112 113 114 115
#ifdef RA_ADAPTER
//TODO: revisit this design
static bool gRASetInfo = false;
#endif
116
OCDeviceEntityHandler defaultDeviceHandler;
117
void* defaultDeviceHandlerCallbackParameter = NULL;
118
static const char COAP_TCP[] = "coap+tcp:";
119

120 121 122
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
123
#define TAG  "OCStack"
124
#define VERIFY_SUCCESS(op, successCode) { if ((op) != (successCode)) \
125
            {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
126
#define VERIFY_NON_NULL(arg, logLevel, retVal) { if (!(arg)) { OC_LOG((logLevel), \
127
             TAG, #arg " is NULL"); return (retVal); } }
128
#define VERIFY_NON_NULL_NR(arg, logLevel) { if (!(arg)) { OC_LOG((logLevel), \
129
             TAG, #arg " is NULL"); return; } }
130
#define VERIFY_NON_NULL_V(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL");\
131
    goto exit;} }
132

Doug Hudson's avatar
Doug Hudson committed
133 134
//TODO: we should allow the server to define this
#define MAX_OBSERVE_AGE (0x2FFFFUL)
135

136
#define MILLISECONDS_PER_SECOND   (1000)
137 138 139 140

//-----------------------------------------------------------------------------
// Private internal function prototypes
//-----------------------------------------------------------------------------
Doug Hudson's avatar
Doug Hudson committed
141 142 143 144 145 146

/**
 * Generate handle of OCDoResource invocation for callback management.
 *
 * @return Generated OCDoResource handle.
 */
147
static OCDoHandle GenerateInvocationHandle();
Doug Hudson's avatar
Doug Hudson committed
148 149 150 151 152 153

/**
 * Initialize resource data structures, variables, etc.
 *
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
154
static OCStackResult initResources();
Doug Hudson's avatar
Doug Hudson committed
155 156 157 158 159 160

/**
 * Add a resource to the end of the linked list of resources.
 *
 * @param resource Resource to be added
 */
161
static void insertResource(OCResource *resource);
Doug Hudson's avatar
Doug Hudson committed
162 163 164 165 166 167 168 169

/**
 * Find a resource in the linked list of resources.
 *
 * @param resource Resource to be found.
 * @return Pointer to resource that was found in the linked list or NULL if the resource was not
 *         found.
 */
170
static OCResource *findResource(OCResource *resource);
Doug Hudson's avatar
Doug Hudson committed
171 172 173 174 175 176 177 178 179 180 181

/**
 * Insert a resource type into a resource's resource type linked list.
 * If resource type already exists, it will not be inserted and the
 * resourceType will be free'd.
 * resourceType->next should be null to avoid memory leaks.
 * Function returns silently for null args.
 *
 * @param resource Resource where resource type is to be inserted.
 * @param resourceType Resource type to be inserted.
 */
182 183
static void insertResourceType(OCResource *resource,
        OCResourceType *resourceType);
Doug Hudson's avatar
Doug Hudson committed
184 185 186 187 188 189 190 191 192

/**
 * Get a resource type at the specified index within a resource.
 *
 * @param handle Handle of resource.
 * @param index Index of resource type.
 *
 * @return Pointer to resource type if found, NULL otherwise.
 */
193 194
static OCResourceType *findResourceTypeAtIndex(OCResourceHandle handle,
        uint8_t index);
Doug Hudson's avatar
Doug Hudson committed
195 196 197 198 199 200 201 202 203 204

/**
 * Insert a resource interface into a resource's resource interface linked list.
 * If resource interface already exists, it will not be inserted and the
 * resourceInterface will be free'd.
 * resourceInterface->next should be null to avoid memory leaks.
 *
 * @param resource Resource where resource interface is to be inserted.
 * @param resourceInterface Resource interface to be inserted.
 */
205 206
static void insertResourceInterface(OCResource *resource,
        OCResourceInterface *resourceInterface);
Doug Hudson's avatar
Doug Hudson committed
207 208 209 210 211 212 213 214 215

/**
 * Get a resource interface at the specified index within a resource.
 *
 * @param handle Handle of resource.
 * @param index Index of resource interface.
 *
 * @return Pointer to resource interface if found, NULL otherwise.
 */
216 217
static OCResourceInterface *findResourceInterfaceAtIndex(
        OCResourceHandle handle, uint8_t index);
Doug Hudson's avatar
Doug Hudson committed
218 219 220 221 222 223

/**
 * Delete all of the dynamically allocated elements that were created for the resource type.
 *
 * @param resourceType Specified resource type.
 */
224
static void deleteResourceType(OCResourceType *resourceType);
Doug Hudson's avatar
Doug Hudson committed
225 226 227 228 229 230

/**
 * Delete all of the dynamically allocated elements that were created for the resource interface.
 *
 * @param resourceInterface Specified resource interface.
 */
231
static void deleteResourceInterface(OCResourceInterface *resourceInterface);
Doug Hudson's avatar
Doug Hudson committed
232 233 234 235 236 237

/**
 * Delete all of the dynamically allocated elements that were created for the resource.
 *
 * @param resource Specified resource.
 */
238
static void deleteResourceElements(OCResource *resource);
Doug Hudson's avatar
Doug Hudson committed
239 240 241 242 243 244 245 246 247

/**
 * Delete resource specified by handle.  Deletes resource and all resourcetype and resourceinterface
 * linked lists.
 *
 * @param handle Handle of resource to be deleted.
 *
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
248
static OCStackResult deleteResource(OCResource *resource);
Doug Hudson's avatar
Doug Hudson committed
249 250 251 252

/**
 * Delete all of the resources in the resource list.
 */
253
static void deleteAllResources();
Doug Hudson's avatar
Doug Hudson committed
254 255 256 257 258 259

/**
 * Increment resource sequence number.  Handles rollover.
 *
 * @param resPtr Pointer to resource.
 */
260
static void incrementSequenceNumber(OCResource * resPtr);
Doug Hudson's avatar
Doug Hudson committed
261 262 263 264 265 266 267 268

/**
 * Verify the lengths of the URI and the query separately.
 *
 * @param inputUri Input URI and query.
 * @param uriLen The length of the initial URI with query.
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
269 270
static OCStackResult verifyUriQueryLength(const char * inputUri,
        uint16_t uriLen);
Doug Hudson's avatar
Doug Hudson committed
271 272 273 274 275 276 277 278 279

/*
 * Attempts to initialize every network interface that the CA Layer might have compiled in.
 *
 * Note: At least one interface must succeed to initialize. If all calls to @ref CASelectNetwork
 * return something other than @ref CA_STATUS_OK, then this function fails.
 *
 * @return ::CA_STATUS_OK on success, some other value upon failure.
 */
280
static CAResult_t OCSelectNetwork();
Doug Hudson's avatar
Doug Hudson committed
281 282

/**
283
 * Get the CoAP ticks after the specified number of milli-seconds.
Doug Hudson's avatar
Doug Hudson committed
284
 *
285
 * @param afterMilliSeconds Milli-seconds.
Doug Hudson's avatar
Doug Hudson committed
286 287 288
 * @return
 *     CoAP ticks
 */
289
static uint32_t GetTicks(uint32_t afterMilliSeconds);
Doug Hudson's avatar
Doug Hudson committed
290 291 292 293 294 295 296

/**
 * Convert CAResponseResult_t to OCStackResult.
 *
 * @param caCode CAResponseResult_t code.
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
297
static OCStackResult CAToOCStackResult(CAResponseResult_t caCode);
Doug Hudson's avatar
Doug Hudson committed
298

299 300 301 302
/**
 * Convert OCStackResult to CAResponseResult_t.
 *
 * @param caCode OCStackResult code.
303
 * @param method OCMethod method the return code replies to.
304
 * @return ::CA_CONTENT on OK, some other value upon failure.
305
 */
306
static CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method);
307

Doug Hudson's avatar
Doug Hudson committed
308
/**
309
 * Convert OCTransportFlags_t to CATransportModifiers_t.
Doug Hudson's avatar
Doug Hudson committed
310
 *
311 312
 * @param ocConType OCTransportFlags_t input.
 * @return CATransportFlags
Doug Hudson's avatar
Doug Hudson committed
313
 */
314
static CATransportFlags_t OCToCATransportFlags(OCTransportFlags ocConType);
Doug Hudson's avatar
Doug Hudson committed
315 316

/**
317
 * Convert CATransportFlags_t to OCTransportModifiers_t.
Doug Hudson's avatar
Doug Hudson committed
318
 *
319 320
 * @param caConType CATransportFlags_t input.
 * @return OCTransportFlags
Doug Hudson's avatar
Doug Hudson committed
321
 */
322
static OCTransportFlags CAToOCTransportFlags(CATransportFlags_t caConType);
Doug Hudson's avatar
Doug Hudson committed
323 324 325 326 327 328 329 330

/**
 * Handle response from presence request.
 *
 * @param endPoint CA remote endpoint.
 * @param responseInfo CA response info.
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
331 332
static OCStackResult HandlePresenceResponse(const CAEndpoint_t *endPoint,
        const CAResponseInfo_t *responseInfo);
Doug Hudson's avatar
Doug Hudson committed
333 334 335 336 337 338 339

/**
 * This function will be called back by CA layer when a response is received.
 *
 * @param endPoint CA remote endpoint.
 * @param responseInfo CA response info.
 */
340
static void HandleCAResponses(const CAEndpoint_t* endPoint,
341
        const CAResponseInfo_t* responseInfo);
Doug Hudson's avatar
Doug Hudson committed
342 343 344 345 346 347 348

/**
 * This function will be called back by CA layer when a request is received.
 *
 * @param endPoint CA remote endpoint.
 * @param requestInfo CA request info.
 */
349
static void HandleCARequests(const CAEndpoint_t* endPoint,
350
        const CARequestInfo_t* requestInfo);
Doug Hudson's avatar
Doug Hudson committed
351 352 353 354 355 356 357 358 359

/**
 * Extract query from a URI.
 *
 * @param uri Full URI with query.
 * @param query Pointer to string that will contain query.
 * @param newURI Pointer to string that will contain URI.
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
360 361
static OCStackResult getQueryFromUri(const char * uri, char** resourceType, char ** newURI);

Doug Hudson's avatar
Doug Hudson committed
362 363 364 365 366 367 368 369 370 371 372
/**
 * Finds a resource type in an OCResourceType link-list.
 *
 * @param resourceTypeList The link-list to be searched through.
 * @param resourceTypeName The key to search for.
 *
 * @return Resource type that matches the key (ie. resourceTypeName) or
 *      NULL if there is either an invalid parameter or this function was unable to find the key.
 */
static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
        const char * resourceTypeName);
373

Mandeep Shetty's avatar
Mandeep Shetty committed
374 375 376 377 378 379 380 381 382 383 384
/**
 * Reset presence TTL for a ClientCB struct. ttlLevel will be set to 0.
 * TTL will be set to maxAge.
 *
 * @param cbNode Callback Node for which presence ttl is to be reset.
 * @param maxAge New value of ttl in seconds.

 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);

385
/**
386 387
 * Ensure the accept header option is set appropriatly before sending the requests and routing
 * header option is updated with destination.
388 389 390 391 392 393 394 395
 *
 * @param object CA remote endpoint.
 * @param requestInfo CA request info.
 *
 * @return ::OC_STACK_OK on success, some other value upon failure.
 */
static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *requestInfo);

Doug Hudson's avatar
Doug Hudson committed
396 397 398 399
//-----------------------------------------------------------------------------
// Internal functions
//-----------------------------------------------------------------------------

400
uint32_t GetTicks(uint32_t afterMilliSeconds)
Yuliya Kamatkova's avatar
Yuliya Kamatkova committed
401 402 403
{
    coap_tick_t now;
    coap_ticks(&now);
404 405 406 407 408 409 410 411 412

    // Guard against overflow of uint32_t
    if (afterMilliSeconds <= ((UINT32_MAX - (uint32_t)now) * MILLISECONDS_PER_SECOND) /
                             COAP_TICKS_PER_SECOND)
    {
        return now + (afterMilliSeconds * COAP_TICKS_PER_SECOND)/MILLISECONDS_PER_SECOND;
    }
    else
    {
413
        return UINT32_MAX;
414
    }
Yuliya Kamatkova's avatar
Yuliya Kamatkova committed
415 416
}

417
void CopyEndpointToDevAddr(const CAEndpoint_t *in, OCDevAddr *out)
Sachin Agrawal's avatar
Sachin Agrawal committed
418
{
419 420 421 422 423
    VERIFY_NON_NULL_NR(in, FATAL);
    VERIFY_NON_NULL_NR(out, FATAL);

    out->adapter = (OCTransportAdapter)in->adapter;
    out->flags = CAToOCTransportFlags(in->flags);
424
    OICStrcpy(out->addr, sizeof(out->addr), in->addr);
425
    out->port = in->port;
Shilpa Sodani's avatar
Shilpa Sodani committed
426
    out->interface = in->interface;
427 428 429
#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
    memcpy(out->routeData, in->routeData, sizeof(out->routeData));
#endif
430 431 432 433 434 435 436 437 438
}

void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out)
{
    VERIFY_NON_NULL_NR(in, FATAL);
    VERIFY_NON_NULL_NR(out, FATAL);

    out->adapter = (CATransportAdapter_t)in->adapter;
    out->flags = OCToCATransportFlags(in->flags);
439
    OICStrcpy(out->addr, sizeof(out->addr), in->addr);
440 441 442
#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
    memcpy(out->routeData, in->routeData, sizeof(out->routeData));
#endif
443
    out->port = in->port;
Shilpa Sodani's avatar
Shilpa Sodani committed
444
    out->interface = in->interface;
445 446 447 448 449 450 451 452 453 454 455
}

void FixUpClientResponse(OCClientResponse *cr)
{
    VERIFY_NON_NULL_NR(cr, FATAL);

    cr->addr = &cr->devAddr;
    cr->connType = (OCConnectivityType)
        ((cr->devAddr.adapter << CT_ADAPTER_SHIFT) | (cr->devAddr.flags & CT_MASK_FLAGS));
}

456 457
static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *requestInfo)
{
458 459 460 461 462 463 464 465 466 467 468 469 470
    VERIFY_NON_NULL(object, FATAL, OC_STACK_INVALID_PARAM);
    VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM);

#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
    OCStackResult rmResult = RMAddInfo(object->routeData, &(requestInfo->info.options),
                                     &(requestInfo->info.numOptions));
    if (OC_STACK_OK != rmResult)
    {
        OC_LOG(ERROR, TAG, "Add destination option failed");
        return rmResult;
    }
#endif

471 472 473 474 475 476 477 478 479 480
    // OC stack prefer CBOR encoded payloads.
    requestInfo->info.acceptFormat = CA_FORMAT_APPLICATION_CBOR;
    CAResult_t result = CASendRequest(object, requestInfo);
    if(CA_STATUS_OK != result)
    {
        OC_LOG_V(ERROR, TAG, "CASendRequest failed with CA error %u", result);
        return CAResultToOCResult(result);
    }
    return OC_STACK_OK;
}
481 482 483 484 485 486 487 488 489 490
//-----------------------------------------------------------------------------
// Internal API function
//-----------------------------------------------------------------------------

// This internal function is called to update the stack with the status of
// observers and communication failures
OCStackResult OCStackFeedBack(CAToken_t token, uint8_t tokenLength, uint8_t status)
{
    OCStackResult result = OC_STACK_ERROR;
    ResourceObserver * observer = NULL;
Jon A. Cruz's avatar
Jon A. Cruz committed
491
    OCEntityHandlerRequest ehRequest = {0};
492 493 494 495

    switch(status)
    {
    case OC_OBSERVER_NOT_INTERESTED:
496
        OC_LOG(DEBUG, TAG, "observer not interested in our notifications");
497 498 499
        observer = GetObserverUsingToken (token, tokenLength);
        if(observer)
        {
John Light's avatar
John Light committed
500 501 502 503 504
            result = FormOCEntityHandlerRequest(&ehRequest,
                                                (OCRequestHandle)NULL,
                                                OC_REST_NOMETHOD,
                                                &observer->devAddr,
                                                (OCResourceHandle)NULL,
505 506
                                                NULL, PAYLOAD_TYPE_REPRESENTATION,
                                                NULL, 0, 0, NULL,
John Light's avatar
John Light committed
507 508
                                                OC_OBSERVE_DEREGISTER,
                                                observer->observeId);
509 510 511 512
            if(result != OC_STACK_OK)
            {
                return result;
            }
513 514
            observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest,
                            observer->resource->entityHandlerCallbackParam);
515
        }
Mandeep Shetty's avatar
Mandeep Shetty committed
516

517 518 519
        result = DeleteObserverUsingToken (token, tokenLength);
        if(result == OC_STACK_OK)
        {
520
            OC_LOG(DEBUG, TAG, "Removed observer successfully");
521 522 523 524
        }
        else
        {
            result = OC_STACK_OK;
525
            OC_LOG(DEBUG, TAG, "Observer Removal failed");
526 527
        }
        break;
Mandeep Shetty's avatar
Mandeep Shetty committed
528

529
    case OC_OBSERVER_STILL_INTERESTED:
530
        OC_LOG(DEBUG, TAG, "observer still interested, reset the failedCount");
531 532 533 534 535 536 537 538 539 540 541 542
        observer = GetObserverUsingToken (token, tokenLength);
        if(observer)
        {
            observer->forceHighQos = 0;
            observer->failedCommCount = 0;
            result = OC_STACK_OK;
        }
        else
        {
            result = OC_STACK_OBSERVER_NOT_FOUND;
        }
        break;
Mandeep Shetty's avatar
Mandeep Shetty committed
543

544
    case OC_OBSERVER_FAILED_COMM:
545
        OC_LOG(DEBUG, TAG, "observer is unreachable");
546 547 548 549 550
        observer = GetObserverUsingToken (token, tokenLength);
        if(observer)
        {
            if(observer->failedCommCount >= MAX_OBSERVER_FAILED_COMM)
            {
John Light's avatar
John Light committed
551 552 553 554 555
                result = FormOCEntityHandlerRequest(&ehRequest,
                                                    (OCRequestHandle)NULL,
                                                    OC_REST_NOMETHOD,
                                                    &observer->devAddr,
                                                    (OCResourceHandle)NULL,
556 557
                                                    NULL, PAYLOAD_TYPE_REPRESENTATION,
                                                    NULL, 0, 0, NULL,
John Light's avatar
John Light committed
558 559
                                                    OC_OBSERVE_DEREGISTER,
                                                    observer->observeId);
560 561 562 563
                if(result != OC_STACK_OK)
                {
                    return OC_STACK_ERROR;
                }
564 565
                observer->resource->entityHandler(OC_OBSERVE_FLAG, &ehRequest,
                                    observer->resource->entityHandlerCallbackParam);
Mandeep Shetty's avatar
Mandeep Shetty committed
566

567 568 569
                result = DeleteObserverUsingToken (token, tokenLength);
                if(result == OC_STACK_OK)
                {
570
                    OC_LOG(DEBUG, TAG, "Removed observer successfully");
571 572 573 574
                }
                else
                {
                    result = OC_STACK_OK;
575
                    OC_LOG(DEBUG, TAG, "Observer Removal failed");
576 577 578 579 580 581 582 583 584 585 586 587
                }
            }
            else
            {
                observer->failedCommCount++;
                result = OC_STACK_CONTINUE;
            }
            observer->forceHighQos = 1;
            OC_LOG_V(DEBUG, TAG, "Failed count for this observer is %d",observer->failedCommCount);
        }
        break;
    default:
588
        OC_LOG(ERROR, TAG, "Unknown status");
589 590 591 592 593
        result = OC_STACK_ERROR;
        break;
        }
    return result;
}
594
OCStackResult CAToOCStackResult(CAResponseResult_t caCode)
595 596 597
{
    OCStackResult ret = OC_STACK_ERROR;

598
    switch(caCode)
599
    {
600 601 602 603 604 605
        case CA_CREATED:
            ret = OC_STACK_RESOURCE_CREATED;
            break;
        case CA_DELETED:
            ret = OC_STACK_RESOURCE_DELETED;
            break;
606 607 608 609
        case CA_CHANGED:
        case CA_CONTENT:
            ret = OC_STACK_OK;
            break;
610 611 612
        case CA_BAD_REQ:
            ret = OC_STACK_INVALID_QUERY;
            break;
613 614 615
        case CA_UNAUTHORIZED_REQ:
            ret = OC_STACK_UNAUTHORIZED_REQ;
            break;
616 617 618 619 620 621
        case CA_BAD_OPT:
            ret = OC_STACK_INVALID_OPTION;
            break;
        case CA_NOT_FOUND:
            ret = OC_STACK_NO_RESOURCE;
            break;
622 623 624
        case CA_RETRANSMIT_TIMEOUT:
            ret = OC_STACK_COMM_ERROR;
            break;
625 626 627 628 629 630
        default:
            break;
    }
    return ret;
}

631
CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method)
632 633 634 635 636 637
{
    CAResponseResult_t ret = CA_INTERNAL_SERVER_ERROR;

    switch(ocCode)
    {
        case OC_STACK_OK:
638 639
           switch (method)
           {
640
               case OC_REST_PUT:
641 642 643 644 645 646 647 648 649 650 651 652 653 654
               case OC_REST_POST:
                   // This Response Code is like HTTP 204 "No Content" but only used in
                   // response to POST and PUT requests.
                   ret = CA_CHANGED;
                   break;
               case OC_REST_GET:
                   // This Response Code is like HTTP 200 "OK" but only used in response to
                   // GET requests.
                   ret = CA_CONTENT;
                   break;
               default:
                   // This should not happen but,
                   // give it a value just in case but output an error
                   ret = CA_CONTENT;
Habib Virji's avatar
Habib Virji committed
655
                   OC_LOG_V(ERROR, TAG, "Unexpected OC_STACK_OK return code for method [%d].", method);
656
            }
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
            break;
        case OC_STACK_RESOURCE_CREATED:
            ret = CA_CREATED;
            break;
        case OC_STACK_RESOURCE_DELETED:
            ret = CA_DELETED;
            break;
        case OC_STACK_INVALID_QUERY:
            ret = CA_BAD_REQ;
            break;
        case OC_STACK_INVALID_OPTION:
            ret = CA_BAD_OPT;
            break;
        case OC_STACK_NO_RESOURCE:
            ret = CA_NOT_FOUND;
            break;
        case OC_STACK_COMM_ERROR:
            ret = CA_RETRANSMIT_TIMEOUT;
            break;
676 677 678
        case OC_STACK_UNAUTHORIZED_REQ:
            ret = CA_UNAUTHORIZED_REQ;
            break;
679 680 681 682 683 684
        default:
            break;
    }
    return ret;
}

685
CATransportFlags_t OCToCATransportFlags(OCTransportFlags ocFlags)
686
{
687
    CATransportFlags_t caFlags = (CATransportFlags_t)ocFlags;
688

689
    // supply default behavior.
690
    if ((caFlags & (CA_IPV6|CA_IPV4)) == 0)
691
    {
692
        caFlags = (CATransportFlags_t)(caFlags|CA_IPV6|CA_IPV4);
693
    }
694
    if ((caFlags & OC_MASK_SCOPE) == 0)
695
    {
696
        caFlags = (CATransportFlags_t)(caFlags|OC_SCOPE_LINK);
697
    }
698
    return caFlags;
699 700
}

701
OCTransportFlags CAToOCTransportFlags(CATransportFlags_t caFlags)
702
{
703
    return (OCTransportFlags)caFlags;
704
}
Doug Hudson's avatar
Doug Hudson committed
705

Mandeep Shetty's avatar
Mandeep Shetty committed
706 707 708 709 710 711 712 713 714 715
static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds)
{
    uint32_t lowerBound  = 0;
    uint32_t higherBound = 0;

    if (!cbNode || !cbNode->presence || !cbNode->presence->timeOut)
    {
        return OC_STACK_INVALID_PARAM;
    }

716
    OC_LOG_V(INFO, TAG, "Update presence TTL, time is %u", GetTicks(0));
Mandeep Shetty's avatar
Mandeep Shetty committed
717 718 719

    cbNode->presence->TTL = maxAgeSeconds;

720
    for (int index = 0; index < PresenceTimeOutSize; index++)
Mandeep Shetty's avatar
Mandeep Shetty committed
721
    {
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
        // Guard against overflow
        if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index]))
                                     * 100)
        {
            lowerBound = GetTicks((PresenceTimeOut[index] *
                                  cbNode->presence->TTL *
                                  MILLISECONDS_PER_SECOND)/100);
        }
        else
        {
            lowerBound = GetTicks(UINT32_MAX);
        }

        if (cbNode->presence->TTL < (UINT32_MAX/(MILLISECONDS_PER_SECOND*PresenceTimeOut[index+1]))
                                     * 100)
        {
            higherBound = GetTicks((PresenceTimeOut[index + 1] *
                                   cbNode->presence->TTL *
                                   MILLISECONDS_PER_SECOND)/100);
        }
        else
        {
            higherBound = GetTicks(UINT32_MAX);
        }
Mandeep Shetty's avatar
Mandeep Shetty committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759

        cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);

        OC_LOG_V(DEBUG, TAG, "lowerBound timeout  %d", lowerBound);
        OC_LOG_V(DEBUG, TAG, "higherBound timeout %d", higherBound);
        OC_LOG_V(DEBUG, TAG, "timeOut entry  %d", cbNode->presence->timeOut[index]);
    }

    cbNode->presence->TTLlevel = 0;

    OC_LOG_V(DEBUG, TAG, "this TTL level %d", cbNode->presence->TTLlevel);
    return OC_STACK_OK;
}

760
const char *convertTriggerEnumToString(OCPresenceTrigger trigger)
761
{
762
    if (trigger == OC_PRESENCE_TRIGGER_CREATE)
763
    {
764
        return OC_RSRVD_TRIGGER_CREATE;
765
    }
766
    else if (trigger == OC_PRESENCE_TRIGGER_CHANGE)
767
    {
768
        return OC_RSRVD_TRIGGER_CHANGE;
769
    }
770 771 772 773 774
    else
    {
        return OC_RSRVD_TRIGGER_DELETE;
    }
}
775

776 777
OCPresenceTrigger convertTriggerStringToEnum(const char * triggerStr)
{
778 779 780 781 782
    if(!triggerStr)
    {
        return OC_PRESENCE_TRIGGER_CREATE;
    }
    else if(strcmp(triggerStr, OC_RSRVD_TRIGGER_CREATE) == 0)
783
    {
784 785 786 787 788 789 790 791 792
        return OC_PRESENCE_TRIGGER_CREATE;
    }
    else if(strcmp(triggerStr, OC_RSRVD_TRIGGER_CHANGE) == 0)
    {
        return OC_PRESENCE_TRIGGER_CHANGE;
    }
    else
    {
        return OC_PRESENCE_TRIGGER_DELETE;
793
    }
794
}
795

796 797 798 799 800
/**
 * The cononical presence allows constructed URIs to be string compared.
 *
 * requestUri must be a char array of size CA_MAX_URI_LENGTH
 */
801 802
static int FormCanonicalPresenceUri(const CAEndpoint_t *endpoint, char *resourceUri,
        char *presenceUri)
803
{
804
    VERIFY_NON_NULL(endpoint   , FATAL, OC_STACK_INVALID_PARAM);
805 806 807
    VERIFY_NON_NULL(resourceUri, FATAL, OC_STACK_INVALID_PARAM);
    VERIFY_NON_NULL(presenceUri, FATAL, OC_STACK_INVALID_PARAM);

John Light's avatar
John Light committed
808
    CAEndpoint_t *ep = (CAEndpoint_t *)endpoint;
809

John Light's avatar
John Light committed
810
    if (ep->adapter == CA_ADAPTER_IP)
811
    {
Omkar Hegde's avatar
Omkar Hegde committed
812
        if ((ep->flags & CA_IPV6) && !(ep->flags & CA_IPV4))
John Light's avatar
John Light committed
813 814 815 816 817 818 819
        {
            if ('\0' == ep->addr[0])  // multicast
            {
                return snprintf(presenceUri, CA_MAX_URI_LENGTH, OC_RSRVD_PRESENCE_URI);
            }
            else
            {
820 821
                return snprintf(presenceUri, CA_MAX_URI_LENGTH, "coap://[%s]:%u%s",
                        ep->addr, ep->port, OC_RSRVD_PRESENCE_URI);
John Light's avatar
John Light committed
822 823 824 825 826 827 828 829 830
            }
        }
        else
        {
            if ('\0' == ep->addr[0])  // multicast
            {
                OICStrcpy(ep->addr, sizeof(ep->addr), OC_MULTICAST_IP);
                ep->port = OC_MULTICAST_PORT;
            }
831 832
            return snprintf(presenceUri, CA_MAX_URI_LENGTH, "coap://%s:%u%s",
                    ep->addr, ep->port, OC_RSRVD_PRESENCE_URI);
John Light's avatar
John Light committed
833
        }
834 835
    }

John Light's avatar
John Light committed
836
    // might work for other adapters (untested, but better than nothing)
837
    return snprintf(presenceUri, CA_MAX_URI_LENGTH, "coap://%s%s", ep->addr,
John Light's avatar
John Light committed
838
                    OC_RSRVD_PRESENCE_URI);
839 840
}

841

842 843
OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint,
                            const CAResponseInfo_t *responseInfo)
844
{
845 846 847
    VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM);
    VERIFY_NON_NULL(responseInfo, FATAL, OC_STACK_INVALID_PARAM);

848 849 850
    OCStackApplicationResult cbResult = OC_STACK_DELETE_TRANSACTION;
    ClientCB * cbNode = NULL;
    char *resourceTypeName = NULL;
Jon A. Cruz's avatar
Jon A. Cruz committed
851
    OCClientResponse response = {.devAddr = {.adapter = OC_DEFAULT_ADAPTER}};
852 853
    OCStackResult result = OC_STACK_ERROR;
    uint32_t maxAge = 0;
854 855 856
    int uriLen;
    char presenceUri[CA_MAX_URI_LENGTH];

857 858 859
    int presenceSubscribe = 0;
    int multicastPresenceSubscribe = 0;

860
    if (responseInfo->result != CA_CONTENT)
861 862 863 864 865
    {
        OC_LOG_V(ERROR, TAG, "HandlePresenceResponse failed %d", responseInfo->result);
        return OC_STACK_ERROR;
    }

John Light's avatar
John Light committed
866
    // check for unicast presence
867
    uriLen = FormCanonicalPresenceUri(endpoint, OC_RSRVD_PRESENCE_URI, presenceUri);
868
    if (uriLen < 0 || (size_t)uriLen >= sizeof (presenceUri))
869
    {
870
        return OC_STACK_INVALID_URI;
871 872
    }

873 874
    cbNode = GetClientCB(NULL, 0, NULL, presenceUri);
    if (cbNode)
875 876 877 878
    {
        presenceSubscribe = 1;
    }
    else
879
    {
John Light's avatar
John Light committed
880
        // check for multiicast presence
Jon A. Cruz's avatar
Jon A. Cruz committed
881 882
        CAEndpoint_t ep = { .adapter = endpoint->adapter,
                            .flags = endpoint->flags };
883

John Light's avatar
John Light committed
884
        uriLen = FormCanonicalPresenceUri(&ep, OC_RSRVD_PRESENCE_URI, presenceUri);
885

886 887
        cbNode = GetClientCB(NULL, 0, NULL, presenceUri);
        if (cbNode)
888
        {
889
            multicastPresenceSubscribe = 1;
890 891 892
        }
    }

893
    if (!presenceSubscribe && !multicastPresenceSubscribe)
894
    {
895
        OC_LOG(ERROR, TAG, "Received a presence notification, but no callback, ignoring");
896 897
        goto exit;
    }
898

899
    response.payload = NULL;
900
    response.result = OC_STACK_OK;
901

902 903
    CopyEndpointToDevAddr(endpoint, &response.devAddr);
    FixUpClientResponse(&response);
904

905
    if (responseInfo->info.payload)
906
    {
907 908 909
        result = OCParsePayload(&response.payload,
                PAYLOAD_TYPE_PRESENCE,
                responseInfo->info.payload,
910 911
                responseInfo->info.payloadSize);

912
        if(result != OC_STACK_OK)
913
        {
914
            OC_LOG(ERROR, TAG, "Presence parse failed");
915 916
            goto exit;
        }
917 918
        if(!response.payload || response.payload->type != PAYLOAD_TYPE_PRESENCE)
        {
919
            OC_LOG(ERROR, TAG, "Presence payload was wrong type");
920 921 922
            result = OC_STACK_ERROR;
            goto exit;
        }
923 924 925
        response.sequenceNumber = ((OCPresencePayload*)response.payload)->sequenceNumber;
        resourceTypeName = ((OCPresencePayload*)response.payload)->resourceType;
        maxAge = ((OCPresencePayload*)response.payload)->maxAge;
926
    }
927

928
    if (presenceSubscribe)
929
    {
930
        if(cbNode->sequenceNumber == response.sequenceNumber)
931
        {
932
            OC_LOG(INFO, TAG, "No presence change");
933 934
            ResetPresenceTTL(cbNode, maxAge);
            OC_LOG_V(INFO, TAG, "ResetPresenceTTL - TTLlevel:%d\n", cbNode->presence->TTLlevel);
935
            goto exit;
936
        }
937

938
        if(maxAge == 0)
939
        {
940
            OC_LOG(INFO, TAG, "Stopping presence");
941 942 943
            response.result = OC_STACK_PRESENCE_STOPPED;
            if(cbNode->presence)
            {
944 945
                OICFree(cbNode->presence->timeOut);
                OICFree(cbNode->presence);
946
                cbNode->presence = NULL;
947 948
            }
        }
949
        else
950
        {
951 952
            if(!cbNode->presence)
            {
953 954
                cbNode->presence = (OCPresence *)OICMalloc(sizeof (OCPresence));

955 956
                if(!(cbNode->presence))
                {
957
                    OC_LOG(ERROR, TAG, "Could not allocate memory for cbNode->presence");
958 959 960 961 962 963 964
                    result = OC_STACK_NO_MEMORY;
                    goto exit;
                }

                VERIFY_NON_NULL_V(cbNode->presence);
                cbNode->presence->timeOut = NULL;
                cbNode->presence->timeOut = (uint32_t *)
965
                        OICMalloc(PresenceTimeOutSize * sizeof(uint32_t));
966 967
                if(!(cbNode->presence->timeOut)){
                    OC_LOG(ERROR, TAG,
968
                                  "Could not allocate memory for cbNode->presence->timeOut");
969
                    OICFree(cbNode->presence);
970 971 972 973 974
                    result = OC_STACK_NO_MEMORY;
                    goto exit;
                }
            }

Mandeep Shetty's avatar
Mandeep Shetty committed
975
            ResetPresenceTTL(cbNode, maxAge);
976 977 978 979

            cbNode->sequenceNumber = response.sequenceNumber;

            // Ensure that a filter is actually applied.
980
            if( resourceTypeName && cbNode->filterResourceType)
981 982 983 984 985
            {
                if(!findResourceType(cbNode->filterResourceType, resourceTypeName))
                {
                    goto exit;
                }
986 987 988 989
            }
        }
    }
    else
990
    {
991 992
        // This is the multicast case
        OCMulticastNode* mcNode = NULL;
993
        mcNode = GetMCPresenceNode(presenceUri);
994 995 996 997 998

        if(mcNode != NULL)
        {
            if(mcNode->nonce == response.sequenceNumber)
            {
999
                OC_LOG(INFO, TAG, "No presence change (Multicast)");
1000 1001 1002
                goto exit;
            }
            mcNode->nonce = response.sequenceNumber;
1003 1004 1005

            if(maxAge == 0)
            {
1006
                OC_LOG(INFO, TAG, "Stopping presence");
1007 1008
                response.result = OC_STACK_PRESENCE_STOPPED;
            }
1009 1010 1011
        }
        else
        {
1012 1013
            char* uri = OICStrdup(presenceUri);
            if (!uri)
1014
            {
1015
                OC_LOG(INFO, TAG,
1016
                    "No Memory for URI to store in the presence node");
1017 1018 1019
                result = OC_STACK_NO_MEMORY;
                goto exit;
            }
1020

1021
            result = AddMCPresenceNode(&mcNode, uri, response.sequenceNumber);
1022
            if(result == OC_STACK_NO_MEMORY)
1023
            {
1024
                OC_LOG(INFO, TAG,
1025
                    "No Memory for Multicast Presence Node");
1026
                OICFree(uri);
1027 1028
                goto exit;
            }
1029