1 /* 2 * libwebsockets - protocol - mqtt 3 * 4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation: 9 * version 2.1 of the License. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19 * MA 02110-1301 USA 20 * 21 * included from libwebsockets.h 22 */ 23 24 #ifndef _LWS_MQTT_H 25 #define _LWS_MQTT_H 1 26 27 struct _lws_mqtt_related; 28 typedef struct _lws_mqtt_related lws_mqtt_related_t; 29 struct lws_mqtt_str_st; 30 typedef struct lws_mqtt_str_st lws_mqtt_str_t; 31 32 #define MQTT_VER_3_1_1 4 33 34 #define LWS_MQTT_FINAL_PART 1 35 36 typedef enum { 37 QOS0, 38 QOS1, 39 QOS2, /* not supported */ 40 RESERVED_QOS_LEVEL, 41 FAILURE_QOS_LEVEL = 0x80 42 } lws_mqtt_qos_levels_t; 43 44 typedef union { 45 struct { 46 uint8_t retain:1; 47 uint8_t qos:2; 48 uint8_t dup:1; 49 uint8_t ctrl_pkt_type:4; 50 } flags; 51 uint8_t bits; 52 } lws_mqtt_fixed_hdr_t; 53 54 /* 55 * MQTT connection parameters, passed into struct 56 * lws_client_connect_info to establish a connection using 57 * lws_client_connect_via_info(). 58 */ 59 typedef struct lws_mqtt_client_connect_param_s { 60 const char *client_id; /* Client ID */ 61 uint16_t keep_alive; /* MQTT keep alive 62 interval in 63 seconds */ 64 uint8_t clean_start; /* MQTT clean 65 session */ 66 struct { 67 const char *topic; 68 const char *message; 69 lws_mqtt_qos_levels_t qos; 70 uint8_t retain; 71 } will_param; /* MQTT LWT 72 parameters */ 73 const char *username; 74 const char *password; 75 } lws_mqtt_client_connect_param_t; 76 77 /* 78 * MQTT publish parameters 79 */ 80 typedef struct lws_mqtt_publish_param_s { 81 char *topic; /* Topic Name */ 82 uint16_t topic_len; 83 const void *payload; /* Publish Payload */ 84 uint32_t payload_len; /* Size of the 85 complete payload */ 86 uint32_t payload_pos; /* where we are in payload */ 87 lws_mqtt_qos_levels_t qos; 88 89 /*--v-Following will be used by LWS-v--*/ 90 uint16_t packet_id; /* Packet ID for QoS > 91 0 */ 92 uint8_t dup:1; /* Retried PUBLISH, 93 for QoS > 0 */ 94 } lws_mqtt_publish_param_t; 95 96 typedef struct topic_elem { 97 const char *name; /* Topic Name */ 98 lws_mqtt_qos_levels_t qos; /* Requested QoS */ 99 100 /*--v-Following will be used by LWS-v--*/ 101 uint8_t acked; 102 } lws_mqtt_topic_elem_t; 103 104 /* 105 * MQTT publish parameters 106 */ 107 typedef struct lws_mqtt_subscribe_param_s { 108 uint32_t num_topics; /* Number of topics */ 109 lws_mqtt_topic_elem_t *topic; /* Array of topic elements */ 110 111 /*--v-Following will be used by LWS-v--*/ 112 uint16_t packet_id; 113 } lws_mqtt_subscribe_param_t; 114 115 typedef enum { 116 LMQCP_RESERVED, 117 LMQCP_CTOS_CONNECT, /* Connection request */ 118 LMQCP_STOC_CONNACK, /* Connection acknowledgment */ 119 LMQCP_PUBLISH, /* Publish Message */ 120 LMQCP_PUBACK, /* QoS 1: Publish acknowledgment */ 121 LMQCP_PUBREC, /* QoS 2.1: Publish received */ 122 LMQCP_PUBREL, /* QoS 2.2: Publish release */ 123 LMQCP_PUBCOMP, /* QoS 2.3: Publish complete */ 124 LMQCP_CTOS_SUBSCRIBE, /* Subscribe request */ 125 LMQCP_STOC_SUBACK, /* Subscribe acknowledgment */ 126 LMQCP_CTOS_UNSUBSCRIBE, /* Unsubscribe request */ 127 LMQCP_STOC_UNSUBACK, /* Unsubscribe acknowledgment */ 128 LMQCP_CTOS_PINGREQ, /* PING request */ 129 LMQCP_STOC_PINGRESP, /* PONG response */ 130 LMQCP_DISCONNECT, /* Disconnect notification */ 131 LMQCP_AUTH /* Authentication exchange */ 132 } lws_mqtt_control_packet_t; 133 134 /* flags from byte 8 of C_TO_S CONNECT */ 135 typedef enum { 136 LMQCFT_USERNAME = (1 << 7), 137 LMQCFT_PASSWORD = (1 << 6), 138 LMQCFT_WILL_RETAIN = (1 << 5), 139 LMQCFT_WILL_QOS = (1 << 3), 140 LMQCFT_WILL_FLAG = (1 << 2), 141 LMQCFT_CLEAN_START = (1 << 1), 142 LMQCFT_RESERVED = (1 << 0), 143 144 LMQCFT_WILL_QOS_MASK = (3 << 3), 145 } lws_mqtt_connect_flags_t; 146 147 /* flags for S_TO_C CONNACK */ 148 typedef enum { 149 LMQCFT_SESSION_PRESENT = (1 << 0), 150 } lws_mqtt_connack_flags_t; 151 152 typedef enum { 153 LMQCP_REASON_SUCCESS = 0x00, 154 LMQCP_REASON_NORMAL_DISCONNECTION = 0x00, 155 LMQCP_REASON_GRANTED_QOS0 = 0x00, 156 LMQCP_REASON_GRANTED_QOS1 = 0x01, 157 LMQCP_REASON_GRANTED_QOS2 = 0x02, 158 LMQCP_REASON_DISCONNECT_WILL = 0x04, 159 LMQCP_REASON_NO_MATCHING_SUBSCRIBER = 0x10, 160 LMQCP_REASON_NO_SUBSCRIPTION_EXISTED = 0x11, 161 LMQCP_REASON_CONTINUE_AUTHENTICATION = 0x18, 162 LMQCP_REASON_RE_AUTHENTICATE = 0x19, 163 164 LMQCP_REASON_UNSPECIFIED_ERROR = 0x80, 165 LMQCP_REASON_MALFORMED_PACKET = 0x81, 166 LMQCP_REASON_PROTOCOL_ERROR = 0x82, 167 LMQCP_REASON_IMPLEMENTATION_SPECIFIC_ERROR = 0x83, 168 169 /* Begin - Error codes for CONNACK */ 170 LMQCP_REASON_UNSUPPORTED_PROTOCOL = 0x84, 171 LMQCP_REASON_CLIENT_ID_INVALID = 0x85, 172 LMQCP_REASON_BAD_CREDENTIALS = 0x86, 173 LMQCP_REASON_NOT_AUTHORIZED = 0x87, 174 /* End - Error codes for CONNACK */ 175 176 LMQCP_REASON_SERVER_UNAVAILABLE = 0x88, 177 LMQCP_REASON_SERVER_BUSY = 0x89, 178 LMQCP_REASON_BANNED = 0x8a, 179 LMQCP_REASON_SERVER_SHUTTING_DOWN = 0x8b, 180 LMQCP_REASON_BAD_AUTHENTICATION_METHOD = 0x8c, 181 LMQCP_REASON_KEEPALIVE_TIMEOUT = 0x8d, 182 LMQCP_REASON_SESSION_TAKEN_OVER = 0x8e, 183 LMQCP_REASON_TOPIC_FILTER_INVALID = 0x8f, 184 LMQCP_REASON_TOPIC_NAME_INVALID = 0x90, 185 LMQCP_REASON_PACKET_ID_IN_USE = 0x91, 186 LMQCP_REASON_PACKET_ID_NOT_FOUND = 0x92, 187 LMQCP_REASON_MAX_RX_EXCEEDED = 0x93, 188 LMQCP_REASON_TOPIC_ALIAS_INVALID = 0x94, 189 LMQCP_REASON_PACKET_TOO_LARGE = 0x95, 190 LMQCP_REASON_RATELIMIT = 0x96, 191 LMQCP_REASON_QUOTA_EXCEEDED = 0x97, 192 LMQCP_REASON_ADMINISTRATIVE_ACTION = 0x98, 193 LMQCP_REASON_PAYLOAD_FORMAT_INVALID = 0x99, 194 LMQCP_REASON_RETAIN_NOT_SUPPORTED = 0x9a, 195 LMQCP_REASON_QOS_NOT_SUPPORTED = 0x9b, 196 LMQCP_REASON_USE_ANOTHER_SERVER = 0x9c, 197 LMQCP_REASON_SERVER_MOVED = 0x9d, 198 LMQCP_REASON_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 0x9e, 199 LMQCP_REASON_CONNECTION_RATE_EXCEEDED = 0x9f, 200 LMQCP_REASON_MAXIMUM_CONNECT_TIME = 0xa0, 201 LMQCP_REASON_SUBSCRIPTION_IDS_NOT_SUPPORTED = 0xa1, 202 LMQCP_REASON_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xa2, 203 } lws_mqtt_reason_t; 204 205 typedef enum { 206 LMQPROP_INVALID, 207 LMQPROP_PAYLOAD_FORMAT_INDICATOR = 0x01, 208 LMQPROP_MESSAGE_EXPIRY_INTERVAL = 0x02, 209 LMQPROP_CONTENT_TYPE = 0x03, 210 LMQPROP_RESPONSE_TOPIC = 0x08, 211 LMQPROP_CORRELATION_DATA = 0x09, 212 LMQPROP_SUBSCRIPTION_IDENTIFIER = 0x0b, 213 LMQPROP_SESSION_EXPIRY_INTERVAL = 0x11, 214 LMQPROP_ASSIGNED_CLIENT_IDENTIFIER = 0x12, 215 LMQPROP_SERVER_KEEP_ALIVE = 0x13, 216 LMQPROP_AUTHENTICATION_METHOD = 0x15, 217 LMQPROP_AUTHENTICATION_DATA = 0x16, 218 LMQPROP_REQUEST_PROBLEM_INFORMATION = 0x17, 219 LMQPROP_WILL_DELAY_INTERVAL = 0x18, 220 LMQPROP_REQUEST_RESPONSE_INFORMATION = 0x19, 221 LMQPROP_RESPONSE_INFORMATION = 0x1a, 222 LMQPROP_SERVER_REFERENCE = 0x1c, 223 LMQPROP_REASON_STRING = 0x1f, 224 LMQPROP_RECEIVE_MAXIMUM = 0x21, 225 LMQPROP_TOPIC_ALIAS_MAXIMUM = 0x22, 226 LMQPROP_TOPIC_ALIAS = 0x23, 227 LMQPROP_MAXIMUM_QOS = 0x24, 228 LMQPROP_RETAIN_AVAILABLE = 0x25, 229 LMQPROP_USER_PROPERTY = 0x26, 230 LMQPROP_MAXIMUM_PACKET_SIZE = 0x27, 231 LMQPROP_WILDCARD_SUBSCRIPTION_AVAIL = 0x28, 232 LMQPROP_SUBSCRIPTION_IDENTIFIER_AVAIL = 0x29, 233 LMQPROP_SHARED_SUBSCRIPTION_AVAIL = 0x2a 234 } lws_mqtt_property; 235 236 int 237 lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len); 238 239 /* returns 0 if bd1 and bd2 are "the same", that includes empty, else nonzero */ 240 LWS_VISIBLE LWS_EXTERN int 241 lws_mqtt_bindata_cmp(const lws_mqtt_str_t *bd1, const lws_mqtt_str_t *bd2); 242 243 LWS_VISIBLE LWS_EXTERN void 244 lws_mqtt_str_init(lws_mqtt_str_t *s, uint8_t *buf, uint16_t lim, char nf); 245 246 LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t * 247 lws_mqtt_str_create(uint16_t lim); 248 249 LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t * 250 lws_mqtt_str_create_init(uint8_t *buf, uint16_t len, uint16_t lim); 251 252 LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t * 253 lws_mqtt_str_create_cstr_dup(const char *buf, uint16_t lim); 254 255 LWS_VISIBLE LWS_EXTERN uint8_t * 256 lws_mqtt_str_next(lws_mqtt_str_t *s, uint16_t *budget); 257 258 LWS_VISIBLE LWS_EXTERN int 259 lws_mqtt_str_advance(lws_mqtt_str_t *s, int n); 260 261 LWS_VISIBLE LWS_EXTERN void 262 lws_mqtt_str_free(lws_mqtt_str_t **s); 263 264 265 /** 266 * lws_mqtt_client_send_publish() - lws_write a publish packet 267 * 268 * \param wsi: the mqtt child wsi 269 * \param pub: additional information on what we're publishing 270 * \param buf: payload to send 271 * \param len: length of data in buf 272 * \param final: flag indicating this is the last part 273 * 274 * Issues part of, or the whole of, a PUBLISH frame. The first part of the 275 * frame contains the header, and uses the .qos and .payload_len parts of \p pub 276 * since MQTT requires the frame to specify the PUBLISH message length at the 277 * start. The \p len paramter may be less than \p pub.payload_len, in which 278 * case subsequent calls with more payload are needed to complete the frame. 279 * 280 * Although the connection is stuck waiting for the remainder, in that it can't 281 * issue any other frames until the current one is completed, lws returns to the 282 * event loop normally and can continue the calls with additional payload even 283 * for huge frames as the data becomes available, consistent with timeout needs 284 * and latency to start any new frame (even, eg, related to ping / pong). 285 * 286 * If you're sending large frames, the OS will typically not allow the data to 287 * be sent all at once to kernel side. So you should ideally cut the payload 288 * up into 1 or 2- mtu sized chunks and send that. 289 * 290 * Final should be set when you're calling with the last part of the payload. 291 */ 292 LWS_VISIBLE LWS_EXTERN int 293 lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub, 294 const void *buf, uint32_t len, int final); 295 296 /** 297 * lws_mqtt_client_send_subcribe() - lws_write a subscribe packet 298 * 299 * \param wsi: the mqtt child wsi 300 * \param sub: which topic(s) we want to subscribe to 301 * 302 * For topics other child streams have not already subscribed to, send a packet 303 * to the server asking to subscribe to them. If all topics listed are already 304 * subscribed to be the shared network connection, just trigger the 305 * LWS_CALLBACK_MQTT_SUBSCRIBED callback as if a SUBACK had come. 306 * 307 * \p sub doesn't need to exist after the return from this function. 308 */ 309 LWS_VISIBLE LWS_EXTERN int 310 lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub); 311 312 /** 313 * lws_mqtt_client_send_unsubcribe() - lws_write a unsubscribe packet 314 * 315 * \param wsi: the mqtt child wsi 316 * \param sub: which topic(s) we want to unsubscribe from 317 * 318 * For topics other child streams are not subscribed to, send a packet 319 * to the server asking to unsubscribe from them. If all topics 320 * listed are already subscribed by other child streams on the shared 321 * network connection, just trigger the LWS_CALLBACK_MQTT_UNSUBSCRIBED 322 * callback as if a UNSUBACK had come. 323 * 324 * \p unsub doesn't need to exist after the return from this function. 325 */ 326 LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT 327 lws_mqtt_client_send_unsubcribe(struct lws *wsi, 328 const lws_mqtt_subscribe_param_t *unsub); 329 330 #endif /* _LWS_MQTT_H */ 331