Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mqtt_client_misc.c
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
Generated on Tue Jul 12 2022 17:10:15 by
1.7.2