1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * MQTT v5 25 * 26 * http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html 27 */ 28 29#include "private-lib-core.h" 30 31#include <string.h> 32#include <sys/types.h> 33#include <assert.h> 34 35 36/* 37 * Encode is done into a buffer of at least 4 bytes space. 38 * 39 * Returns -1 for error, or number of bytes used 40 */ 41 42int 43lws_mqtt_vbi_encode(uint32_t value, void *buf) 44{ 45 uint8_t *p = (uint8_t *)buf, b; 46 47 if (value > 0xfffffff) { 48 assert(0); 49 return -1; 50 } 51 52 do { 53 b = value & 0x7f; 54 value >>= 7; 55 if (value) 56 *p++ = (0x80 | b); 57 else 58 *p++ = b; 59 } while (value); 60 61 return lws_ptr_diff(p, (uint8_t *)buf); 62} 63 64void 65lws_mqtt_vbi_init(lws_mqtt_vbi *vbi) 66{ 67 vbi->value = 0; 68 vbi->consumed = 0; 69 vbi->budget = 4; 70} 71 72void 73lws_mqtt_2byte_init(lws_mqtt_vbi *vbi) 74{ 75 vbi->value = 0; 76 vbi->consumed = 0; 77 vbi->budget = 2; 78} 79 80void 81lws_mqtt_4byte_init(lws_mqtt_vbi *vbi) 82{ 83 vbi->value = 0; 84 vbi->consumed = 0; 85 vbi->budget = 4; 86} 87 88lws_mqtt_stateful_primitive_return_t 89lws_mqtt_vbi_r(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len) 90{ 91 uint8_t multiplier = 0; 92 if (!vbi->budget) { 93 lwsl_info("%s: bad vbi\n", __func__); 94 95 return LMSPR_FAILED_ALREADY_COMPLETED; 96 } 97 98 while (*len && vbi->budget--) { 99 uint8_t u = *((*in)++); 100 101 (*len)--; 102 vbi->consumed++; 103 vbi->value = vbi->value + (uint32_t)((u & 0x7f) << multiplier); 104 multiplier = (uint8_t)(multiplier + 7); 105 if (!(u & 0x80)) 106 return LMSPR_COMPLETED; /* finished */ 107 } 108 109 if (!vbi->budget) { /* should have ended on b7 = 0 and exited then... */ 110 lwsl_info("%s: bad vbi\n", __func__); 111 112 return LMSPR_FAILED_FORMAT; 113 } 114 115 return LMSPR_NEED_MORE; 116} 117 118lws_mqtt_stateful_primitive_return_t 119lws_mqtt_mb_parse(lws_mqtt_vbi *vbi, const uint8_t **in, size_t *len) 120{ 121 if (!vbi->budget) 122 return LMSPR_FAILED_ALREADY_COMPLETED; 123 124 while (*len && vbi->budget--) { 125 vbi->value = (vbi->value << 8) | *((*in)++); 126 (*len)--; 127 vbi->consumed++; 128 } 129 130 return vbi->budget ? LMSPR_NEED_MORE : LMSPR_COMPLETED; 131} 132 133/* 134 * You can leave buf NULL, if so it will be allocated on the heap once the 135 * actual length is known. nf should be 0, it will be set at allocation time. 136 * 137 * Or you can ensure no allocation and use an external buffer by setting buf 138 * and lim. But buf must be in the ep context somehow, since it may have to 139 * survive returns to the event loop unchanged. Set nf to 0 in this case. 140 * 141 * Or you can set buf to an externally allocated buffer, in which case you may 142 * set nf so it will be freed when the string is "freed". 143 */ 144 145void 146lws_mqtt_str_init(lws_mqtt_str_t *s, uint8_t *buf, uint16_t lim, char nf) 147{ 148 s->len = 0; /* at COMPLETED, consumed count is s->len + 2 */ 149 s->pos = 0; 150 s->buf = buf; 151 s->limit = lim; 152 s->len_valid = 0; 153 s->needs_freeing = nf; 154} 155 156lws_mqtt_str_t * 157lws_mqtt_str_create(uint16_t lim) 158{ 159 lws_mqtt_str_t *s = lws_malloc(sizeof(*s) + lim + 1, __func__); 160 161 if (!s) 162 return NULL; 163 164 s->len = 0; 165 s->pos = 0; 166 s->buf = (uint8_t *)&s[1]; 167 s->limit = lim; 168 s->len_valid = 0; 169 s->needs_freeing = 1; 170 171 return s; 172} 173 174lws_mqtt_str_t * 175lws_mqtt_str_create_init(uint8_t *buf, uint16_t len, uint16_t lim) 176{ 177 lws_mqtt_str_t *s; 178 179 if (!lim) 180 lim = len; 181 182 s = lws_mqtt_str_create(lim); 183 184 if (!s) 185 return NULL; 186 187 memcpy(s->buf, buf, len); 188 s->len = len; 189 s->len_valid = 1; 190 s->pos = len; 191 192 return s; 193} 194 195 196lws_mqtt_str_t * 197lws_mqtt_str_create_cstr_dup(const char *buf, uint16_t lim) 198{ 199 size_t len = strlen(buf); 200 201 if (!lim) 202 lim = (uint16_t)len; 203 204 return lws_mqtt_str_create_init((uint8_t *)buf, (uint16_t)len, lim); 205} 206 207uint8_t * 208lws_mqtt_str_next(lws_mqtt_str_t *s, uint16_t *budget) 209{ 210 if (budget) 211 *budget = (uint16_t)(s->limit - s->pos); 212 213 return &s->buf[s->pos]; 214} 215 216int 217lws_mqtt_str_advance(lws_mqtt_str_t *s, int n) 218{ 219 if (n > s->limit - s->pos) { 220 lwsl_err("%s: attempted overflow %d vs %d\n", __func__, 221 n, s->limit - s->pos); 222 return 1; 223 } 224 225 s->pos = (uint16_t)(s->pos + (uint16_t)n); 226 s->len = (uint16_t)(s->len + (uint16_t)n); 227 228 return 0; 229} 230 231void 232lws_mqtt_str_free(lws_mqtt_str_t **ps) 233{ 234 lws_mqtt_str_t *s = *ps; 235 236 if (!s || !s->needs_freeing) 237 return; 238 239 /* buf may be independently allocated or allocated along with the 240 * lws_mqtt_str_t at the end... if so the whole lws_mqtt_str_t is freed. 241 */ 242 243 if (s->buf != (uint8_t *)&s[1]) 244 lws_free_set_NULL(s->buf); 245 else 246 lws_free_set_NULL(*ps); 247} 248 249/* 250 * Parses and allocates for lws_mqtt_str_t in a fragmentation-immune, but 251 * efficient for bulk data way. 252 * 253 * Returns: LMSPR_NEED_MORE if needs more data, 254 * LMSPR_COMPLETED if complete, <0 for error 255 * 256 * *len is reduced by, and *in is advanced by, the amount of data actually used, 257 * except in error case 258 * 259 * lws_mqtt_str_free() must be called after calling this successfully 260 * or not. 261 */ 262lws_mqtt_stateful_primitive_return_t 263lws_mqtt_str_parse(lws_mqtt_str_t *s, const uint8_t **in, size_t *len) 264{ 265 const uint8_t *oin = *in; 266 267 /* handle the length + allocation if needed */ 268 while (*len && !s->len_valid && s->pos < 2) { 269 s->len = (uint16_t)((s->len << 8) | *((*in)++)); 270 (*len)--; 271 oin = *in; 272 if (++s->pos == 2) { 273 if (s->len > s->limit) 274 return LMSPR_FAILED_OVERSIZE; 275 276 s->pos = 0; 277 s->len_valid = 1; 278 279 if (!s->len) /* do not need to allocate */ 280 return LMSPR_COMPLETED; 281 282 if (!s->buf) { 283 s->buf = lws_malloc(s->len, __func__); 284 if (!s->buf) 285 return LMSPR_FAILED_OOM; 286 287 s->needs_freeing = 1; 288 } 289 } 290 } 291 292 /* handle copying bulk data into allocation */ 293 if (s->len_valid && *len) { 294 uint16_t span = (uint16_t)(s->len - s->pos); 295 296 if (span > *len) 297 span = (uint16_t)*len; 298 299 memcpy(s->buf + s->pos, *in, span); 300 *in += span; 301 s->pos = (uint16_t)(s->pos + (uint16_t)span); 302 } 303 304 *len -= (unsigned long)(*in - oin); 305 306 return s->buf && s->pos == s->len ? LMSPR_COMPLETED : LMSPR_NEED_MORE; 307} 308 309int 310lws_mqtt_bindata_cmp(const lws_mqtt_str_t *bd1, 311 const lws_mqtt_str_t *bd2) 312{ 313 if (bd1->len != bd2->len) 314 return 1; 315 316 if (!!bd1->buf != !!bd2->buf) 317 return 1; 318 319 if (!bd1->buf && !bd2->buf) 320 return 0; 321 322 return memcmp(bd1->buf, bd2->buf, bd1->len); 323} 324 325