]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_subscription.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-IoT-Libraries / c_sdk / aws / jobs / src / aws_iot_jobs_subscription.c
1 /*\r
2  * AWS IoT Jobs V1.0.0\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  */\r
22 \r
23 /**\r
24  * @file aws_iot_jobs_subscription.c\r
25  * @brief Implements functions for interacting with the Jobs library's\r
26  * subscription list.\r
27  */\r
28 \r
29 /* The config header is always included first. */\r
30 #include "iot_config.h"\r
31 \r
32 /* Standard includes. */\r
33 #include <string.h>\r
34 \r
35 /* Jobs internal include. */\r
36 #include "private/aws_iot_jobs_internal.h"\r
37 \r
38 /* Error handling include. */\r
39 #include "iot_error.h"\r
40 \r
41 /* Platform layer includes. */\r
42 #include "platform/iot_threads.h"\r
43 \r
44 /* MQTT include. */\r
45 #include "iot_mqtt.h"\r
46 \r
47 /*-----------------------------------------------------------*/\r
48 \r
49 /**\r
50  * @brief Match two #_jobsSubscription_t by Thing Name.\r
51  *\r
52  * @param[in] pSubscriptionLink Pointer to the link member of a #_jobsSubscription_t\r
53  * containing the Thing Name to check.\r
54  * @param[in] pMatch Pointer to a `AwsIotThingName_t`.\r
55  *\r
56  * @return `true` if the Thing Names match; `false` otherwise.\r
57  */\r
58 static bool _jobsSubscription_match( const IotLink_t * pSubscriptionLink,\r
59                                      void * pMatch );\r
60 \r
61 /*-----------------------------------------------------------*/\r
62 \r
63 /**\r
64  * @brief List of active Jobs subscriptions objects.\r
65  */\r
66 IotListDouble_t _AwsIotJobsSubscriptions = { 0 };\r
67 \r
68 /**\r
69  * @brief Protects #_AwsIotJobsSubscriptions from concurrent access.\r
70  */\r
71 IotMutex_t _AwsIotJobsSubscriptionsMutex;\r
72 \r
73 /*-----------------------------------------------------------*/\r
74 \r
75 static bool _jobsSubscription_match( const IotLink_t * pSubscriptionLink,\r
76                                      void * pMatch )\r
77 {\r
78     bool match = false;\r
79 \r
80     /* Because this function is called from a container function, the given link\r
81      * must never be NULL. */\r
82     AwsIotJobs_Assert( pSubscriptionLink != NULL );\r
83 \r
84     const _jobsSubscription_t * pSubscription = IotLink_Container( _jobsSubscription_t,\r
85                                                                    pSubscriptionLink,\r
86                                                                    link );\r
87     const AwsIotThingName_t * pThingName = ( AwsIotThingName_t * ) pMatch;\r
88 \r
89     if( pThingName->thingNameLength == pSubscription->thingNameLength )\r
90     {\r
91         /* Check for matching Thing Names. */\r
92         match = ( strncmp( pThingName->pThingName,\r
93                            pSubscription->pThingName,\r
94                            pThingName->thingNameLength ) == 0 );\r
95     }\r
96 \r
97     return match;\r
98 }\r
99 \r
100 /*-----------------------------------------------------------*/\r
101 \r
102 _jobsSubscription_t * _AwsIotJobs_FindSubscription( const char * pThingName,\r
103                                                     size_t thingNameLength,\r
104                                                     bool createIfNotFound )\r
105 {\r
106     _jobsSubscription_t * pSubscription = NULL;\r
107     IotLink_t * pSubscriptionLink = NULL;\r
108     AwsIotThingName_t thingName = { 0 };\r
109 \r
110     thingName.pThingName = pThingName;\r
111     thingName.thingNameLength = thingNameLength;\r
112 \r
113     /* Search the list for an existing subscription for Thing Name. */\r
114     pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotJobsSubscriptions ),\r
115                                                       NULL,\r
116                                                       _jobsSubscription_match,\r
117                                                       &thingName );\r
118 \r
119     /* Check if a subscription was found. */\r
120     if( pSubscriptionLink == NULL )\r
121     {\r
122         if( createIfNotFound == true )\r
123         {\r
124             /* No subscription found. Allocate a new subscription. */\r
125             pSubscription = AwsIotJobs_MallocSubscription( sizeof( _jobsSubscription_t ) + thingNameLength );\r
126 \r
127             if( pSubscription != NULL )\r
128             {\r
129                 /* Clear the new subscription. */\r
130                 ( void ) memset( pSubscription, 0x00, sizeof( _jobsSubscription_t ) + thingNameLength );\r
131 \r
132                 /* Set the Thing Name length and copy the Thing Name into the new subscription. */\r
133                 pSubscription->thingNameLength = thingNameLength;\r
134                 ( void ) memcpy( pSubscription->pThingName, pThingName, thingNameLength );\r
135 \r
136                 /* Add the new subscription to the subscription list. */\r
137                 IotListDouble_InsertHead( &( _AwsIotJobsSubscriptions ),\r
138                                           &( pSubscription->link ) );\r
139 \r
140                 IotLogDebug( "Created new Jobs subscriptions object for %.*s.",\r
141                              thingNameLength,\r
142                              pThingName );\r
143             }\r
144             else\r
145             {\r
146                 IotLogError( "Failed to allocate memory for %.*s Jobs subscriptions.",\r
147                              thingNameLength,\r
148                              pThingName );\r
149             }\r
150         }\r
151     }\r
152     else\r
153     {\r
154         IotLogDebug( "Found existing Jobs subscriptions object for %.*s.",\r
155                      thingNameLength,\r
156                      pThingName );\r
157 \r
158         pSubscription = IotLink_Container( _jobsSubscription_t, pSubscriptionLink, link );\r
159     }\r
160 \r
161     return pSubscription;\r
162 }\r
163 \r
164 /*-----------------------------------------------------------*/\r
165 \r
166 void _AwsIotJobs_RemoveSubscription( _jobsSubscription_t * pSubscription,\r
167                                      _jobsSubscription_t ** pRemovedSubscription )\r
168 {\r
169     IOT_FUNCTION_ENTRY( bool, true );\r
170     int32_t i = 0, callbackIndex = 0;\r
171 \r
172     IotLogDebug( "Checking if subscription object for %.*s can be removed.",\r
173                  pSubscription->thingNameLength,\r
174                  pSubscription->pThingName );\r
175 \r
176     /* Check for active operations. If any Jobs operation's subscription\r
177      * reference count is not 0, then the subscription cannot be removed. */\r
178     for( i = 0; i < JOBS_OPERATION_COUNT; i++ )\r
179     {\r
180         if( pSubscription->operationReferences[ i ] > 0 )\r
181         {\r
182             IotLogDebug( "Reference count %ld for %.*s subscription object. "\r
183                          "Subscription cannot be removed yet.",\r
184                          ( long int ) pSubscription->operationReferences[ i ],\r
185                          pSubscription->thingNameLength,\r
186                          pSubscription->pThingName );\r
187 \r
188             IOT_SET_AND_GOTO_CLEANUP( false );\r
189         }\r
190         else if( pSubscription->operationReferences[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION )\r
191         {\r
192             IotLogDebug( "Subscription object for %.*s has persistent subscriptions. "\r
193                          "Subscription will not be removed.",\r
194                          pSubscription->thingNameLength,\r
195                          pSubscription->pThingName );\r
196 \r
197             IOT_SET_AND_GOTO_CLEANUP( false );\r
198         }\r
199     }\r
200 \r
201     /* Check for active subscriptions. If any Jobs callbacks are active, then the\r
202      * subscription cannot be removed. */\r
203     if( pSubscription->callbackReferences > 0 )\r
204     {\r
205         IotLogDebug( "Notify callbacks are using %.*s subscription object. "\r
206                      "Subscription cannot be removed yet.",\r
207                      pSubscription->thingNameLength,\r
208                      pSubscription->pThingName );\r
209 \r
210         IOT_SET_AND_GOTO_CLEANUP( false );\r
211     }\r
212 \r
213     for( i = 0; i < JOBS_CALLBACK_COUNT; i++ )\r
214     {\r
215         for( callbackIndex = 0; callbackIndex < AWS_IOT_JOBS_NOTIFY_CALLBACKS; callbackIndex++ )\r
216         {\r
217             if( pSubscription->callbacks[ i ][ callbackIndex ].function != NULL )\r
218             {\r
219                 IotLogDebug( "Found active Jobs %s callback for %.*s subscription object. "\r
220                              "Subscription cannot be removed yet.",\r
221                              _pAwsIotJobsCallbackNames[ i ],\r
222                              pSubscription->thingNameLength,\r
223                              pSubscription->pThingName );\r
224 \r
225                 IOT_SET_AND_GOTO_CLEANUP( false );\r
226             }\r
227         }\r
228     }\r
229 \r
230     /* Remove the subscription if unused. */\r
231     IOT_FUNCTION_CLEANUP_BEGIN();\r
232 \r
233     if( status == true )\r
234     {\r
235         /* No Jobs operation subscription references or active Jobs callbacks.\r
236          * Remove the subscription object. */\r
237         IotListDouble_Remove( &( pSubscription->link ) );\r
238 \r
239         IotLogDebug( "Removed subscription object for %.*s.",\r
240                      pSubscription->thingNameLength,\r
241                      pSubscription->pThingName );\r
242 \r
243         /* If the caller requested the removed subscription, set the output parameter.\r
244          * Otherwise, free the memory used by the subscription. */\r
245         if( pRemovedSubscription != NULL )\r
246         {\r
247             *pRemovedSubscription = pSubscription;\r
248         }\r
249         else\r
250         {\r
251             _AwsIotJobs_DestroySubscription( pSubscription );\r
252         }\r
253     }\r
254 }\r
255 \r
256 /*-----------------------------------------------------------*/\r
257 \r
258 void _AwsIotJobs_DestroySubscription( void * pData )\r
259 {\r
260     _jobsSubscription_t * pSubscription = ( _jobsSubscription_t * ) pData;\r
261 \r
262     /* Free the topic buffer if allocated. */\r
263     if( pSubscription->pTopicBuffer != NULL )\r
264     {\r
265         AwsIotJobs_FreeString( pSubscription->pTopicBuffer );\r
266     }\r
267 \r
268     /* Free memory used by subscription. */\r
269     AwsIotJobs_FreeSubscription( pSubscription );\r
270 }\r
271 \r
272 /*-----------------------------------------------------------*/\r
273 \r
274 AwsIotJobsError_t _AwsIotJobs_IncrementReferences( _jobsOperation_t * pOperation,\r
275                                                    char * pTopicBuffer,\r
276                                                    uint16_t operationTopicLength,\r
277                                                    AwsIotMqttCallbackFunction_t callback )\r
278 {\r
279     IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS );\r
280     const _jobsOperationType_t type = pOperation->type;\r
281     _jobsSubscription_t * pSubscription = pOperation->pSubscription;\r
282     IotMqttError_t subscriptionStatus = IOT_MQTT_STATUS_PENDING;\r
283     AwsIotSubscriptionInfo_t subscriptionInfo = { 0 };\r
284 \r
285     /* Do nothing if this operation has persistent subscriptions. */\r
286     if( pSubscription->operationReferences[ type ] == AWS_IOT_PERSISTENT_SUBSCRIPTION )\r
287     {\r
288         IotLogDebug( "Jobs %s for %.*s has persistent subscriptions. Reference "\r
289                      "count will not be incremented.",\r
290                      _pAwsIotJobsOperationNames[ type ],\r
291                      pSubscription->thingNameLength,\r
292                      pSubscription->pThingName );\r
293 \r
294         IOT_GOTO_CLEANUP();\r
295     }\r
296 \r
297     /* When persistent subscriptions are not present, the reference count must\r
298      * not be negative. */\r
299     AwsIotJobs_Assert( pSubscription->operationReferences[ type ] >= 0 );\r
300 \r
301     /* Check if there are any existing references for this operation. */\r
302     if( pSubscription->operationReferences[ type ] == 0 )\r
303     {\r
304         /* Set the parameters needed to add subscriptions. */\r
305         subscriptionInfo.mqttConnection = pOperation->mqttConnection;\r
306         subscriptionInfo.callbackFunction = callback;\r
307         subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs;\r
308         subscriptionInfo.pTopicFilterBase = pTopicBuffer;\r
309         subscriptionInfo.topicFilterBaseLength = operationTopicLength;\r
310 \r
311         subscriptionStatus = AwsIot_ModifySubscriptions( IotMqtt_SubscribeSync,\r
312                                                          &subscriptionInfo );\r
313 \r
314         /* Convert MQTT return code to Jobs return code. */\r
315         switch( subscriptionStatus )\r
316         {\r
317             case IOT_MQTT_SUCCESS:\r
318                 status = AWS_IOT_JOBS_SUCCESS;\r
319                 break;\r
320 \r
321             case IOT_MQTT_NO_MEMORY:\r
322                 status = AWS_IOT_JOBS_NO_MEMORY;\r
323                 break;\r
324 \r
325             default:\r
326                 status = AWS_IOT_JOBS_MQTT_ERROR;\r
327                 break;\r
328         }\r
329 \r
330         if( status != AWS_IOT_JOBS_SUCCESS )\r
331         {\r
332             IOT_GOTO_CLEANUP();\r
333         }\r
334     }\r
335 \r
336     /* Increment the number of subscription references for this operation when\r
337      * the keep subscriptions flag is not set. */\r
338     if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS ) == 0 )\r
339     {\r
340         ( pSubscription->operationReferences[ type ] )++;\r
341 \r
342         IotLogDebug( "Jobs %s subscriptions for %.*s now has count %d.",\r
343                      _pAwsIotJobsOperationNames[ type ],\r
344                      pSubscription->thingNameLength,\r
345                      pSubscription->pThingName,\r
346                      pSubscription->operationReferences[ type ] );\r
347     }\r
348     /* Otherwise, set the persistent subscriptions flag. */\r
349     else\r
350     {\r
351         pSubscription->operationReferences[ type ] = AWS_IOT_PERSISTENT_SUBSCRIPTION;\r
352 \r
353         IotLogDebug( "Set persistent subscriptions flag for Jobs %s of %.*s.",\r
354                      _pAwsIotJobsOperationNames[ type ],\r
355                      pSubscription->thingNameLength,\r
356                      pSubscription->pThingName );\r
357     }\r
358 \r
359     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
360 }\r
361 \r
362 /*-----------------------------------------------------------*/\r
363 \r
364 void _AwsIotJobs_DecrementReferences( _jobsOperation_t * pOperation,\r
365                                       char * pTopicBuffer,\r
366                                       _jobsSubscription_t ** pRemovedSubscription )\r
367 {\r
368     const _jobsOperationType_t type = pOperation->type;\r
369     _jobsSubscription_t * pSubscription = pOperation->pSubscription;\r
370     uint16_t operationTopicLength = 0;\r
371     AwsIotSubscriptionInfo_t subscriptionInfo = { 0 };\r
372     AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER;\r
373 \r
374     /* Do nothing if this Jobs operation has persistent subscriptions. */\r
375     if( pSubscription->operationReferences[ type ] != AWS_IOT_PERSISTENT_SUBSCRIPTION )\r
376     {\r
377         /* Decrement the number of subscription references for this operation.\r
378          * Ensure that it's positive. */\r
379         ( pSubscription->operationReferences[ type ] )--;\r
380         AwsIotJobs_Assert( pSubscription->operationReferences[ type ] >= 0 );\r
381 \r
382         /* Check if the number of references has reached 0. */\r
383         if( pSubscription->operationReferences[ type ] == 0 )\r
384         {\r
385             IotLogDebug( "Reference count for %.*s %s is 0. Unsubscribing.",\r
386                          pSubscription->thingNameLength,\r
387                          pSubscription->pThingName,\r
388                          _pAwsIotJobsOperationNames[ type ] );\r
389 \r
390             /* Subscription must have a topic buffer. */\r
391             AwsIotJobs_Assert( pSubscription->pTopicBuffer != NULL );\r
392 \r
393             /* Set the parameters needed to generate a Jobs topic. */\r
394             requestInfo.pThingName = pSubscription->pThingName;\r
395             requestInfo.thingNameLength = pSubscription->thingNameLength;\r
396             requestInfo.pJobId = pOperation->pJobId;\r
397             requestInfo.jobIdLength = pOperation->jobIdLength;\r
398 \r
399             /* Generate the prefix of the Jobs topic. This function will not\r
400              * fail when given a buffer. */\r
401             ( void ) _AwsIotJobs_GenerateJobsTopic( ( _jobsOperationType_t ) type,\r
402                                                     &requestInfo,\r
403                                                     &( pSubscription->pTopicBuffer ),\r
404                                                     &operationTopicLength );\r
405 \r
406             /* Set the parameters needed to remove subscriptions. */\r
407             subscriptionInfo.mqttConnection = pOperation->mqttConnection;\r
408             subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs;\r
409             subscriptionInfo.pTopicFilterBase = pTopicBuffer;\r
410             subscriptionInfo.topicFilterBaseLength = operationTopicLength;\r
411 \r
412             ( void ) AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync,\r
413                                                  &subscriptionInfo );\r
414         }\r
415 \r
416         /* Check if this subscription should be deleted. */\r
417         _AwsIotJobs_RemoveSubscription( pSubscription,\r
418                                         pRemovedSubscription );\r
419     }\r
420     else\r
421     {\r
422         IotLogDebug( "Jobs %s for %.*s has persistent subscriptions. Reference "\r
423                      "count will not be decremented.",\r
424                      _pAwsIotJobsOperationNames[ type ],\r
425                      pSubscription->thingNameLength,\r
426                      pSubscription->pThingName );\r
427     }\r
428 }\r
429 \r
430 /*-----------------------------------------------------------*/\r
431 \r
432 AwsIotJobsError_t AwsIotJobs_RemovePersistentSubscriptions( const AwsIotJobsRequestInfo_t * pRequestInfo,\r
433                                                             uint32_t flags )\r
434 {\r
435     IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS );\r
436     int32_t i = 0;\r
437     uint16_t operationTopicLength = 0;\r
438     IotMqttError_t unsubscribeStatus = IOT_MQTT_STATUS_PENDING;\r
439     AwsIotSubscriptionInfo_t subscriptionInfo = { 0 };\r
440     _jobsSubscription_t * pSubscription = NULL;\r
441     IotLink_t * pSubscriptionLink = NULL;\r
442     AwsIotThingName_t thingName = { 0 };\r
443 \r
444     thingName.pThingName = pRequestInfo->pThingName;\r
445     thingName.thingNameLength = pRequestInfo->thingNameLength;\r
446 \r
447     IotLogInfo( "Removing persistent subscriptions for %.*s.",\r
448                 pRequestInfo->thingNameLength,\r
449                 pRequestInfo->pThingName );\r
450 \r
451     /* Check parameters. */\r
452     if( pRequestInfo->mqttConnection == IOT_MQTT_CONNECTION_INITIALIZER )\r
453     {\r
454         IotLogError( "MQTT connection is not initialized." );\r
455 \r
456         IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER );\r
457     }\r
458 \r
459     if( AwsIot_ValidateThingName( pRequestInfo->pThingName,\r
460                                   pRequestInfo->thingNameLength ) == false )\r
461     {\r
462         IotLogError( "Thing Name is not valid." );\r
463 \r
464         IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER );\r
465     }\r
466 \r
467     if( ( ( flags & AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS ) != 0 ) ||\r
468         ( ( flags & AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS ) != 0 ) )\r
469     {\r
470         if( ( pRequestInfo->pJobId == NULL ) || ( pRequestInfo->jobIdLength == 0 ) )\r
471         {\r
472             IotLogError( "Job ID must be set." );\r
473 \r
474             IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER );\r
475         }\r
476 \r
477         if( pRequestInfo->jobIdLength > JOBS_MAX_ID_LENGTH )\r
478         {\r
479             IotLogError( "Job ID cannot be longer than %d.",\r
480                          JOBS_MAX_ID_LENGTH );\r
481 \r
482             IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER );\r
483         }\r
484     }\r
485 \r
486     IotMutex_Lock( &( _AwsIotJobsSubscriptionsMutex ) );\r
487 \r
488     /* Search the list for an existing subscription for Thing Name. */\r
489     pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotJobsSubscriptions ),\r
490                                                       NULL,\r
491                                                       _jobsSubscription_match,\r
492                                                       &thingName );\r
493 \r
494     if( pSubscriptionLink != NULL )\r
495     {\r
496         IotLogDebug( "Found subscription object for %.*s. Checking for persistent "\r
497                      "subscriptions to remove.",\r
498                      pRequestInfo->thingNameLength,\r
499                      pRequestInfo->pThingName );\r
500 \r
501         pSubscription = IotLink_Container( _jobsSubscription_t, pSubscriptionLink, link );\r
502 \r
503         for( i = 0; i < JOBS_OPERATION_COUNT; i++ )\r
504         {\r
505             if( ( flags & ( 0x1UL << i ) ) != 0 )\r
506             {\r
507                 IotLogDebug( "Removing %.*s %s persistent subscriptions.",\r
508                              pRequestInfo->thingNameLength,\r
509                              pRequestInfo->pThingName,\r
510                              _pAwsIotJobsOperationNames[ i ] );\r
511 \r
512                 /* Subscription must have a topic buffer. */\r
513                 AwsIotJobs_Assert( pSubscription->pTopicBuffer != NULL );\r
514 \r
515                 if( pSubscription->operationReferences[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION )\r
516                 {\r
517                     /* Generate the prefix of the Jobs topic. This function will not\r
518                      * fail when given a buffer. */\r
519                     ( void ) _AwsIotJobs_GenerateJobsTopic( ( _jobsOperationType_t ) i,\r
520                                                             pRequestInfo,\r
521                                                             &( pSubscription->pTopicBuffer ),\r
522                                                             &operationTopicLength );\r
523 \r
524                     /* Set the parameters needed to remove subscriptions. */\r
525                     subscriptionInfo.mqttConnection = pRequestInfo->mqttConnection;\r
526                     subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs;\r
527                     subscriptionInfo.pTopicFilterBase = pSubscription->pTopicBuffer;\r
528                     subscriptionInfo.topicFilterBaseLength = operationTopicLength;\r
529 \r
530                     unsubscribeStatus = AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync,\r
531                                                                     &subscriptionInfo );\r
532 \r
533                     /* Convert MQTT return code to Shadow return code. */\r
534                     switch( unsubscribeStatus )\r
535                     {\r
536                         case IOT_MQTT_SUCCESS:\r
537                             status = AWS_IOT_JOBS_SUCCESS;\r
538                             break;\r
539 \r
540                         case IOT_MQTT_NO_MEMORY:\r
541                             status = AWS_IOT_JOBS_NO_MEMORY;\r
542                             break;\r
543 \r
544                         default:\r
545                             status = AWS_IOT_JOBS_MQTT_ERROR;\r
546                             break;\r
547                     }\r
548 \r
549                     if( status != AWS_IOT_JOBS_SUCCESS )\r
550                     {\r
551                         break;\r
552                     }\r
553 \r
554                     /* Clear the persistent subscriptions flag and check if the\r
555                      * subscription can be removed. */\r
556                     pSubscription->operationReferences[ i ] = 0;\r
557                     _AwsIotJobs_RemoveSubscription( pSubscription, NULL );\r
558                 }\r
559                 else\r
560                 {\r
561                     IotLogDebug( "%.*s %s does not have persistent subscriptions.",\r
562                                  pRequestInfo->thingNameLength,\r
563                                  pRequestInfo->pThingName,\r
564                                  _pAwsIotJobsOperationNames[ i ] );\r
565                 }\r
566             }\r
567         }\r
568     }\r
569     else\r
570     {\r
571         IotLogWarn( "No subscription object found for %.*s",\r
572                     pRequestInfo->thingNameLength,\r
573                     pRequestInfo->pThingName );\r
574     }\r
575 \r
576     IotMutex_Unlock( &( _AwsIotJobsSubscriptionsMutex ) );\r
577 \r
578     IOT_FUNCTION_EXIT_NO_CLEANUP();\r
579 }\r
580 \r
581 /*-----------------------------------------------------------*/\r