1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * Sakthi Kannan <saktr@amazon.com> 6d4afb5ceSopenharmony_ci * 7d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 8d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 9d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 10d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 12d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 13d4afb5ceSopenharmony_ci * 14d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 15d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 16d4afb5ceSopenharmony_ci * 17d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 24d4afb5ceSopenharmony_ci */ 25d4afb5ceSopenharmony_ci 26d4afb5ceSopenharmony_ci#include <private-lib-core.h> 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci#define MQTT_CONNECT_MSG_BASE_LEN (12) 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_cistruct lws * 31d4afb5ceSopenharmony_cilws_mqtt_client_send_connect(struct lws *wsi) 32d4afb5ceSopenharmony_ci{ 33d4afb5ceSopenharmony_ci /* static int */ 34d4afb5ceSopenharmony_ci /* lws_mqttc_abs_writeable(lws_abs_protocol_inst_t *api, size_t budget) */ 35d4afb5ceSopenharmony_ci const lws_mqttc_t *c = &wsi->mqtt->client; 36d4afb5ceSopenharmony_ci uint8_t b[256 + LWS_PRE], *start = b + LWS_PRE, *p = start; 37d4afb5ceSopenharmony_ci unsigned int len = MQTT_CONNECT_MSG_BASE_LEN; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci switch (lwsi_state(wsi)) { 40d4afb5ceSopenharmony_ci case LRS_MQTTC_IDLE: 41d4afb5ceSopenharmony_ci /* 42d4afb5ceSopenharmony_ci * Transport connected - this is our chance to do the 43d4afb5ceSopenharmony_ci * protocol connect action. 44d4afb5ceSopenharmony_ci */ 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci /* 1. Fixed Headers */ 47d4afb5ceSopenharmony_ci if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_CONNECT, 0, 0, 0)) { 48d4afb5ceSopenharmony_ci lwsl_err("%s: Failled to fill fixed header\n", __func__); 49d4afb5ceSopenharmony_ci return NULL; 50d4afb5ceSopenharmony_ci } 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci /* 53d4afb5ceSopenharmony_ci * 2. Remaining length - Add the lengths of client ID, 54d4afb5ceSopenharmony_ci * username and password and their length fields if 55d4afb5ceSopenharmony_ci * the respective flags are set. 56d4afb5ceSopenharmony_ci */ 57d4afb5ceSopenharmony_ci len += c->id->len; 58d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_USERNAME && c->username) { 59d4afb5ceSopenharmony_ci len = len + (unsigned int)c->username->len + 2; 60d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_PASSWORD) 61d4afb5ceSopenharmony_ci len += (unsigned int)(c->password ? c->password->len : 0) + 2u; 62d4afb5ceSopenharmony_ci } 63d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_WILL_FLAG && c->will.topic) { 64d4afb5ceSopenharmony_ci len = len + (unsigned int)c->will.topic->len + 2; 65d4afb5ceSopenharmony_ci len += (c->will.message ? c->will.message->len : 0) + 2u; 66d4afb5ceSopenharmony_ci } 67d4afb5ceSopenharmony_ci p += lws_mqtt_vbi_encode(len, p); 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci /* 70d4afb5ceSopenharmony_ci * 3. Variable Header - Protocol name & level, Connect 71d4afb5ceSopenharmony_ci * flags and keep alive time (in secs). 72d4afb5ceSopenharmony_ci */ 73d4afb5ceSopenharmony_ci lws_ser_wu16be(p, 4); /* Length of protocol name */ 74d4afb5ceSopenharmony_ci p += 2; 75d4afb5ceSopenharmony_ci *p++ = 'M'; 76d4afb5ceSopenharmony_ci *p++ = 'Q'; 77d4afb5ceSopenharmony_ci *p++ = 'T'; 78d4afb5ceSopenharmony_ci *p++ = 'T'; 79d4afb5ceSopenharmony_ci *p++ = MQTT_VER_3_1_1; 80d4afb5ceSopenharmony_ci *p++ = (uint8_t)c->conn_flags; 81d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->keep_alive_secs); 82d4afb5ceSopenharmony_ci p += 2; 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci /* 85d4afb5ceSopenharmony_ci * 4. Payload - Client ID, Will topic & message, 86d4afb5ceSopenharmony_ci * Username & password. 87d4afb5ceSopenharmony_ci */ 88d4afb5ceSopenharmony_ci if (lws_mqtt_str_is_not_empty(c->id)) { 89d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->id->len); 90d4afb5ceSopenharmony_ci p += 2; 91d4afb5ceSopenharmony_ci memcpy(p, c->id->buf, c->id->len); 92d4afb5ceSopenharmony_ci p += c->id->len; 93d4afb5ceSopenharmony_ci } else { 94d4afb5ceSopenharmony_ci /* 95d4afb5ceSopenharmony_ci * If the Client supplies a zero-byte 96d4afb5ceSopenharmony_ci * ClientId, the Client MUST also set 97d4afb5ceSopenharmony_ci * CleanSession to 1 [MQTT-3.1.3-7]. 98d4afb5ceSopenharmony_ci */ 99d4afb5ceSopenharmony_ci if (!(c->conn_flags & LMQCFT_CLEAN_START)) { 100d4afb5ceSopenharmony_ci lwsl_err("%s: Empty client ID needs a clean start\n", 101d4afb5ceSopenharmony_ci __func__); 102d4afb5ceSopenharmony_ci return NULL; 103d4afb5ceSopenharmony_ci } 104d4afb5ceSopenharmony_ci *p++ = 0; 105d4afb5ceSopenharmony_ci } 106d4afb5ceSopenharmony_ci 107d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_WILL_FLAG) { 108d4afb5ceSopenharmony_ci if (lws_mqtt_str_is_not_empty(c->will.topic)) { 109d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->will.topic->len); 110d4afb5ceSopenharmony_ci p += 2; 111d4afb5ceSopenharmony_ci memcpy(p, c->will.topic->buf, c->will.topic->len); 112d4afb5ceSopenharmony_ci p += c->will.topic->len; 113d4afb5ceSopenharmony_ci if (lws_mqtt_str_is_not_empty(c->will.message)) { 114d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->will.message->len); 115d4afb5ceSopenharmony_ci p += 2; 116d4afb5ceSopenharmony_ci memcpy(p, c->will.message->buf, 117d4afb5ceSopenharmony_ci c->will.message->len); 118d4afb5ceSopenharmony_ci p += c->will.message->len; 119d4afb5ceSopenharmony_ci } else { 120d4afb5ceSopenharmony_ci lws_ser_wu16be(p, 0); 121d4afb5ceSopenharmony_ci p += 2; 122d4afb5ceSopenharmony_ci } 123d4afb5ceSopenharmony_ci } else { 124d4afb5ceSopenharmony_ci lwsl_err("%s: Missing Will Topic\n", __func__); 125d4afb5ceSopenharmony_ci return NULL; 126d4afb5ceSopenharmony_ci } 127d4afb5ceSopenharmony_ci } 128d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_USERNAME) { 129d4afb5ceSopenharmony_ci /* 130d4afb5ceSopenharmony_ci * Detailed sanity check on the username and 131d4afb5ceSopenharmony_ci * password strings. 132d4afb5ceSopenharmony_ci */ 133d4afb5ceSopenharmony_ci if (lws_mqtt_str_is_not_empty(c->username)) { 134d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->username->len); 135d4afb5ceSopenharmony_ci p += 2; 136d4afb5ceSopenharmony_ci memcpy(p, c->username->buf, c->username->len); 137d4afb5ceSopenharmony_ci p += c->username->len; 138d4afb5ceSopenharmony_ci } else { 139d4afb5ceSopenharmony_ci lwsl_err("%s: Empty / missing Username!\n", 140d4afb5ceSopenharmony_ci __func__); 141d4afb5ceSopenharmony_ci return NULL; 142d4afb5ceSopenharmony_ci } 143d4afb5ceSopenharmony_ci if (c->conn_flags & LMQCFT_PASSWORD) { 144d4afb5ceSopenharmony_ci if (lws_mqtt_str_is_not_empty(c->password)) { 145d4afb5ceSopenharmony_ci lws_ser_wu16be(p, c->password->len); 146d4afb5ceSopenharmony_ci p += 2; 147d4afb5ceSopenharmony_ci memcpy(p, c->password->buf, 148d4afb5ceSopenharmony_ci c->password->len); 149d4afb5ceSopenharmony_ci p += c->password->len; 150d4afb5ceSopenharmony_ci } else { 151d4afb5ceSopenharmony_ci lws_ser_wu16be(p, 0); 152d4afb5ceSopenharmony_ci p += 2; 153d4afb5ceSopenharmony_ci } 154d4afb5ceSopenharmony_ci } 155d4afb5ceSopenharmony_ci } else if (c->conn_flags & LMQCFT_PASSWORD) { 156d4afb5ceSopenharmony_ci lwsl_err("%s: Unsupported - Password without username\n", 157d4afb5ceSopenharmony_ci __func__); 158d4afb5ceSopenharmony_ci return NULL; 159d4afb5ceSopenharmony_ci } 160d4afb5ceSopenharmony_ci break; 161d4afb5ceSopenharmony_ci default: 162d4afb5ceSopenharmony_ci lwsl_err("%s: unexpected state %d\n", __func__, lwsi_state(wsi)); 163d4afb5ceSopenharmony_ci 164d4afb5ceSopenharmony_ci return NULL; 165d4afb5ceSopenharmony_ci } 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci /* 168d4afb5ceSopenharmony_ci * Perform the actual write 169d4afb5ceSopenharmony_ci */ 170d4afb5ceSopenharmony_ci if (lws_write(wsi, (unsigned char *)&b[LWS_PRE], lws_ptr_diff_size_t(p, start), 171d4afb5ceSopenharmony_ci LWS_WRITE_BINARY) != lws_ptr_diff(p, start)) { 172d4afb5ceSopenharmony_ci lwsl_notice("%s: write failed\n", __func__); 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci return NULL; 175d4afb5ceSopenharmony_ci } 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_ci return wsi; 178d4afb5ceSopenharmony_ci} 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_cistruct lws * 181d4afb5ceSopenharmony_cilws_mqtt_client_send_disconnect(struct lws *wsi) 182d4afb5ceSopenharmony_ci{ 183d4afb5ceSopenharmony_ci uint8_t b[256 + LWS_PRE], *start = b + LWS_PRE, *p = start; 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci /* 1. Fixed Headers */ 186d4afb5ceSopenharmony_ci if (lws_mqtt_fill_fixed_header(p++, LMQCP_DISCONNECT, 0, 0, 0)) 187d4afb5ceSopenharmony_ci { 188d4afb5ceSopenharmony_ci lwsl_err("%s: Failled to fill fixed header\n", __func__); 189d4afb5ceSopenharmony_ci return NULL; 190d4afb5ceSopenharmony_ci } 191d4afb5ceSopenharmony_ci *p++ = 0; 192d4afb5ceSopenharmony_ci if (lws_write(wsi, (unsigned char *)&b[LWS_PRE], lws_ptr_diff_size_t(p, start), 193d4afb5ceSopenharmony_ci LWS_WRITE_BINARY) != lws_ptr_diff(p, start)) { 194d4afb5ceSopenharmony_ci lwsl_err("%s: write failed\n", __func__); 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci return NULL; 197d4afb5ceSopenharmony_ci } 198d4afb5ceSopenharmony_ci 199d4afb5ceSopenharmony_ci return wsi; 200d4afb5ceSopenharmony_ci} 201