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.
MQTTPacket.c
00001 /******************************************************************************* 00002 * Copyright (c) 2014 IBM Corp. 00003 * 00004 * All rights reserved. This program and the accompanying materials 00005 * are made available under the terms of the Eclipse Public License v1.0 00006 * and Eclipse Distribution License v1.0 which accompany this distribution. 00007 * 00008 * The Eclipse Public License is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * and the Eclipse Distribution License is available at 00011 * http://www.eclipse.org/org/documents/edl-v10.php. 00012 * 00013 * Contributors: 00014 * Ian Craggs - initial API and implementation and/or initial documentation 00015 * Sergio R. Caprile - non-blocking packet read functions for stream transport 00016 *******************************************************************************/ 00017 00018 #include "StackTrace.h" 00019 #include "MQTTPacket.h" 00020 00021 #include <string.h> 00022 00023 /** 00024 * Encodes the message length according to the MQTT algorithm 00025 * @param buf the buffer into which the encoded data is written 00026 * @param length the length to be encoded 00027 * @return the number of bytes written to buffer 00028 */ 00029 int MQTTPacket_encode(unsigned char* buf, int length) 00030 { 00031 int rc = 0; 00032 00033 FUNC_ENTRY; 00034 do 00035 { 00036 char d = length % 128; 00037 length /= 128; 00038 /* if there are more digits to encode, set the top bit of this digit */ 00039 if (length > 0) 00040 d |= 0x80; 00041 buf[rc++] = d; 00042 } while (length > 0); 00043 FUNC_EXIT_RC(rc); 00044 return rc; 00045 } 00046 00047 00048 /** 00049 * Decodes the message length according to the MQTT algorithm 00050 * @param getcharfn pointer to function to read the next character from the data source 00051 * @param value the decoded length returned 00052 * @return the number of bytes read from the socket 00053 */ 00054 int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value) 00055 { 00056 unsigned char c; 00057 int multiplier = 1; 00058 int len = 0; 00059 #define MAX_NO_OF_REMAINING_LENGTH_BYTES 4 00060 00061 FUNC_ENTRY; 00062 *value = 0; 00063 do 00064 { 00065 int rc = MQTTPACKET_READ_ERROR; 00066 00067 if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) 00068 { 00069 rc = MQTTPACKET_READ_ERROR; /* bad data */ 00070 goto exit; 00071 } 00072 rc = (*getcharfn)(&c, 1); 00073 if (rc != 1) 00074 goto exit; 00075 *value += (c & 127) * multiplier; 00076 multiplier *= 128; 00077 } while ((c & 128) != 0); 00078 exit: 00079 FUNC_EXIT_RC(len); 00080 return len; 00081 } 00082 00083 00084 int MQTTPacket_len(int rem_len) 00085 { 00086 rem_len += 1; /* header byte */ 00087 00088 /* now remaining_length field */ 00089 if (rem_len < 128) 00090 rem_len += 1; 00091 else if (rem_len < 16384) 00092 rem_len += 2; 00093 else if (rem_len < 2097151) 00094 rem_len += 3; 00095 else 00096 rem_len += 4; 00097 return rem_len; 00098 } 00099 00100 00101 static unsigned char* bufptr; 00102 00103 int bufchar(unsigned char* c, int count) 00104 { 00105 int i; 00106 00107 for (i = 0; i < count; ++i) 00108 *c = *bufptr++; 00109 return count; 00110 } 00111 00112 00113 int MQTTPacket_decodeBuf(unsigned char* buf, int* value) 00114 { 00115 bufptr = buf; 00116 return MQTTPacket_decode(bufchar, value); 00117 } 00118 00119 /** 00120 * Calculates an integer from two bytes read from the input buffer 00121 * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned 00122 * @return the integer value calculated 00123 */ 00124 int readInt(unsigned char** pptr) 00125 { 00126 unsigned char* ptr = *pptr; 00127 int len = 256*(*ptr) + (*(ptr+1)); 00128 *pptr += 2; 00129 return len; 00130 } 00131 00132 00133 /** 00134 * Reads one character from the input buffer. 00135 * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned 00136 * @return the character read 00137 */ 00138 char readChar(unsigned char** pptr) 00139 { 00140 char c = **pptr; 00141 (*pptr)++; 00142 return c; 00143 } 00144 00145 00146 /** 00147 * Writes one character to an output buffer. 00148 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned 00149 * @param c the character to write 00150 */ 00151 void writeChar(unsigned char** pptr, char c) 00152 { 00153 **pptr = c; 00154 (*pptr)++; 00155 } 00156 00157 00158 /** 00159 * Writes an integer as 2 bytes to an output buffer. 00160 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned 00161 * @param anInt the integer to write 00162 */ 00163 void writeInt(unsigned char** pptr, int anInt) 00164 { 00165 **pptr = (unsigned char)(anInt / 256); 00166 (*pptr)++; 00167 **pptr = (unsigned char)(anInt % 256); 00168 (*pptr)++; 00169 } 00170 00171 00172 /** 00173 * Writes a "UTF" string to an output buffer. Converts C string to length-delimited. 00174 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned 00175 * @param string the C string to write 00176 */ 00177 void writeCString(unsigned char** pptr, const char* string) 00178 { 00179 int len = strlen(string); 00180 writeInt(pptr, len); 00181 memcpy(*pptr, string, len); 00182 *pptr += len; 00183 } 00184 00185 00186 int getLenStringLen(char* ptr) 00187 { 00188 int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1)); 00189 return len; 00190 } 00191 00192 void writeMQTTString(unsigned char** pptr, MQTTString mqttstring) 00193 { 00194 if (mqttstring.lenstring.len > 0) 00195 { 00196 writeInt(pptr, mqttstring.lenstring.len); 00197 memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len); 00198 *pptr += mqttstring.lenstring.len; 00199 } 00200 else if (mqttstring.cstring) 00201 writeCString(pptr, mqttstring.cstring); 00202 else 00203 writeInt(pptr, 0); 00204 } 00205 00206 00207 /** 00208 * @param mqttstring the MQTTString structure into which the data is to be read 00209 * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned 00210 * @param enddata pointer to the end of the data: do not read beyond 00211 * @return 1 if successful, 0 if not 00212 */ 00213 int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata) 00214 { 00215 int rc = 0; 00216 00217 FUNC_ENTRY; 00218 /* the first two bytes are the length of the string */ 00219 if (enddata - (*pptr) > 1) /* enough length to read the integer? */ 00220 { 00221 mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */ 00222 if (&(*pptr)[mqttstring->lenstring.len] <= enddata) 00223 { 00224 mqttstring->lenstring.data = (char*)*pptr; 00225 *pptr += mqttstring->lenstring.len; 00226 rc = 1; 00227 } 00228 } 00229 mqttstring->cstring = NULL; 00230 FUNC_EXIT_RC(rc); 00231 return rc; 00232 } 00233 00234 00235 /** 00236 * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string 00237 * @param mqttstring the string to return the length of 00238 * @return the length of the string 00239 */ 00240 int MQTTstrlen(MQTTString mqttstring) 00241 { 00242 int rc = 0; 00243 00244 if (mqttstring.cstring) 00245 rc = strlen(mqttstring.cstring); 00246 else 00247 rc = mqttstring.lenstring.len; 00248 return rc; 00249 } 00250 00251 00252 /** 00253 * Compares an MQTTString to a C string 00254 * @param a the MQTTString to compare 00255 * @param bptr the C string to compare 00256 * @return boolean - equal or not 00257 */ 00258 int MQTTPacket_equals(MQTTString* a, char* bptr) 00259 { 00260 int alen = 0, 00261 blen = 0; 00262 char *aptr; 00263 00264 if (a->cstring) 00265 { 00266 aptr = a->cstring; 00267 alen = strlen(a->cstring); 00268 } 00269 else 00270 { 00271 aptr = a->lenstring.data; 00272 alen = a->lenstring.len; 00273 } 00274 blen = strlen(bptr); 00275 00276 return (alen == blen) && (strncmp(aptr, bptr, alen) == 0); 00277 } 00278 00279 00280 /** 00281 * Helper function to read packet data from some source into a buffer 00282 * @param buf the buffer into which the packet will be serialized 00283 * @param buflen the length in bytes of the supplied buffer 00284 * @param getfn pointer to a function which will read any number of bytes from the needed source 00285 * @return integer MQTT packet type, or -1 on error 00286 * @note the whole message must fit into the caller's buffer 00287 */ 00288 int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int)) 00289 { 00290 int rc = -1; 00291 MQTTHeader header = {0}; 00292 int len = 0; 00293 int rem_len = 0; 00294 00295 /* 1. read the header byte. This has the packet type in it */ 00296 if ((*getfn)(buf, 1) != 1) 00297 goto exit; 00298 00299 len = 1; 00300 /* 2. read the remaining length. This is variable in itself */ 00301 MQTTPacket_decode(getfn, &rem_len); 00302 len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */ 00303 00304 /* 3. read the rest of the buffer using a callback to supply the rest of the data */ 00305 if((rem_len + len) > buflen) 00306 goto exit; 00307 if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len)) 00308 goto exit; 00309 00310 header.byte = buf[0]; 00311 rc = header.bits.type; 00312 exit: 00313 return rc; 00314 } 00315 00316 /** 00317 * Decodes the message length according to the MQTT algorithm, non-blocking 00318 * @param trp pointer to a transport structure holding what is needed to solve getting data from it 00319 * @param value the decoded length returned 00320 * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error 00321 */ 00322 static int MQTTPacket_decodenb(MQTTTransport *trp) 00323 { 00324 unsigned char c; 00325 int rc = MQTTPACKET_READ_ERROR; 00326 00327 FUNC_ENTRY; 00328 if(trp->len == 0){ /* initialize on first call */ 00329 trp->multiplier = 1; 00330 trp->rem_len = 0; 00331 } 00332 do { 00333 int frc; 00334 if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES) 00335 goto exit; 00336 if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1) 00337 goto exit; 00338 if (frc == 0){ 00339 rc = 0; 00340 goto exit; 00341 } 00342 ++(trp->len); 00343 trp->rem_len += (c & 127) * trp->multiplier; 00344 trp->multiplier *= 128; 00345 } while ((c & 128) != 0); 00346 rc = trp->len; 00347 exit: 00348 FUNC_EXIT_RC(rc); 00349 return rc; 00350 } 00351 00352 /** 00353 * Helper function to read packet data from some source into a buffer, non-blocking 00354 * @param buf the buffer into which the packet will be serialized 00355 * @param buflen the length in bytes of the supplied buffer 00356 * @param trp pointer to a transport structure holding what is needed to solve getting data from it 00357 * @return integer MQTT packet type, 0 for call again, or -1 on error 00358 * @note the whole message must fit into the caller's buffer 00359 */ 00360 int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp) 00361 { 00362 int rc = -1, frc; 00363 MQTTHeader header = {0}; 00364 00365 switch(trp->state){ 00366 default: 00367 trp->state = 0; 00368 /*FALLTHROUGH*/ 00369 case 0: 00370 /* read the header byte. This has the packet type in it */ 00371 if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1) 00372 goto exit; 00373 if (frc == 0) 00374 return 0; 00375 trp->len = 0; 00376 ++trp->state; 00377 /*FALLTHROUGH*/ 00378 /* read the remaining length. This is variable in itself */ 00379 case 1: 00380 if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR) 00381 goto exit; 00382 if(frc == 0) 00383 return 0; 00384 trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */ 00385 if((trp->rem_len + trp->len) > buflen) 00386 goto exit; 00387 ++trp->state; 00388 /*FALLTHROUGH*/ 00389 case 2: 00390 if(trp->rem_len){ 00391 /* read the rest of the buffer using a callback to supply the rest of the data */ 00392 if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1) 00393 goto exit; 00394 if (frc == 0) 00395 return 0; 00396 trp->rem_len -= frc; 00397 trp->len += frc; 00398 if(trp->rem_len) 00399 return 0; 00400 } 00401 header.byte = buf[0]; 00402 rc = header.bits.type; 00403 break; 00404 } 00405 00406 exit: 00407 trp->state = 0; 00408 return rc; 00409 } 00410
Generated on Thu Jul 14 2022 12:58:42 by
