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