• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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