• 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->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 = 23;
56 
57 	if (len > 23) /* 3.1.3.1-5: Server MUST... between 1 and 23 chars... */
58 		return 1;
59 
60 	*ms = lws_mqtt_str_create((uint16_t)(len + 1));
61 	if (!*ms)
62 		return 1;
63 
64 	buf = lws_mqtt_str_next(*ms, NULL);
65 
66 	if (client_id) {
67 		lws_strnncpy((char *)buf, client_id, len, len + 1);
68 		lwsl_notice("%s: User space provided a client ID '%s'\n",
69 			    __func__, (const char *)buf);
70 	} else {
71 		lwsl_notice("%s: generating random client id\n", __func__);
72 		n = len * sizeof(ran[0]);
73 		if (lws_get_random(context, ran, n) != n) {
74 			lws_mqtt_str_free(ms);
75 
76 			return 1;
77 		}
78 
79 		for (n = 0; n < len; n++)
80 			buf[n] = code[ran[n] % 62];
81 		buf[len] = '\0';
82 	}
83 
84 	lws_mqtt_str_advance(*ms, (uint16_t)len);
85 
86 	return 0;
87 }
88 
89 int
lws_read_mqtt(struct lws * wsi,unsigned char * buf,lws_filepos_t len)90 lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
91 {
92 	lws_mqttc_t *c = &wsi->mqtt->client;
93 
94 	return _lws_mqtt_rx_parser(wsi, &c->par, buf, len);
95 }
96 
97 int
lws_create_client_mqtt_object(const struct lws_client_connect_info * i,struct lws * wsi)98 lws_create_client_mqtt_object(const struct lws_client_connect_info *i,
99 			      struct lws *wsi)
100 {
101 	lws_mqttc_t *c;
102 	const lws_mqtt_client_connect_param_t *cp = i->mqtt_cp;
103 
104 	/* allocate the ws struct for the wsi */
105 	wsi->mqtt = lws_zalloc(sizeof(*wsi->mqtt), "client mqtt struct");
106 	if (!wsi->mqtt)
107 		goto oom;
108 
109 	wsi->mqtt->wsi = wsi;
110 	c = &wsi->mqtt->client;
111 
112 	if (lws_mqtt_generate_id(wsi, &c->id, cp->client_id)) {
113 		lwsl_err("%s: Error generating client ID\n", __func__);
114 		return 1;
115 	}
116 	lwsl_info("%s: using client id '%.*s'\n", __func__, c->id->len,
117 			(const char *)c->id->buf);
118 
119 	if (cp->clean_start || !cp->client_id[0])
120 		c->conn_flags = LMQCFT_CLEAN_START;
121 
122 	c->keep_alive_secs = cp->keep_alive;
123 
124 	if (cp->will_param.topic &&
125 	    *cp->will_param.topic) {
126 		c->will.topic = lws_mqtt_str_create_cstr_dup(
127 						cp->will_param.topic, 0);
128 		if (!c->will.topic)
129 			goto oom1;
130 		c->conn_flags |= LMQCFT_WILL_FLAG;
131 		if (cp->will_param.message) {
132 			c->will.message = lws_mqtt_str_create_cstr_dup(
133 						cp->will_param.message, 0);
134 			if (!c->will.message)
135 				goto oom2;
136 		}
137 		c->conn_flags |= (cp->will_param.qos << 3) & LMQCFT_WILL_QOS_MASK;
138 		c->conn_flags |= (!!cp->will_param.retain) * LMQCFT_WILL_RETAIN;
139 	}
140 
141 	if (cp->username &&
142 	    *cp->username) {
143 		c->username = lws_mqtt_str_create_cstr_dup(cp->username, 0);
144 		if (!c->username)
145 			goto oom3;
146 		c->conn_flags |= LMQCFT_USERNAME;
147 		if (cp->password) {
148 			c->password =
149 				lws_mqtt_str_create_cstr_dup(cp->password, 0);
150 			if (!c->password)
151 				goto oom4;
152 			c->conn_flags |= LMQCFT_PASSWORD;
153 		}
154 	}
155 
156 	return 0;
157 oom4:
158 	lws_mqtt_str_free(&c->username);
159 oom3:
160 	lws_mqtt_str_free(&c->will.message);
161 oom2:
162 	lws_mqtt_str_free(&c->will.topic);
163 oom1:
164 	lws_mqtt_str_free(&c->id);
165 oom:
166 	lwsl_err("%s: OOM!\n", __func__);
167 	return 1;
168 }
169 
170 int
lws_mqtt_client_socket_service(struct lws * wsi,struct lws_pollfd * pollfd,struct lws * wsi_conn)171 lws_mqtt_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
172 			  struct lws *wsi_conn)
173 {
174 	struct lws_context *context = wsi->context;
175 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
176 	int n = 0, m = 0;
177 	struct lws_tokens ebuf;
178 	int buffered = 0;
179 	char pending = 0;
180 #if defined(LWS_WITH_TLS)
181 	char erbuf[128];
182 #endif
183 	const char *cce = NULL;
184 
185 	switch (lwsi_state(wsi)) {
186 #if defined(LWS_WITH_SOCKS5)
187 	/* SOCKS Greeting Reply */
188 	case LRS_WAITING_SOCKS_GREETING_REPLY:
189 	case LRS_WAITING_SOCKS_AUTH_REPLY:
190 	case LRS_WAITING_SOCKS_CONNECT_REPLY:
191 
192 		switch (lws_socks5c_handle_state(wsi, pollfd, &cce)) {
193 		case LW5CHS_RET_RET0:
194 			return 0;
195 		case LW5CHS_RET_BAIL3:
196 			goto bail3;
197 		case LW5CHS_RET_STARTHS:
198 
199 			/*
200 			 * Now we got the socks5 connection, we need to go down
201 			 * the tls path on it if that's what we want
202 			 */
203 
204 			if (!(wsi->tls.use_ssl & LCCSCF_USE_SSL))
205 				goto start_ws_handshake;
206 
207 			switch (lws_client_create_tls(wsi, &cce, 0)) {
208 			case 0:
209 				break;
210 			case 1:
211 				return 0;
212 			default:
213 				goto bail3;
214 			}
215 
216 			break;
217 
218 		default:
219 			break;
220 		}
221 		break;
222 #endif
223 	case LRS_WAITING_DNS:
224 		/*
225 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
226 		 * timeout protection set in client-handshake.c
227 		 */
228 		if (!lws_client_connect_2_dnsreq(wsi)) {
229 			/* closed */
230 			lwsl_client("closed\n");
231 			return -1;
232 		}
233 
234 		/* either still pending connection, or changed mode */
235 		return 0;
236 
237 	case LRS_WAITING_CONNECT:
238 
239 		/*
240 		 * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
241 		 * timeout protection set in client-handshake.c
242 		 */
243 		if (pollfd->revents & LWS_POLLOUT)
244 			lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
245 		break;
246 
247 #if defined(LWS_WITH_TLS)
248 	case LRS_WAITING_SSL:
249 
250 		if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
251 			n = lws_ssl_client_connect2(wsi, erbuf, sizeof(erbuf));
252 			if (!n)
253 				return 0;
254 			if (n < 0) {
255 				cce = erbuf;
256 				goto bail3;
257 			}
258 		} else
259 			wsi->tls.ssl = NULL;
260 #endif /* LWS_WITH_TLS */
261 
262 #if defined(LWS_WITH_DETAILED_LATENCY)
263 		if (context->detailed_latency_cb) {
264 			wsi->detlat.type = LDLT_TLS_NEG_CLIENT;
265 			wsi->detlat.latencies[LAT_DUR_PROXY_CLIENT_REQ_TO_WRITE] =
266 				lws_now_usecs() -
267 				wsi->detlat.earliest_write_req_pre_write;
268 			wsi->detlat.latencies[LAT_DUR_USERCB] = 0;
269 			lws_det_lat_cb(wsi->context, &wsi->detlat);
270 		}
271 #endif
272 #if 0
273 		if (wsi->client_h2_alpn) {
274 			/*
275 			 * We connected to the server and set up tls, and
276 			 * negotiated "h2".
277 			 *
278 			 * So this is it, we are an h2 master client connection
279 			 * now, not an h1 client connection.
280 			 */
281 #if defined(LWS_WITH_TLS)
282 			lws_tls_server_conn_alpn(wsi);
283 #endif
284 
285 			/* send the H2 preface to legitimize the connection */
286 			if (lws_h2_issue_preface(wsi)) {
287 				cce = "error sending h2 preface";
288 				goto bail3;
289 			}
290 
291 			break;
292 		}
293 #endif
294 
295 		/* fallthru */
296 
297 #if defined(LWS_WITH_SOCKS5)
298 start_ws_handshake:
299 #endif
300 		lwsi_set_state(wsi, LRS_MQTTC_IDLE);
301 		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
302 				context->timeout_secs);
303 
304 		/* fallthru */
305 
306 	case LRS_MQTTC_IDLE:
307 		/*
308 		 * we should be ready to send out MQTT CONNECT
309 		 */
310 		lwsl_info("%s: wsi %p: Transport established, send out CONNECT\n",
311 				__func__, wsi);
312 		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
313 			return -1;
314 		if (!lws_mqtt_client_send_connect(wsi)) {
315 			lwsl_err("%s: Unable to send MQTT CONNECT\n", __func__);
316 			return -1;
317 		}
318 		if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
319 			return -1;
320 
321 		lwsi_set_state(wsi, LRS_MQTTC_AWAIT_CONNACK);
322 		return 0;
323 
324 	case LRS_ESTABLISHED:
325 	case LRS_MQTTC_AWAIT_CONNACK:
326 		buffered = 0;
327 		ebuf.token = pt->serv_buf;
328 		ebuf.len = wsi->context->pt_serv_buf_size;
329 
330 		if ((unsigned int)ebuf.len > wsi->context->pt_serv_buf_size)
331 			ebuf.len = wsi->context->pt_serv_buf_size;
332 
333 		if ((int)pending > ebuf.len)
334 			pending = ebuf.len;
335 
336 		ebuf.len = lws_ssl_capable_read(wsi, ebuf.token,
337 						pending ? (int)pending :
338 						ebuf.len);
339 		switch (ebuf.len) {
340 		case 0:
341 			lwsl_info("%s: zero length read\n",
342 				  __func__);
343 			goto fail;
344 		case LWS_SSL_CAPABLE_MORE_SERVICE:
345 			lwsl_info("SSL Capable more service\n");
346 			return 0;
347 		case LWS_SSL_CAPABLE_ERROR:
348 			lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n",
349 					__func__);
350 			goto fail;
351 		}
352 
353 		if (ebuf.len < 0)
354 			n = -1;
355 		else
356 			n = lws_read_mqtt(wsi, ebuf.token, ebuf.len);
357 		if (n < 0) {
358 			lwsl_err("%s: Parsing packet failed\n", __func__);
359 			goto fail;
360 		}
361 
362 		m = ebuf.len - n;
363 		// lws_buflist_describe(&wsi->buflist, wsi, __func__);
364 		lwsl_debug("%s: consuming %d / %d\n", __func__, n, ebuf.len);
365 		if (lws_buflist_aware_finished_consuming(wsi, &ebuf, m,
366 							 buffered,
367 							 __func__))
368 			return -1;
369 
370 		return 0;
371 
372 #if defined(LWS_WITH_TLS) || defined(LWS_WITH_SOCKS5)
373 bail3:
374 #endif
375 		lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
376 		if (cce)
377 			lwsl_info("reason: %s\n", cce);
378 		lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
379 
380 		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
381 		return -1;
382 
383 	default:
384 		break;
385 	}
386 
387 	return 0;
388 fail:
389 	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "mqtt svc fail");
390 
391 	return LWS_HPI_RET_WSI_ALREADY_DIED;
392 }
393