summaryrefslogtreecommitdiff
path: root/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/private/aws_iot_shadow_internal.h
blob: f3795f3718193bce6d5e61fc5443b77360f71886 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
/*
 * AWS IoT Shadow V2.1.0
 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file aws_iot_shadow_internal.h
 * @brief Internal header of Shadow library. This header should not be included in
 * typical application code.
 */

#ifndef AWS_IOT_SHADOW_INTERNAL_H_
#define AWS_IOT_SHADOW_INTERNAL_H_

/* The config header is always included first. */
#include "iot_config.h"

/* Linear containers (lists and queues) include. */
#include "iot_linear_containers.h"

/* Platform layer types include. */
#include "types/iot_platform_types.h"

/* Shadow include. */
#include "aws_iot_shadow.h"

/* AWS IoT include. */
#include "aws_iot.h"

/**
 * @def AwsIotShadow_Assert( expression )
 * @brief Assertion macro for the Shadow library.
 *
 * Set @ref AWS_IOT_SHADOW_ENABLE_ASSERTS to `1` to enable assertions in the Shadow
 * library.
 *
 * @param[in] expression Expression to be evaluated.
 */
#if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1
    #ifndef AwsIotShadow_Assert
        #ifdef Iot_DefaultAssert
            #define AwsIotShadow_Assert( expression )    Iot_DefaultAssert( expression )
        #else
            #error "Asserts are enabled for Shadow, but AwsIotShadow_Assert is not defined"
        #endif
    #endif
#else /* if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1 */
    #define AwsIotShadow_Assert( expression )
#endif /* if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1 */

/* Configure logs for Shadow functions. */
#ifdef AWS_IOT_LOG_LEVEL_SHADOW
    #define LIBRARY_LOG_LEVEL        AWS_IOT_LOG_LEVEL_SHADOW
#else
    #ifdef IOT_LOG_LEVEL_GLOBAL
        #define LIBRARY_LOG_LEVEL    IOT_LOG_LEVEL_GLOBAL
    #else
        #define LIBRARY_LOG_LEVEL    IOT_LOG_NONE
    #endif
#endif

#define LIBRARY_LOG_NAME    ( "Shadow" )
#include "iot_logging_setup.h"

/*
 * Provide default values for undefined memory allocation functions based on
 * the usage of dynamic memory allocation.
 */
#if IOT_STATIC_MEMORY_ONLY == 1
    #include "iot_static_memory.h"

/**
 * @brief Allocate a #_shadowOperation_t. This function should have the same
 * signature as [malloc]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
 */
    void * AwsIotShadow_MallocOperation( size_t size );

/**
 * @brief Free a #_shadowOperation_t. This function should have the same
 * signature as [free]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
 */
    void AwsIotShadow_FreeOperation( void * ptr );

/**
 * @brief Allocate a buffer for a short string, used for topic names or client
 * tokens. This function should have the same signature as [malloc]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
 */
    #define AwsIotShadow_MallocString    Iot_MallocMessageBuffer

/**
 * @brief Free a string. This function should have the same signature as
 * [free]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
 */
    #define AwsIotShadow_FreeString      Iot_FreeMessageBuffer

/**
 * @brief Allocate a #_shadowSubscription_t. This function should have the
 * same signature as [malloc]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).
 */
    void * AwsIotShadow_MallocSubscription( size_t size );

/**
 * @brief Free a #_shadowSubscription_t. This function should have the same
 * signature as [free]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
 */
    void AwsIotShadow_FreeSubscription( void * ptr );
