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