• 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 
25 /*
26  * You can leave buf NULL, if so it will be allocated on the heap once the
27  * actual length is known.  nf should be 0, it will be set at allocation time.
28  *
29  * Or you can ensure no allocation and use an external buffer by setting buf
30  * and lim.  But buf must be in the ep context somehow, since it may have to
31  * survive returns to the event loop unchanged.  Set nf to 0 in this case.
32  *
33  * Or you can set buf to an externally allocated buffer, in which case you may
34  * set nf so it will be freed when the string is "freed".
35  */
36 
37 #include "private-lib-core.h"
38 /* #include "lws-mqtt.h" */
39 /* 3.1.3.1-5: MUST allow... that contain only the characters... */
40 
41 static const uint8_t *code = (const uint8_t *)
42 	"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
43 
44 static int
lws_mqtt_generate_id(struct lws * wsi,lws_mqtt_str_t ** ms,const char * client_id)45 lws_mqtt_generate_id(struct lws* wsi, lws_mqtt_str_t **ms, const char *client_id)
46 {
47 	struct lws_context *context = wsi->a.context;
48 	uint16_t ran[24]; /* 16-bit so wrap bias from %62 diluted by ~1000 */
49 	size_t n, len;
50 	uint8_t *buf;
51 
52 	if (client_id)
53 		len = strlen(client_id);
54 	else
55 		len = LWS_MQTT_RANDOM_CIDLEN;
56 
57 	*ms = lws_mqtt_str_create((uint16_t)(len + 1));
58 	if (!*ms)
59 		return 1;
60 
61 	buf = lws_mqtt_str_next(*ms, NULL);
62 
63 	if (client_id) {
64 		lws_strnncpy((char *)buf, client_id, len, len + 1);
65 		lwsl_notice("%s: User space provided a client ID '%s'\n",
66 			    __func__, (const char *)buf);
67 	} else {
68 		lwsl_notice("%s: generating random client id\n", __func__);
69 		n = len * sizeof(ran[0]);
70 		if (lws_get_random(context, ran, n) != n) {
71 			lws_mqtt_str_free(ms);
72 
73 			return 1;
74 		}
75 
76 		for (n = 0; n < len; n++)
77 			buf[n] = code[ran[n] % 62];
78 		buf[len] = '\0';
79 	}
80 
81 	if (lws_mqtt_str_advance(*ms, (uint16_t)len)) {
82 		lws_mqtt_str_free(ms);
83 
84 		return 1;
85 	}
86 
87 	return 0;
88 }
89 
90 int
lws_read_mqtt(struct lws * wsi,unsigned char * buf,lws_filepos_t len)91 lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
92 {
93 	lws_mqttc_t *c = &wsi->mqtt->client;
94 
95 	return _lws_mqtt_rx_parser(wsi, &c->par, buf, (size_t)len);
96 }
97 
98 int
lws_create_client_mqtt_object(const struct lws_client_connect_info * i,struct lws * wsi)99 lws_create_client_mqtt_object(const struct lws_client_connect_info *i,
100 			      struct lws *wsi)
101 {
102 	lws_mqttc_t *c;
103 	const lws_mqtt_client_connect_param_t *cp = i->mqtt_cp;
104 
105 	/* allocate the ws struct for the wsi */
106 	wsi->mqtt = lws_zalloc(sizeof(*wsi->mqtt), "client mqtt struct");
107 	if (!wsi->mqtt)
108 		goto oom;
109 
110 	wsi->mqtt->wsi = wsi;
111 	c = &wsi->mqtt->client;
112 
113 	if (lws_mqtt_generate_id(wsi, &c->id, cp->client_id)) {
114 		lwsl_err("%s: Error generating client ID\n", __func__);
115 		return 1;
116 	}
117 	lwsl_info("%s: using client id '%.*s'\n", __func__, c->id->len,
118 			(const char *)c->id->buf);
119 
120 	if (cp->clean_start || !(cp->client_id &&
121 				 cp->client_id[0]))
122 		c->conn_flags = LMQCFT_CLEAN_START;
123 	if (cp->client_id_nofree)
124 		c->conn_flags |= LMQCFT_CLIENT_ID_NOFREE;
125 	if (cp->username_nofree)
126 		c->conn_flags |= LMQCFT_USERNAME_NOFREE;
127 	if (cp->password_nofree)
128 		c->conn_flags |= LMQCFT_PASSWORD_NOFREE;
129 
130 	if (!(c->conn_flags & LMQCFT_CLIENT_ID_NOFREE))
131 		lws_free((void *)cp->client_id);
132 
133 	c->keep_alive_secs = cp->keep_alive;
134 	c->aws_iot = cp->aws_iot;
135 
136 	if (cp->will_param.topic &&
137 	    *cp->will_param.topic) {
138 		c->will.topic = lws_mqtt_str_create_cstr_dup(
139 						cp->will_param.topic, 0);
140 		if (!c->will.topic)
141 			goto oom1;
142 		c->conn_flags |= LMQCFT_WILL_FLAG;
143 		if (cp->will_param.message) {
144 			c->will.message = lws_mqtt_str_create_cstr_dup(
145 						cp->will_param.message, 0);
146 			if (!c->will.message)
147 				goto oom2;
148 		}
149 		c->conn_flags = (uint16_t)(unsigned int)(c->conn_flags | ((cp->will_param.qos << 3) & LMQCFT_WILL_QOS_MASK));
150 		c->conn_flags |= (uint16_t)((!!cp->will_param.retain) * LMQCFT_WILL_RETAIN);
151 	}
152 
153 	if (cp->username &&
154 	    *cp->username) {
155 		c->username = lws_mqtt_str_create_cstr_dup(cp->username, 0);
156 		if (!c->username)
157 			goto oom3;
158 		c->conn_flags |= LMQCFT_USERNAME;
159 		if (!(c->conn_flags & LMQCFT_USERNAME_NOFREE))
160 			lws_free((void *)cp->username);
161 		if (cp->password) {
162 			c->password =
163 				lws_mqtt_str_create_cstr_dup(cp->password, 0);
164 			if (!c->password)
165 				goto oom4;
166 			c->conn_flags |= LMQCFT_PASSWORD;
167 			if (!(c->conn_flags & LMQCFT_PASSWORD_NOFREE))
168 				lws_free((void *)cp->password);
169 		}
170 	}
171 
172 	return 0;
173 oom4:
174 	lws_mqtt_str_free(&c->username);
175 oom3:
176 	lws_mqtt_str_free(&c->will.message);
177 oom2:
178 	lws_mqtt_str_free(&c->will.topic);
179 oom1:
180 	lws_mqtt_str_free(&c->id);
181 oom:
182 	lwsl_err("%s: OOM!\n", __func__);
183 	return 1;
184 }
185 
186 int
lws_mqtt_client_socket_service(struct lws * wsi,struct lws_pollfd * pollfd,struct lws * wsi_conn)187 lws_mqtt_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
188 			  struct lws *wsi_conn)
189 {
190 	struct lws_context *context = wsi->a.context;
191 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
192 	int n = 0, m = 0;
193 	struct lws_tokens ebuf;
194 	int buffered = 0;
195 	int pending = 0;
196 #if defined(LWS_WITH_TLS)
197 	char erbuf[128];
198 #endif
199 	const char *cce = NULL;
200 
201 	switch (lwsi_state(wsi)) {
202 #if defined(LWS_WITH_SOCKS5)
203 	/* SOCKS Greeting Reply */
204 	case LRS_WAITING_SOCKS_GREETING_REPLY:
205 	case LRS_WAITING_SOCKS_AUTH_REPLY:
206 	case LRS_WAITING_SOCKS_CONNECT_REPLY:
207 
208 		switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
209 		case LW5CHS_RET_RET0:
210 			return 0;
211 		case LW5CHS_RET_BAIL3:
212 			goto bail3;
213 		case LW5CHS_RET_STARTHS:
214 
215 			/*
216 			 * Now we got the socks5 connection, we need to go down
217 			 * the tls path on it if that's what we want
218 			 */
219 
220 			if (!(wsi->tls.use_ssl & LCCSCF_USE_SSL))
221 				goto start_ws_handshake;
222 
223 			switch (lws_client_create_tls(wsi, &cce, 0)) {
224 			case 0:
225 				break;
226 			case 1:
227 				return 0;
228 			default:
229 				goto bail3;
230 			}
231 
232 			break;
233 
234 		default:
235 			break;
236 		}
237 		break;
238 #endif
239 	case LRS_WAITING_DNS:
240 		/*
241 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
242 		 * timeout protection set in client-handshake.c
243 		 */
244 		if (!lws_client_connect_2_dnsreq(wsi)) {
245 			/* closed */
246 			lwsl_client("closed\n");
247 			return -1;
248 		}
249 
250 		/* either still pending connection, or changed mode */
251 		return 0;
252 
253 	case LRS_WAITING_CONNECT:
254 
255 		/*
256 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
257 		 * timeout protection set in client-handshake.c
258 		 */
259 		if (pollfd->revents & LWS_POLLOUT)
260 			lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
261 		break;
262 
263 #if defined(LWS_WITH_TLS)
264 	case LRS_WAITING_SSL:
265 
266 		if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
267 			n = lws_ssl_client_connect2(wsi, erbuf, sizeof(erbuf));
268 			if (!n)
269 				return 0;
270 			if (n < 0) {
271 				cce = erbuf;
272 				goto bail3;
273 			}
274 		} else
275 			wsi->tls.ssl = NULL;
276 #endif /* LWS_WITH_TLS */
277 
278 		/* fallthru */
279 
280 #if defined(LWS_WITH_SOCKS5)
281 start_ws_handshake:
282 #endif
283 		lwsi_set_state(wsi, LRS_MQTTC_IDLE);
284 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
285 				(int)context->timeout_secs);
286 
287 		/* fallthru */
288 
289 	case LRS_MQTTC_IDLE:
290 		/*
291 		 * we should be ready to send out MQTT CONNECT
292 		 */
293 		lwsl_info("%s: %s: Transport established, send out CONNECT\n",
294 				__func__, lws_wsi_tag(wsi));
295 		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
296 			return -1;
297 		if (!lws_mqtt_client_send_connect(wsi)) {
298 			lwsl_err("%s: Unable to send MQTT CONNECT\n", __func__);
299 			return -1;
300 		}
301 		if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
302 			return -1;
303 
304 		lwsi_set_state(wsi, LRS_MQTTC_AWAIT_CONNACK);
305 		return 0;
306 
307 	case LRS_ESTABLISHED:
308 	case LRS_MQTTC_AWAIT_CONNACK:
309 		buffered = 0;
310 		ebuf.token = pt->serv_buf;
311 		ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
312 
313 		if ((unsigned int)ebuf.len > wsi->a.context->pt_serv_buf_size)
314 			ebuf.len = (int)wsi->a.context->pt_serv_buf_size;
315 
316 		if ((int)pending > ebuf.len)
317 			pending = (char)ebuf.len;
318 
319 		ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
320 						(unsigned int)(pending ? pending :
321 						ebuf.len));
322 		switch (ebuf.len) {
323 		case 0:
324 			lwsl_info("%s: zero length read\n",
325 				  __func__);
326 			goto fail;
327 		case LWS_SSL_CAPABLE_MORE_SERVICE:
328 			lwsl_info("SSL Capable more service\n");
329 			return 0;
330 		case LWS_SSL_CAPABLE_ERROR:
331 			lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n",
332 					__func__);
333 			goto fail;
334 		}
335 
336 		if (ebuf.len < 0)
337 			n = -1;
338 		else
339 			n = lws_read_mqtt(wsi, ebuf.token, (unsigned int)ebuf.len);
340 		if (n < 0) {
341 			lwsl_err("%s: Parsing packet failed\n", __func__);
342 			goto fail;
343 		}
344 
345 		m = ebuf.len - n;
346 		// lws_buflist_describe(&wsi->buflist, wsi, __func__);
347 		lwsl_debug("%s: consuming %d / %d\n", __func__, n, ebuf.len);
348 		if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m,
349 							 buffered,
350 							 __func__))
351 			return -1;
352 
353 		return 0;
354 
355 #if defined(LWS_WITH_TLS) || defined(LWS_WITH_SOCKS5)
356 bail3:
357 #endif
358 		lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
359 		if (cce)
360 			lwsl_info("reason: %s\n", cce);
361 		lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
362 
363 		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
364 		return -1;
365 
366 	default:
367 		break;
368 	}
369 
370 	return 0;
371 fail:
372 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "mqtt svc fail");
373 
374 	return LWS_HPI_RET_WSI_ALREADY_DIED;
375 }
376