#else /* if IOT_STATIC_MEMORY_ONLY == 1 */
    #ifndef AwsIotShadow_MallocOperation
        #ifdef Iot_DefaultMalloc
            #define AwsIotShadow_MallocOperation    Iot_DefaultMalloc
        #else
            #error "No malloc function defined for AwsIotShadow_MallocOperation"
        #endif
    #endif

    #ifndef AwsIotShadow_FreeOperation
        #ifdef Iot_DefaultFree
            #define AwsIotShadow_FreeOperation    Iot_DefaultFree
        #else
            #error "No free function defined for AwsIotShadow_FreeOperation"
        #endif
    #endif

    #ifndef AwsIotShadow_MallocString
        #ifdef Iot_DefaultMalloc
            #define AwsIotShadow_MallocString    Iot_DefaultMalloc
        #else
            #error "No malloc function defined for AwsIotShadow_MallocString"
        #endif
    #endif

    #ifndef AwsIotShadow_FreeString
        #ifdef Iot_DefaultFree
            #define AwsIotShadow_FreeString    Iot_DefaultFree
        #else
            #error "No free function defined for AwsIotShadow_FreeString"
        #endif
    #endif

    #ifndef AwsIotShadow_MallocSubscription
        #ifdef Iot_DefaultMalloc
            #define AwsIotShadow_MallocSubscription    Iot_DefaultMalloc
        #else
            #error "No malloc function defined for AwsIotShadow_MallocSubscription"
        #endif
    #endif

    #ifndef AwsIotShadow_FreeSubscription
        #ifdef Iot_DefaultFree
            #define AwsIotShadow_FreeSubscription    Iot_DefaultFree
        #else
            #error "No free function defined for AwsIotShadow_FreeSubscription"
        #endif
    #endif
#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */

/**
 * @cond DOXYGEN_IGNORE
 * Doxygen should ignore this section.
 *
 * Provide default values for undefined configuration constants.
 */
#ifndef AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS
    #define AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS    ( 5000 )
#endif
/** @endcond */

/**
 * @brief The number of currently available Shadow operations.
 *
 * The 3 Shadow operations are DELETE, GET, and UPDATE.
 */
#define SHADOW_OPERATION_COUNT                   ( 3 )

/**
 * @brief The number of currently available Shadow callbacks.
 *
 * The 2 Shadow callbacks are `update/delta` (AKA "Delta") and `/update/documents`
 * (AKA "Updated").
 */
#define SHADOW_CALLBACK_COUNT                    ( 2 )

/**
 * @brief The string representing a Shadow DELETE operation in a Shadow MQTT topic.
 */
#define SHADOW_DELETE_OPERATION_STRING           "/shadow/delete"

/**
 * @brief The length of #SHADOW_DELETE_OPERATION_STRING.
 */
#define SHADOW_DELETE_OPERATION_STRING_LENGTH    ( ( uint16_t ) ( sizeof( SHADOW_DELETE_OPERATION_STRING ) - 1 ) )

/**
 * @brief The string representing a Shadow GET operation in a Shadow MQTT topic.
 */
#define SHADOW_GET_OPERATION_STRING              "/shadow/get"

/**
 * @brief The length of #SHADOW_GET_OPERATION_STRING.
 */
#define SHADOW_GET_OPERATION_STRING_LENGTH       ( ( uint16_t ) ( sizeof( SHADOW_GET_OPERATION_STRING ) - 1 ) )

/**
 * @brief The string representing a Shadow UPDATE operation in a Shadow MQTT topic.
 */
#define SHADOW_UPDATE_OPERATION_STRING           "/shadow/update"

/**
 * @brief The length of #SHADOW_UPDATE_OPERATION_STRING.
 */
#define SHADOW_UPDATE_OPERATION_STRING_LENGTH    ( ( uint16_t ) ( sizeof( SHADOW_UPDATE_OPERATION_STRING ) - 1 ) )

/**
 * @brief The suffix for a Shadow delta topic.
 */
#define SHADOW_DELTA_SUFFIX                      "/delta"

/**
 * @brief The length of #SHADOW_DELTA_SUFFIX.
 */
#define SHADOW_DELTA_SUFFIX_LENGTH               ( ( uint16_t ) ( sizeof( SHADOW_DELTA_SUFFIX ) - 1 ) )

/**
 * @brief The suffix for a Shadow updated topic.
 */
#define SHADOW_UPDATED_SUFFIX                    "/documents"

/**
 * @brief The length of #SHADOW_UPDATED_SUFFIX.
 */
#define SHADOW_UPDATED_SUFFIX_LENGTH             ( ( uint16_t ) ( sizeof( SHADOW_UPDATED_SUFFIX ) - 1 ) )

/**
 * @brief The length of the longest Shadow suffix.
 */
#define SHADOW_LONGEST_SUFFIX_LENGTH             SHADOW_UPDATED_SUFFIX_LENGTH

