2 * Amazon FreeRTOS MQTT V2.0.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file iot_mqtt_validate.c
\r
28 * @brief Implements functions that validate the structs of the MQTT library.
\r
31 /* The config header is always included first. */
\r
32 #include "iot_config.h"
\r
34 /* Error handling include. */
\r
35 #include "private/iot_error.h"
\r
37 /* MQTT internal include. */
\r
38 #include "private/iot_mqtt_internal.h"
\r
40 /*-----------------------------------------------------------*/
\r
42 bool _IotMqtt_ValidateConnect( const IotMqttConnectInfo_t * pConnectInfo )
\r
44 IOT_FUNCTION_ENTRY( bool, true );
\r
46 /* Check for NULL. */
\r
47 if( pConnectInfo == NULL )
\r
49 IotLogError( "MQTT connection information cannot be NULL." );
\r
51 IOT_SET_AND_GOTO_CLEANUP( false );
\r
58 /* Check that a client identifier was set. */
\r
59 if( pConnectInfo->pClientIdentifier == NULL )
\r
61 IotLogError( "Client identifier must be set." );
\r
63 IOT_SET_AND_GOTO_CLEANUP( false );
\r
70 /* Check for a zero-length client identifier. Zero-length client identifiers
\r
71 * are not allowed with clean sessions. */
\r
72 if( pConnectInfo->clientIdentifierLength == 0 )
\r
74 IotLogWarn( "A zero-length client identifier was provided." );
\r
76 if( pConnectInfo->cleanSession == true )
\r
78 IotLogError( "A zero-length client identifier cannot be used with a clean session." );
\r
80 IOT_SET_AND_GOTO_CLEANUP( false );
\r
92 /* Check that the number of persistent session subscriptions is valid. */
\r
93 if( pConnectInfo->cleanSession == false )
\r
95 if( pConnectInfo->pPreviousSubscriptions != NULL )
\r
97 if( pConnectInfo->previousSubscriptionCount == 0 )
\r
99 IotLogError( "Previous subscription count cannot be 0." );
\r
101 IOT_SET_AND_GOTO_CLEANUP( false );
\r
118 /* In MQTT 3.1.1, servers are not obligated to accept client identifiers longer
\r
119 * than 23 characters. */
\r
120 if( pConnectInfo->clientIdentifierLength > 23 )
\r
122 IotLogWarn( "A client identifier length of %hu is longer than 23, which is "
\r
123 "the longest client identifier a server must accept.",
\r
124 pConnectInfo->clientIdentifierLength );
\r
131 /* Check for compatibility with the AWS IoT MQTT service limits. */
\r
132 if( pConnectInfo->awsIotMqttMode == true )
\r
134 /* Check that client identifier is within the service limit. */
\r
135 if( pConnectInfo->clientIdentifierLength > AWS_IOT_MQTT_SERVER_MAX_CLIENTID )
\r
137 IotLogError( "AWS IoT does not support client identifiers longer than %d bytes.",
\r
138 AWS_IOT_MQTT_SERVER_MAX_CLIENTID );
\r
140 IOT_SET_AND_GOTO_CLEANUP( false );
\r
147 /* Check for compliance with AWS IoT keep-alive limits. */
\r
148 if( pConnectInfo->keepAliveSeconds == 0 )
\r
150 IotLogWarn( "AWS IoT does not support disabling keep-alive. Default keep-alive "
\r
151 "of %d seconds will be used.",
\r
152 AWS_IOT_MQTT_SERVER_MAX_KEEPALIVE );
\r
154 else if( pConnectInfo->keepAliveSeconds < AWS_IOT_MQTT_SERVER_MIN_KEEPALIVE )
\r
156 IotLogWarn( "AWS IoT does not support keep-alive intervals less than %d seconds. "
\r
157 "An interval of %d seconds will be used.",
\r
158 AWS_IOT_MQTT_SERVER_MIN_KEEPALIVE,
\r
159 AWS_IOT_MQTT_SERVER_MIN_KEEPALIVE );
\r
161 else if( pConnectInfo->keepAliveSeconds > AWS_IOT_MQTT_SERVER_MAX_KEEPALIVE )
\r
163 IotLogWarn( "AWS IoT does not support keep-alive intervals greater than %d seconds. "
\r
164 "An interval of %d seconds will be used.",
\r
165 AWS_IOT_MQTT_SERVER_MAX_KEEPALIVE,
\r
166 AWS_IOT_MQTT_SERVER_MAX_KEEPALIVE );
\r
178 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
181 /*-----------------------------------------------------------*/
\r
183 bool _IotMqtt_ValidatePublish( bool awsIotMqttMode,
\r
184 const IotMqttPublishInfo_t * pPublishInfo )
\r
186 IOT_FUNCTION_ENTRY( bool, true );
\r
188 /* Check for NULL. */
\r
189 if( pPublishInfo == NULL )
\r
191 IotLogError( "Publish information cannot be NULL." );
\r
193 IOT_SET_AND_GOTO_CLEANUP( false );
\r
200 /* Check topic name for NULL or zero-length. */
\r
201 if( pPublishInfo->pTopicName == NULL )
\r
203 IotLogError( "Publish topic name must be set." );
\r
210 if( pPublishInfo->topicNameLength == 0 )
\r
212 IotLogError( "Publish topic name length cannot be 0." );
\r
214 IOT_SET_AND_GOTO_CLEANUP( false );
\r
221 /* Only allow NULL payloads with zero length. */
\r
222 if( pPublishInfo->pPayload == NULL )
\r
224 if( pPublishInfo->payloadLength != 0 )
\r
226 IotLogError( "Nonzero payload length cannot have a NULL payload." );
\r
228 IOT_SET_AND_GOTO_CLEANUP( false );
\r
240 /* Check for a valid QoS. */
\r
241 if( pPublishInfo->qos != IOT_MQTT_QOS_0 )
\r
243 if( pPublishInfo->qos != IOT_MQTT_QOS_1 )
\r
245 IotLogError( "Publish QoS must be either 0 or 1." );
\r
247 IOT_SET_AND_GOTO_CLEANUP( false );
\r
259 /* Check the retry parameters. */
\r
260 if( pPublishInfo->retryLimit > 0 )
\r
262 if( pPublishInfo->retryMs == 0 )
\r
264 IotLogError( "Publish retry time must be positive." );
\r
266 IOT_SET_AND_GOTO_CLEANUP( false );
\r
278 /* Check for compatibility with AWS IoT MQTT server. */
\r
279 if( awsIotMqttMode == true )
\r
281 /* Check for retained message. */
\r
282 if( pPublishInfo->retain == true )
\r
284 IotLogError( "AWS IoT does not support retained publish messages." );
\r
286 IOT_SET_AND_GOTO_CLEANUP( false );
\r
293 /* Check topic name length. */
\r
294 if( pPublishInfo->topicNameLength > AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH )
\r
296 IotLogError( "AWS IoT does not support topic names longer than %d bytes.",
\r
297 AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH );
\r
299 IOT_SET_AND_GOTO_CLEANUP( false );
\r
311 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
314 /*-----------------------------------------------------------*/
\r
316 bool _IotMqtt_ValidateOperation( IotMqttOperation_t operation )
\r
318 IOT_FUNCTION_ENTRY( bool, true );
\r
320 /* Check for NULL. */
\r
321 if( operation == NULL )
\r
323 IotLogError( "Operation reference cannot be NULL." );
\r
325 IOT_SET_AND_GOTO_CLEANUP( false );
\r
332 /* Check that reference is waitable. */
\r
333 if( ( operation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) != IOT_MQTT_FLAG_WAITABLE )
\r
335 IotLogError( "Operation is not waitable." );
\r
337 IOT_SET_AND_GOTO_CLEANUP( false );
\r
344 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
347 /*-----------------------------------------------------------*/
\r
349 bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation,
\r
350 bool awsIotMqttMode,
\r
351 const IotMqttSubscription_t * pListStart,
\r
354 IOT_FUNCTION_ENTRY( bool, true );
\r
357 const IotMqttSubscription_t * pListElement = NULL;
\r
359 /* Operation must be either subscribe or unsubscribe. */
\r
360 IotMqtt_Assert( ( operation == IOT_MQTT_SUBSCRIBE ) ||
\r
361 ( operation == IOT_MQTT_UNSUBSCRIBE ) );
\r
363 /* Check for empty list. */
\r
364 if( pListStart == NULL )
\r
366 IotLogError( "Subscription list pointer cannot be NULL." );
\r
368 IOT_SET_AND_GOTO_CLEANUP( false );
\r
375 if( listSize == 0 )
\r
377 IotLogError( "Empty subscription list." );
\r
379 IOT_SET_AND_GOTO_CLEANUP( false );
\r
386 /* AWS IoT supports at most 8 topic filters in a single SUBSCRIBE packet. */
\r
387 if( awsIotMqttMode == true )
\r
389 if( listSize > AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE )
\r
391 IotLogError( "AWS IoT does not support more than %d topic filters per "
\r
392 "subscription request.",
\r
393 AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE );
\r
395 IOT_SET_AND_GOTO_CLEANUP( false );
\r
407 for( i = 0; i < listSize; i++ )
\r
409 pListElement = &( pListStart[ i ] );
\r
411 /* Check for a valid QoS and callback function when subscribing. */
\r
412 if( operation == IOT_MQTT_SUBSCRIBE )
\r
414 if( pListElement->qos != IOT_MQTT_QOS_0 )
\r
416 if( pListElement->qos != IOT_MQTT_QOS_1 )
\r
418 IotLogError( "Subscription QoS must be either 0 or 1." );
\r
420 IOT_SET_AND_GOTO_CLEANUP( false );
\r
432 if( pListElement->callback.function == NULL )
\r
434 IotLogError( "Callback function must be set." );
\r
436 IOT_SET_AND_GOTO_CLEANUP( false );
\r
448 /* Check subscription topic filter. */
\r
449 if( pListElement->pTopicFilter == NULL )
\r
451 IotLogError( "Subscription topic filter cannot be NULL." );
\r
453 IOT_SET_AND_GOTO_CLEANUP( false );
\r
460 if( pListElement->topicFilterLength == 0 )
\r
462 IotLogError( "Subscription topic filter length cannot be 0." );
\r
464 IOT_SET_AND_GOTO_CLEANUP( false );
\r
471 /* Check for compatibility with AWS IoT MQTT server. */
\r
472 if( awsIotMqttMode == true )
\r
474 /* Check topic filter length. */
\r
475 if( pListElement->topicFilterLength > AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH )
\r
477 IotLogError( "AWS IoT does not support topic filters longer than %d bytes.",
\r
478 AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH );
\r
480 IOT_SET_AND_GOTO_CLEANUP( false );
\r
492 /* Check that the wildcards '+' and '#' are being used correctly. */
\r
493 for( j = 0; j < pListElement->topicFilterLength; j++ )
\r
495 switch( pListElement->pTopicFilter[ j ] )
\r
497 /* Check that the single level wildcard '+' is used correctly. */
\r
500 /* Unless '+' is the first character in the filter, it must be preceded by '/'. */
\r
503 if( pListElement->pTopicFilter[ j - 1 ] != '/' )
\r
505 IotLogError( "Invalid topic filter %.*s -- '+' must be preceded by '/'.",
\r
506 pListElement->topicFilterLength,
\r
507 pListElement->pTopicFilter );
\r
509 IOT_SET_AND_GOTO_CLEANUP( false );
\r
521 /* Unless '+' is the last character in the filter, it must be succeeded by '/'. */
\r
522 if( j < pListElement->topicFilterLength - 1 )
\r
524 if( pListElement->pTopicFilter[ j + 1 ] != '/' )
\r
526 IotLogError( "Invalid topic filter %.*s -- '+' must be succeeded by '/'.",
\r
527 pListElement->topicFilterLength,
\r
528 pListElement->pTopicFilter );
\r
530 IOT_SET_AND_GOTO_CLEANUP( false );
\r
544 /* Check that the multi-level wildcard '#' is used correctly. */
\r
547 /* '#' must be the last character in the filter. */
\r
548 if( j != pListElement->topicFilterLength - 1 )
\r
550 IotLogError( "Invalid topic filter %.*s -- '#' must be the last character.",
\r
551 pListElement->topicFilterLength,
\r
552 pListElement->pTopicFilter );
\r
554 IOT_SET_AND_GOTO_CLEANUP( false );
\r
561 /* Unless '#' is standalone, it must be preceded by '/'. */
\r
562 if( pListElement->topicFilterLength > 1 )
\r
564 if( pListElement->pTopicFilter[ j - 1 ] != '/' )
\r
566 IotLogError( "Invalid topic filter %.*s -- '#' must be preceded by '/'.",
\r
567 pListElement->topicFilterLength,
\r
568 pListElement->pTopicFilter );
\r
570 IOT_SET_AND_GOTO_CLEANUP( false );
\r
590 IOT_FUNCTION_EXIT_NO_CLEANUP();
\r
593 /*-----------------------------------------------------------*/
\r