Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mqtt_client_misc.c Source File

mqtt_client_misc.c

Go to the documentation of this file.
00001 /**
00002  * @file mqtt_client_misc.c
00003  * @brief Helper functions for MQTT client
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL MQTT_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "mqtt/mqtt_client.h"
00035 #include "mqtt/mqtt_client_packet.h"
00036 #include "mqtt/mqtt_client_transport.h"
00037 #include "mqtt/mqtt_client_misc.h"
00038 #include "debug.h"
00039 
00040 //Check TCP/IP stack configuration
00041 #if (MQTT_CLIENT_SUPPORT == ENABLED)
00042 
00043 
00044 /**
00045  * @brief Update MQTT client state
00046  * @param[in] context Pointer to the MQTT client context
00047  * @param[in] newState New state to switch to
00048  **/
00049 
00050 void mqttClientChangeState(MqttClientContext *context, MqttClientState newState)
00051 {
00052    //Switch to the new state
00053    context->state = newState;
00054 }
00055 
00056 
00057 /**
00058  * @brief Check keep-alive time interval
00059  * @param[in] context Pointer to the MQTT client context
00060  * @return Error code
00061  **/
00062 
00063 error_t mqttClientCheckKeepAlive(MqttClientContext *context)
00064 {
00065    error_t error;
00066    systime_t time;
00067    systime_t keepAlive;
00068 
00069    //Initialize status code
00070    error = NO_ERROR;
00071 
00072    //In the absence of sending any other control packets, the client must
00073    //send a PINGREQ packet
00074    if(context->state == MQTT_CLIENT_STATE_IDLE ||
00075       context->state == MQTT_CLIENT_STATE_PACKET_SENT)
00076    {
00077       //A keep-alive value of zero has the effect of turning off the keep
00078       //alive mechanism
00079       if(context->settings.keepAlive != 0)
00080       {
00081          //Get current time
00082          time = osGetSystemTime();
00083 
00084          //Convert the keep-alive value to milliseconds
00085          keepAlive = context->settings.keepAlive * 1000;
00086 
00087          //It is the responsibility of the client to ensure that the interval
00088          //between control packets being sent does not exceed the keep-alive value
00089          if(timeCompare(time, context->keepAliveTimestamp + keepAlive) >= 0)
00090          {
00091             //Format PINGREQ packet
00092             error = mqttClientFormatPingReq(context);
00093 
00094             //Check status code
00095             if(!error)
00096             {
00097                //Debug message
00098                TRACE_INFO("MQTT: Sending PINGREQ packet (%" PRIuSIZE " bytes)...\r\n", context->packetLen);
00099                TRACE_DEBUG_ARRAY("  ", context->packet, context->packetLen);
00100 
00101                //Point to the beginning of the packet
00102                context->packetPos = 0;
00103 
00104                //Send PINGREQ packet
00105                mqttClientChangeState(context, MQTT_CLIENT_STATE_SENDING_PACKET);
00106             }
00107          }
00108       }
00109    }
00110 
00111    //Return status code
00112    return error;
00113 }
00114 
00115 
00116 /**
00117  * @brief Serialize fixed header
00118  * @param[in] buffer Pointer to the output buffer
00119  * @param[in,out] pos Current position
00120  * @param[in] type MQTT control packet type
00121  * @param[in] dup DUP flag
00122  * @param[in] qos QoS field
00123  * @param[in] retain RETAIN flag
00124  * @param[in] remainingLen Length of the variable header and the payload
00125  * @return Error code
00126  **/
00127 
00128 error_t mqttSerializeHeader(uint8_t *buffer, size_t *pos, MqttPacketType type,
00129    bool_t dup, MqttQosLevel qos, bool_t retain, size_t remainingLen)
00130 {
00131    uint_t i;
00132    uint_t k;
00133    size_t n;
00134    MqttPacketHeader *header;
00135 
00136    //Point to the current position
00137    n = *pos;
00138 
00139    //The Remaining Length is encoded using a variable length encoding scheme
00140    if(remainingLen < 128)
00141       k = 1;
00142    else if(remainingLen < 16384)
00143       k = 2;
00144    else if(remainingLen < 2097152)
00145       k = 3;
00146    else if(remainingLen < 268435456)
00147       k = 4;
00148    else
00149       return ERROR_INVALID_LENGTH;
00150 
00151    //Sanity check
00152    if(n < (sizeof(MqttPacketHeader) + k))
00153       return ERROR_BUFFER_OVERFLOW;
00154 
00155    //Position where to format the header
00156    n -= sizeof(MqttPacketHeader) + k;
00157 
00158    //Point to the MQTT packet header
00159    header = (MqttPacketHeader *) (buffer + n);
00160 
00161    //Encode the first byte of the header
00162    header->type = type;
00163    header->dup = dup;
00164    header->qos = qos;
00165    header->retain = retain;
00166 
00167    //Encode the Remaining Length field
00168    for(i = 0; i < k; i++)
00169    {
00170       //The least significant seven bits of each byte encode the data
00171       header->length[i] = remainingLen & 0xFF;
00172       remainingLen >>= 7;
00173 
00174       //The most significant bit is used to indicate that there are
00175       //following bytes in the representation
00176       if(remainingLen > 0)
00177          header->length[i] |= 0x80;
00178    }
00179 
00180    //Update current position
00181    *pos = n;
00182 
00183    //Successful processing
00184    return NO_ERROR;
00185 }
00186 
00187 
00188 /**
00189  * @brief Write a 8-bit integer to the output buffer
00190  * @param[in] buffer Pointer to the output buffer
00191  * @param[in] bufferLen Maximum number of bytes the output buffer can hold
00192  * @param[in,out] pos Current position
00193  * @param[in] value 8-bit integer to be serialized
00194  * @return Error code
00195  **/
00196 
00197 error_t mqttSerializeByte(uint8_t *buffer, size_t bufferLen,
00198    size_t *pos, uint8_t value)
00199 {
00200    size_t n;
00201 
00202    //Point to the current position
00203    n = *pos;
00204 
00205    //Make sure the output buffer is large enough
00206    if((n + sizeof(uint8_t)) > bufferLen)
00207       return ERROR_BUFFER_OVERFLOW;
00208 
00209    //Write the byte to the output buffer
00210    buffer[n++] = value;
00211 
00212    //Advance current position
00213    *pos = n;
00214 
00215    //Successful processing
00216    return NO_ERROR;
00217 }
00218 
00219 
00220 /**
00221  * @brief Write a 16-bit integer to the output buffer
00222  * @param[in] buffer Pointer to the output buffer
00223  * @param[in] bufferLen Maximum number of bytes the output buffer can hold
00224  * @param[in,out] pos Current position
00225  * @param[in] value 16-bit integer to be serialized
00226  * @return Error code
00227  **/
00228 
00229 error_t mqttSerializeShort(uint8_t *buffer, size_t bufferLen,
00230    size_t *pos, uint16_t value)
00231 {
00232    size_t n;
00233 
00234    //Point to the current position
00235    n = *pos;
00236 
00237    //Make sure the output buffer is large enough
00238    if((n + sizeof(uint16_t)) > bufferLen)
00239       return ERROR_BUFFER_OVERFLOW;
00240 
00241    //Write the short integer to the output buffer
00242    buffer[n++] = MSB(value);
00243    buffer[n++] = LSB(value);
00244 
00245    //Advance current position
00246    *pos = n;
00247 
00248    //Successful processing
00249    return NO_ERROR;
00250 }
00251 
00252 
00253 /**
00254  * @brief Serialize string
00255  * @param[in] buffer Pointer to the output buffer
00256  * @param[in] bufferLen Maximum number of bytes the output buffer can hold
00257  * @param[in,out] pos Current position
00258  * @param[in] string Pointer to the string to be serialized
00259  * @param[in] stringLen Length of the string, in bytes
00260  * @return Error code
00261  **/
00262 
00263 error_t mqttSerializeString(uint8_t *buffer, size_t bufferLen,
00264    size_t *pos, const void *string, size_t stringLen)
00265 {
00266    size_t n;
00267 
00268    //Point to the current position
00269    n = *pos;
00270 
00271    //Make sure the output buffer is large enough to hold the string
00272    if((n + sizeof(uint16_t) + stringLen) > bufferLen)
00273       return ERROR_BUFFER_OVERFLOW;
00274 
00275    //Encode the length field
00276    buffer[n++] = MSB(stringLen);
00277    buffer[n++] = LSB(stringLen);
00278 
00279    //Write the string to the output buffer
00280    memcpy(buffer + n, string, stringLen);
00281 
00282    //Advance current position
00283    *pos = n + stringLen;
00284 
00285    //Successful processing
00286    return NO_ERROR;
00287 }
00288 
00289 
00290 /**
00291  * @brief Serialize raw data
00292  * @param[in] buffer Pointer to the output buffer
00293  * @param[in] bufferLen Maximum number of bytes the output buffer can hold
00294  * @param[in,out] pos Current position
00295  * @param[in] data Pointer to the raw data to be serialized
00296  * @param[in] dataLen Length of the raw data, in bytes
00297  * @return Error code
00298  **/
00299 
00300 error_t mqttSerializeData(uint8_t *buffer, size_t bufferLen,
00301    size_t *pos, const void *data, size_t dataLen)
00302 {
00303    size_t n;
00304 
00305    //Point to the current position
00306    n = *pos;
00307 
00308    //Make sure the output buffer is large enough to hold the data
00309    if((n + dataLen) > bufferLen)
00310       return ERROR_BUFFER_OVERFLOW;
00311 
00312    //Write the data to the output buffer
00313    memcpy(buffer + n, data, dataLen);
00314 
00315    //Advance current position
00316    *pos = n + dataLen;
00317 
00318    //Successful processing
00319    return NO_ERROR;
00320 }
00321 
00322 
00323 /**
00324  * @brief Deserialize fixed header
00325  * @param[in] buffer Pointer to the input buffer
00326  * @param[in] bufferLen Length of the input buffer
00327  * @param[in,out] pos Current position
00328  * @param[out] type MQTT control packet type
00329  * @param[out] dup DUP flag from the fixed header
00330  * @param[out] qos QoS field from the fixed header
00331  * @param[out] retain RETAIN flag from the fixed header
00332  * @param[out] remainingLen Length of the variable header and the payload
00333  * @return Error code
00334  **/
00335 
00336 error_t mqttDeserializeHeader(uint8_t *buffer, size_t bufferLen, size_t *pos,
00337    MqttPacketType *type, bool_t *dup, MqttQosLevel *qos, bool_t *retain, size_t *remainingLen)
00338 {
00339    uint_t i;
00340    size_t n;
00341    MqttPacketHeader *header;
00342 
00343    //Point to the current position
00344    n = *pos;
00345 
00346    //Make sure the input buffer is large enough
00347    if((n + sizeof(MqttPacketHeader)) > bufferLen)
00348       return ERROR_INVALID_LENGTH;
00349 
00350    //Point to the MQTT packet header
00351    header = (MqttPacketHeader *) (buffer + n);
00352 
00353    //Save MQTT control packet type
00354    *type = (MqttPacketType) header->type;
00355 
00356    //Save flags
00357    *dup = header->dup;
00358    *qos = (MqttQosLevel) header->qos;
00359    *retain = header->retain;
00360 
00361    //Advance current position
00362    n += sizeof(MqttPacketHeader);
00363 
00364    //Prepare to decode the Remaining Length field
00365    *remainingLen = 0;
00366 
00367    //The Remaining Length is encoded using a variable length encoding scheme
00368    for(i = 0; i < 4; i++)
00369    {
00370       //Sanity check
00371       if((n + sizeof(uint8_t)) > bufferLen)
00372          return ERROR_INVALID_LENGTH;
00373 
00374       //Advance current position
00375       n += sizeof(uint8_t);
00376 
00377       //The most significant bit is used to indicate that there are
00378       //following bytes in the representation
00379       if(header->length[i] & 0x80)
00380       {
00381          //Applications can send control packets of size up to 256 MB
00382          if(i == 3)
00383             return ERROR_INVALID_SYNTAX;
00384 
00385          //The least significant seven bits of each byte encode the data
00386          *remainingLen |= (header->length[i] & 0x7F) << (7 * i);
00387       }
00388       else
00389       {
00390          //The least significant seven bits of each byte encode the data
00391          *remainingLen |= header->length[i] << (7 * i);
00392          //This is the last byte
00393          break;
00394       }
00395    }
00396 
00397    //Return the current position
00398    *pos = n;
00399 
00400    //Successful processing
00401    return NO_ERROR;
00402 }
00403 
00404 
00405 /**
00406  * @brief Read a 8-bit integer from the input buffer
00407  * @param[in] buffer Pointer to the input buffer
00408  * @param[in] bufferLen Length of the input buffer
00409  * @param[in,out] pos Current position
00410  * @param[out] value Value of the 8-bit integer
00411  * @return Error code
00412  **/
00413 
00414 error_t mqttDeserializeByte(uint8_t *buffer, size_t bufferLen,
00415    size_t *pos, uint8_t *value)
00416 {
00417    size_t n;
00418 
00419    //Point to the current position
00420    n = *pos;
00421 
00422    //Make sure the input buffer is large enough
00423    if((n + sizeof(uint8_t)) > bufferLen)
00424       return ERROR_BUFFER_OVERFLOW;
00425 
00426    //Read the short integer from the input buffer
00427    *value = buffer[n];
00428 
00429    //Advance current position
00430    *pos = n + sizeof(uint8_t);
00431 
00432    //Successful processing
00433    return NO_ERROR;
00434 }
00435 
00436 
00437 /**
00438  * @brief Read a 16-bit integer from the input buffer
00439  * @param[in] buffer Pointer to the input buffer
00440  * @param[in] bufferLen Length of the input buffer
00441  * @param[in,out] pos Current position
00442  * @param[out] value Value of the 16-bit integer
00443  * @return Error code
00444  **/
00445 
00446 error_t mqttDeserializeShort(uint8_t *buffer, size_t bufferLen,
00447    size_t *pos, uint16_t *value)
00448 {
00449    size_t n;
00450 
00451    //Point to the current position
00452    n = *pos;
00453 
00454    //Make sure the input buffer is large enough
00455    if((n + sizeof(uint16_t)) > bufferLen)
00456       return ERROR_BUFFER_OVERFLOW;
00457 
00458    //Read the short integer from the input buffer
00459    *value = (buffer[n] << 8) | buffer[n + 1];
00460 
00461    //Advance current position
00462    *pos = n + sizeof(uint16_t);
00463 
00464    //Successful processing
00465    return NO_ERROR;
00466 }
00467 
00468 
00469 /**
00470  * @brief Deserialize string
00471  * @param[in] buffer Pointer to the input buffer
00472  * @param[in] bufferLen Length of the input buffer
00473  * @param[in,out] pos Current position
00474  * @param[out] string Pointer to the string
00475  * @param[out] stringLen Length of the string, in bytes
00476  * @return Error code
00477  **/
00478 
00479 error_t mqttDeserializeString(uint8_t *buffer, size_t bufferLen,
00480    size_t *pos, char_t **string, size_t *stringLen)
00481 {
00482    size_t n;
00483 
00484    //Point to the current position
00485    n = *pos;
00486 
00487    //Make sure the input buffer is large enough
00488    if((n + sizeof(uint16_t)) > bufferLen)
00489       return ERROR_BUFFER_OVERFLOW;
00490 
00491    //Decode the length field
00492    *stringLen = (buffer[n] << 8) | buffer[n + 1];
00493 
00494    //Make sure the input buffer is large enough
00495    if((n + sizeof(uint16_t) + *stringLen) > bufferLen)
00496       return ERROR_BUFFER_OVERFLOW;
00497 
00498    //Read the string from the input buffer
00499    *string = (char_t *) buffer + n + 2;
00500 
00501    //Advance current position
00502    *pos = n + 2 + *stringLen;
00503 
00504    //Successful processing
00505    return NO_ERROR;
00506 }
00507 
00508 #endif
00509