/**
 * @brief The macro to convert MQTT error codes to Shadow error codes.
 * Below are the conversions happening.
 * IOT_MQTT_SUCCESS to AWS_IOT_SHADOW_SUCCESS
 * IOT_MQTT_NO_MEMORY to AWS_IOT_SHADOW_NO_MEMORY
 * all other error codes to AWS_IOT_SHADOW_MQTT_ERROR
 */
#define SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( X ) \
    ( ( X ) == IOT_MQTT_SUCCESS ) ? AWS_IOT_SHADOW_SUCCESS : \
    ( ( X ) == IOT_MQTT_NO_MEMORY ) ? AWS_IOT_SHADOW_NO_MEMORY : \
    AWS_IOT_SHADOW_MQTT_ERROR

/*----------------------- Shadow internal data types ------------------------*/

/**
 * @brief Enumerations representing each of the Shadow library's API functions.
 */
typedef enum _shadowOperationType
{
    /* Shadow operations. */
    SHADOW_DELETE = 0, /**< @ref shadow_function_deleteasync */
    SHADOW_GET = 1,    /**< @ref shadow_function_getasync */
    SHADOW_UPDATE = 2, /**< @ref shadow_function_updateasync */

    /* Shadow callbacks. */
    SET_DELTA_CALLBACK = 3,  /**< @ref shadow_function_setdeltacallback */
    SET_UPDATED_CALLBACK = 4 /**< @ref shadow_function_setupdatedcallback */
} _shadowOperationType_t;

/**
 * @brief Enumerations representing each of the Shadow callback functions.
 */
typedef enum _shadowCallbackType
{
    DELTA_CALLBACK = 0,  /**< Delta callback. */
    UPDATED_CALLBACK = 1 /**< Updated callback. */
} _shadowCallbackType_t;

/**
 * @brief Represents a Shadow subscriptions object.
 *
 * These structures are stored in a list.
 */
typedef struct _shadowSubscription
{
    IotLink_t link;                                                /**< @brief List link member. */

    int32_t references[ SHADOW_OPERATION_COUNT ];                  /**< @brief Reference counter for Shadow operation topics. */
    AwsIotShadowCallbackInfo_t callbacks[ SHADOW_CALLBACK_COUNT ]; /**< @brief Shadow callbacks for this Thing. */

    /**
     * @brief Buffer allocated for removing Shadow topics.
     *
     * This buffer is pre-allocated to ensure that memory is available when
     * unsubscribing.
     */
    char * pTopicBuffer;

    size_t thingNameLength; /**< @brief Length of Thing Name. */
    char pThingName[];      /**< @brief Thing Name associated with this subscriptions object. */
} _shadowSubscription_t;

/**
 * @brief Internal structure representing a single Shadow operation (DELETE,
 * GET, or UPDATE).
 *
 * A list of these structures keeps track of all in-progress Shadow operations.
 */
typedef struct _shadowOperation
{
    IotLink_t link; /**< @brief List link member. */

    /* Basic operation information. */
    _shadowOperationType_t type;           /**< @brief Operation type. */
    uint32_t flags;                        /**< @brief Flags passed to operation API function. */
    AwsIotShadowError_t status;            /**< @brief Status of operation. */

    IotMqttConnection_t mqttConnection;    /**< @brief MQTT connection associated with this operation. */
    _shadowSubscription_t * pSubscription; /**< @brief Shadow subscriptions object associated with this operation. */

    union
    {
        /* Members valid only for a GET operation. */
        struct
        {
            /**
             * @brief Function to allocate memory for an incoming Shadow document.
             *
             * Only used when the flag #AWS_IOT_SHADOW_FLAG_WAITABLE is set.
             */
            void *( *mallocDocument )( size_t );

            const char * pDocument; /**< @brief Retrieved Shadow document. */
            size_t documentLength;  /**< @brief Length of retrieved Shadow document. */
        } get;

        /* Members valid only for an UPDATE operation. */
        struct
        {
            const char * pClientToken; /**< @brief Client token in update document. */
            size_t clientTokenLength;  /**< @brief Length of client token. */
        } update;
    } u;                               /**< @brief Valid member depends on _shadowOperation_t.type. */

    /* How to notify of an operation's completion. */
    union
    {
        IotSemaphore_t waitSemaphore;        /**< @brief Semaphore to be used with @ref shadow_function_wait. */
        AwsIotShadowCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */
    } notify;                                /**< @brief How to notify of an operation's completion. */
} _shadowOperation_t;

