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
42 int
lws_mqtt_vbi_encode(uint32_t value,void * buf)43 lws_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
64 void
lws_mqtt_vbi_init(lws_mqtt_vbi * vbi)65 lws_mqtt_vbi_init(lws_mqtt_vbi *vbi)
66 {
67 vbi->value = 0;
68 vbi->consumed = 0;
69 vbi->budget = 4;
70 }
71
72 void
lws_mqtt_2byte_init(lws_mqtt_vbi * vbi)73 lws_mqtt_2byte_init(lws_mqtt_vbi *vbi)
74 {
75 vbi->value = 0;
76 vbi->consumed = 0;
77 vbi->budget = 2;
78 }
79
80 void
lws_mqtt_4byte_init(lws_mqtt_vbi * vbi)81 lws_mqtt_4byte_init(lws_mqtt_vbi *vbi)
82 {
83 vbi->value = 0;
84 vbi->consumed = 0;
85 vbi->budget = 4;
86 }
87
88 lws_mqtt_stateful_primitive_return_t
lws_mqtt_vbi_r(lws_mqtt_vbi * vbi,const uint8_t ** in,size_t * len)89 lws_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
118 lws_mqtt_stateful_primitive_return_t
lws_mqtt_mb_parse(lws_mqtt_vbi * vbi,const uint8_t ** in,size_t * len)119 lws_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
145 void
lws_mqtt_str_init(lws_mqtt_str_t * s,uint8_t * buf,uint16_t lim,char nf)146 lws_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
156 lws_mqtt_str_t *
lws_mqtt_str_create(uint16_t lim)157 lws_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
174 lws_mqtt_str_t *
lws_mqtt_str_create_init(uint8_t * buf,uint16_t len,uint16_t lim)175 lws_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
196 lws_mqtt_str_t *
lws_mqtt_str_create_cstr_dup(const char * buf,uint16_t lim)197 lws_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
207 uint8_t *
lws_mqtt_str_next(lws_mqtt_str_t * s,uint16_t * budget)208 lws_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
216 int
lws_mqtt_str_advance(lws_mqtt_str_t * s,int n)217 lws_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
231 void
lws_mqtt_str_free(lws_mqtt_str_t ** ps)232 lws_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 */
262 lws_mqtt_stateful_primitive_return_t
lws_mqtt_str_parse(lws_mqtt_str_t * s,const uint8_t ** in,size_t * len)263 lws_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
309 int
lws_mqtt_bindata_cmp(const lws_mqtt_str_t * bd1,const lws_mqtt_str_t * bd2)310 lws_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