bool _IotMqtt_ValidateSubscriptionList()

in device_firmware/libraries/c_sdk/standard/mqtt/src/iot_mqtt_validate.c [349:591]


bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation,
                                        bool awsIotMqttMode,
                                        const IotMqttSubscription_t * pListStart,
                                        size_t listSize )
{
    IOT_FUNCTION_ENTRY( bool, true );
    size_t i = 0;
    uint16_t j = 0;
    const IotMqttSubscription_t * pListElement = NULL;

    /* Operation must be either subscribe or unsubscribe. */
    IotMqtt_Assert( ( operation == IOT_MQTT_SUBSCRIBE ) ||
                    ( operation == IOT_MQTT_UNSUBSCRIBE ) );

    /* Check for empty list. */
    if( pListStart == NULL )
    {
        IotLogError( "Subscription list pointer cannot be NULL." );

        IOT_SET_AND_GOTO_CLEANUP( false );
    }
    else
    {
        EMPTY_ELSE_MARKER;
    }

    if( listSize == 0 )
    {
        IotLogError( "Empty subscription list." );

        IOT_SET_AND_GOTO_CLEANUP( false );
    }
    else
    {
        EMPTY_ELSE_MARKER;
    }

    /* AWS IoT supports at most 8 topic filters in a single SUBSCRIBE packet. */
    if( awsIotMqttMode == true )
    {
        if( listSize > AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE )
        {
            IotLogError( "AWS IoT does not support more than %d topic filters per "
                         "subscription request.",
                         AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE );

            IOT_SET_AND_GOTO_CLEANUP( false );
        }
        else
        {
            EMPTY_ELSE_MARKER;
        }
    }
    else
    {
        EMPTY_ELSE_MARKER;
    }

    for( i = 0; i < listSize; i++ )
    {
        pListElement = &( pListStart[ i ] );

        /* Check for a valid QoS and callback function when subscribing. */
        if( operation == IOT_MQTT_SUBSCRIBE )
        {
            if( pListElement->qos != IOT_MQTT_QOS_0 )
            {
                if( pListElement->qos != IOT_MQTT_QOS_1 )
                {
                    IotLogError( "Subscription QoS must be either 0 or 1." );

                    IOT_SET_AND_GOTO_CLEANUP( false );
                }
                else
                {
                    EMPTY_ELSE_MARKER;
                }
            }
            else
            {
                EMPTY_ELSE_MARKER;
            }

            if( pListElement->callback.function == NULL )
            {
                IotLogError( "Callback function must be set." );

                IOT_SET_AND_GOTO_CLEANUP( false );
            }
            else
            {
                EMPTY_ELSE_MARKER;
            }
        }
        else
        {
            EMPTY_ELSE_MARKER;
        }

        /* Check subscription topic filter. */
        if( pListElement->pTopicFilter == NULL )
        {
            IotLogError( "Subscription topic filter cannot be NULL." );

            IOT_SET_AND_GOTO_CLEANUP( false );
        }
        else
        {
            EMPTY_ELSE_MARKER;
        }

        if( pListElement->topicFilterLength == 0 )
        {
            IotLogError( "Subscription topic filter length cannot be 0." );

            IOT_SET_AND_GOTO_CLEANUP( false );
        }
        else
        {
            EMPTY_ELSE_MARKER;
        }

        /* Check for compatibility with AWS IoT MQTT server. */
        if( awsIotMqttMode == true )
        {
            /* Check topic filter length. */
            if( pListElement->topicFilterLength > AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH )
            {
                IotLogError( "AWS IoT does not support topic filters longer than %d bytes.",
                             AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH );

                IOT_SET_AND_GOTO_CLEANUP( false );
            }
            else
            {
                EMPTY_ELSE_MARKER;
            }
        }
        else
        {
            EMPTY_ELSE_MARKER;
        }

        /* Check that the wildcards '+' and '#' are being used correctly. */
        for( j = 0; j < pListElement->topicFilterLength; j++ )
        {
            switch( pListElement->pTopicFilter[ j ] )
            {
                /* Check that the single level wildcard '+' is used correctly. */
                case '+':

                    /* Unless '+' is the first character in the filter, it must be preceded by '/'. */
                    if( j > 0 )
                    {
                        if( pListElement->pTopicFilter[ j - 1 ] != '/' )
                        {
                            IotLogError( "Invalid topic filter %.*s -- '+' must be preceded by '/'.",
                                         pListElement->topicFilterLength,
                                         pListElement->pTopicFilter );

                            IOT_SET_AND_GOTO_CLEANUP( false );
                        }
                        else
                        {
                            EMPTY_ELSE_MARKER;
                        }
                    }
                    else
                    {
                        EMPTY_ELSE_MARKER;
                    }

                    /* Unless '+' is the last character in the filter, it must be succeeded by '/'. */
                    if( j < pListElement->topicFilterLength - 1 )
                    {
                        if( pListElement->pTopicFilter[ j + 1 ] != '/' )
                        {
                            IotLogError( "Invalid topic filter %.*s -- '+' must be succeeded by '/'.",
                                         pListElement->topicFilterLength,
                                         pListElement->pTopicFilter );

                            IOT_SET_AND_GOTO_CLEANUP( false );
                        }
                        else
                        {
                            EMPTY_ELSE_MARKER;
                        }
                    }
                    else
                    {
                        EMPTY_ELSE_MARKER;
                    }

                    break;

                /* Check that the multi-level wildcard '#' is used correctly. */
                case '#':

                    /* '#' must be the last character in the filter. */
                    if( j != pListElement->topicFilterLength - 1 )
                    {
                        IotLogError( "Invalid topic filter %.*s -- '#' must be the last character.",
                                     pListElement->topicFilterLength,
                                     pListElement->pTopicFilter );

                        IOT_SET_AND_GOTO_CLEANUP( false );
                    }
                    else
                    {
                        EMPTY_ELSE_MARKER;
                    }

                    /* Unless '#' is standalone, it must be preceded by '/'. */
                    if( pListElement->topicFilterLength > 1 )
                    {
                        if( pListElement->pTopicFilter[ j - 1 ] != '/' )
                        {
                            IotLogError( "Invalid topic filter %.*s -- '#' must be preceded by '/'.",
                                         pListElement->topicFilterLength,
                                         pListElement->pTopicFilter );

                            IOT_SET_AND_GOTO_CLEANUP( false );
                        }
                        else
                        {
                            EMPTY_ELSE_MARKER;
                        }
                    }
                    else
                    {
                        EMPTY_ELSE_MARKER;
                    }

                    break;

                default:
                    break;
            }
        }
    }

    IOT_FUNCTION_EXIT_NO_CLEANUP();
}