/* Declarations of names printed in logs. */
#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE
    extern const char * const _pAwsIotShadowOperationNames[];
    extern const char * const _pAwsIotShadowCallbackNames[];
#endif

/* Declarations of variables for internal Shadow files. */
extern uint32_t _AwsIotShadowMqttTimeoutMs;
extern IotListDouble_t _AwsIotShadowPendingOperations;
extern IotListDouble_t _AwsIotShadowSubscriptions;
extern IotMutex_t _AwsIotShadowPendingOperationsMutex;
extern IotMutex_t _AwsIotShadowSubscriptionsMutex;

/*----------------------- Shadow operation functions ------------------------*/

/**
 * @brief Create a record for a new in-progress Shadow operation.
 *
 * @param[out] pNewOperation Set to point to the new operation on success.
 * @param[in] operation The type of Shadow operation.
 * @param[in] flags Flags variables passed to a user-facing Shadow function.
 * @param[in] pCallbackInfo User-provided callback function and parameter.
 *
 * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY
 */
AwsIotShadowError_t _AwsIotShadow_CreateOperation( _shadowOperation_t ** pNewOperation,
                                                   _shadowOperationType_t operation,
                                                   uint32_t flags,
                                                   const AwsIotShadowCallbackInfo_t * pCallbackInfo );

/**
 * @brief Free resources used to record a Shadow operation. This is called when
 * the operation completes.
 *
 * @param[in] pData The operation which completed. This parameter is of type
 * `void*` to match the signature of [free]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
 */
void _AwsIotShadow_DestroyOperation( void * pData );

/**
 * @brief Fill a buffer with a Shadow topic.
 *
 * @param[in] type One of: DELETE, GET, UPDATE.
 * @param[in] pThingName Thing Name to place in the topic.
 * @param[in] thingNameLength Length of `pThingName`.
 * @param[out] pTopicBuffer Address of the buffer for the Shadow topic. If the
 * pointer at this address is `NULL`, this function will allocate a new buffer;
 * otherwise, it will use the provided buffer.
 * @param[out] pOperationTopicLength Length of the Shadow operation topic (excluding
 * any suffix) placed in `pTopicBuffer`.
 *
 * @warning This function does not check the length of `pTopicBuffer`! Any provided
 * buffer must be large enough to accommodate the full Shadow topic, plus
 * #SHADOW_LONGEST_SUFFIX_LENGTH.
 *
 * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY. This function
 * will not return #AWS_IOT_SHADOW_NO_MEMORY when a buffer is provided.
 */
AwsIotShadowError_t _AwsIotShadow_GenerateShadowTopic( _shadowOperationType_t type,
                                                       const char * pThingName,
                                                       size_t thingNameLength,
                                                       char ** pTopicBuffer,
                                                       uint16_t * pOperationTopicLength );

/**
 * @brief Process a Shadow operation by sending the necessary MQTT packets.
 *
 * @param[in] mqttConnection The MQTT connection to use.
 * @param[in] pThingName Thing Name for the Shadow operation.
 * @param[in] thingNameLength Length of `pThingName`.
 * @param[in] pOperation Operation data to process.
 * @param[in] pDocumentInfo Information on the Shadow document for GET or UPDATE
 * operations.
 *
 * @return #AWS_IOT_SHADOW_STATUS_PENDING on success. On error, one of
 * #AWS_IOT_SHADOW_NO_MEMORY or #AWS_IOT_SHADOW_MQTT_ERROR.
 */
AwsIotShadowError_t _AwsIotShadow_ProcessOperation( IotMqttConnection_t mqttConnection,
                                                    const char * pThingName,
                                                    size_t thingNameLength,
                                                    _shadowOperation_t * pOperation,
                                                    const AwsIotShadowDocumentInfo_t * pDocumentInfo );

/*---------------------- Shadow subscription functions ----------------------*/

/**
 * @brief Find a Shadow subscription object. May create a new subscription object
 * and adds it to the subscription list if not found.
 *
 * @param[in] pThingName Thing Name in the subscription object.
 * @param[in] thingNameLength Length of `pThingName`.
 * @param[in] createIfNotFound If `true`, attempt to create a new subscription
 * object if no match is found.
 *
 * @return Pointer to a Shadow subscription object, either found or newly
 * allocated. Returns `NULL` if no subscription object is found and a new
 * subscription object could not be allocated.
 *
 * @note This function should be called with the subscription list mutex locked.
 */
_shadowSubscription_t * _AwsIotShadow_FindSubscription( const char * pThingName,
                                                        size_t thingNameLength,
                                                        bool createIfNotFound );

/**
 * @brief Remove a Shadow subscription object from the subscription list if
 * unreferenced.
 *
 * @param[in] pSubscription Subscription object to check. If this object has no
 * active references, it is removed from the subscription list.
 * @param[out] pRemovedSubscription Removed subscription object, if any. Optional;
 * pass `NULL` to ignore. If not `NULL`, this parameter will be set to the removed
 * subscription and that subscription will not be destroyed.
 *
 * @note This function should be called with the subscription list mutex locked.
 */
void _AwsIotShadow_RemoveSubscription( _shadowSubscription_t * pSubscription,
                                       _shadowSubscription_t ** pRemovedSubscription );

/**
 * @brief Free resources used for a Shadow subscription object.
 *
 * @param[in] pData The subscription object to destroy. This parameter is of type
 * `void*` to match the signature of [free]
 * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).
 */
void _AwsIotShadow_DestroySubscription( void * pData );

/**
 * @brief Increment the reference count of a Shadow subscriptions object.
 *
 * Also adds MQTT subscriptions if necessary.
 *
 * @param[in] pOperation The operation for which the reference count should be
 * incremented.
 * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if
 * subscriptions need to be added.
 * @param[in] operationTopicLength The length of the operation topic in `pTopicBuffer`.
 * @param[in] callback MQTT callback function for when this operation completes.
 *
 * @warning This function does not check the length of `pTopicBuffer`! Any provided
 * buffer must already contain the Shadow operation topic, plus enough space for the
 * status suffix.
 *
 * @return #AWS_IOT_SHADOW_SUCCESS on success. On error, one of
 * #AWS_IOT_SHADOW_NO_MEMORY or #AWS_IOT_SHADOW_MQTT_ERROR.
 *
 * @note This function should be called with the subscription list mutex locked.
 */
AwsIotShadowError_t _AwsIotShadow_IncrementReferences( _shadowOperation_t * pOperation,
                                                       char * pTopicBuffer,
                                                       uint16_t operationTopicLength,
                                                       AwsIotMqttCallbackFunction_t callback );

/**
 * @brief Decrement the reference count of a Shadow subscriptions object.
 *
 * Also removed MQTT subscriptions and deletes the subscription object if necessary.
 *
 * @param[in] pOperation The operation for which the reference count should be
 * decremented.
 * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if
 * subscriptions need to be removed.
 * @param[out] pRemovedSubscription Set to point to a removed subscription.
 * Optional; pass `NULL` to ignore. If not `NULL`, this function will not destroy
 * a removed subscription.
 *
 * @warning This function does not check the length of `pTopicBuffer`! Any provided
 * buffer must be large enough to accommodate the full Shadow topic, plus
 * #SHADOW_LONGEST_SUFFIX_LENGTH.
 *
 * @note This function should be called with the subscription list mutex locked.
 */
void _AwsIotShadow_DecrementReferences( _shadowOperation_t * pOperation,
                                        char * pTopicBuffer,
                                        _shadowSubscription_t ** pRemovedSubscription );

/*------------------------- Shadow parser functions -------------------------*/

/**
 * @brief Parse a Shadow error document.
 *
 * @param[in] pErrorDocument The error document to parse.
 * @param[in] errorDocumentLength The length of `pErrorDocument`.
 *
 * @return One of the #AwsIotShadowError_t ranging from 400 to 500 on success.
 * #AWS_IOT_SHADOW_BAD_RESPONSE on error.
 */
AwsIotShadowError_t _AwsIotShadow_ParseErrorDocument( const char * pErrorDocument,
                                                      size_t errorDocumentLength );

#endif /* ifndef AWS_IOT_SHADOW_INTERNAL_H_ */