1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker *
13*1c60b9acSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker *
24*1c60b9acSAndroid Build Coastguard Worker * MQTT v5
25*1c60b9acSAndroid Build Coastguard Worker *
26*1c60b9acSAndroid Build Coastguard Worker * http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
27*1c60b9acSAndroid Build Coastguard Worker *
28*1c60b9acSAndroid Build Coastguard Worker * Control Packet structure
29*1c60b9acSAndroid Build Coastguard Worker *
30*1c60b9acSAndroid Build Coastguard Worker * - Always: 2+ byte: Fixed Hdr
31*1c60b9acSAndroid Build Coastguard Worker * - Required in some: variable: Variable Hdr + [(CONNECT)Will Props] + Props
32*1c60b9acSAndroid Build Coastguard Worker * - Required in some: variable: Payload
33*1c60b9acSAndroid Build Coastguard Worker *
34*1c60b9acSAndroid Build Coastguard Worker * For CONNECT, the props if present MUST be in the order [MQTT-3.1.3-1]
35*1c60b9acSAndroid Build Coastguard Worker *
36*1c60b9acSAndroid Build Coastguard Worker * - Client Identifier
37*1c60b9acSAndroid Build Coastguard Worker * - Will Properties
38*1c60b9acSAndroid Build Coastguard Worker * - Will Topic
39*1c60b9acSAndroid Build Coastguard Worker * - Will Payload
40*1c60b9acSAndroid Build Coastguard Worker * - User Name
41*1c60b9acSAndroid Build Coastguard Worker * - Password
42*1c60b9acSAndroid Build Coastguard Worker */
43*1c60b9acSAndroid Build Coastguard Worker
44*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
45*1c60b9acSAndroid Build Coastguard Worker #include <string.h>
46*1c60b9acSAndroid Build Coastguard Worker #include <sys/types.h>
47*1c60b9acSAndroid Build Coastguard Worker #include <assert.h>
48*1c60b9acSAndroid Build Coastguard Worker
49*1c60b9acSAndroid Build Coastguard Worker typedef enum {
50*1c60b9acSAndroid Build Coastguard Worker LMQPRS_AWAITING_CONNECT,
51*1c60b9acSAndroid Build Coastguard Worker
52*1c60b9acSAndroid Build Coastguard Worker } lws_mqtt_protocol_server_connstate_t;
53*1c60b9acSAndroid Build Coastguard Worker
54*1c60b9acSAndroid Build Coastguard Worker const char * const reason_names_g1[] = {
55*1c60b9acSAndroid Build Coastguard Worker "Success / Normal disconnection / QoS0",
56*1c60b9acSAndroid Build Coastguard Worker "QoS1",
57*1c60b9acSAndroid Build Coastguard Worker "QoS2",
58*1c60b9acSAndroid Build Coastguard Worker "Disconnect Will",
59*1c60b9acSAndroid Build Coastguard Worker "No matching subscriber",
60*1c60b9acSAndroid Build Coastguard Worker "No subscription existed",
61*1c60b9acSAndroid Build Coastguard Worker "Continue authentication",
62*1c60b9acSAndroid Build Coastguard Worker "Re-authenticate"
63*1c60b9acSAndroid Build Coastguard Worker };
64*1c60b9acSAndroid Build Coastguard Worker
65*1c60b9acSAndroid Build Coastguard Worker const char * const reason_names_g2[] = {
66*1c60b9acSAndroid Build Coastguard Worker "Unspecified error",
67*1c60b9acSAndroid Build Coastguard Worker "Malformed packet",
68*1c60b9acSAndroid Build Coastguard Worker "Protocol error",
69*1c60b9acSAndroid Build Coastguard Worker "Implementation specific error",
70*1c60b9acSAndroid Build Coastguard Worker "Unsupported protocol",
71*1c60b9acSAndroid Build Coastguard Worker "Client ID invalid",
72*1c60b9acSAndroid Build Coastguard Worker "Bad credentials",
73*1c60b9acSAndroid Build Coastguard Worker "Not Authorized",
74*1c60b9acSAndroid Build Coastguard Worker "Server Unavailable",
75*1c60b9acSAndroid Build Coastguard Worker "Server Busy",
76*1c60b9acSAndroid Build Coastguard Worker "Banned",
77*1c60b9acSAndroid Build Coastguard Worker "Server Shutting Down",
78*1c60b9acSAndroid Build Coastguard Worker "Bad Authentication Method",
79*1c60b9acSAndroid Build Coastguard Worker "Keepalive Timeout",
80*1c60b9acSAndroid Build Coastguard Worker "Session taken over",
81*1c60b9acSAndroid Build Coastguard Worker "Topic Filter Invalid",
82*1c60b9acSAndroid Build Coastguard Worker "Packet ID in use",
83*1c60b9acSAndroid Build Coastguard Worker "Packet ID not found",
84*1c60b9acSAndroid Build Coastguard Worker "Max RX Exceeded",
85*1c60b9acSAndroid Build Coastguard Worker "Topic Alias Invalid",
86*1c60b9acSAndroid Build Coastguard Worker "Packet too large",
87*1c60b9acSAndroid Build Coastguard Worker "Ratelimit",
88*1c60b9acSAndroid Build Coastguard Worker "Quota Exceeded",
89*1c60b9acSAndroid Build Coastguard Worker "Administrative Action",
90*1c60b9acSAndroid Build Coastguard Worker "Payload format invalid",
91*1c60b9acSAndroid Build Coastguard Worker "Retain not supported",
92*1c60b9acSAndroid Build Coastguard Worker "QoS not supported",
93*1c60b9acSAndroid Build Coastguard Worker "Use another server",
94*1c60b9acSAndroid Build Coastguard Worker "Server Moved",
95*1c60b9acSAndroid Build Coastguard Worker "Shared subscriptions not supported",
96*1c60b9acSAndroid Build Coastguard Worker "Connection rate exceeded",
97*1c60b9acSAndroid Build Coastguard Worker "Maximum Connect Time",
98*1c60b9acSAndroid Build Coastguard Worker "Subscription IDs not supported",
99*1c60b9acSAndroid Build Coastguard Worker "Wildcard subscriptions not supported"
100*1c60b9acSAndroid Build Coastguard Worker };
101*1c60b9acSAndroid Build Coastguard Worker
102*1c60b9acSAndroid Build Coastguard Worker #define LMQCP_WILL_PROPERTIES 0
103*1c60b9acSAndroid Build Coastguard Worker
104*1c60b9acSAndroid Build Coastguard Worker /* For each property, a bitmap describing which commands it is valid for */
105*1c60b9acSAndroid Build Coastguard Worker
106*1c60b9acSAndroid Build Coastguard Worker static const uint16_t property_valid[] = {
107*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_PAYLOAD_FORMAT_INDICATOR] = (1 << LMQCP_PUBLISH) |
108*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES),
109*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_MESSAGE_EXPIRY_INTERVAL] = (1 << LMQCP_PUBLISH) |
110*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES),
111*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_CONTENT_TYPE] = (1 << LMQCP_PUBLISH) |
112*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES),
113*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_RESPONSE_TOPIC] = (1 << LMQCP_PUBLISH) |
114*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES),
115*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_CORRELATION_DATA] = (1 << LMQCP_PUBLISH) |
116*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES),
117*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SUBSCRIPTION_IDENTIFIER] = (1 << LMQCP_PUBLISH) |
118*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_CTOS_SUBSCRIBE),
119*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SESSION_EXPIRY_INTERVAL] = (1 << LMQCP_CTOS_CONNECT) |
120*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK) |
121*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_DISCONNECT),
122*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_ASSIGNED_CLIENT_IDENTIFIER] = (1 << LMQCP_STOC_CONNACK),
123*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SERVER_KEEP_ALIVE] = (1 << LMQCP_STOC_CONNACK),
124*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_AUTHENTICATION_METHOD] = (1 << LMQCP_CTOS_CONNECT) |
125*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK) |
126*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_AUTH),
127*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_AUTHENTICATION_DATA] = (1 << LMQCP_CTOS_CONNECT) |
128*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK) |
129*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_AUTH),
130*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_REQUEST_PROBLEM_INFORMATION] = (1 << LMQCP_CTOS_CONNECT),
131*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_WILL_DELAY_INTERVAL] = (1 << LMQCP_WILL_PROPERTIES),
132*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_REQUEST_RESPONSE_INFORMATION] = (1 << LMQCP_CTOS_CONNECT),
133*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_RESPONSE_INFORMATION] = (1 << LMQCP_STOC_CONNACK),
134*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SERVER_REFERENCE] = (1 << LMQCP_STOC_CONNACK) |
135*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_DISCONNECT),
136*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_REASON_STRING] = (1 << LMQCP_STOC_CONNACK) |
137*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBACK) |
138*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBREC) |
139*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBREL) |
140*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBCOMP) |
141*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_SUBACK) |
142*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_UNSUBACK) |
143*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_DISCONNECT) |
144*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_AUTH),
145*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_RECEIVE_MAXIMUM] = (1 << LMQCP_CTOS_CONNECT) |
146*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK),
147*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_TOPIC_ALIAS_MAXIMUM] = (1 << LMQCP_CTOS_CONNECT) |
148*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK),
149*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_TOPIC_ALIAS] = (1 << LMQCP_PUBLISH),
150*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_MAXIMUM_QOS] = (1 << LMQCP_STOC_CONNACK),
151*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_RETAIN_AVAILABLE] = (1 << LMQCP_STOC_CONNACK),
152*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_USER_PROPERTY] = (1 << LMQCP_CTOS_CONNECT) |
153*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK) |
154*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBLISH) |
155*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_WILL_PROPERTIES) |
156*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBACK) |
157*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBREC) |
158*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBREL) |
159*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_PUBCOMP) |
160*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_CTOS_SUBSCRIBE) |
161*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_SUBACK) |
162*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_CTOS_UNSUBSCRIBE) |
163*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_UNSUBACK) |
164*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_DISCONNECT) |
165*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_AUTH),
166*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_MAXIMUM_PACKET_SIZE] = (1 << LMQCP_CTOS_CONNECT) |
167*1c60b9acSAndroid Build Coastguard Worker (1 << LMQCP_STOC_CONNACK),
168*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_WILDCARD_SUBSCRIPTION_AVAIL] = (1 << LMQCP_STOC_CONNACK),
169*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SUBSCRIPTION_IDENTIFIER_AVAIL] = (1 << LMQCP_STOC_CONNACK),
170*1c60b9acSAndroid Build Coastguard Worker [LMQPROP_SHARED_SUBSCRIPTION_AVAIL] = (1 << LMQCP_STOC_CONNACK)
171*1c60b9acSAndroid Build Coastguard Worker };
172*1c60b9acSAndroid Build Coastguard Worker
173*1c60b9acSAndroid Build Coastguard Worker
174*1c60b9acSAndroid Build Coastguard Worker /*
175*1c60b9acSAndroid Build Coastguard Worker * For each command index, maps flags, id, qos and payload legality
176*1c60b9acSAndroid Build Coastguard Worker * notice in most cases PUBLISH requires further processing
177*1c60b9acSAndroid Build Coastguard Worker */
178*1c60b9acSAndroid Build Coastguard Worker static const uint8_t map_flags[] = {
179*1c60b9acSAndroid Build Coastguard Worker [LMQCP_RESERVED] = 0x00,
180*1c60b9acSAndroid Build Coastguard Worker [LMQCP_CTOS_CONNECT] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
181*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PAYLOAD |
182*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
183*1c60b9acSAndroid Build Coastguard Worker [LMQCP_STOC_CONNACK] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
184*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
185*1c60b9acSAndroid Build Coastguard Worker [LMQCP_PUBLISH] = LMQCP_LUT_FLAG_PAYLOAD | /* option */
186*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_QOS12 | 0x00,
187*1c60b9acSAndroid Build Coastguard Worker [LMQCP_PUBACK] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
188*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
189*1c60b9acSAndroid Build Coastguard Worker [LMQCP_PUBREC] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
190*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
191*1c60b9acSAndroid Build Coastguard Worker [LMQCP_PUBREL] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
192*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
193*1c60b9acSAndroid Build Coastguard Worker [LMQCP_PUBCOMP] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
194*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
195*1c60b9acSAndroid Build Coastguard Worker [LMQCP_CTOS_SUBSCRIBE] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
196*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PAYLOAD |
197*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
198*1c60b9acSAndroid Build Coastguard Worker [LMQCP_STOC_SUBACK] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
199*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PAYLOAD |
200*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x00,
201*1c60b9acSAndroid Build Coastguard Worker [LMQCP_CTOS_UNSUBSCRIBE] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
202*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PAYLOAD |
203*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_HAS | 0x02,
204*1c60b9acSAndroid Build Coastguard Worker [LMQCP_STOC_UNSUBACK] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
205*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PAYLOAD |
206*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
207*1c60b9acSAndroid Build Coastguard Worker [LMQCP_CTOS_PINGREQ] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
208*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
209*1c60b9acSAndroid Build Coastguard Worker [LMQCP_STOC_PINGRESP] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
210*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
211*1c60b9acSAndroid Build Coastguard Worker [LMQCP_DISCONNECT] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
212*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
213*1c60b9acSAndroid Build Coastguard Worker [LMQCP_AUTH] = LMQCP_LUT_FLAG_RESERVED_FLAGS |
214*1c60b9acSAndroid Build Coastguard Worker LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00,
215*1c60b9acSAndroid Build Coastguard Worker };
216*1c60b9acSAndroid Build Coastguard Worker
217*1c60b9acSAndroid Build Coastguard Worker void
lws_mqttc_state_transition(lws_mqttc_t * c,lwsgs_mqtt_states_t s)218*1c60b9acSAndroid Build Coastguard Worker lws_mqttc_state_transition(lws_mqttc_t *c, lwsgs_mqtt_states_t s)
219*1c60b9acSAndroid Build Coastguard Worker {
220*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: ep %p: state %d -> %d\n", __func__, c, c->estate, s);
221*1c60b9acSAndroid Build Coastguard Worker c->estate = s;
222*1c60b9acSAndroid Build Coastguard Worker }
223*1c60b9acSAndroid Build Coastguard Worker
224*1c60b9acSAndroid Build Coastguard Worker static int
lws_mqtt_pconsume(lws_mqtt_parser_t * par,int consumed)225*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_pconsume(lws_mqtt_parser_t *par, int consumed)
226*1c60b9acSAndroid Build Coastguard Worker {
227*1c60b9acSAndroid Build Coastguard Worker par->consumed += (unsigned int)consumed;
228*1c60b9acSAndroid Build Coastguard Worker
229*1c60b9acSAndroid Build Coastguard Worker if (par->consumed > par->props_len)
230*1c60b9acSAndroid Build Coastguard Worker return -1;
231*1c60b9acSAndroid Build Coastguard Worker
232*1c60b9acSAndroid Build Coastguard Worker /* more properties coming */
233*1c60b9acSAndroid Build Coastguard Worker
234*1c60b9acSAndroid Build Coastguard Worker if (par->consumed < par->props_len) {
235*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PROP_ID_VBI;
236*1c60b9acSAndroid Build Coastguard Worker return 0;
237*1c60b9acSAndroid Build Coastguard Worker }
238*1c60b9acSAndroid Build Coastguard Worker
239*1c60b9acSAndroid Build Coastguard Worker /* properties finished: are we headed for payload or idle? */
240*1c60b9acSAndroid Build Coastguard Worker
241*1c60b9acSAndroid Build Coastguard Worker if ((map_flags[ctl_pkt_type(par)] & LMQCP_LUT_FLAG_PAYLOAD) &&
242*1c60b9acSAndroid Build Coastguard Worker /* A PUBLISH packet MUST NOT contain a Packet Identifier if
243*1c60b9acSAndroid Build Coastguard Worker * its QoS value is set to 0 [MQTT-2.2.1-2]. */
244*1c60b9acSAndroid Build Coastguard Worker (ctl_pkt_type(par) != LMQCP_PUBLISH ||
245*1c60b9acSAndroid Build Coastguard Worker (par->packet_type_flags & 6))) {
246*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PAYLOAD;
247*1c60b9acSAndroid Build Coastguard Worker return 0;
248*1c60b9acSAndroid Build Coastguard Worker }
249*1c60b9acSAndroid Build Coastguard Worker
250*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_IDLE;
251*1c60b9acSAndroid Build Coastguard Worker
252*1c60b9acSAndroid Build Coastguard Worker return 0;
253*1c60b9acSAndroid Build Coastguard Worker }
254*1c60b9acSAndroid Build Coastguard Worker
255*1c60b9acSAndroid Build Coastguard Worker static int
lws_mqtt_set_client_established(struct lws * wsi)256*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_set_client_established(struct lws *wsi)
257*1c60b9acSAndroid Build Coastguard Worker {
258*1c60b9acSAndroid Build Coastguard Worker lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
259*1c60b9acSAndroid Build Coastguard Worker &role_ops_mqtt);
260*1c60b9acSAndroid Build Coastguard Worker
261*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(wsi->a.protocol->callback,
262*1c60b9acSAndroid Build Coastguard Worker wsi, LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED,
263*1c60b9acSAndroid Build Coastguard Worker wsi->user_space, NULL, 0) < 0) {
264*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: MQTT_ESTABLISHED failed\n", __func__);
265*1c60b9acSAndroid Build Coastguard Worker
266*1c60b9acSAndroid Build Coastguard Worker return -1;
267*1c60b9acSAndroid Build Coastguard Worker }
268*1c60b9acSAndroid Build Coastguard Worker /*
269*1c60b9acSAndroid Build Coastguard Worker * If we made a new connection and got the ACK, our connection is
270*1c60b9acSAndroid Build Coastguard Worker * definitely working in both directions at the moment
271*1c60b9acSAndroid Build Coastguard Worker */
272*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
273*1c60b9acSAndroid Build Coastguard Worker
274*1c60b9acSAndroid Build Coastguard Worker /* clear connection timeout */
275*1c60b9acSAndroid Build Coastguard Worker lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
276*1c60b9acSAndroid Build Coastguard Worker
277*1c60b9acSAndroid Build Coastguard Worker return 0;
278*1c60b9acSAndroid Build Coastguard Worker }
279*1c60b9acSAndroid Build Coastguard Worker
280*1c60b9acSAndroid Build Coastguard Worker
281*1c60b9acSAndroid Build Coastguard Worker static lws_mqtt_match_topic_return_t
lws_mqtt_is_topic_matched(const char * sub,const char * pub)282*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_is_topic_matched(const char* sub, const char* pub)
283*1c60b9acSAndroid Build Coastguard Worker {
284*1c60b9acSAndroid Build Coastguard Worker const char *ppos = pub, *spos = sub;
285*1c60b9acSAndroid Build Coastguard Worker
286*1c60b9acSAndroid Build Coastguard Worker if (!ppos || !spos) {
287*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_MATCH_ERROR;
288*1c60b9acSAndroid Build Coastguard Worker }
289*1c60b9acSAndroid Build Coastguard Worker
290*1c60b9acSAndroid Build Coastguard Worker while (*spos) {
291*1c60b9acSAndroid Build Coastguard Worker if (*ppos == '#' || *ppos == '+') {
292*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: PUBLISH to wildcard "
293*1c60b9acSAndroid Build Coastguard Worker "topic \"%s\" not supported\n",
294*1c60b9acSAndroid Build Coastguard Worker __func__, pub);
295*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_MATCH_ERROR;
296*1c60b9acSAndroid Build Coastguard Worker }
297*1c60b9acSAndroid Build Coastguard Worker /* foo/+/bar == foo/xyz/bar ? */
298*1c60b9acSAndroid Build Coastguard Worker if (*spos == '+') {
299*1c60b9acSAndroid Build Coastguard Worker /* Skip ahead */
300*1c60b9acSAndroid Build Coastguard Worker while (*ppos != '\0' && *ppos != '/') {
301*1c60b9acSAndroid Build Coastguard Worker ppos++;
302*1c60b9acSAndroid Build Coastguard Worker }
303*1c60b9acSAndroid Build Coastguard Worker } else if (*spos == '#') {
304*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_MATCH;
305*1c60b9acSAndroid Build Coastguard Worker } else {
306*1c60b9acSAndroid Build Coastguard Worker if (*ppos == '\0') {
307*1c60b9acSAndroid Build Coastguard Worker /* foo/bar == foo/bar/# ? */
308*1c60b9acSAndroid Build Coastguard Worker if (!strncmp(spos, "/#", 2))
309*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_MATCH;
310*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_NOMATCH;
311*1c60b9acSAndroid Build Coastguard Worker /* Non-matching character */
312*1c60b9acSAndroid Build Coastguard Worker } else if (*ppos != *spos) {
313*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_NOMATCH;
314*1c60b9acSAndroid Build Coastguard Worker }
315*1c60b9acSAndroid Build Coastguard Worker ppos++;
316*1c60b9acSAndroid Build Coastguard Worker }
317*1c60b9acSAndroid Build Coastguard Worker spos++;
318*1c60b9acSAndroid Build Coastguard Worker }
319*1c60b9acSAndroid Build Coastguard Worker
320*1c60b9acSAndroid Build Coastguard Worker if (*spos == '\0' && *ppos == '\0')
321*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_MATCH;
322*1c60b9acSAndroid Build Coastguard Worker
323*1c60b9acSAndroid Build Coastguard Worker return LMMTR_TOPIC_NOMATCH;
324*1c60b9acSAndroid Build Coastguard Worker }
325*1c60b9acSAndroid Build Coastguard Worker
lws_mqtt_find_sub(struct _lws_mqtt_related * mqtt,const char * ptopic)326*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t* lws_mqtt_find_sub(struct _lws_mqtt_related* mqtt,
327*1c60b9acSAndroid Build Coastguard Worker const char* ptopic) {
328*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *s = mqtt->subs_head;
329*1c60b9acSAndroid Build Coastguard Worker
330*1c60b9acSAndroid Build Coastguard Worker while (s) {
331*1c60b9acSAndroid Build Coastguard Worker /* SUB topic == PUB topic ? */
332*1c60b9acSAndroid Build Coastguard Worker /* foo/bar/xyz == foo/bar/xyz ? */
333*1c60b9acSAndroid Build Coastguard Worker if (!s->wildcard) {
334*1c60b9acSAndroid Build Coastguard Worker if (!strcmp((const char*)s->topic, ptopic))
335*1c60b9acSAndroid Build Coastguard Worker return s;
336*1c60b9acSAndroid Build Coastguard Worker } else {
337*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_is_topic_matched(
338*1c60b9acSAndroid Build Coastguard Worker s->topic, ptopic) == LMMTR_TOPIC_MATCH)
339*1c60b9acSAndroid Build Coastguard Worker return s;
340*1c60b9acSAndroid Build Coastguard Worker }
341*1c60b9acSAndroid Build Coastguard Worker
342*1c60b9acSAndroid Build Coastguard Worker s = s->next;
343*1c60b9acSAndroid Build Coastguard Worker }
344*1c60b9acSAndroid Build Coastguard Worker
345*1c60b9acSAndroid Build Coastguard Worker return NULL;
346*1c60b9acSAndroid Build Coastguard Worker }
347*1c60b9acSAndroid Build Coastguard Worker
348*1c60b9acSAndroid Build Coastguard Worker static lws_mqtt_validate_topic_return_t
lws_mqtt_validate_topic(const char * topic,size_t topiclen,uint8_t awsiot)349*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_validate_topic(const char *topic, size_t topiclen, uint8_t awsiot)
350*1c60b9acSAndroid Build Coastguard Worker {
351*1c60b9acSAndroid Build Coastguard Worker size_t spos = 0;
352*1c60b9acSAndroid Build Coastguard Worker const char *sub = topic;
353*1c60b9acSAndroid Build Coastguard Worker int8_t slashes = 0;
354*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_validate_topic_return_t ret = LMVTR_VALID;
355*1c60b9acSAndroid Build Coastguard Worker
356*1c60b9acSAndroid Build Coastguard Worker if (awsiot) {
357*1c60b9acSAndroid Build Coastguard Worker if (topiclen > LWS_MQTT_MAX_AWSIOT_TOPICLEN)
358*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_OVERSIZE;
359*1c60b9acSAndroid Build Coastguard Worker if (topic[0] == '$') {
360*1c60b9acSAndroid Build Coastguard Worker ret = LMVTR_VALID_SHADOW;
361*1c60b9acSAndroid Build Coastguard Worker slashes = -3;
362*1c60b9acSAndroid Build Coastguard Worker }
363*1c60b9acSAndroid Build Coastguard Worker } else {
364*1c60b9acSAndroid Build Coastguard Worker if (topiclen > LWS_MQTT_MAX_TOPICLEN)
365*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_OVERSIZE;
366*1c60b9acSAndroid Build Coastguard Worker if (topic[0] == '$')
367*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_WILDCARD_FORMAT;
368*1c60b9acSAndroid Build Coastguard Worker }
369*1c60b9acSAndroid Build Coastguard Worker
370*1c60b9acSAndroid Build Coastguard Worker while (*sub != 0) {
371*1c60b9acSAndroid Build Coastguard Worker if (sub[0] == '+') {
372*1c60b9acSAndroid Build Coastguard Worker /* topic == "+foo" || "a/+foo" ? */
373*1c60b9acSAndroid Build Coastguard Worker if (spos > 0 && sub[-1] != '/')
374*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_WILDCARD_FORMAT;
375*1c60b9acSAndroid Build Coastguard Worker
376*1c60b9acSAndroid Build Coastguard Worker /* topic == "foo+" or "foo+/a" ? */
377*1c60b9acSAndroid Build Coastguard Worker if (sub[1] != 0 && sub[1] != '/')
378*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_WILDCARD_FORMAT;
379*1c60b9acSAndroid Build Coastguard Worker
380*1c60b9acSAndroid Build Coastguard Worker ret = LMVTR_VALID_WILDCARD;
381*1c60b9acSAndroid Build Coastguard Worker } else if (sub[0] == '#') {
382*1c60b9acSAndroid Build Coastguard Worker /* topic == "foo#" ? */
383*1c60b9acSAndroid Build Coastguard Worker if (spos > 0 && sub[-1] != '/')
384*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_WILDCARD_FORMAT;
385*1c60b9acSAndroid Build Coastguard Worker
386*1c60b9acSAndroid Build Coastguard Worker /* topic == "#foo" ? */
387*1c60b9acSAndroid Build Coastguard Worker if (sub[1] != 0)
388*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_WILDCARD_FORMAT;
389*1c60b9acSAndroid Build Coastguard Worker
390*1c60b9acSAndroid Build Coastguard Worker ret = LMVTR_VALID_WILDCARD;
391*1c60b9acSAndroid Build Coastguard Worker } else if (sub[0] == '/') {
392*1c60b9acSAndroid Build Coastguard Worker slashes++;
393*1c60b9acSAndroid Build Coastguard Worker }
394*1c60b9acSAndroid Build Coastguard Worker spos++;
395*1c60b9acSAndroid Build Coastguard Worker sub++;
396*1c60b9acSAndroid Build Coastguard Worker }
397*1c60b9acSAndroid Build Coastguard Worker
398*1c60b9acSAndroid Build Coastguard Worker if (awsiot && (slashes < 0 || slashes > 7))
399*1c60b9acSAndroid Build Coastguard Worker return LMVTR_FAILED_SHADOW_FORMAT;
400*1c60b9acSAndroid Build Coastguard Worker
401*1c60b9acSAndroid Build Coastguard Worker return ret;
402*1c60b9acSAndroid Build Coastguard Worker }
403*1c60b9acSAndroid Build Coastguard Worker
404*1c60b9acSAndroid Build Coastguard Worker static lws_mqtt_subs_t *
lws_mqtt_create_sub(struct _lws_mqtt_related * mqtt,const char * topic)405*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_create_sub(struct _lws_mqtt_related *mqtt, const char *topic)
406*1c60b9acSAndroid Build Coastguard Worker {
407*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *mysub;
408*1c60b9acSAndroid Build Coastguard Worker size_t topiclen = strlen(topic);
409*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_validate_topic_return_t flag;
410*1c60b9acSAndroid Build Coastguard Worker
411*1c60b9acSAndroid Build Coastguard Worker flag = lws_mqtt_validate_topic(topic, topiclen, mqtt->client.aws_iot);
412*1c60b9acSAndroid Build Coastguard Worker switch (flag) {
413*1c60b9acSAndroid Build Coastguard Worker case LMVTR_FAILED_OVERSIZE:
414*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Topic is too long\n",
415*1c60b9acSAndroid Build Coastguard Worker __func__);
416*1c60b9acSAndroid Build Coastguard Worker return NULL;
417*1c60b9acSAndroid Build Coastguard Worker case LMVTR_FAILED_SHADOW_FORMAT:
418*1c60b9acSAndroid Build Coastguard Worker case LMVTR_FAILED_WILDCARD_FORMAT:
419*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Invalid topic format \"%s\"\n",
420*1c60b9acSAndroid Build Coastguard Worker __func__, topic);
421*1c60b9acSAndroid Build Coastguard Worker return NULL;
422*1c60b9acSAndroid Build Coastguard Worker
423*1c60b9acSAndroid Build Coastguard Worker case LMVTR_VALID:
424*1c60b9acSAndroid Build Coastguard Worker case LMVTR_VALID_WILDCARD:
425*1c60b9acSAndroid Build Coastguard Worker case LMVTR_VALID_SHADOW:
426*1c60b9acSAndroid Build Coastguard Worker mysub = lws_malloc(sizeof(*mysub) + topiclen + 1, "sub");
427*1c60b9acSAndroid Build Coastguard Worker if (!mysub) {
428*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Error allocating mysub\n",
429*1c60b9acSAndroid Build Coastguard Worker __func__);
430*1c60b9acSAndroid Build Coastguard Worker return NULL;
431*1c60b9acSAndroid Build Coastguard Worker }
432*1c60b9acSAndroid Build Coastguard Worker mysub->wildcard = (flag == LMVTR_VALID_WILDCARD);
433*1c60b9acSAndroid Build Coastguard Worker mysub->shadow = (flag == LMVTR_VALID_SHADOW);
434*1c60b9acSAndroid Build Coastguard Worker break;
435*1c60b9acSAndroid Build Coastguard Worker
436*1c60b9acSAndroid Build Coastguard Worker default:
437*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Unknown flag - %d\n",
438*1c60b9acSAndroid Build Coastguard Worker __func__, flag);
439*1c60b9acSAndroid Build Coastguard Worker return NULL;
440*1c60b9acSAndroid Build Coastguard Worker }
441*1c60b9acSAndroid Build Coastguard Worker
442*1c60b9acSAndroid Build Coastguard Worker mysub->next = mqtt->subs_head;
443*1c60b9acSAndroid Build Coastguard Worker mqtt->subs_head = mysub;
444*1c60b9acSAndroid Build Coastguard Worker memcpy(mysub->topic, topic, strlen(topic) + 1);
445*1c60b9acSAndroid Build Coastguard Worker mysub->ref_count = 1;
446*1c60b9acSAndroid Build Coastguard Worker
447*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: Created mysub %p for wsi->mqtt %p\n",
448*1c60b9acSAndroid Build Coastguard Worker __func__, mysub, mqtt);
449*1c60b9acSAndroid Build Coastguard Worker
450*1c60b9acSAndroid Build Coastguard Worker return mysub;
451*1c60b9acSAndroid Build Coastguard Worker }
452*1c60b9acSAndroid Build Coastguard Worker
453*1c60b9acSAndroid Build Coastguard Worker static int
lws_mqtt_client_remove_subs(struct _lws_mqtt_related * mqtt)454*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_client_remove_subs(struct _lws_mqtt_related *mqtt)
455*1c60b9acSAndroid Build Coastguard Worker {
456*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *s = mqtt->subs_head;
457*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *temp = NULL;
458*1c60b9acSAndroid Build Coastguard Worker
459*1c60b9acSAndroid Build Coastguard Worker
460*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: Called to remove subs from wsi->mqtt %p\n",
461*1c60b9acSAndroid Build Coastguard Worker __func__, mqtt);
462*1c60b9acSAndroid Build Coastguard Worker
463*1c60b9acSAndroid Build Coastguard Worker while (s && s->next) {
464*1c60b9acSAndroid Build Coastguard Worker if (s->next->ref_count == 0)
465*1c60b9acSAndroid Build Coastguard Worker break;
466*1c60b9acSAndroid Build Coastguard Worker s = s->next;
467*1c60b9acSAndroid Build Coastguard Worker }
468*1c60b9acSAndroid Build Coastguard Worker
469*1c60b9acSAndroid Build Coastguard Worker if (s && s->next) {
470*1c60b9acSAndroid Build Coastguard Worker temp = s->next;
471*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: Removing sub %p from wsi->mqtt %p\n",
472*1c60b9acSAndroid Build Coastguard Worker __func__, temp, mqtt);
473*1c60b9acSAndroid Build Coastguard Worker s->next = temp->next;
474*1c60b9acSAndroid Build Coastguard Worker lws_free(temp);
475*1c60b9acSAndroid Build Coastguard Worker return 0;
476*1c60b9acSAndroid Build Coastguard Worker }
477*1c60b9acSAndroid Build Coastguard Worker return 1;
478*1c60b9acSAndroid Build Coastguard Worker }
479*1c60b9acSAndroid Build Coastguard Worker
480*1c60b9acSAndroid Build Coastguard Worker int
_lws_mqtt_rx_parser(struct lws * wsi,lws_mqtt_parser_t * par,const uint8_t * buf,size_t len)481*1c60b9acSAndroid Build Coastguard Worker _lws_mqtt_rx_parser(struct lws *wsi, lws_mqtt_parser_t *par,
482*1c60b9acSAndroid Build Coastguard Worker const uint8_t *buf, size_t len)
483*1c60b9acSAndroid Build Coastguard Worker {
484*1c60b9acSAndroid Build Coastguard Worker struct lws *w;
485*1c60b9acSAndroid Build Coastguard Worker int n;
486*1c60b9acSAndroid Build Coastguard Worker
487*1c60b9acSAndroid Build Coastguard Worker if (par->flag_pending_send_reason_close)
488*1c60b9acSAndroid Build Coastguard Worker return 0;
489*1c60b9acSAndroid Build Coastguard Worker
490*1c60b9acSAndroid Build Coastguard Worker /*
491*1c60b9acSAndroid Build Coastguard Worker * Stateful, fragmentation-immune parser
492*1c60b9acSAndroid Build Coastguard Worker *
493*1c60b9acSAndroid Build Coastguard Worker * Notice that len can always be 1 if under attack, even over tls if
494*1c60b9acSAndroid Build Coastguard Worker * the server is compromised or malicious.
495*1c60b9acSAndroid Build Coastguard Worker */
496*1c60b9acSAndroid Build Coastguard Worker
497*1c60b9acSAndroid Build Coastguard Worker while (len) {
498*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: %d, len = %d\n", __func__, par->state, (int)len);
499*1c60b9acSAndroid Build Coastguard Worker switch (par->state) {
500*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_IDLE:
501*1c60b9acSAndroid Build Coastguard Worker par->packet_type_flags = *buf++;
502*1c60b9acSAndroid Build Coastguard Worker len--;
503*1c60b9acSAndroid Build Coastguard Worker
504*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CLIENT)
505*1c60b9acSAndroid Build Coastguard Worker /*
506*1c60b9acSAndroid Build Coastguard Worker * The case where we sent the connect, but we received
507*1c60b9acSAndroid Build Coastguard Worker * something else before any CONNACK
508*1c60b9acSAndroid Build Coastguard Worker */
509*1c60b9acSAndroid Build Coastguard Worker if (lwsi_state(wsi) == LRS_MQTTC_AWAIT_CONNACK &&
510*1c60b9acSAndroid Build Coastguard Worker par->packet_type_flags >> 4 != LMQCP_STOC_CONNACK) {
511*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: server sent non-CONNACK\n",
512*1c60b9acSAndroid Build Coastguard Worker __func__);
513*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
514*1c60b9acSAndroid Build Coastguard Worker }
515*1c60b9acSAndroid Build Coastguard Worker #endif /* LWS_WITH_CLIENT */
516*1c60b9acSAndroid Build Coastguard Worker
517*1c60b9acSAndroid Build Coastguard Worker n = map_flags[par->packet_type_flags >> 4];
518*1c60b9acSAndroid Build Coastguard Worker /*
519*1c60b9acSAndroid Build Coastguard Worker * Where a flag bit is marked as “Reserved”, it is
520*1c60b9acSAndroid Build Coastguard Worker * reserved for future use and MUST be set to the value
521*1c60b9acSAndroid Build Coastguard Worker * listed [MQTT-2.1.3-1].
522*1c60b9acSAndroid Build Coastguard Worker */
523*1c60b9acSAndroid Build Coastguard Worker if ((n & LMQCP_LUT_FLAG_RESERVED_FLAGS) &&
524*1c60b9acSAndroid Build Coastguard Worker ((par->packet_type_flags & 0x0f) != (n & 0x0f))) {
525*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: %s: bad flags, 0x%02x mask 0x%02x (len %d)\n",
526*1c60b9acSAndroid Build Coastguard Worker __func__, lws_wsi_tag(wsi),
527*1c60b9acSAndroid Build Coastguard Worker par->packet_type_flags, n, (int)len + 1);
528*1c60b9acSAndroid Build Coastguard Worker lwsl_hexdump_err(buf - 1, len + 1);
529*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
530*1c60b9acSAndroid Build Coastguard Worker }
531*1c60b9acSAndroid Build Coastguard Worker
532*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received pkt type 0x%x / flags 0x%x\n",
533*1c60b9acSAndroid Build Coastguard Worker __func__, par->packet_type_flags >> 4,
534*1c60b9acSAndroid Build Coastguard Worker par->packet_type_flags & 0xf);
535*1c60b9acSAndroid Build Coastguard Worker
536*1c60b9acSAndroid Build Coastguard Worker /* allows us to know if a property that can only be
537*1c60b9acSAndroid Build Coastguard Worker * given once, appears twice */
538*1c60b9acSAndroid Build Coastguard Worker memset(par->props_seen, 0, sizeof(par->props_seen));
539*1c60b9acSAndroid Build Coastguard Worker par->state = par->packet_type_flags & 0xf0;
540*1c60b9acSAndroid Build Coastguard Worker break;
541*1c60b9acSAndroid Build Coastguard Worker
542*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_PACKET:
543*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received CONNECT pkt\n", __func__);
544*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_REMAINING_LEN_VBI;
545*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
546*1c60b9acSAndroid Build Coastguard Worker break;
547*1c60b9acSAndroid Build Coastguard Worker
548*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_REMAINING_LEN_VBI:
549*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
550*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
551*1c60b9acSAndroid Build Coastguard Worker break;
552*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
553*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
554*1c60b9acSAndroid Build Coastguard Worker n = map_flags[ctl_pkt_type(par)];
555*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&par->s_temp, par->temp,
556*1c60b9acSAndroid Build Coastguard Worker sizeof(par->temp), 0);
557*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_VH_PNAME;
558*1c60b9acSAndroid Build Coastguard Worker break;
559*1c60b9acSAndroid Build Coastguard Worker default:
560*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: bad vbi\n", __func__);
561*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
562*1c60b9acSAndroid Build Coastguard Worker }
563*1c60b9acSAndroid Build Coastguard Worker break;
564*1c60b9acSAndroid Build Coastguard Worker
565*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_VH_PNAME:
566*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_str_parse(&par->s_temp, &buf, &len)) {
567*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
568*1c60b9acSAndroid Build Coastguard Worker break;
569*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
570*1c60b9acSAndroid Build Coastguard Worker if (par->s_temp.len != 4 ||
571*1c60b9acSAndroid Build Coastguard Worker memcmp(par->s_temp.buf, "MQTT",
572*1c60b9acSAndroid Build Coastguard Worker par->s_temp.len)) {
573*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: protocol name: %.*s\n",
574*1c60b9acSAndroid Build Coastguard Worker __func__, par->s_temp.len,
575*1c60b9acSAndroid Build Coastguard Worker par->s_temp.buf);
576*1c60b9acSAndroid Build Coastguard Worker goto send_unsupp_connack_and_close;
577*1c60b9acSAndroid Build Coastguard Worker }
578*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_VH_PVERSION;
579*1c60b9acSAndroid Build Coastguard Worker break;
580*1c60b9acSAndroid Build Coastguard Worker default:
581*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: bad protocol name\n", __func__);
582*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
583*1c60b9acSAndroid Build Coastguard Worker }
584*1c60b9acSAndroid Build Coastguard Worker break;
585*1c60b9acSAndroid Build Coastguard Worker
586*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_VH_PVERSION:
587*1c60b9acSAndroid Build Coastguard Worker par->conn_protocol_version = *buf++;
588*1c60b9acSAndroid Build Coastguard Worker len--;
589*1c60b9acSAndroid Build Coastguard Worker if (par->conn_protocol_version != 5) {
590*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: unsupported MQTT version %d\n",
591*1c60b9acSAndroid Build Coastguard Worker __func__, par->conn_protocol_version);
592*1c60b9acSAndroid Build Coastguard Worker goto send_unsupp_connack_and_close;
593*1c60b9acSAndroid Build Coastguard Worker }
594*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_VH_FLAGS;
595*1c60b9acSAndroid Build Coastguard Worker break;
596*1c60b9acSAndroid Build Coastguard Worker
597*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_VH_FLAGS:
598*1c60b9acSAndroid Build Coastguard Worker par->cpkt_flags = *buf++;
599*1c60b9acSAndroid Build Coastguard Worker len--;
600*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_flags & 1) {
601*1c60b9acSAndroid Build Coastguard Worker /*
602*1c60b9acSAndroid Build Coastguard Worker * The Server MUST validate that the reserved
603*1c60b9acSAndroid Build Coastguard Worker * flag in the CONNECT packet is set to 0
604*1c60b9acSAndroid Build Coastguard Worker * [MQTT-3.1.2-3].
605*1c60b9acSAndroid Build Coastguard Worker */
606*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_MALFORMED_PACKET;
607*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
608*1c60b9acSAndroid Build Coastguard Worker }
609*1c60b9acSAndroid Build Coastguard Worker /*
610*1c60b9acSAndroid Build Coastguard Worker * conn_flags specifies the Will Properties that should
611*1c60b9acSAndroid Build Coastguard Worker * appear in the payload section
612*1c60b9acSAndroid Build Coastguard Worker */
613*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_2byte_init(&par->vbit);
614*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_VH_KEEPALIVE;
615*1c60b9acSAndroid Build Coastguard Worker break;
616*1c60b9acSAndroid Build Coastguard Worker
617*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_VH_KEEPALIVE:
618*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
619*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
620*1c60b9acSAndroid Build Coastguard Worker break;
621*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
622*1c60b9acSAndroid Build Coastguard Worker par->keepalive = (uint16_t)par->vbit.value;
623*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
624*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNECT_VH_PROPERTIES_VBI_LEN;
625*1c60b9acSAndroid Build Coastguard Worker break;
626*1c60b9acSAndroid Build Coastguard Worker default:
627*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: ka bad vbi\n", __func__);
628*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
629*1c60b9acSAndroid Build Coastguard Worker }
630*1c60b9acSAndroid Build Coastguard Worker break;
631*1c60b9acSAndroid Build Coastguard Worker
632*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PINGRESP_ZERO:
633*1c60b9acSAndroid Build Coastguard Worker len--;
634*1c60b9acSAndroid Build Coastguard Worker /* second byte of PINGRESP must be zero */
635*1c60b9acSAndroid Build Coastguard Worker if (*buf++)
636*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
637*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
638*1c60b9acSAndroid Build Coastguard Worker
639*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNECT_VH_PROPERTIES_VBI_LEN:
640*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
641*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
642*1c60b9acSAndroid Build Coastguard Worker break;
643*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
644*1c60b9acSAndroid Build Coastguard Worker /* reset consumption counter */
645*1c60b9acSAndroid Build Coastguard Worker par->consumed = 0;
646*1c60b9acSAndroid Build Coastguard Worker par->props_len = par->vbit.value;
647*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
648*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PROP_ID_VBI;
649*1c60b9acSAndroid Build Coastguard Worker break;
650*1c60b9acSAndroid Build Coastguard Worker default:
651*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: connpr bad vbi\n", __func__);
652*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
653*1c60b9acSAndroid Build Coastguard Worker }
654*1c60b9acSAndroid Build Coastguard Worker break;
655*1c60b9acSAndroid Build Coastguard Worker
656*1c60b9acSAndroid Build Coastguard Worker /* PUBREC */
657*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBREC_PACKET:
658*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received PUBREC pkt\n", __func__);
659*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
660*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
661*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
662*1c60b9acSAndroid Build Coastguard Worker break;
663*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
664*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
665*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: PUBREC pkt len = %d\n",
666*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
667*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen < 2)
668*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
669*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBREC_VH_PKT_ID;
670*1c60b9acSAndroid Build Coastguard Worker break;
671*1c60b9acSAndroid Build Coastguard Worker default:
672*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: pubrec bad vbi\n", __func__);
673*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
674*1c60b9acSAndroid Build Coastguard Worker }
675*1c60b9acSAndroid Build Coastguard Worker break;
676*1c60b9acSAndroid Build Coastguard Worker
677*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBREC_VH_PKT_ID:
678*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
679*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 3\n", __func__);
680*1c60b9acSAndroid Build Coastguard Worker return -1;
681*1c60b9acSAndroid Build Coastguard Worker }
682*1c60b9acSAndroid Build Coastguard Worker
683*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
684*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = par->cpkt_id;
685*1c60b9acSAndroid Build Coastguard Worker buf += 2;
686*1c60b9acSAndroid Build Coastguard Worker len -= 2;
687*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen -= 2;
688*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
689*1c60b9acSAndroid Build Coastguard Worker
690*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
691*1c60b9acSAndroid Build Coastguard Worker
692*1c60b9acSAndroid Build Coastguard Worker /* PUBREL */
693*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBREL_PACKET:
694*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received PUBREL pkt\n", __func__);
695*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
696*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
697*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
698*1c60b9acSAndroid Build Coastguard Worker break;
699*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
700*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
701*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: PUBREL pkt len = %d\n",
702*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
703*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen < 2)
704*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
705*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBREL_VH_PKT_ID;
706*1c60b9acSAndroid Build Coastguard Worker break;
707*1c60b9acSAndroid Build Coastguard Worker default:
708*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: pubrel bad vbi\n", __func__);
709*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
710*1c60b9acSAndroid Build Coastguard Worker }
711*1c60b9acSAndroid Build Coastguard Worker break;
712*1c60b9acSAndroid Build Coastguard Worker
713*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBREL_VH_PKT_ID:
714*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
715*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 3\n", __func__);
716*1c60b9acSAndroid Build Coastguard Worker return -1;
717*1c60b9acSAndroid Build Coastguard Worker }
718*1c60b9acSAndroid Build Coastguard Worker
719*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
720*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = par->cpkt_id;
721*1c60b9acSAndroid Build Coastguard Worker buf += 2;
722*1c60b9acSAndroid Build Coastguard Worker len -= 2;
723*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen -= 2;
724*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
725*1c60b9acSAndroid Build Coastguard Worker
726*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
727*1c60b9acSAndroid Build Coastguard Worker
728*1c60b9acSAndroid Build Coastguard Worker /* PUBCOMP */
729*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBCOMP_PACKET:
730*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received PUBCOMP pkt\n", __func__);
731*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
732*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
733*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
734*1c60b9acSAndroid Build Coastguard Worker break;
735*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
736*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
737*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: PUBCOMP pkt len = %d\n",
738*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
739*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen < 2)
740*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
741*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBCOMP_VH_PKT_ID;
742*1c60b9acSAndroid Build Coastguard Worker break;
743*1c60b9acSAndroid Build Coastguard Worker default:
744*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: pubcmp bad vbi\n", __func__);
745*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
746*1c60b9acSAndroid Build Coastguard Worker }
747*1c60b9acSAndroid Build Coastguard Worker break;
748*1c60b9acSAndroid Build Coastguard Worker
749*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBCOMP_VH_PKT_ID:
750*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
751*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 3\n", __func__);
752*1c60b9acSAndroid Build Coastguard Worker return -1;
753*1c60b9acSAndroid Build Coastguard Worker }
754*1c60b9acSAndroid Build Coastguard Worker
755*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
756*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = par->cpkt_id;
757*1c60b9acSAndroid Build Coastguard Worker buf += 2;
758*1c60b9acSAndroid Build Coastguard Worker len -= 2;
759*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen -= 2;
760*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
761*1c60b9acSAndroid Build Coastguard Worker
762*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
763*1c60b9acSAndroid Build Coastguard Worker
764*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBLISH_PACKET:
765*1c60b9acSAndroid Build Coastguard Worker if (lwsi_role_client(wsi) && wsi->mqtt->inside_subscribe) {
766*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: Topic rx before subscribing\n",
767*1c60b9acSAndroid Build Coastguard Worker __func__);
768*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
769*1c60b9acSAndroid Build Coastguard Worker }
770*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: received PUBLISH pkt\n", __func__);
771*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBLISH_REMAINING_LEN_VBI;
772*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
773*1c60b9acSAndroid Build Coastguard Worker break;
774*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBLISH_REMAINING_LEN_VBI:
775*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
776*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
777*1c60b9acSAndroid Build Coastguard Worker break;
778*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
779*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
780*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: PUBLISH pkt len = %d\n",
781*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
782*1c60b9acSAndroid Build Coastguard Worker /* Move on to PUBLISH's variable header */
783*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBLISH_VH_TOPIC;
784*1c60b9acSAndroid Build Coastguard Worker break;
785*1c60b9acSAndroid Build Coastguard Worker default:
786*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: pubrem bad vbi\n", __func__);
787*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
788*1c60b9acSAndroid Build Coastguard Worker }
789*1c60b9acSAndroid Build Coastguard Worker break;
790*1c60b9acSAndroid Build Coastguard Worker
791*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBLISH_VH_TOPIC:
792*1c60b9acSAndroid Build Coastguard Worker {
793*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_publish_param_t *pub = NULL;
794*1c60b9acSAndroid Build Coastguard Worker
795*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
796*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: topic too short\n", __func__);
797*1c60b9acSAndroid Build Coastguard Worker return -1;
798*1c60b9acSAndroid Build Coastguard Worker }
799*1c60b9acSAndroid Build Coastguard Worker
800*1c60b9acSAndroid Build Coastguard Worker /* Topic len */
801*1c60b9acSAndroid Build Coastguard Worker par->n = lws_ser_ru16be(buf);
802*1c60b9acSAndroid Build Coastguard Worker buf += 2;
803*1c60b9acSAndroid Build Coastguard Worker len -= 2;
804*1c60b9acSAndroid Build Coastguard Worker
805*1c60b9acSAndroid Build Coastguard Worker if (len < par->n) {/* the way this is written... */
806*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage\n", __func__);
807*1c60b9acSAndroid Build Coastguard Worker return -1;
808*1c60b9acSAndroid Build Coastguard Worker }
809*1c60b9acSAndroid Build Coastguard Worker
810*1c60b9acSAndroid Build Coastguard Worker /* Invalid topic len */
811*1c60b9acSAndroid Build Coastguard Worker if (par->n == 0) {
812*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: zero topic len\n", __func__);
813*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_MALFORMED_PACKET;
814*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
815*1c60b9acSAndroid Build Coastguard Worker }
816*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: PUBLISH topic len %d\n",
817*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->n);
818*1c60b9acSAndroid Build Coastguard Worker assert(!wsi->mqtt->rx_cpkt_param);
819*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->rx_cpkt_param = lws_zalloc(
820*1c60b9acSAndroid Build Coastguard Worker sizeof(lws_mqtt_publish_param_t), "rx pub param");
821*1c60b9acSAndroid Build Coastguard Worker if (!wsi->mqtt->rx_cpkt_param)
822*1c60b9acSAndroid Build Coastguard Worker goto oom;
823*1c60b9acSAndroid Build Coastguard Worker pub = (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
824*1c60b9acSAndroid Build Coastguard Worker
825*1c60b9acSAndroid Build Coastguard Worker pub->topic_len = (uint16_t)par->n;
826*1c60b9acSAndroid Build Coastguard Worker
827*1c60b9acSAndroid Build Coastguard Worker /* Topic Name */
828*1c60b9acSAndroid Build Coastguard Worker pub->topic = (char *)lws_zalloc((size_t)pub->topic_len + 1,
829*1c60b9acSAndroid Build Coastguard Worker "rx publish topic");
830*1c60b9acSAndroid Build Coastguard Worker if (!pub->topic)
831*1c60b9acSAndroid Build Coastguard Worker goto oom;
832*1c60b9acSAndroid Build Coastguard Worker lws_strncpy(pub->topic, (const char *)buf,
833*1c60b9acSAndroid Build Coastguard Worker (size_t)pub->topic_len + 1);
834*1c60b9acSAndroid Build Coastguard Worker buf += pub->topic_len;
835*1c60b9acSAndroid Build Coastguard Worker len -= pub->topic_len;
836*1c60b9acSAndroid Build Coastguard Worker
837*1c60b9acSAndroid Build Coastguard Worker /* Extract QoS Level from Fixed Header Flags */
838*1c60b9acSAndroid Build Coastguard Worker pub->qos = (lws_mqtt_qos_levels_t)
839*1c60b9acSAndroid Build Coastguard Worker ((par->packet_type_flags >> 1) & 0x3);
840*1c60b9acSAndroid Build Coastguard Worker
841*1c60b9acSAndroid Build Coastguard Worker pub->payload_pos = 0;
842*1c60b9acSAndroid Build Coastguard Worker
843*1c60b9acSAndroid Build Coastguard Worker pub->payload_len = par->cpkt_remlen -
844*1c60b9acSAndroid Build Coastguard Worker (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
845*1c60b9acSAndroid Build Coastguard Worker
846*1c60b9acSAndroid Build Coastguard Worker switch (pub->qos) {
847*1c60b9acSAndroid Build Coastguard Worker case QOS0:
848*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PAYLOAD;
849*1c60b9acSAndroid Build Coastguard Worker if (pub->payload_len == 0)
850*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
851*1c60b9acSAndroid Build Coastguard Worker
852*1c60b9acSAndroid Build Coastguard Worker break;
853*1c60b9acSAndroid Build Coastguard Worker case QOS1:
854*1c60b9acSAndroid Build Coastguard Worker case QOS2:
855*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBLISH_VH_PKT_ID;
856*1c60b9acSAndroid Build Coastguard Worker break;
857*1c60b9acSAndroid Build Coastguard Worker default:
858*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_MALFORMED_PACKET;
859*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(pub->topic);
860*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
861*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
862*1c60b9acSAndroid Build Coastguard Worker }
863*1c60b9acSAndroid Build Coastguard Worker break;
864*1c60b9acSAndroid Build Coastguard Worker }
865*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBLISH_VH_PKT_ID:
866*1c60b9acSAndroid Build Coastguard Worker {
867*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_publish_param_t *pub =
868*1c60b9acSAndroid Build Coastguard Worker (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
869*1c60b9acSAndroid Build Coastguard Worker
870*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
871*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 2\n", __func__);
872*1c60b9acSAndroid Build Coastguard Worker return -1;
873*1c60b9acSAndroid Build Coastguard Worker }
874*1c60b9acSAndroid Build Coastguard Worker
875*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
876*1c60b9acSAndroid Build Coastguard Worker buf += 2;
877*1c60b9acSAndroid Build Coastguard Worker len -= 2;
878*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->peer_ack_pkt_id = par->cpkt_id;
879*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: Packet ID %d\n",
880*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_id);
881*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PAYLOAD;
882*1c60b9acSAndroid Build Coastguard Worker pub->payload_pos = 0;
883*1c60b9acSAndroid Build Coastguard Worker pub->payload_len = par->cpkt_remlen -
884*1c60b9acSAndroid Build Coastguard Worker (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
885*1c60b9acSAndroid Build Coastguard Worker if (pub->payload_len == 0)
886*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
887*1c60b9acSAndroid Build Coastguard Worker
888*1c60b9acSAndroid Build Coastguard Worker break;
889*1c60b9acSAndroid Build Coastguard Worker }
890*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PAYLOAD:
891*1c60b9acSAndroid Build Coastguard Worker {
892*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_publish_param_t *pub =
893*1c60b9acSAndroid Build Coastguard Worker (lws_mqtt_publish_param_t *)wsi->mqtt->rx_cpkt_param;
894*1c60b9acSAndroid Build Coastguard Worker if (pub == NULL) {
895*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Uninitialized pub_param\n",
896*1c60b9acSAndroid Build Coastguard Worker __func__);
897*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
898*1c60b9acSAndroid Build Coastguard Worker }
899*1c60b9acSAndroid Build Coastguard Worker
900*1c60b9acSAndroid Build Coastguard Worker pub->payload = buf;
901*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
902*1c60b9acSAndroid Build Coastguard Worker }
903*1c60b9acSAndroid Build Coastguard Worker
904*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNACK_PACKET:
905*1c60b9acSAndroid Build Coastguard Worker if (!lwsi_role_client(wsi)) {
906*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: CONNACK is only Server to Client",
907*1c60b9acSAndroid Build Coastguard Worker __func__);
908*1c60b9acSAndroid Build Coastguard Worker goto send_unsupp_connack_and_close;
909*1c60b9acSAndroid Build Coastguard Worker }
910*1c60b9acSAndroid Build Coastguard Worker
911*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received CONNACK pkt\n", __func__);
912*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
913*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
914*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
915*1c60b9acSAndroid Build Coastguard Worker break;
916*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
917*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
918*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: CONNACK pkt len = %d\n",
919*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
920*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen != 2)
921*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
922*1c60b9acSAndroid Build Coastguard Worker
923*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNACK_VH_FLAGS;
924*1c60b9acSAndroid Build Coastguard Worker break;
925*1c60b9acSAndroid Build Coastguard Worker default:
926*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: connack bad vbi\n", __func__);
927*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
928*1c60b9acSAndroid Build Coastguard Worker }
929*1c60b9acSAndroid Build Coastguard Worker break;
930*1c60b9acSAndroid Build Coastguard Worker
931*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNACK_VH_FLAGS:
932*1c60b9acSAndroid Build Coastguard Worker {
933*1c60b9acSAndroid Build Coastguard Worker lws_mqttc_t *c = &wsi->mqtt->client;
934*1c60b9acSAndroid Build Coastguard Worker par->cpkt_flags = *buf++;
935*1c60b9acSAndroid Build Coastguard Worker len--;
936*1c60b9acSAndroid Build Coastguard Worker
937*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_flags & ~LMQCFT_SESSION_PRESENT) {
938*1c60b9acSAndroid Build Coastguard Worker /*
939*1c60b9acSAndroid Build Coastguard Worker * Byte 1 is the "Connect Acknowledge
940*1c60b9acSAndroid Build Coastguard Worker * Flags". Bits 7-1 are reserved and
941*1c60b9acSAndroid Build Coastguard Worker * MUST be set to 0.
942*1c60b9acSAndroid Build Coastguard Worker */
943*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_MALFORMED_PACKET;
944*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
945*1c60b9acSAndroid Build Coastguard Worker }
946*1c60b9acSAndroid Build Coastguard Worker /*
947*1c60b9acSAndroid Build Coastguard Worker * If the Server accepts a connection with
948*1c60b9acSAndroid Build Coastguard Worker * CleanSession set to 1, the Server MUST set
949*1c60b9acSAndroid Build Coastguard Worker * Session Present to 0 in the CONNACK packet
950*1c60b9acSAndroid Build Coastguard Worker * in addition to setting a zero return code
951*1c60b9acSAndroid Build Coastguard Worker * in the CONNACK packet [MQTT-3.2.2-1]. If
952*1c60b9acSAndroid Build Coastguard Worker * the Server accepts a connection with
953*1c60b9acSAndroid Build Coastguard Worker * CleanSession set to 0, the value set in
954*1c60b9acSAndroid Build Coastguard Worker * Session Present depends on whether the
955*1c60b9acSAndroid Build Coastguard Worker * Server already has stored Session state for
956*1c60b9acSAndroid Build Coastguard Worker * the supplied client ID. If the Server has
957*1c60b9acSAndroid Build Coastguard Worker * stored Session state, it MUST set
958*1c60b9acSAndroid Build Coastguard Worker * SessionPresent to 1 in the CONNACK packet
959*1c60b9acSAndroid Build Coastguard Worker * [MQTT-3.2.2-2]. If the Server does not have
960*1c60b9acSAndroid Build Coastguard Worker * stored Session state, it MUST set Session
961*1c60b9acSAndroid Build Coastguard Worker * Present to 0 in the CONNACK packet. This is
962*1c60b9acSAndroid Build Coastguard Worker * in addition to setting a zero return code
963*1c60b9acSAndroid Build Coastguard Worker * in the CONNACK packet [MQTT-3.2.2-3].
964*1c60b9acSAndroid Build Coastguard Worker */
965*1c60b9acSAndroid Build Coastguard Worker if ((c->conn_flags & LMQCFT_CLEAN_START) &&
966*1c60b9acSAndroid Build Coastguard Worker (par->cpkt_flags & LMQCFT_SESSION_PRESENT))
967*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
968*1c60b9acSAndroid Build Coastguard Worker
969*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->session_resumed = ((unsigned int)par->cpkt_flags &
970*1c60b9acSAndroid Build Coastguard Worker LMQCFT_SESSION_PRESENT);
971*1c60b9acSAndroid Build Coastguard Worker
972*1c60b9acSAndroid Build Coastguard Worker /* Move on to Connect Return Code */
973*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_CONNACK_VH_RETURN_CODE;
974*1c60b9acSAndroid Build Coastguard Worker break;
975*1c60b9acSAndroid Build Coastguard Worker }
976*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_CONNACK_VH_RETURN_CODE:
977*1c60b9acSAndroid Build Coastguard Worker par->conn_rc = *buf++;
978*1c60b9acSAndroid Build Coastguard Worker len--;
979*1c60b9acSAndroid Build Coastguard Worker /*
980*1c60b9acSAndroid Build Coastguard Worker * If a server sends a CONNACK packet containing a
981*1c60b9acSAndroid Build Coastguard Worker * non-zero return code it MUST then close the Network
982*1c60b9acSAndroid Build Coastguard Worker * Connection [MQTT-3.2.2-5]
983*1c60b9acSAndroid Build Coastguard Worker */
984*1c60b9acSAndroid Build Coastguard Worker switch (par->conn_rc) {
985*1c60b9acSAndroid Build Coastguard Worker case 0:
986*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
987*1c60b9acSAndroid Build Coastguard Worker case 1:
988*1c60b9acSAndroid Build Coastguard Worker case 2:
989*1c60b9acSAndroid Build Coastguard Worker case 3:
990*1c60b9acSAndroid Build Coastguard Worker case 4:
991*1c60b9acSAndroid Build Coastguard Worker case 5:
992*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_UNSUPPORTED_PROTOCOL +
993*1c60b9acSAndroid Build Coastguard Worker par->conn_rc - 1;
994*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
995*1c60b9acSAndroid Build Coastguard Worker default:
996*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: bad connack retcode\n", __func__);
997*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
998*1c60b9acSAndroid Build Coastguard Worker }
999*1c60b9acSAndroid Build Coastguard Worker break;
1000*1c60b9acSAndroid Build Coastguard Worker
1001*1c60b9acSAndroid Build Coastguard Worker /* SUBACK */
1002*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_SUBACK_PACKET:
1003*1c60b9acSAndroid Build Coastguard Worker if (!lwsi_role_client(wsi)) {
1004*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: SUBACK is only Server to Client",
1005*1c60b9acSAndroid Build Coastguard Worker __func__);
1006*1c60b9acSAndroid Build Coastguard Worker goto send_unsupp_connack_and_close;
1007*1c60b9acSAndroid Build Coastguard Worker }
1008*1c60b9acSAndroid Build Coastguard Worker
1009*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received SUBACK pkt\n", __func__);
1010*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1011*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
1012*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1013*1c60b9acSAndroid Build Coastguard Worker break;
1014*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1015*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
1016*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: SUBACK pkt len = %d\n",
1017*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
1018*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen <= 2)
1019*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1020*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_SUBACK_VH_PKT_ID;
1021*1c60b9acSAndroid Build Coastguard Worker break;
1022*1c60b9acSAndroid Build Coastguard Worker default:
1023*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: suback bad vbi\n", __func__);
1024*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1025*1c60b9acSAndroid Build Coastguard Worker }
1026*1c60b9acSAndroid Build Coastguard Worker break;
1027*1c60b9acSAndroid Build Coastguard Worker
1028*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_SUBACK_VH_PKT_ID:
1029*1c60b9acSAndroid Build Coastguard Worker
1030*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
1031*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 4\n", __func__);
1032*1c60b9acSAndroid Build Coastguard Worker return -1;
1033*1c60b9acSAndroid Build Coastguard Worker }
1034*1c60b9acSAndroid Build Coastguard Worker
1035*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
1036*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = par->cpkt_id;
1037*1c60b9acSAndroid Build Coastguard Worker buf += 2;
1038*1c60b9acSAndroid Build Coastguard Worker len -= 2;
1039*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen -= 2;
1040*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
1041*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_SUBACK_PAYLOAD;
1042*1c60b9acSAndroid Build Coastguard Worker *par->temp = 0;
1043*1c60b9acSAndroid Build Coastguard Worker break;
1044*1c60b9acSAndroid Build Coastguard Worker
1045*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_SUBACK_PAYLOAD:
1046*1c60b9acSAndroid Build Coastguard Worker {
1047*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_qos_levels_t qos = (lws_mqtt_qos_levels_t)*buf++;
1048*1c60b9acSAndroid Build Coastguard Worker
1049*1c60b9acSAndroid Build Coastguard Worker len--;
1050*1c60b9acSAndroid Build Coastguard Worker switch (qos) {
1051*1c60b9acSAndroid Build Coastguard Worker case QOS0:
1052*1c60b9acSAndroid Build Coastguard Worker case QOS1:
1053*1c60b9acSAndroid Build Coastguard Worker case QOS2:
1054*1c60b9acSAndroid Build Coastguard Worker break;
1055*1c60b9acSAndroid Build Coastguard Worker case FAILURE_QOS_LEVEL:
1056*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1057*1c60b9acSAndroid Build Coastguard Worker
1058*1c60b9acSAndroid Build Coastguard Worker default:
1059*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_MALFORMED_PACKET;
1060*1c60b9acSAndroid Build Coastguard Worker goto send_reason_and_close;
1061*1c60b9acSAndroid Build Coastguard Worker }
1062*1c60b9acSAndroid Build Coastguard Worker
1063*1c60b9acSAndroid Build Coastguard Worker if (++(par->n) == par->cpkt_remlen) {
1064*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
1065*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
1066*1c60b9acSAndroid Build Coastguard Worker }
1067*1c60b9acSAndroid Build Coastguard Worker
1068*1c60b9acSAndroid Build Coastguard Worker break;
1069*1c60b9acSAndroid Build Coastguard Worker }
1070*1c60b9acSAndroid Build Coastguard Worker
1071*1c60b9acSAndroid Build Coastguard Worker /* UNSUBACK */
1072*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_UNSUBACK_PACKET:
1073*1c60b9acSAndroid Build Coastguard Worker if (!lwsi_role_client(wsi)) {
1074*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: UNSUBACK is only Server to Client",
1075*1c60b9acSAndroid Build Coastguard Worker __func__);
1076*1c60b9acSAndroid Build Coastguard Worker goto send_unsupp_connack_and_close;
1077*1c60b9acSAndroid Build Coastguard Worker }
1078*1c60b9acSAndroid Build Coastguard Worker
1079*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: received UNSUBACK pkt\n", __func__);
1080*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1081*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
1082*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1083*1c60b9acSAndroid Build Coastguard Worker break;
1084*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1085*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
1086*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: UNSUBACK pkt len = %d\n",
1087*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
1088*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen < 2)
1089*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1090*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_UNSUBACK_VH_PKT_ID;
1091*1c60b9acSAndroid Build Coastguard Worker break;
1092*1c60b9acSAndroid Build Coastguard Worker default:
1093*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: unsuback bad vbi\n", __func__);
1094*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1095*1c60b9acSAndroid Build Coastguard Worker }
1096*1c60b9acSAndroid Build Coastguard Worker break;
1097*1c60b9acSAndroid Build Coastguard Worker
1098*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_UNSUBACK_VH_PKT_ID:
1099*1c60b9acSAndroid Build Coastguard Worker
1100*1c60b9acSAndroid Build Coastguard Worker if (len < 2) {
1101*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 3\n", __func__);
1102*1c60b9acSAndroid Build Coastguard Worker return -1;
1103*1c60b9acSAndroid Build Coastguard Worker }
1104*1c60b9acSAndroid Build Coastguard Worker
1105*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(buf);
1106*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = par->cpkt_id;
1107*1c60b9acSAndroid Build Coastguard Worker buf += 2;
1108*1c60b9acSAndroid Build Coastguard Worker len -= 2;
1109*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen -= 2;
1110*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
1111*1c60b9acSAndroid Build Coastguard Worker
1112*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
1113*1c60b9acSAndroid Build Coastguard Worker
1114*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBACK_PACKET:
1115*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1116*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
1117*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1118*1c60b9acSAndroid Build Coastguard Worker break;
1119*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1120*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen = par->vbit.value;
1121*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: PUBACK pkt len = %d\n", __func__,
1122*1c60b9acSAndroid Build Coastguard Worker (int)par->cpkt_remlen);
1123*1c60b9acSAndroid Build Coastguard Worker /*
1124*1c60b9acSAndroid Build Coastguard Worker * must be 4 or more, with special case that 2
1125*1c60b9acSAndroid Build Coastguard Worker * means success with no reason code or props
1126*1c60b9acSAndroid Build Coastguard Worker */
1127*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen <= 1 ||
1128*1c60b9acSAndroid Build Coastguard Worker par->cpkt_remlen == 3)
1129*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1130*1c60b9acSAndroid Build Coastguard Worker
1131*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBACK_VH_PKT_ID;
1132*1c60b9acSAndroid Build Coastguard Worker par->fixed_seen[2] = par->fixed_seen[3] = 0;
1133*1c60b9acSAndroid Build Coastguard Worker par->fixed = 0;
1134*1c60b9acSAndroid Build Coastguard Worker par->n = 0;
1135*1c60b9acSAndroid Build Coastguard Worker break;
1136*1c60b9acSAndroid Build Coastguard Worker default:
1137*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: puback bad vbi\n", __func__);
1138*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1139*1c60b9acSAndroid Build Coastguard Worker }
1140*1c60b9acSAndroid Build Coastguard Worker break;
1141*1c60b9acSAndroid Build Coastguard Worker
1142*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBACK_VH_PKT_ID:
1143*1c60b9acSAndroid Build Coastguard Worker /*
1144*1c60b9acSAndroid Build Coastguard Worker * There are 3 fixed bytes and then a VBI for the
1145*1c60b9acSAndroid Build Coastguard Worker * property section length
1146*1c60b9acSAndroid Build Coastguard Worker */
1147*1c60b9acSAndroid Build Coastguard Worker par->fixed_seen[par->fixed++] = *buf++;
1148*1c60b9acSAndroid Build Coastguard Worker if (len < par->cpkt_remlen - par->n) {
1149*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: len breakage 4\n", __func__);
1150*1c60b9acSAndroid Build Coastguard Worker return -1;
1151*1c60b9acSAndroid Build Coastguard Worker }
1152*1c60b9acSAndroid Build Coastguard Worker len--;
1153*1c60b9acSAndroid Build Coastguard Worker par->n++;
1154*1c60b9acSAndroid Build Coastguard Worker if (par->fixed == 2)
1155*1c60b9acSAndroid Build Coastguard Worker par->cpkt_id = lws_ser_ru16be(par->fixed_seen);
1156*1c60b9acSAndroid Build Coastguard Worker
1157*1c60b9acSAndroid Build Coastguard Worker if (par->fixed == 3) {
1158*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1159*1c60b9acSAndroid Build Coastguard Worker par->props_consumed = 0;
1160*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBACK_PROPERTIES_LEN_VBI;
1161*1c60b9acSAndroid Build Coastguard Worker }
1162*1c60b9acSAndroid Build Coastguard Worker /* length of 2 is truncated packet and we completed it */
1163*1c60b9acSAndroid Build Coastguard Worker if (par->cpkt_remlen == par->fixed)
1164*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
1165*1c60b9acSAndroid Build Coastguard Worker break;
1166*1c60b9acSAndroid Build Coastguard Worker
1167*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PUBACK_PROPERTIES_LEN_VBI:
1168*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
1169*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1170*1c60b9acSAndroid Build Coastguard Worker break;
1171*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1172*1c60b9acSAndroid Build Coastguard Worker par->props_len = par->vbit.value;
1173*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: PUBACK props len = %d\n",
1174*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->cpkt_remlen);
1175*1c60b9acSAndroid Build Coastguard Worker /*
1176*1c60b9acSAndroid Build Coastguard Worker * If there are no properties, this is a
1177*1c60b9acSAndroid Build Coastguard Worker * command completion event in itself
1178*1c60b9acSAndroid Build Coastguard Worker */
1179*1c60b9acSAndroid Build Coastguard Worker if (!par->props_len)
1180*1c60b9acSAndroid Build Coastguard Worker goto cmd_completion;
1181*1c60b9acSAndroid Build Coastguard Worker
1182*1c60b9acSAndroid Build Coastguard Worker /*
1183*1c60b9acSAndroid Build Coastguard Worker * Otherwise consume the properties before
1184*1c60b9acSAndroid Build Coastguard Worker * completing the command
1185*1c60b9acSAndroid Build Coastguard Worker */
1186*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1187*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PUBACK_VH_PKT_ID;
1188*1c60b9acSAndroid Build Coastguard Worker break;
1189*1c60b9acSAndroid Build Coastguard Worker default:
1190*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: puback pr bad vbi\n", __func__);
1191*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1192*1c60b9acSAndroid Build Coastguard Worker }
1193*1c60b9acSAndroid Build Coastguard Worker break;
1194*1c60b9acSAndroid Build Coastguard Worker
1195*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_EAT_PROPERTIES_AND_COMPLETE:
1196*1c60b9acSAndroid Build Coastguard Worker /*
1197*1c60b9acSAndroid Build Coastguard Worker * TODO: stash the props
1198*1c60b9acSAndroid Build Coastguard Worker */
1199*1c60b9acSAndroid Build Coastguard Worker par->props_consumed++;
1200*1c60b9acSAndroid Build Coastguard Worker len--;
1201*1c60b9acSAndroid Build Coastguard Worker buf++;
1202*1c60b9acSAndroid Build Coastguard Worker if (par->props_len != par->props_consumed)
1203*1c60b9acSAndroid Build Coastguard Worker break;
1204*1c60b9acSAndroid Build Coastguard Worker
1205*1c60b9acSAndroid Build Coastguard Worker cmd_completion:
1206*1c60b9acSAndroid Build Coastguard Worker /*
1207*1c60b9acSAndroid Build Coastguard Worker * We come here when we understood we just processed
1208*1c60b9acSAndroid Build Coastguard Worker * the last byte of a command packet, regardless of the
1209*1c60b9acSAndroid Build Coastguard Worker * packet type
1210*1c60b9acSAndroid Build Coastguard Worker */
1211*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_IDLE;
1212*1c60b9acSAndroid Build Coastguard Worker
1213*1c60b9acSAndroid Build Coastguard Worker switch (par->packet_type_flags >> 4) {
1214*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_CONNACK:
1215*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cmd_completion: CONNACK\n",
1216*1c60b9acSAndroid Build Coastguard Worker __func__);
1217*1c60b9acSAndroid Build Coastguard Worker
1218*1c60b9acSAndroid Build Coastguard Worker /*
1219*1c60b9acSAndroid Build Coastguard Worker * Getting the CONNACK means we are the first,
1220*1c60b9acSAndroid Build Coastguard Worker * the nwsi, and we succeeded to create a new
1221*1c60b9acSAndroid Build Coastguard Worker * network connection ourselves.
1222*1c60b9acSAndroid Build Coastguard Worker *
1223*1c60b9acSAndroid Build Coastguard Worker * Since others may join us sharing the nwsi,
1224*1c60b9acSAndroid Build Coastguard Worker * and we may close while they still want to use
1225*1c60b9acSAndroid Build Coastguard Worker * it, our wsi lifecycle alone can no longer
1226*1c60b9acSAndroid Build Coastguard Worker * define the lifecycle of the nwsi... it means
1227*1c60b9acSAndroid Build Coastguard Worker * we need to do a "magic trick" and instead of
1228*1c60b9acSAndroid Build Coastguard Worker * being both the nwsi and act like a child
1229*1c60b9acSAndroid Build Coastguard Worker * stream, create a new wsi to take over the
1230*1c60b9acSAndroid Build Coastguard Worker * nwsi duties and turn our wsi into a child of
1231*1c60b9acSAndroid Build Coastguard Worker * the nwsi with its own lifecycle.
1232*1c60b9acSAndroid Build Coastguard Worker *
1233*1c60b9acSAndroid Build Coastguard Worker * The nwsi gets a mostly empty wsi->nwsi used
1234*1c60b9acSAndroid Build Coastguard Worker * to track already-subscribed topics globally
1235*1c60b9acSAndroid Build Coastguard Worker * for the connection.
1236*1c60b9acSAndroid Build Coastguard Worker */
1237*1c60b9acSAndroid Build Coastguard Worker
1238*1c60b9acSAndroid Build Coastguard Worker /* we were under SENT_CLIENT_HANDSHAKE timeout */
1239*1c60b9acSAndroid Build Coastguard Worker lws_set_timeout(wsi, 0, 0);
1240*1c60b9acSAndroid Build Coastguard Worker
1241*1c60b9acSAndroid Build Coastguard Worker w = lws_create_new_server_wsi(wsi->a.vhost,
1242*1c60b9acSAndroid Build Coastguard Worker wsi->tsi, "mqtt_sid1");
1243*1c60b9acSAndroid Build Coastguard Worker if (!w) {
1244*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: sid 1 migrate failed\n",
1245*1c60b9acSAndroid Build Coastguard Worker __func__);
1246*1c60b9acSAndroid Build Coastguard Worker return -1;
1247*1c60b9acSAndroid Build Coastguard Worker }
1248*1c60b9acSAndroid Build Coastguard Worker
1249*1c60b9acSAndroid Build Coastguard Worker wsi->mux.highest_sid = 1;
1250*1c60b9acSAndroid Build Coastguard Worker lws_wsi_mux_insert(w, wsi, wsi->mux.highest_sid++);
1251*1c60b9acSAndroid Build Coastguard Worker
1252*1c60b9acSAndroid Build Coastguard Worker wsi->mux_substream = 1;
1253*1c60b9acSAndroid Build Coastguard Worker w->mux_substream = 1;
1254*1c60b9acSAndroid Build Coastguard Worker w->client_mux_substream = 1;
1255*1c60b9acSAndroid Build Coastguard Worker wsi->client_mux_migrated = 1;
1256*1c60b9acSAndroid Build Coastguard Worker wsi->told_user_closed = 1; /* don't tell nwsi closed */
1257*1c60b9acSAndroid Build Coastguard Worker
1258*1c60b9acSAndroid Build Coastguard Worker lwsi_set_state(w, LRS_ESTABLISHED);
1259*1c60b9acSAndroid Build Coastguard Worker lwsi_set_state(wsi, LRS_ESTABLISHED);
1260*1c60b9acSAndroid Build Coastguard Worker lwsi_set_role(w, lwsi_role(wsi));
1261*1c60b9acSAndroid Build Coastguard Worker
1262*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CLIENT)
1263*1c60b9acSAndroid Build Coastguard Worker w->flags = wsi->flags;
1264*1c60b9acSAndroid Build Coastguard Worker #endif
1265*1c60b9acSAndroid Build Coastguard Worker
1266*1c60b9acSAndroid Build Coastguard Worker w->mqtt = wsi->mqtt;
1267*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt = lws_zalloc(sizeof(*wsi->mqtt), "nwsi mqtt");
1268*1c60b9acSAndroid Build Coastguard Worker if (!wsi->mqtt)
1269*1c60b9acSAndroid Build Coastguard Worker return -1;
1270*1c60b9acSAndroid Build Coastguard Worker w->mqtt->wsi = w;
1271*1c60b9acSAndroid Build Coastguard Worker w->a.protocol = wsi->a.protocol;
1272*1c60b9acSAndroid Build Coastguard Worker if (w->user_space &&
1273*1c60b9acSAndroid Build Coastguard Worker !w->user_space_externally_allocated)
1274*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(w->user_space);
1275*1c60b9acSAndroid Build Coastguard Worker w->user_space = wsi->user_space;
1276*1c60b9acSAndroid Build Coastguard Worker wsi->user_space = NULL;
1277*1c60b9acSAndroid Build Coastguard Worker w->user_space_externally_allocated =
1278*1c60b9acSAndroid Build Coastguard Worker wsi->user_space_externally_allocated;
1279*1c60b9acSAndroid Build Coastguard Worker if (lws_ensure_user_space(w))
1280*1c60b9acSAndroid Build Coastguard Worker goto bail1;
1281*1c60b9acSAndroid Build Coastguard Worker w->a.opaque_user_data = wsi->a.opaque_user_data;
1282*1c60b9acSAndroid Build Coastguard Worker wsi->a.opaque_user_data = NULL;
1283*1c60b9acSAndroid Build Coastguard Worker w->stash = wsi->stash;
1284*1c60b9acSAndroid Build Coastguard Worker wsi->stash = NULL;
1285*1c60b9acSAndroid Build Coastguard Worker
1286*1c60b9acSAndroid Build Coastguard Worker lws_mux_mark_immortal(w);
1287*1c60b9acSAndroid Build Coastguard Worker
1288*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: migrated nwsi %s to sid 1 %s\n",
1289*1c60b9acSAndroid Build Coastguard Worker __func__, lws_wsi_tag(wsi),
1290*1c60b9acSAndroid Build Coastguard Worker lws_wsi_tag(w));
1291*1c60b9acSAndroid Build Coastguard Worker
1292*1c60b9acSAndroid Build Coastguard Worker /*
1293*1c60b9acSAndroid Build Coastguard Worker * It was the last thing we were waiting for
1294*1c60b9acSAndroid Build Coastguard Worker * before we can be fully ESTABLISHED
1295*1c60b9acSAndroid Build Coastguard Worker */
1296*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_set_client_established(w)) {
1297*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: set EST fail\n", __func__);
1298*1c60b9acSAndroid Build Coastguard Worker return -1;
1299*1c60b9acSAndroid Build Coastguard Worker }
1300*1c60b9acSAndroid Build Coastguard Worker
1301*1c60b9acSAndroid Build Coastguard Worker /* get the ball rolling */
1302*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1303*1c60b9acSAndroid Build Coastguard Worker
1304*1c60b9acSAndroid Build Coastguard Worker /* well, add the queued guys as children */
1305*1c60b9acSAndroid Build Coastguard Worker lws_wsi_mux_apply_queue(wsi);
1306*1c60b9acSAndroid Build Coastguard Worker break;
1307*1c60b9acSAndroid Build Coastguard Worker
1308*1c60b9acSAndroid Build Coastguard Worker bail1:
1309*1c60b9acSAndroid Build Coastguard Worker /* undo the insert */
1310*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list = w->mux.sibling_list;
1311*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_count--;
1312*1c60b9acSAndroid Build Coastguard Worker
1313*1c60b9acSAndroid Build Coastguard Worker if (w->user_space)
1314*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(w->user_space);
1315*1c60b9acSAndroid Build Coastguard Worker w->a.vhost->protocols[0].callback(w,
1316*1c60b9acSAndroid Build Coastguard Worker LWS_CALLBACK_WSI_DESTROY,
1317*1c60b9acSAndroid Build Coastguard Worker NULL, NULL, 0);
1318*1c60b9acSAndroid Build Coastguard Worker __lws_vhost_unbind_wsi(w); /* cx + vh lock */
1319*1c60b9acSAndroid Build Coastguard Worker lws_free(w);
1320*1c60b9acSAndroid Build Coastguard Worker
1321*1c60b9acSAndroid Build Coastguard Worker return 0;
1322*1c60b9acSAndroid Build Coastguard Worker
1323*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBREC:
1324*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cmd_completion: PUBREC\n",
1325*1c60b9acSAndroid Build Coastguard Worker __func__);
1326*1c60b9acSAndroid Build Coastguard Worker /*
1327*1c60b9acSAndroid Build Coastguard Worker * Figure out which child asked for this
1328*1c60b9acSAndroid Build Coastguard Worker */
1329*1c60b9acSAndroid Build Coastguard Worker n = 0;
1330*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1331*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1332*1c60b9acSAndroid Build Coastguard Worker if (w->mqtt->unacked_publish &&
1333*1c60b9acSAndroid Build Coastguard Worker w->mqtt->ack_pkt_id == par->cpkt_id) {
1334*1c60b9acSAndroid Build Coastguard Worker char requested_close = 0;
1335*1c60b9acSAndroid Build Coastguard Worker
1336*1c60b9acSAndroid Build Coastguard Worker w->mqtt->unacked_publish = 0;
1337*1c60b9acSAndroid Build Coastguard Worker w->mqtt->unacked_pubrel = 1;
1338*1c60b9acSAndroid Build Coastguard Worker
1339*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
1340*1c60b9acSAndroid Build Coastguard Worker w->a.protocol->callback,
1341*1c60b9acSAndroid Build Coastguard Worker w, LWS_CALLBACK_MQTT_ACK,
1342*1c60b9acSAndroid Build Coastguard Worker w->user_space, NULL, 0) < 0) {
1343*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: MQTT_ACK requests close\n",
1344*1c60b9acSAndroid Build Coastguard Worker __func__);
1345*1c60b9acSAndroid Build Coastguard Worker requested_close = 1;
1346*1c60b9acSAndroid Build Coastguard Worker }
1347*1c60b9acSAndroid Build Coastguard Worker n = 1;
1348*1c60b9acSAndroid Build Coastguard Worker
1349*1c60b9acSAndroid Build Coastguard Worker /*
1350*1c60b9acSAndroid Build Coastguard Worker * We got an assertive PUBREC,
1351*1c60b9acSAndroid Build Coastguard Worker * no need for timeout wait
1352*1c60b9acSAndroid Build Coastguard Worker * any more
1353*1c60b9acSAndroid Build Coastguard Worker */
1354*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&w->mqtt->
1355*1c60b9acSAndroid Build Coastguard Worker sul_qos_puback_pubrec_wait);
1356*1c60b9acSAndroid Build Coastguard Worker
1357*1c60b9acSAndroid Build Coastguard Worker if (requested_close) {
1358*1c60b9acSAndroid Build Coastguard Worker __lws_close_free_wsi(w,
1359*1c60b9acSAndroid Build Coastguard Worker 0, "ack cb");
1360*1c60b9acSAndroid Build Coastguard Worker break;
1361*1c60b9acSAndroid Build Coastguard Worker }
1362*1c60b9acSAndroid Build Coastguard Worker
1363*1c60b9acSAndroid Build Coastguard Worker break;
1364*1c60b9acSAndroid Build Coastguard Worker }
1365*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1366*1c60b9acSAndroid Build Coastguard Worker
1367*1c60b9acSAndroid Build Coastguard Worker if (!n) {
1368*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unsolicited PUBREC\n",
1369*1c60b9acSAndroid Build Coastguard Worker __func__);
1370*1c60b9acSAndroid Build Coastguard Worker return -1;
1371*1c60b9acSAndroid Build Coastguard Worker }
1372*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->send_pubrel = 1;
1373*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
1374*1c60b9acSAndroid Build Coastguard Worker break;
1375*1c60b9acSAndroid Build Coastguard Worker
1376*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBCOMP:
1377*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cmd_completion: PUBCOMP\n",
1378*1c60b9acSAndroid Build Coastguard Worker __func__);
1379*1c60b9acSAndroid Build Coastguard Worker n = 0;
1380*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1381*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1382*1c60b9acSAndroid Build Coastguard Worker if (w->mqtt->unacked_pubrel > 0 &&
1383*1c60b9acSAndroid Build Coastguard Worker w->mqtt->ack_pkt_id == par->cpkt_id) {
1384*1c60b9acSAndroid Build Coastguard Worker w->mqtt->unacked_pubrel = 0;
1385*1c60b9acSAndroid Build Coastguard Worker n = 1;
1386*1c60b9acSAndroid Build Coastguard Worker }
1387*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1388*1c60b9acSAndroid Build Coastguard Worker
1389*1c60b9acSAndroid Build Coastguard Worker if (!n) {
1390*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unsolicited PUBCOMP\n",
1391*1c60b9acSAndroid Build Coastguard Worker __func__);
1392*1c60b9acSAndroid Build Coastguard Worker return -1;
1393*1c60b9acSAndroid Build Coastguard Worker }
1394*1c60b9acSAndroid Build Coastguard Worker
1395*1c60b9acSAndroid Build Coastguard Worker /*
1396*1c60b9acSAndroid Build Coastguard Worker * If we published something and PUBCOMP arrived,
1397*1c60b9acSAndroid Build Coastguard Worker * our connection is definitely working in both
1398*1c60b9acSAndroid Build Coastguard Worker * directions at the moment.
1399*1c60b9acSAndroid Build Coastguard Worker */
1400*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1401*1c60b9acSAndroid Build Coastguard Worker break;
1402*1c60b9acSAndroid Build Coastguard Worker
1403*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBREL:
1404*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: cmd_completion: PUBREL\n",
1405*1c60b9acSAndroid Build Coastguard Worker __func__);
1406*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->send_pubcomp = 1;
1407*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
1408*1c60b9acSAndroid Build Coastguard Worker break;
1409*1c60b9acSAndroid Build Coastguard Worker
1410*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBACK:
1411*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cmd_completion: PUBACK\n",
1412*1c60b9acSAndroid Build Coastguard Worker __func__);
1413*1c60b9acSAndroid Build Coastguard Worker
1414*1c60b9acSAndroid Build Coastguard Worker /*
1415*1c60b9acSAndroid Build Coastguard Worker * Figure out which child asked for this
1416*1c60b9acSAndroid Build Coastguard Worker */
1417*1c60b9acSAndroid Build Coastguard Worker
1418*1c60b9acSAndroid Build Coastguard Worker n = 0;
1419*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1420*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1421*1c60b9acSAndroid Build Coastguard Worker if (w->mqtt->unacked_publish &&
1422*1c60b9acSAndroid Build Coastguard Worker w->mqtt->ack_pkt_id == par->cpkt_id) {
1423*1c60b9acSAndroid Build Coastguard Worker char requested_close = 0;
1424*1c60b9acSAndroid Build Coastguard Worker
1425*1c60b9acSAndroid Build Coastguard Worker w->mqtt->unacked_publish = 0;
1426*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
1427*1c60b9acSAndroid Build Coastguard Worker w->a.protocol->callback,
1428*1c60b9acSAndroid Build Coastguard Worker w, LWS_CALLBACK_MQTT_ACK,
1429*1c60b9acSAndroid Build Coastguard Worker w->user_space, NULL, 0) < 0) {
1430*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: MQTT_ACK requests close\n",
1431*1c60b9acSAndroid Build Coastguard Worker __func__);
1432*1c60b9acSAndroid Build Coastguard Worker requested_close = 1;
1433*1c60b9acSAndroid Build Coastguard Worker }
1434*1c60b9acSAndroid Build Coastguard Worker n = 1;
1435*1c60b9acSAndroid Build Coastguard Worker
1436*1c60b9acSAndroid Build Coastguard Worker /*
1437*1c60b9acSAndroid Build Coastguard Worker * We got an assertive PUBACK,
1438*1c60b9acSAndroid Build Coastguard Worker * no need for ACK timeout wait
1439*1c60b9acSAndroid Build Coastguard Worker * any more
1440*1c60b9acSAndroid Build Coastguard Worker */
1441*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&w->mqtt->sul_qos_puback_pubrec_wait);
1442*1c60b9acSAndroid Build Coastguard Worker
1443*1c60b9acSAndroid Build Coastguard Worker if (requested_close) {
1444*1c60b9acSAndroid Build Coastguard Worker __lws_close_free_wsi(w,
1445*1c60b9acSAndroid Build Coastguard Worker 0, "ack cb");
1446*1c60b9acSAndroid Build Coastguard Worker break;
1447*1c60b9acSAndroid Build Coastguard Worker }
1448*1c60b9acSAndroid Build Coastguard Worker
1449*1c60b9acSAndroid Build Coastguard Worker break;
1450*1c60b9acSAndroid Build Coastguard Worker }
1451*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1452*1c60b9acSAndroid Build Coastguard Worker
1453*1c60b9acSAndroid Build Coastguard Worker if (!n) {
1454*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unsolicited PUBACK\n",
1455*1c60b9acSAndroid Build Coastguard Worker __func__);
1456*1c60b9acSAndroid Build Coastguard Worker return -1;
1457*1c60b9acSAndroid Build Coastguard Worker }
1458*1c60b9acSAndroid Build Coastguard Worker
1459*1c60b9acSAndroid Build Coastguard Worker /*
1460*1c60b9acSAndroid Build Coastguard Worker * If we published something and it was acked,
1461*1c60b9acSAndroid Build Coastguard Worker * our connection is definitely working in both
1462*1c60b9acSAndroid Build Coastguard Worker * directions at the moment.
1463*1c60b9acSAndroid Build Coastguard Worker */
1464*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1465*1c60b9acSAndroid Build Coastguard Worker break;
1466*1c60b9acSAndroid Build Coastguard Worker
1467*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_PINGRESP:
1468*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cmd_completion: PINGRESP\n",
1469*1c60b9acSAndroid Build Coastguard Worker __func__);
1470*1c60b9acSAndroid Build Coastguard Worker /*
1471*1c60b9acSAndroid Build Coastguard Worker * If we asked for a PINGRESP and it came,
1472*1c60b9acSAndroid Build Coastguard Worker * our connection is definitely working in both
1473*1c60b9acSAndroid Build Coastguard Worker * directions at the moment.
1474*1c60b9acSAndroid Build Coastguard Worker */
1475*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1476*1c60b9acSAndroid Build Coastguard Worker break;
1477*1c60b9acSAndroid Build Coastguard Worker
1478*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_SUBACK:
1479*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cmd_completion: SUBACK\n",
1480*1c60b9acSAndroid Build Coastguard Worker __func__);
1481*1c60b9acSAndroid Build Coastguard Worker
1482*1c60b9acSAndroid Build Coastguard Worker /*
1483*1c60b9acSAndroid Build Coastguard Worker * Figure out which child asked for this
1484*1c60b9acSAndroid Build Coastguard Worker */
1485*1c60b9acSAndroid Build Coastguard Worker
1486*1c60b9acSAndroid Build Coastguard Worker n = 0;
1487*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1488*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1489*1c60b9acSAndroid Build Coastguard Worker if (w->mqtt->inside_subscribe &&
1490*1c60b9acSAndroid Build Coastguard Worker w->mqtt->ack_pkt_id == par->cpkt_id) {
1491*1c60b9acSAndroid Build Coastguard Worker w->mqtt->inside_subscribe = 0;
1492*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
1493*1c60b9acSAndroid Build Coastguard Worker w->a.protocol->callback,
1494*1c60b9acSAndroid Build Coastguard Worker w, LWS_CALLBACK_MQTT_SUBSCRIBED,
1495*1c60b9acSAndroid Build Coastguard Worker w->user_space, NULL, 0) < 0) {
1496*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: MQTT_SUBSCRIBE failed\n",
1497*1c60b9acSAndroid Build Coastguard Worker __func__);
1498*1c60b9acSAndroid Build Coastguard Worker return -1;
1499*1c60b9acSAndroid Build Coastguard Worker }
1500*1c60b9acSAndroid Build Coastguard Worker n = 1;
1501*1c60b9acSAndroid Build Coastguard Worker break;
1502*1c60b9acSAndroid Build Coastguard Worker }
1503*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1504*1c60b9acSAndroid Build Coastguard Worker
1505*1c60b9acSAndroid Build Coastguard Worker if (!n) {
1506*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unsolicited SUBACK\n",
1507*1c60b9acSAndroid Build Coastguard Worker __func__);
1508*1c60b9acSAndroid Build Coastguard Worker return -1;
1509*1c60b9acSAndroid Build Coastguard Worker }
1510*1c60b9acSAndroid Build Coastguard Worker
1511*1c60b9acSAndroid Build Coastguard Worker /*
1512*1c60b9acSAndroid Build Coastguard Worker * If we subscribed to something and SUBACK came,
1513*1c60b9acSAndroid Build Coastguard Worker * our connection is definitely working in both
1514*1c60b9acSAndroid Build Coastguard Worker * directions at the moment.
1515*1c60b9acSAndroid Build Coastguard Worker */
1516*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1517*1c60b9acSAndroid Build Coastguard Worker
1518*1c60b9acSAndroid Build Coastguard Worker break;
1519*1c60b9acSAndroid Build Coastguard Worker
1520*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_UNSUBACK:
1521*1c60b9acSAndroid Build Coastguard Worker {
1522*1c60b9acSAndroid Build Coastguard Worker char requested_close = 0;
1523*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: cmd_completion: UNSUBACK\n",
1524*1c60b9acSAndroid Build Coastguard Worker __func__);
1525*1c60b9acSAndroid Build Coastguard Worker /*
1526*1c60b9acSAndroid Build Coastguard Worker * Figure out which child asked for this
1527*1c60b9acSAndroid Build Coastguard Worker */
1528*1c60b9acSAndroid Build Coastguard Worker n = 0;
1529*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1530*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1531*1c60b9acSAndroid Build Coastguard Worker if (w->mqtt->inside_unsubscribe &&
1532*1c60b9acSAndroid Build Coastguard Worker w->mqtt->ack_pkt_id == par->cpkt_id) {
1533*1c60b9acSAndroid Build Coastguard Worker struct lws *nwsi = lws_get_network_wsi(w);
1534*1c60b9acSAndroid Build Coastguard Worker
1535*1c60b9acSAndroid Build Coastguard Worker /*
1536*1c60b9acSAndroid Build Coastguard Worker * No more subscribers left,
1537*1c60b9acSAndroid Build Coastguard Worker * remove the topic from nwsi
1538*1c60b9acSAndroid Build Coastguard Worker */
1539*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_client_remove_subs(nwsi->mqtt);
1540*1c60b9acSAndroid Build Coastguard Worker
1541*1c60b9acSAndroid Build Coastguard Worker w->mqtt->inside_unsubscribe = 0;
1542*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
1543*1c60b9acSAndroid Build Coastguard Worker w->a.protocol->callback,
1544*1c60b9acSAndroid Build Coastguard Worker w, LWS_CALLBACK_MQTT_UNSUBSCRIBED,
1545*1c60b9acSAndroid Build Coastguard Worker w->user_space, NULL, 0) < 0) {
1546*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: MQTT_UNSUBACK requests close\n",
1547*1c60b9acSAndroid Build Coastguard Worker __func__);
1548*1c60b9acSAndroid Build Coastguard Worker requested_close = 1;
1549*1c60b9acSAndroid Build Coastguard Worker }
1550*1c60b9acSAndroid Build Coastguard Worker n = 1;
1551*1c60b9acSAndroid Build Coastguard Worker
1552*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&w->mqtt->sul_unsuback_wait);
1553*1c60b9acSAndroid Build Coastguard Worker if (requested_close) {
1554*1c60b9acSAndroid Build Coastguard Worker __lws_close_free_wsi(w,
1555*1c60b9acSAndroid Build Coastguard Worker 0, "unsub ack cb");
1556*1c60b9acSAndroid Build Coastguard Worker break;
1557*1c60b9acSAndroid Build Coastguard Worker }
1558*1c60b9acSAndroid Build Coastguard Worker break;
1559*1c60b9acSAndroid Build Coastguard Worker }
1560*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1561*1c60b9acSAndroid Build Coastguard Worker
1562*1c60b9acSAndroid Build Coastguard Worker if (!n) {
1563*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unsolicited UNSUBACK\n",
1564*1c60b9acSAndroid Build Coastguard Worker __func__);
1565*1c60b9acSAndroid Build Coastguard Worker return -1;
1566*1c60b9acSAndroid Build Coastguard Worker }
1567*1c60b9acSAndroid Build Coastguard Worker
1568*1c60b9acSAndroid Build Coastguard Worker
1569*1c60b9acSAndroid Build Coastguard Worker /*
1570*1c60b9acSAndroid Build Coastguard Worker * If we unsubscribed to something and
1571*1c60b9acSAndroid Build Coastguard Worker * UNSUBACK came, our connection is
1572*1c60b9acSAndroid Build Coastguard Worker * definitely working in both
1573*1c60b9acSAndroid Build Coastguard Worker * directions at the moment.
1574*1c60b9acSAndroid Build Coastguard Worker */
1575*1c60b9acSAndroid Build Coastguard Worker lws_validity_confirmed(wsi);
1576*1c60b9acSAndroid Build Coastguard Worker
1577*1c60b9acSAndroid Build Coastguard Worker break;
1578*1c60b9acSAndroid Build Coastguard Worker }
1579*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBLISH:
1580*1c60b9acSAndroid Build Coastguard Worker {
1581*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_publish_param_t *pub =
1582*1c60b9acSAndroid Build Coastguard Worker (lws_mqtt_publish_param_t *)
1583*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->rx_cpkt_param;
1584*1c60b9acSAndroid Build Coastguard Worker size_t chunk;
1585*1c60b9acSAndroid Build Coastguard Worker
1586*1c60b9acSAndroid Build Coastguard Worker if (pub == NULL) {
1587*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: no pub\n", __func__);
1588*1c60b9acSAndroid Build Coastguard Worker return -1;
1589*1c60b9acSAndroid Build Coastguard Worker }
1590*1c60b9acSAndroid Build Coastguard Worker
1591*1c60b9acSAndroid Build Coastguard Worker /*
1592*1c60b9acSAndroid Build Coastguard Worker * RX PUBLISH is delivered to any children that
1593*1c60b9acSAndroid Build Coastguard Worker * registered for the related topic
1594*1c60b9acSAndroid Build Coastguard Worker */
1595*1c60b9acSAndroid Build Coastguard Worker
1596*1c60b9acSAndroid Build Coastguard Worker n = wsi->role_ops->rx_cb[lwsi_role_server(wsi)];
1597*1c60b9acSAndroid Build Coastguard Worker
1598*1c60b9acSAndroid Build Coastguard Worker chunk = pub->payload_len - pub->payload_pos;
1599*1c60b9acSAndroid Build Coastguard Worker if (chunk > len)
1600*1c60b9acSAndroid Build Coastguard Worker chunk = len;
1601*1c60b9acSAndroid Build Coastguard Worker
1602*1c60b9acSAndroid Build Coastguard Worker lws_start_foreach_ll(struct lws *, w,
1603*1c60b9acSAndroid Build Coastguard Worker wsi->mux.child_list) {
1604*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_find_sub(w->mqtt,
1605*1c60b9acSAndroid Build Coastguard Worker pub->topic))
1606*1c60b9acSAndroid Build Coastguard Worker if (w->a.protocol->callback(
1607*1c60b9acSAndroid Build Coastguard Worker w, (enum lws_callback_reasons)n,
1608*1c60b9acSAndroid Build Coastguard Worker w->user_space,
1609*1c60b9acSAndroid Build Coastguard Worker (void *)pub,
1610*1c60b9acSAndroid Build Coastguard Worker chunk)) {
1611*1c60b9acSAndroid Build Coastguard Worker par->payload_consumed = 0;
1612*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(pub->topic);
1613*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
1614*1c60b9acSAndroid Build Coastguard Worker return 1;
1615*1c60b9acSAndroid Build Coastguard Worker }
1616*1c60b9acSAndroid Build Coastguard Worker } lws_end_foreach_ll(w, mux.sibling_list);
1617*1c60b9acSAndroid Build Coastguard Worker
1618*1c60b9acSAndroid Build Coastguard Worker
1619*1c60b9acSAndroid Build Coastguard Worker pub->payload_pos += (uint32_t)chunk;
1620*1c60b9acSAndroid Build Coastguard Worker len -= chunk;
1621*1c60b9acSAndroid Build Coastguard Worker buf += chunk;
1622*1c60b9acSAndroid Build Coastguard Worker
1623*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: post pos %d, plen %d, len %d\n",
1624*1c60b9acSAndroid Build Coastguard Worker __func__, (int)pub->payload_pos,
1625*1c60b9acSAndroid Build Coastguard Worker (int)pub->payload_len, (int)len);
1626*1c60b9acSAndroid Build Coastguard Worker
1627*1c60b9acSAndroid Build Coastguard Worker if (pub->payload_pos != pub->payload_len) {
1628*1c60b9acSAndroid Build Coastguard Worker /*
1629*1c60b9acSAndroid Build Coastguard Worker * More chunks of the payload pending,
1630*1c60b9acSAndroid Build Coastguard Worker * blocking this connection from doing
1631*1c60b9acSAndroid Build Coastguard Worker * anything else
1632*1c60b9acSAndroid Build Coastguard Worker */
1633*1c60b9acSAndroid Build Coastguard Worker par->state = LMQCPP_PAYLOAD;
1634*1c60b9acSAndroid Build Coastguard Worker break;
1635*1c60b9acSAndroid Build Coastguard Worker }
1636*1c60b9acSAndroid Build Coastguard Worker
1637*1c60b9acSAndroid Build Coastguard Worker if (pub->qos == 1) {
1638*1c60b9acSAndroid Build Coastguard Worker /* For QOS = 1, send out PUBACK */
1639*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->send_puback = 1;
1640*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
1641*1c60b9acSAndroid Build Coastguard Worker } else if (pub->qos == 2) {
1642*1c60b9acSAndroid Build Coastguard Worker /* For QOS = 2, send out PUBREC */
1643*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->send_pubrec = 1;
1644*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
1645*1c60b9acSAndroid Build Coastguard Worker }
1646*1c60b9acSAndroid Build Coastguard Worker
1647*1c60b9acSAndroid Build Coastguard Worker par->payload_consumed = 0;
1648*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(pub->topic);
1649*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(wsi->mqtt->rx_cpkt_param);
1650*1c60b9acSAndroid Build Coastguard Worker
1651*1c60b9acSAndroid Build Coastguard Worker break;
1652*1c60b9acSAndroid Build Coastguard Worker }
1653*1c60b9acSAndroid Build Coastguard Worker default:
1654*1c60b9acSAndroid Build Coastguard Worker break;
1655*1c60b9acSAndroid Build Coastguard Worker }
1656*1c60b9acSAndroid Build Coastguard Worker
1657*1c60b9acSAndroid Build Coastguard Worker break;
1658*1c60b9acSAndroid Build Coastguard Worker
1659*1c60b9acSAndroid Build Coastguard Worker
1660*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_ID_VBI:
1661*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_vbi_r(&par->vbit, &buf, &len)) {
1662*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1663*1c60b9acSAndroid Build Coastguard Worker break;
1664*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1665*1c60b9acSAndroid Build Coastguard Worker par->consumed = (uint32_t)((unsigned int)par->consumed + (unsigned int)(unsigned char)par->vbit.consumed);
1666*1c60b9acSAndroid Build Coastguard Worker if (par->vbit.value >
1667*1c60b9acSAndroid Build Coastguard Worker LWS_ARRAY_SIZE(property_valid)) {
1668*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: undef prop id 0x%x\n",
1669*1c60b9acSAndroid Build Coastguard Worker __func__, (int)par->vbit.value);
1670*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1671*1c60b9acSAndroid Build Coastguard Worker }
1672*1c60b9acSAndroid Build Coastguard Worker if (!(property_valid[par->vbit.value] &
1673*1c60b9acSAndroid Build Coastguard Worker (1 << ctl_pkt_type(par)))) {
1674*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: prop id 0x%x invalid for"
1675*1c60b9acSAndroid Build Coastguard Worker " control pkt %d\n", __func__,
1676*1c60b9acSAndroid Build Coastguard Worker (int)par->vbit.value,
1677*1c60b9acSAndroid Build Coastguard Worker ctl_pkt_type(par));
1678*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1679*1c60b9acSAndroid Build Coastguard Worker }
1680*1c60b9acSAndroid Build Coastguard Worker par->prop_id = par->vbit.value;
1681*1c60b9acSAndroid Build Coastguard Worker par->flag_prop_multi = !!(
1682*1c60b9acSAndroid Build Coastguard Worker par->props_seen[par->prop_id >> 3] &
1683*1c60b9acSAndroid Build Coastguard Worker (1 << (par->prop_id & 7)));
1684*1c60b9acSAndroid Build Coastguard Worker par->props_seen[par->prop_id >> 3] =
1685*1c60b9acSAndroid Build Coastguard Worker (uint8_t)((par->props_seen[par->prop_id >> 3]) | (1 << (par->prop_id & 7)));
1686*1c60b9acSAndroid Build Coastguard Worker /*
1687*1c60b9acSAndroid Build Coastguard Worker * even if it's not a vbi property arg,
1688*1c60b9acSAndroid Build Coastguard Worker * .consumed of this will be zero the first time
1689*1c60b9acSAndroid Build Coastguard Worker */
1690*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_vbi_init(&par->vbit);
1691*1c60b9acSAndroid Build Coastguard Worker /*
1692*1c60b9acSAndroid Build Coastguard Worker * if it's a string, next state must set the
1693*1c60b9acSAndroid Build Coastguard Worker * destination and size limit itself. But
1694*1c60b9acSAndroid Build Coastguard Worker * resetting it generically here lets it use
1695*1c60b9acSAndroid Build Coastguard Worker * lws_mqtt_str_first() to understand it's the
1696*1c60b9acSAndroid Build Coastguard Worker * first time around.
1697*1c60b9acSAndroid Build Coastguard Worker */
1698*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&par->s_temp, NULL, 0, 0);
1699*1c60b9acSAndroid Build Coastguard Worker
1700*1c60b9acSAndroid Build Coastguard Worker /* property arg state enums are so encoded */
1701*1c60b9acSAndroid Build Coastguard Worker par->state = 0x100 | par->vbit.value;
1702*1c60b9acSAndroid Build Coastguard Worker break;
1703*1c60b9acSAndroid Build Coastguard Worker default:
1704*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: prop id bad vbi\n", __func__);
1705*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1706*1c60b9acSAndroid Build Coastguard Worker }
1707*1c60b9acSAndroid Build Coastguard Worker break;
1708*1c60b9acSAndroid Build Coastguard Worker
1709*1c60b9acSAndroid Build Coastguard Worker /*
1710*1c60b9acSAndroid Build Coastguard Worker * All possible property payloads... restricting which ones
1711*1c60b9acSAndroid Build Coastguard Worker * can appear in which control packets is already done above
1712*1c60b9acSAndroid Build Coastguard Worker * in LMQCPP_PROP_ID_VBI
1713*1c60b9acSAndroid Build Coastguard Worker */
1714*1c60b9acSAndroid Build Coastguard Worker
1715*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_REQUEST_PROBLEM_INFO_1BYTE:
1716*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_REQUEST_REPSONSE_INFO_1BYTE:
1717*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_MAXIMUM_QOS_1BYTE:
1718*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_RETAIN_AVAILABLE_1BYTE:
1719*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE_1BYTE:
1720*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE_1BYTE:
1721*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SHARED_SUBSCRIPTION_AVAILABLE_1BYTE:
1722*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_PAYLOAD_FORMAT_INDICATOR_1BYTE: /* 3.3.2.3.2 */
1723*1c60b9acSAndroid Build Coastguard Worker if (par->flag_prop_multi)
1724*1c60b9acSAndroid Build Coastguard Worker goto singular_prop_seen_twice;
1725*1c60b9acSAndroid Build Coastguard Worker par->payload_format = *buf++;
1726*1c60b9acSAndroid Build Coastguard Worker len--;
1727*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_pconsume(par, 1))
1728*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1729*1c60b9acSAndroid Build Coastguard Worker break;
1730*1c60b9acSAndroid Build Coastguard Worker
1731*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_MAXIMUM_PACKET_SIZE_4BYTE:
1732*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_WILL_DELAY_INTERVAL_4BYTE:
1733*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SESSION_EXPIRY_INTERVAL_4BYTE:
1734*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_MSG_EXPIRY_INTERVAL_4BYTE:
1735*1c60b9acSAndroid Build Coastguard Worker if (par->flag_prop_multi)
1736*1c60b9acSAndroid Build Coastguard Worker goto singular_prop_seen_twice;
1737*1c60b9acSAndroid Build Coastguard Worker
1738*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_mb_first(&par->vbit))
1739*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_4byte_init(&par->vbit);
1740*1c60b9acSAndroid Build Coastguard Worker
1741*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_mb_parse(&par->vbit, &buf, &len)) {
1742*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1743*1c60b9acSAndroid Build Coastguard Worker break;
1744*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1745*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_pconsume(par, par->vbit.consumed))
1746*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1747*1c60b9acSAndroid Build Coastguard Worker break;
1748*1c60b9acSAndroid Build Coastguard Worker default:
1749*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1750*1c60b9acSAndroid Build Coastguard Worker }
1751*1c60b9acSAndroid Build Coastguard Worker break;
1752*1c60b9acSAndroid Build Coastguard Worker
1753*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SERVER_KEEPALIVE_2BYTE:
1754*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_RECEIVE_MAXIMUM_2BYTE:
1755*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_TOPIC_MAXIMUM_2BYTE:
1756*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_TOPIC_ALIAS_2BYTE:
1757*1c60b9acSAndroid Build Coastguard Worker if (par->flag_prop_multi)
1758*1c60b9acSAndroid Build Coastguard Worker goto singular_prop_seen_twice;
1759*1c60b9acSAndroid Build Coastguard Worker
1760*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_mb_first(&par->vbit))
1761*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_2byte_init(&par->vbit);
1762*1c60b9acSAndroid Build Coastguard Worker
1763*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_mb_parse(&par->vbit, &buf, &len)) {
1764*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1765*1c60b9acSAndroid Build Coastguard Worker break;
1766*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1767*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_pconsume(par, par->vbit.consumed))
1768*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1769*1c60b9acSAndroid Build Coastguard Worker break;
1770*1c60b9acSAndroid Build Coastguard Worker default:
1771*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1772*1c60b9acSAndroid Build Coastguard Worker }
1773*1c60b9acSAndroid Build Coastguard Worker break;
1774*1c60b9acSAndroid Build Coastguard Worker
1775*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_ASSIGNED_CLIENTID_UTF8S:
1776*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_AUTH_METHOD_UTF8S:
1777*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_USER_PROPERTY_NAME_UTF8S:
1778*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_USER_PROPERTY_VALUE_UTF8S:
1779*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_RESPONSE_INFO_UTF8S:
1780*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SERVER_REFERENCE_UTF8S:
1781*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_REASON_STRING_UTF8S:
1782*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_RESPONSE_TOPIC_UTF8S:
1783*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_CONTENT_TYPE_UTF8S:
1784*1c60b9acSAndroid Build Coastguard Worker if (par->flag_prop_multi)
1785*1c60b9acSAndroid Build Coastguard Worker goto singular_prop_seen_twice;
1786*1c60b9acSAndroid Build Coastguard Worker
1787*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_first(&par->s_temp))
1788*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&par->s_temp, par->temp,
1789*1c60b9acSAndroid Build Coastguard Worker sizeof(par->temp), 0);
1790*1c60b9acSAndroid Build Coastguard Worker
1791*1c60b9acSAndroid Build Coastguard Worker switch (lws_mqtt_str_parse(&par->s_temp, &buf, &len)) {
1792*1c60b9acSAndroid Build Coastguard Worker case LMSPR_NEED_MORE:
1793*1c60b9acSAndroid Build Coastguard Worker break;
1794*1c60b9acSAndroid Build Coastguard Worker case LMSPR_COMPLETED:
1795*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_pconsume(par, par->s_temp.len))
1796*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1797*1c60b9acSAndroid Build Coastguard Worker break;
1798*1c60b9acSAndroid Build Coastguard Worker
1799*1c60b9acSAndroid Build Coastguard Worker default:
1800*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: bad protocol name\n", __func__);
1801*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1802*1c60b9acSAndroid Build Coastguard Worker }
1803*1c60b9acSAndroid Build Coastguard Worker break;
1804*1c60b9acSAndroid Build Coastguard Worker
1805*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_SUBSCRIPTION_ID_VBI:
1806*1c60b9acSAndroid Build Coastguard Worker
1807*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_CORRELATION_BINDATA:
1808*1c60b9acSAndroid Build Coastguard Worker case LMQCPP_PROP_AUTH_DATA_BINDATA:
1809*1c60b9acSAndroid Build Coastguard Worker
1810*1c60b9acSAndroid Build Coastguard Worker /* TODO */
1811*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Unimplemented packet state 0x%x\n",
1812*1c60b9acSAndroid Build Coastguard Worker __func__, par->state);
1813*1c60b9acSAndroid Build Coastguard Worker return -1;
1814*1c60b9acSAndroid Build Coastguard Worker }
1815*1c60b9acSAndroid Build Coastguard Worker }
1816*1c60b9acSAndroid Build Coastguard Worker
1817*1c60b9acSAndroid Build Coastguard Worker return 0;
1818*1c60b9acSAndroid Build Coastguard Worker
1819*1c60b9acSAndroid Build Coastguard Worker oom:
1820*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: OOM!\n", __func__);
1821*1c60b9acSAndroid Build Coastguard Worker goto send_protocol_error_and_close;
1822*1c60b9acSAndroid Build Coastguard Worker
1823*1c60b9acSAndroid Build Coastguard Worker singular_prop_seen_twice:
1824*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: property appears twice\n", __func__);
1825*1c60b9acSAndroid Build Coastguard Worker
1826*1c60b9acSAndroid Build Coastguard Worker send_protocol_error_and_close:
1827*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: peac\n", __func__);
1828*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_PROTOCOL_ERROR;
1829*1c60b9acSAndroid Build Coastguard Worker
1830*1c60b9acSAndroid Build Coastguard Worker send_reason_and_close:
1831*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: srac\n", __func__);
1832*1c60b9acSAndroid Build Coastguard Worker par->flag_pending_send_reason_close = 1;
1833*1c60b9acSAndroid Build Coastguard Worker goto ask;
1834*1c60b9acSAndroid Build Coastguard Worker
1835*1c60b9acSAndroid Build Coastguard Worker send_unsupp_connack_and_close:
1836*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: unsupac\n", __func__);
1837*1c60b9acSAndroid Build Coastguard Worker par->reason = LMQCP_REASON_UNSUPPORTED_PROTOCOL;
1838*1c60b9acSAndroid Build Coastguard Worker par->flag_pending_send_connack_close = 1;
1839*1c60b9acSAndroid Build Coastguard Worker
1840*1c60b9acSAndroid Build Coastguard Worker ask:
1841*1c60b9acSAndroid Build Coastguard Worker /* Should we ask for clients? */
1842*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
1843*1c60b9acSAndroid Build Coastguard Worker
1844*1c60b9acSAndroid Build Coastguard Worker return -1;
1845*1c60b9acSAndroid Build Coastguard Worker }
1846*1c60b9acSAndroid Build Coastguard Worker
1847*1c60b9acSAndroid Build Coastguard Worker int
lws_mqtt_fill_fixed_header(uint8_t * p,lws_mqtt_control_packet_t ctrl_pkt_type,uint8_t dup,lws_mqtt_qos_levels_t qos,uint8_t retain)1848*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_fill_fixed_header(uint8_t *p, lws_mqtt_control_packet_t ctrl_pkt_type,
1849*1c60b9acSAndroid Build Coastguard Worker uint8_t dup, lws_mqtt_qos_levels_t qos,
1850*1c60b9acSAndroid Build Coastguard Worker uint8_t retain)
1851*1c60b9acSAndroid Build Coastguard Worker {
1852*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_fixed_hdr_t hdr;
1853*1c60b9acSAndroid Build Coastguard Worker
1854*1c60b9acSAndroid Build Coastguard Worker hdr.bits = 0;
1855*1c60b9acSAndroid Build Coastguard Worker hdr.flags.ctrl_pkt_type = ctrl_pkt_type & 0xf;
1856*1c60b9acSAndroid Build Coastguard Worker
1857*1c60b9acSAndroid Build Coastguard Worker switch(ctrl_pkt_type) {
1858*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBLISH:
1859*1c60b9acSAndroid Build Coastguard Worker hdr.flags.dup = !!dup;
1860*1c60b9acSAndroid Build Coastguard Worker /*
1861*1c60b9acSAndroid Build Coastguard Worker * A PUBLISH Packet MUST NOT have both QoS bits set to
1862*1c60b9acSAndroid Build Coastguard Worker * 1. If a Server or Client receives a PUBLISH Packet
1863*1c60b9acSAndroid Build Coastguard Worker * which has both QoS bits set to 1 it MUST close the
1864*1c60b9acSAndroid Build Coastguard Worker * Network Connection [MQTT-3.3.1-4].
1865*1c60b9acSAndroid Build Coastguard Worker */
1866*1c60b9acSAndroid Build Coastguard Worker if (qos >= RESERVED_QOS_LEVEL) {
1867*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Unsupport QoS level 0x%x\n",
1868*1c60b9acSAndroid Build Coastguard Worker __func__, qos);
1869*1c60b9acSAndroid Build Coastguard Worker return -1;
1870*1c60b9acSAndroid Build Coastguard Worker }
1871*1c60b9acSAndroid Build Coastguard Worker hdr.flags.qos = qos & 3;
1872*1c60b9acSAndroid Build Coastguard Worker hdr.flags.retain = !!retain;
1873*1c60b9acSAndroid Build Coastguard Worker break;
1874*1c60b9acSAndroid Build Coastguard Worker
1875*1c60b9acSAndroid Build Coastguard Worker case LMQCP_CTOS_CONNECT:
1876*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_CONNACK:
1877*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBACK:
1878*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBREC:
1879*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBCOMP:
1880*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_SUBACK:
1881*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_UNSUBACK:
1882*1c60b9acSAndroid Build Coastguard Worker case LMQCP_CTOS_PINGREQ:
1883*1c60b9acSAndroid Build Coastguard Worker case LMQCP_STOC_PINGRESP:
1884*1c60b9acSAndroid Build Coastguard Worker case LMQCP_DISCONNECT:
1885*1c60b9acSAndroid Build Coastguard Worker case LMQCP_AUTH:
1886*1c60b9acSAndroid Build Coastguard Worker hdr.bits &= 0xf0;
1887*1c60b9acSAndroid Build Coastguard Worker break;
1888*1c60b9acSAndroid Build Coastguard Worker
1889*1c60b9acSAndroid Build Coastguard Worker /*
1890*1c60b9acSAndroid Build Coastguard Worker * Bits 3,2,1 and 0 of the fixed header of the PUBREL,
1891*1c60b9acSAndroid Build Coastguard Worker * SUBSCRIBE, UNSUBSCRIBE Control Packets are reserved and
1892*1c60b9acSAndroid Build Coastguard Worker * MUST be set to 0,0,1 and 0 respectively. The Server MUST
1893*1c60b9acSAndroid Build Coastguard Worker * treat any other value as malformed and close the Network
1894*1c60b9acSAndroid Build Coastguard Worker * Connection [MQTT-3.6.1-1], [MQTT-3.8.1-1], [MQTT-3.10.1-1].
1895*1c60b9acSAndroid Build Coastguard Worker */
1896*1c60b9acSAndroid Build Coastguard Worker case LMQCP_PUBREL:
1897*1c60b9acSAndroid Build Coastguard Worker case LMQCP_CTOS_SUBSCRIBE:
1898*1c60b9acSAndroid Build Coastguard Worker case LMQCP_CTOS_UNSUBSCRIBE:
1899*1c60b9acSAndroid Build Coastguard Worker hdr.bits |= 0x02;
1900*1c60b9acSAndroid Build Coastguard Worker break;
1901*1c60b9acSAndroid Build Coastguard Worker
1902*1c60b9acSAndroid Build Coastguard Worker default:
1903*1c60b9acSAndroid Build Coastguard Worker return -1;
1904*1c60b9acSAndroid Build Coastguard Worker }
1905*1c60b9acSAndroid Build Coastguard Worker
1906*1c60b9acSAndroid Build Coastguard Worker *p = hdr.bits;
1907*1c60b9acSAndroid Build Coastguard Worker
1908*1c60b9acSAndroid Build Coastguard Worker return 0;
1909*1c60b9acSAndroid Build Coastguard Worker }
1910*1c60b9acSAndroid Build Coastguard Worker
1911*1c60b9acSAndroid Build Coastguard Worker /*
1912*1c60b9acSAndroid Build Coastguard Worker * This fires if the wsi did a PUBLISH under QoS1 or QoS2, but no PUBACK or
1913*1c60b9acSAndroid Build Coastguard Worker * PUBREC came before the timeout period
1914*1c60b9acSAndroid Build Coastguard Worker */
1915*1c60b9acSAndroid Build Coastguard Worker
1916*1c60b9acSAndroid Build Coastguard Worker static void
lws_mqtt_publish_resend(struct lws_sorted_usec_list * sul)1917*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_publish_resend(struct lws_sorted_usec_list *sul)
1918*1c60b9acSAndroid Build Coastguard Worker {
1919*1c60b9acSAndroid Build Coastguard Worker struct _lws_mqtt_related *mqtt = lws_container_of(sul,
1920*1c60b9acSAndroid Build Coastguard Worker struct _lws_mqtt_related, sul_qos_puback_pubrec_wait);
1921*1c60b9acSAndroid Build Coastguard Worker
1922*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi));
1923*1c60b9acSAndroid Build Coastguard Worker
1924*1c60b9acSAndroid Build Coastguard Worker if (mqtt->wsi->a.protocol->callback(mqtt->wsi, LWS_CALLBACK_MQTT_RESEND,
1925*1c60b9acSAndroid Build Coastguard Worker mqtt->wsi->user_space, NULL, 0))
1926*1c60b9acSAndroid Build Coastguard Worker lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC);
1927*1c60b9acSAndroid Build Coastguard Worker }
1928*1c60b9acSAndroid Build Coastguard Worker
1929*1c60b9acSAndroid Build Coastguard Worker static void
lws_mqtt_unsuback_timeout(struct lws_sorted_usec_list * sul)1930*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_unsuback_timeout(struct lws_sorted_usec_list *sul)
1931*1c60b9acSAndroid Build Coastguard Worker {
1932*1c60b9acSAndroid Build Coastguard Worker struct _lws_mqtt_related *mqtt = lws_container_of(sul,
1933*1c60b9acSAndroid Build Coastguard Worker struct _lws_mqtt_related, sul_unsuback_wait);
1934*1c60b9acSAndroid Build Coastguard Worker
1935*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi));
1936*1c60b9acSAndroid Build Coastguard Worker
1937*1c60b9acSAndroid Build Coastguard Worker if (mqtt->wsi->a.protocol->callback(mqtt->wsi,
1938*1c60b9acSAndroid Build Coastguard Worker LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT,
1939*1c60b9acSAndroid Build Coastguard Worker mqtt->wsi->user_space, NULL, 0))
1940*1c60b9acSAndroid Build Coastguard Worker lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC);
1941*1c60b9acSAndroid Build Coastguard Worker }
1942*1c60b9acSAndroid Build Coastguard Worker
1943*1c60b9acSAndroid Build Coastguard Worker int
lws_mqtt_client_send_publish(struct lws * wsi,lws_mqtt_publish_param_t * pub,const void * buf,uint32_t len,int is_complete)1944*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub,
1945*1c60b9acSAndroid Build Coastguard Worker const void *buf, uint32_t len, int is_complete)
1946*1c60b9acSAndroid Build Coastguard Worker {
1947*1c60b9acSAndroid Build Coastguard Worker struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
1948*1c60b9acSAndroid Build Coastguard Worker uint8_t *b = (uint8_t *)pt->serv_buf, *start, *p;
1949*1c60b9acSAndroid Build Coastguard Worker struct lws *nwsi = lws_get_network_wsi(wsi);
1950*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_t mqtt_vh_payload;
1951*1c60b9acSAndroid Build Coastguard Worker uint32_t vh_len, rem_len;
1952*1c60b9acSAndroid Build Coastguard Worker
1953*1c60b9acSAndroid Build Coastguard Worker assert(pub->topic);
1954*1c60b9acSAndroid Build Coastguard Worker
1955*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: len = %d, is_complete = %d\n",
1956*1c60b9acSAndroid Build Coastguard Worker __func__, (int)len, (int)is_complete);
1957*1c60b9acSAndroid Build Coastguard Worker
1958*1c60b9acSAndroid Build Coastguard Worker if (lwsi_state(wsi) != LRS_ESTABLISHED) {
1959*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: %s: unknown state 0x%x\n", __func__,
1960*1c60b9acSAndroid Build Coastguard Worker lws_wsi_tag(wsi), lwsi_state(wsi));
1961*1c60b9acSAndroid Build Coastguard Worker assert(0);
1962*1c60b9acSAndroid Build Coastguard Worker return 1;
1963*1c60b9acSAndroid Build Coastguard Worker }
1964*1c60b9acSAndroid Build Coastguard Worker
1965*1c60b9acSAndroid Build Coastguard Worker if (wsi->mqtt->inside_payload) {
1966*1c60b9acSAndroid Build Coastguard Worker /*
1967*1c60b9acSAndroid Build Coastguard Worker * Headers are filled, we are sending
1968*1c60b9acSAndroid Build Coastguard Worker * the payload - a buffer with LWS_PRE
1969*1c60b9acSAndroid Build Coastguard Worker * in front it.
1970*1c60b9acSAndroid Build Coastguard Worker */
1971*1c60b9acSAndroid Build Coastguard Worker start = (uint8_t *)buf;
1972*1c60b9acSAndroid Build Coastguard Worker p = start + len;
1973*1c60b9acSAndroid Build Coastguard Worker if (is_complete)
1974*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->inside_payload = 0;
1975*1c60b9acSAndroid Build Coastguard Worker goto do_write;
1976*1c60b9acSAndroid Build Coastguard Worker }
1977*1c60b9acSAndroid Build Coastguard Worker
1978*1c60b9acSAndroid Build Coastguard Worker start = b + LWS_PRE;
1979*1c60b9acSAndroid Build Coastguard Worker p = start;
1980*1c60b9acSAndroid Build Coastguard Worker /*
1981*1c60b9acSAndroid Build Coastguard Worker * Fill headers and the first chunk of the
1982*1c60b9acSAndroid Build Coastguard Worker * payload (if any)
1983*1c60b9acSAndroid Build Coastguard Worker */
1984*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_fill_fixed_header(p++, LMQCP_PUBLISH,
1985*1c60b9acSAndroid Build Coastguard Worker 0, pub->qos, 0)) {
1986*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Failed to fill fixed header\n", __func__);
1987*1c60b9acSAndroid Build Coastguard Worker return 1;
1988*1c60b9acSAndroid Build Coastguard Worker }
1989*1c60b9acSAndroid Build Coastguard Worker
1990*1c60b9acSAndroid Build Coastguard Worker /*
1991*1c60b9acSAndroid Build Coastguard Worker * Topic len field + Topic len + Packet ID
1992*1c60b9acSAndroid Build Coastguard Worker * (for QOS>0) + Payload len
1993*1c60b9acSAndroid Build Coastguard Worker */
1994*1c60b9acSAndroid Build Coastguard Worker vh_len = (unsigned int)(2 + pub->topic_len + ((pub->qos) ? 2 : 0));
1995*1c60b9acSAndroid Build Coastguard Worker rem_len = vh_len + pub->payload_len;
1996*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: Remaining len = %d\n", __func__, (int) rem_len);
1997*1c60b9acSAndroid Build Coastguard Worker
1998*1c60b9acSAndroid Build Coastguard Worker /* Will the chunk of payload fit? */
1999*1c60b9acSAndroid Build Coastguard Worker if ((vh_len + len) >=
2000*1c60b9acSAndroid Build Coastguard Worker (wsi->a.context->pt_serv_buf_size - LWS_PRE)) {
2001*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Payload is too big\n", __func__);
2002*1c60b9acSAndroid Build Coastguard Worker return 1;
2003*1c60b9acSAndroid Build Coastguard Worker }
2004*1c60b9acSAndroid Build Coastguard Worker
2005*1c60b9acSAndroid Build Coastguard Worker p += lws_mqtt_vbi_encode(rem_len, p);
2006*1c60b9acSAndroid Build Coastguard Worker
2007*1c60b9acSAndroid Build Coastguard Worker /* Topic's Len */
2008*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, pub->topic_len);
2009*1c60b9acSAndroid Build Coastguard Worker p += 2;
2010*1c60b9acSAndroid Build Coastguard Worker
2011*1c60b9acSAndroid Build Coastguard Worker /*
2012*1c60b9acSAndroid Build Coastguard Worker * Init lws_mqtt_str for "MQTT Variable
2013*1c60b9acSAndroid Build Coastguard Worker * Headers + payload" (only the supplied
2014*1c60b9acSAndroid Build Coastguard Worker * chuncked payload)
2015*1c60b9acSAndroid Build Coastguard Worker */
2016*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p,
2017*1c60b9acSAndroid Build Coastguard Worker (uint16_t)(unsigned int)(pub->topic_len + ((pub->qos) ? 2u : 0u) + len),
2018*1c60b9acSAndroid Build Coastguard Worker 0);
2019*1c60b9acSAndroid Build Coastguard Worker
2020*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2021*1c60b9acSAndroid Build Coastguard Worker lws_strncpy((char *)p, pub->topic, (size_t)pub->topic_len+1);
2022*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, pub->topic_len)) {
2023*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: a\n", __func__);
2024*1c60b9acSAndroid Build Coastguard Worker return 1;
2025*1c60b9acSAndroid Build Coastguard Worker }
2026*1c60b9acSAndroid Build Coastguard Worker
2027*1c60b9acSAndroid Build Coastguard Worker /* Packet ID */
2028*1c60b9acSAndroid Build Coastguard Worker if (pub->qos != QOS0) {
2029*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2030*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = pub->packet_id = ++nwsi->mqtt->pkt_id;
2031*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: pkt_id = %d\n", __func__,
2032*1c60b9acSAndroid Build Coastguard Worker (int)wsi->mqtt->ack_pkt_id);
2033*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, pub->packet_id);
2034*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 2)) {
2035*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: b\n", __func__);
2036*1c60b9acSAndroid Build Coastguard Worker return 1;
2037*1c60b9acSAndroid Build Coastguard Worker }
2038*1c60b9acSAndroid Build Coastguard Worker }
2039*1c60b9acSAndroid Build Coastguard Worker
2040*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2041*1c60b9acSAndroid Build Coastguard Worker memcpy(p, buf, len);
2042*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, (int)len))
2043*1c60b9acSAndroid Build Coastguard Worker return 1;
2044*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2045*1c60b9acSAndroid Build Coastguard Worker
2046*1c60b9acSAndroid Build Coastguard Worker if (!is_complete)
2047*1c60b9acSAndroid Build Coastguard Worker nwsi->mqtt->inside_payload = wsi->mqtt->inside_payload = 1;
2048*1c60b9acSAndroid Build Coastguard Worker
2049*1c60b9acSAndroid Build Coastguard Worker do_write:
2050*1c60b9acSAndroid Build Coastguard Worker
2051*1c60b9acSAndroid Build Coastguard Worker // lwsl_hexdump_err(start, lws_ptr_diff(p, start));
2052*1c60b9acSAndroid Build Coastguard Worker
2053*1c60b9acSAndroid Build Coastguard Worker if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
2054*1c60b9acSAndroid Build Coastguard Worker lws_ptr_diff(p, start)) {
2055*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: write failed\n", __func__);
2056*1c60b9acSAndroid Build Coastguard Worker return 1;
2057*1c60b9acSAndroid Build Coastguard Worker }
2058*1c60b9acSAndroid Build Coastguard Worker
2059*1c60b9acSAndroid Build Coastguard Worker if (!is_complete) {
2060*1c60b9acSAndroid Build Coastguard Worker /* still some more chunks to come... */
2061*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
2062*1c60b9acSAndroid Build Coastguard Worker
2063*1c60b9acSAndroid Build Coastguard Worker return 0;
2064*1c60b9acSAndroid Build Coastguard Worker }
2065*1c60b9acSAndroid Build Coastguard Worker
2066*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->inside_payload = nwsi->mqtt->inside_payload = 0;
2067*1c60b9acSAndroid Build Coastguard Worker
2068*1c60b9acSAndroid Build Coastguard Worker if (pub->qos != QOS0)
2069*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->unacked_publish = 1;
2070*1c60b9acSAndroid Build Coastguard Worker
2071*1c60b9acSAndroid Build Coastguard Worker /* this was the last part of the publish message */
2072*1c60b9acSAndroid Build Coastguard Worker
2073*1c60b9acSAndroid Build Coastguard Worker if (pub->qos == QOS0) {
2074*1c60b9acSAndroid Build Coastguard Worker /*
2075*1c60b9acSAndroid Build Coastguard Worker * There won't be any real PUBACK, act like we got one
2076*1c60b9acSAndroid Build Coastguard Worker * so the user callback logic is the same for QoS0 or
2077*1c60b9acSAndroid Build Coastguard Worker * QoS1
2078*1c60b9acSAndroid Build Coastguard Worker */
2079*1c60b9acSAndroid Build Coastguard Worker if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_MQTT_ACK,
2080*1c60b9acSAndroid Build Coastguard Worker wsi->user_space, NULL, 0)) {
2081*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: ACK callback exited\n", __func__);
2082*1c60b9acSAndroid Build Coastguard Worker return 1;
2083*1c60b9acSAndroid Build Coastguard Worker }
2084*1c60b9acSAndroid Build Coastguard Worker } else if (pub->qos == QOS1 || pub->qos == QOS2) {
2085*1c60b9acSAndroid Build Coastguard Worker /* For QoS1 or QoS2, if no PUBACK or PUBREC coming after 3s,
2086*1c60b9acSAndroid Build Coastguard Worker * we must RETRY the publish
2087*1c60b9acSAndroid Build Coastguard Worker */
2088*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->sul_qos_puback_pubrec_wait.cb = lws_mqtt_publish_resend;
2089*1c60b9acSAndroid Build Coastguard Worker __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend],
2090*1c60b9acSAndroid Build Coastguard Worker &wsi->mqtt->sul_qos_puback_pubrec_wait,
2091*1c60b9acSAndroid Build Coastguard Worker 3 * LWS_USEC_PER_SEC);
2092*1c60b9acSAndroid Build Coastguard Worker }
2093*1c60b9acSAndroid Build Coastguard Worker
2094*1c60b9acSAndroid Build Coastguard Worker return 0;
2095*1c60b9acSAndroid Build Coastguard Worker }
2096*1c60b9acSAndroid Build Coastguard Worker
2097*1c60b9acSAndroid Build Coastguard Worker int
lws_mqtt_client_send_subcribe(struct lws * wsi,lws_mqtt_subscribe_param_t * sub)2098*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub)
2099*1c60b9acSAndroid Build Coastguard Worker {
2100*1c60b9acSAndroid Build Coastguard Worker struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
2101*1c60b9acSAndroid Build Coastguard Worker uint8_t *b = (uint8_t *)pt->serv_buf + LWS_PRE, *start = b, *p = start;
2102*1c60b9acSAndroid Build Coastguard Worker struct lws *nwsi = lws_get_network_wsi(wsi);
2103*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_t mqtt_vh_payload;
2104*1c60b9acSAndroid Build Coastguard Worker uint8_t exists[8], extant;
2105*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *mysub;
2106*1c60b9acSAndroid Build Coastguard Worker uint32_t rem_len;
2107*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2108*1c60b9acSAndroid Build Coastguard Worker uint32_t tops;
2109*1c60b9acSAndroid Build Coastguard Worker #endif
2110*1c60b9acSAndroid Build Coastguard Worker uint32_t n;
2111*1c60b9acSAndroid Build Coastguard Worker
2112*1c60b9acSAndroid Build Coastguard Worker assert(sub->num_topics);
2113*1c60b9acSAndroid Build Coastguard Worker assert(sub->num_topics < sizeof(exists));
2114*1c60b9acSAndroid Build Coastguard Worker
2115*1c60b9acSAndroid Build Coastguard Worker switch (lwsi_state(wsi)) {
2116*1c60b9acSAndroid Build Coastguard Worker case LRS_ESTABLISHED: /* Protocol connection established */
2117*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_SUBSCRIBE,
2118*1c60b9acSAndroid Build Coastguard Worker 0, 0, 0)) {
2119*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Failed to fill fixed header\n", __func__);
2120*1c60b9acSAndroid Build Coastguard Worker return 1;
2121*1c60b9acSAndroid Build Coastguard Worker }
2122*1c60b9acSAndroid Build Coastguard Worker
2123*1c60b9acSAndroid Build Coastguard Worker /*
2124*1c60b9acSAndroid Build Coastguard Worker * The stream wants to subscribe to one or more topic, but
2125*1c60b9acSAndroid Build Coastguard Worker * the shared nwsi may already be subscribed to some or all of
2126*1c60b9acSAndroid Build Coastguard Worker * them from interactions with other streams. For those cases,
2127*1c60b9acSAndroid Build Coastguard Worker * we filter them from the list the child wants until we just
2128*1c60b9acSAndroid Build Coastguard Worker * have ones that are new to the nwsi. If nothing left, we just
2129*1c60b9acSAndroid Build Coastguard Worker * synthesize the callback to the child as if SUBACK had come
2130*1c60b9acSAndroid Build Coastguard Worker * and we're done, otherwise just ask the server for topics that
2131*1c60b9acSAndroid Build Coastguard Worker * are new to the wsi.
2132*1c60b9acSAndroid Build Coastguard Worker */
2133*1c60b9acSAndroid Build Coastguard Worker
2134*1c60b9acSAndroid Build Coastguard Worker extant = 0;
2135*1c60b9acSAndroid Build Coastguard Worker memset(&exists, 0, sizeof(exists));
2136*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < sub->num_topics; n++) {
2137*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: Subscribing to topic[%d] = \"%s\"\n",
2138*1c60b9acSAndroid Build Coastguard Worker __func__, (int)n, sub->topic[n].name);
2139*1c60b9acSAndroid Build Coastguard Worker
2140*1c60b9acSAndroid Build Coastguard Worker mysub = lws_mqtt_find_sub(nwsi->mqtt, sub->topic[n].name);
2141*1c60b9acSAndroid Build Coastguard Worker if (mysub && mysub->ref_count) {
2142*1c60b9acSAndroid Build Coastguard Worker mysub->ref_count++; /* another stream using it */
2143*1c60b9acSAndroid Build Coastguard Worker exists[n] = 1;
2144*1c60b9acSAndroid Build Coastguard Worker extant++;
2145*1c60b9acSAndroid Build Coastguard Worker }
2146*1c60b9acSAndroid Build Coastguard Worker
2147*1c60b9acSAndroid Build Coastguard Worker /*
2148*1c60b9acSAndroid Build Coastguard Worker * Attach the topic we're subscribing to, to wsi->mqtt
2149*1c60b9acSAndroid Build Coastguard Worker */
2150*1c60b9acSAndroid Build Coastguard Worker if (!lws_mqtt_create_sub(wsi->mqtt, sub->topic[n].name)) {
2151*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: create sub fail\n", __func__);
2152*1c60b9acSAndroid Build Coastguard Worker return 1;
2153*1c60b9acSAndroid Build Coastguard Worker }
2154*1c60b9acSAndroid Build Coastguard Worker }
2155*1c60b9acSAndroid Build Coastguard Worker
2156*1c60b9acSAndroid Build Coastguard Worker if (extant == sub->num_topics) {
2157*1c60b9acSAndroid Build Coastguard Worker /*
2158*1c60b9acSAndroid Build Coastguard Worker * It turns out there's nothing to do here, the nwsi has
2159*1c60b9acSAndroid Build Coastguard Worker * already subscribed to all the topics this stream
2160*1c60b9acSAndroid Build Coastguard Worker * wanted. Just tell it it can have them.
2161*1c60b9acSAndroid Build Coastguard Worker */
2162*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: all topics already subscribed\n", __func__);
2163*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
2164*1c60b9acSAndroid Build Coastguard Worker wsi->a.protocol->callback,
2165*1c60b9acSAndroid Build Coastguard Worker wsi, LWS_CALLBACK_MQTT_SUBSCRIBED,
2166*1c60b9acSAndroid Build Coastguard Worker wsi->user_space, NULL, 0) < 0) {
2167*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: MQTT_SUBSCRIBE failed\n",
2168*1c60b9acSAndroid Build Coastguard Worker __func__);
2169*1c60b9acSAndroid Build Coastguard Worker return -1;
2170*1c60b9acSAndroid Build Coastguard Worker }
2171*1c60b9acSAndroid Build Coastguard Worker
2172*1c60b9acSAndroid Build Coastguard Worker return 0;
2173*1c60b9acSAndroid Build Coastguard Worker }
2174*1c60b9acSAndroid Build Coastguard Worker
2175*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2176*1c60b9acSAndroid Build Coastguard Worker /*
2177*1c60b9acSAndroid Build Coastguard Worker * zero or more of the topics already existed, but not all,
2178*1c60b9acSAndroid Build Coastguard Worker * so we must go to the server with a filtered list of the
2179*1c60b9acSAndroid Build Coastguard Worker * new ones only
2180*1c60b9acSAndroid Build Coastguard Worker */
2181*1c60b9acSAndroid Build Coastguard Worker
2182*1c60b9acSAndroid Build Coastguard Worker tops = sub->num_topics - extant;
2183*1c60b9acSAndroid Build Coastguard Worker #endif
2184*1c60b9acSAndroid Build Coastguard Worker
2185*1c60b9acSAndroid Build Coastguard Worker /*
2186*1c60b9acSAndroid Build Coastguard Worker * Pid + (Topic len field + Topic len + Req. QoS) x Num of Topics
2187*1c60b9acSAndroid Build Coastguard Worker */
2188*1c60b9acSAndroid Build Coastguard Worker rem_len = 2;
2189*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < sub->num_topics; n++)
2190*1c60b9acSAndroid Build Coastguard Worker if (!exists[n])
2191*1c60b9acSAndroid Build Coastguard Worker rem_len += (2 + (uint32_t)strlen(sub->topic[n].name) + (uint32_t)1);
2192*1c60b9acSAndroid Build Coastguard Worker
2193*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->sub_size = (uint16_t)rem_len;
2194*1c60b9acSAndroid Build Coastguard Worker
2195*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2196*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: Number of topics = %d, Remaining len = %d\n",
2197*1c60b9acSAndroid Build Coastguard Worker __func__, (int)tops, (int)rem_len);
2198*1c60b9acSAndroid Build Coastguard Worker #endif
2199*1c60b9acSAndroid Build Coastguard Worker
2200*1c60b9acSAndroid Build Coastguard Worker p += lws_mqtt_vbi_encode(rem_len, p);
2201*1c60b9acSAndroid Build Coastguard Worker
2202*1c60b9acSAndroid Build Coastguard Worker if ((rem_len + lws_ptr_diff_size_t(p, start)) >=
2203*1c60b9acSAndroid Build Coastguard Worker wsi->a.context->pt_serv_buf_size) {
2204*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Payload is too big\n", __func__);
2205*1c60b9acSAndroid Build Coastguard Worker return 1;
2206*1c60b9acSAndroid Build Coastguard Worker }
2207*1c60b9acSAndroid Build Coastguard Worker
2208*1c60b9acSAndroid Build Coastguard Worker /* Init lws_mqtt_str */
2209*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p, (uint16_t)rem_len, 0);
2210*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2211*1c60b9acSAndroid Build Coastguard Worker
2212*1c60b9acSAndroid Build Coastguard Worker /* Packet ID */
2213*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = sub->packet_id = ++nwsi->mqtt->pkt_id;
2214*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: pkt_id = %d\n", __func__,
2215*1c60b9acSAndroid Build Coastguard Worker (int)sub->packet_id);
2216*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id);
2217*1c60b9acSAndroid Build Coastguard Worker
2218*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
2219*1c60b9acSAndroid Build Coastguard Worker return 1;
2220*1c60b9acSAndroid Build Coastguard Worker
2221*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2222*1c60b9acSAndroid Build Coastguard Worker
2223*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < sub->num_topics; n++) {
2224*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: topics[%d] = %s\n", __func__,
2225*1c60b9acSAndroid Build Coastguard Worker (int)n, sub->topic[n].name);
2226*1c60b9acSAndroid Build Coastguard Worker
2227*1c60b9acSAndroid Build Coastguard Worker /* if the nwsi already has it, don't ask server for it */
2228*1c60b9acSAndroid Build Coastguard Worker if (exists[n]) {
2229*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: topics[%d] \"%s\" exists in nwsi\n",
2230*1c60b9acSAndroid Build Coastguard Worker __func__, (int)n, sub->topic[n].name);
2231*1c60b9acSAndroid Build Coastguard Worker continue;
2232*1c60b9acSAndroid Build Coastguard Worker }
2233*1c60b9acSAndroid Build Coastguard Worker
2234*1c60b9acSAndroid Build Coastguard Worker /*
2235*1c60b9acSAndroid Build Coastguard Worker * Attach the topic we're subscribing to, to nwsi->mqtt
2236*1c60b9acSAndroid Build Coastguard Worker * so we know the nwsi itself has a subscription to it
2237*1c60b9acSAndroid Build Coastguard Worker */
2238*1c60b9acSAndroid Build Coastguard Worker
2239*1c60b9acSAndroid Build Coastguard Worker if (!lws_mqtt_create_sub(nwsi->mqtt, sub->topic[n].name))
2240*1c60b9acSAndroid Build Coastguard Worker return 1;
2241*1c60b9acSAndroid Build Coastguard Worker
2242*1c60b9acSAndroid Build Coastguard Worker /* Topic's Len */
2243*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, (uint16_t)strlen(sub->topic[n].name));
2244*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
2245*1c60b9acSAndroid Build Coastguard Worker return 1;
2246*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2247*1c60b9acSAndroid Build Coastguard Worker
2248*1c60b9acSAndroid Build Coastguard Worker /* Topic Name */
2249*1c60b9acSAndroid Build Coastguard Worker lws_strncpy((char *)p, sub->topic[n].name,
2250*1c60b9acSAndroid Build Coastguard Worker strlen(sub->topic[n].name) + 1);
2251*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload,
2252*1c60b9acSAndroid Build Coastguard Worker (int)strlen(sub->topic[n].name)))
2253*1c60b9acSAndroid Build Coastguard Worker return 1;
2254*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2255*1c60b9acSAndroid Build Coastguard Worker
2256*1c60b9acSAndroid Build Coastguard Worker /* QoS */
2257*1c60b9acSAndroid Build Coastguard Worker *p = (uint8_t)sub->topic[n].qos;
2258*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 1))
2259*1c60b9acSAndroid Build Coastguard Worker return 1;
2260*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2261*1c60b9acSAndroid Build Coastguard Worker }
2262*1c60b9acSAndroid Build Coastguard Worker break;
2263*1c60b9acSAndroid Build Coastguard Worker
2264*1c60b9acSAndroid Build Coastguard Worker default:
2265*1c60b9acSAndroid Build Coastguard Worker return 1;
2266*1c60b9acSAndroid Build Coastguard Worker }
2267*1c60b9acSAndroid Build Coastguard Worker
2268*1c60b9acSAndroid Build Coastguard Worker if (wsi->mqtt->inside_resume_session)
2269*1c60b9acSAndroid Build Coastguard Worker return 0;
2270*1c60b9acSAndroid Build Coastguard Worker
2271*1c60b9acSAndroid Build Coastguard Worker if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
2272*1c60b9acSAndroid Build Coastguard Worker lws_ptr_diff(p, start))
2273*1c60b9acSAndroid Build Coastguard Worker return 1;
2274*1c60b9acSAndroid Build Coastguard Worker
2275*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->inside_subscribe = 1;
2276*1c60b9acSAndroid Build Coastguard Worker
2277*1c60b9acSAndroid Build Coastguard Worker return 0;
2278*1c60b9acSAndroid Build Coastguard Worker }
2279*1c60b9acSAndroid Build Coastguard Worker
2280*1c60b9acSAndroid Build Coastguard Worker int
lws_mqtt_client_send_unsubcribe(struct lws * wsi,const lws_mqtt_subscribe_param_t * unsub)2281*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_client_send_unsubcribe(struct lws *wsi,
2282*1c60b9acSAndroid Build Coastguard Worker const lws_mqtt_subscribe_param_t *unsub)
2283*1c60b9acSAndroid Build Coastguard Worker {
2284*1c60b9acSAndroid Build Coastguard Worker struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
2285*1c60b9acSAndroid Build Coastguard Worker uint8_t *b = (uint8_t *)pt->serv_buf + LWS_PRE, *start = b, *p = start;
2286*1c60b9acSAndroid Build Coastguard Worker struct lws *nwsi = lws_get_network_wsi(wsi);
2287*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_t mqtt_vh_payload;
2288*1c60b9acSAndroid Build Coastguard Worker uint8_t send_unsub[8], orphaned;
2289*1c60b9acSAndroid Build Coastguard Worker uint32_t rem_len, n;
2290*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_subs_t *mysub;
2291*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2292*1c60b9acSAndroid Build Coastguard Worker uint32_t tops;
2293*1c60b9acSAndroid Build Coastguard Worker #endif
2294*1c60b9acSAndroid Build Coastguard Worker
2295*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: Enter\n", __func__);
2296*1c60b9acSAndroid Build Coastguard Worker
2297*1c60b9acSAndroid Build Coastguard Worker switch (lwsi_state(wsi)) {
2298*1c60b9acSAndroid Build Coastguard Worker case LRS_ESTABLISHED: /* Protocol connection established */
2299*1c60b9acSAndroid Build Coastguard Worker orphaned = 0;
2300*1c60b9acSAndroid Build Coastguard Worker memset(&send_unsub, 0, sizeof(send_unsub));
2301*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < unsub->num_topics; n++) {
2302*1c60b9acSAndroid Build Coastguard Worker mysub = lws_mqtt_find_sub(nwsi->mqtt,
2303*1c60b9acSAndroid Build Coastguard Worker unsub->topic[n].name);
2304*1c60b9acSAndroid Build Coastguard Worker assert(mysub);
2305*1c60b9acSAndroid Build Coastguard Worker
2306*1c60b9acSAndroid Build Coastguard Worker if (mysub && --mysub->ref_count == 0) {
2307*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: Need to send UNSUB\n", __func__);
2308*1c60b9acSAndroid Build Coastguard Worker send_unsub[n] = 1;
2309*1c60b9acSAndroid Build Coastguard Worker orphaned++;
2310*1c60b9acSAndroid Build Coastguard Worker }
2311*1c60b9acSAndroid Build Coastguard Worker }
2312*1c60b9acSAndroid Build Coastguard Worker
2313*1c60b9acSAndroid Build Coastguard Worker if (!orphaned) {
2314*1c60b9acSAndroid Build Coastguard Worker /*
2315*1c60b9acSAndroid Build Coastguard Worker * The nwsi still has other subscribers bound to the
2316*1c60b9acSAndroid Build Coastguard Worker * topics.
2317*1c60b9acSAndroid Build Coastguard Worker *
2318*1c60b9acSAndroid Build Coastguard Worker * So, don't send UNSUB to server, and just fake the
2319*1c60b9acSAndroid Build Coastguard Worker * UNSUB ACK event for the guy going away.
2320*1c60b9acSAndroid Build Coastguard Worker */
2321*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: unsubscribed!\n", __func__);
2322*1c60b9acSAndroid Build Coastguard Worker if (user_callback_handle_rxflow(
2323*1c60b9acSAndroid Build Coastguard Worker wsi->a.protocol->callback,
2324*1c60b9acSAndroid Build Coastguard Worker wsi, LWS_CALLBACK_MQTT_UNSUBSCRIBED,
2325*1c60b9acSAndroid Build Coastguard Worker wsi->user_space, NULL, 0) < 0) {
2326*1c60b9acSAndroid Build Coastguard Worker /*
2327*1c60b9acSAndroid Build Coastguard Worker * We can't directly close here, because the
2328*1c60b9acSAndroid Build Coastguard Worker * caller still has the wsi. Inform the
2329*1c60b9acSAndroid Build Coastguard Worker * caller that we want to close
2330*1c60b9acSAndroid Build Coastguard Worker */
2331*1c60b9acSAndroid Build Coastguard Worker
2332*1c60b9acSAndroid Build Coastguard Worker return 1;
2333*1c60b9acSAndroid Build Coastguard Worker }
2334*1c60b9acSAndroid Build Coastguard Worker
2335*1c60b9acSAndroid Build Coastguard Worker return 0;
2336*1c60b9acSAndroid Build Coastguard Worker }
2337*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2338*1c60b9acSAndroid Build Coastguard Worker /*
2339*1c60b9acSAndroid Build Coastguard Worker * one or more of the topics needs to be unsubscribed
2340*1c60b9acSAndroid Build Coastguard Worker * from, so we must go to the server with a filtered
2341*1c60b9acSAndroid Build Coastguard Worker * list of the new ones only
2342*1c60b9acSAndroid Build Coastguard Worker */
2343*1c60b9acSAndroid Build Coastguard Worker
2344*1c60b9acSAndroid Build Coastguard Worker tops = orphaned;
2345*1c60b9acSAndroid Build Coastguard Worker #endif
2346*1c60b9acSAndroid Build Coastguard Worker
2347*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_fill_fixed_header(p++, LMQCP_CTOS_UNSUBSCRIBE,
2348*1c60b9acSAndroid Build Coastguard Worker 0, 0, 0)) {
2349*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Failed to fill fixed header\n", __func__);
2350*1c60b9acSAndroid Build Coastguard Worker return 1;
2351*1c60b9acSAndroid Build Coastguard Worker }
2352*1c60b9acSAndroid Build Coastguard Worker
2353*1c60b9acSAndroid Build Coastguard Worker /*
2354*1c60b9acSAndroid Build Coastguard Worker * Pid + (Topic len field + Topic len) x Num of Topics
2355*1c60b9acSAndroid Build Coastguard Worker */
2356*1c60b9acSAndroid Build Coastguard Worker rem_len = 2;
2357*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < unsub->num_topics; n++)
2358*1c60b9acSAndroid Build Coastguard Worker if (send_unsub[n])
2359*1c60b9acSAndroid Build Coastguard Worker rem_len += (2 + (uint32_t)strlen(unsub->topic[n].name));
2360*1c60b9acSAndroid Build Coastguard Worker
2361*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->sub_size = (uint16_t)rem_len;
2362*1c60b9acSAndroid Build Coastguard Worker
2363*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
2364*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: Number of topics = %d, Remaining len = %d\n",
2365*1c60b9acSAndroid Build Coastguard Worker __func__, (int)tops, (int)rem_len);
2366*1c60b9acSAndroid Build Coastguard Worker #endif
2367*1c60b9acSAndroid Build Coastguard Worker
2368*1c60b9acSAndroid Build Coastguard Worker p += lws_mqtt_vbi_encode(rem_len, p);
2369*1c60b9acSAndroid Build Coastguard Worker
2370*1c60b9acSAndroid Build Coastguard Worker if ((rem_len + lws_ptr_diff_size_t(p, start)) >=
2371*1c60b9acSAndroid Build Coastguard Worker wsi->a.context->pt_serv_buf_size) {
2372*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Payload is too big\n", __func__);
2373*1c60b9acSAndroid Build Coastguard Worker return 1;
2374*1c60b9acSAndroid Build Coastguard Worker }
2375*1c60b9acSAndroid Build Coastguard Worker
2376*1c60b9acSAndroid Build Coastguard Worker /* Init lws_mqtt_str */
2377*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_str_init(&mqtt_vh_payload, (uint8_t *)p, (uint16_t)rem_len, 0);
2378*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2379*1c60b9acSAndroid Build Coastguard Worker
2380*1c60b9acSAndroid Build Coastguard Worker /* Packet ID */
2381*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->ack_pkt_id = ++nwsi->mqtt->pkt_id;
2382*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: pkt_id = %d\n", __func__,
2383*1c60b9acSAndroid Build Coastguard Worker (int)wsi->mqtt->ack_pkt_id);
2384*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id);
2385*1c60b9acSAndroid Build Coastguard Worker
2386*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
2387*1c60b9acSAndroid Build Coastguard Worker return 1;
2388*1c60b9acSAndroid Build Coastguard Worker
2389*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2390*1c60b9acSAndroid Build Coastguard Worker
2391*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < unsub->num_topics; n++) {
2392*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: topics[%d] = %s\n", __func__,
2393*1c60b9acSAndroid Build Coastguard Worker (int)n, unsub->topic[n].name);
2394*1c60b9acSAndroid Build Coastguard Worker
2395*1c60b9acSAndroid Build Coastguard Worker /*
2396*1c60b9acSAndroid Build Coastguard Worker * Subscriber still bound to it, don't UBSUB
2397*1c60b9acSAndroid Build Coastguard Worker * from the server
2398*1c60b9acSAndroid Build Coastguard Worker */
2399*1c60b9acSAndroid Build Coastguard Worker if (!send_unsub[n])
2400*1c60b9acSAndroid Build Coastguard Worker continue;
2401*1c60b9acSAndroid Build Coastguard Worker
2402*1c60b9acSAndroid Build Coastguard Worker /* Topic's Len */
2403*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu16be(p, (uint16_t)strlen(unsub->topic[n].name));
2404*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload, 2))
2405*1c60b9acSAndroid Build Coastguard Worker return 1;
2406*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2407*1c60b9acSAndroid Build Coastguard Worker
2408*1c60b9acSAndroid Build Coastguard Worker /* Topic Name */
2409*1c60b9acSAndroid Build Coastguard Worker lws_strncpy((char *)p, unsub->topic[n].name,
2410*1c60b9acSAndroid Build Coastguard Worker strlen(unsub->topic[n].name) + 1);
2411*1c60b9acSAndroid Build Coastguard Worker if (lws_mqtt_str_advance(&mqtt_vh_payload,
2412*1c60b9acSAndroid Build Coastguard Worker (int)strlen(unsub->topic[n].name)))
2413*1c60b9acSAndroid Build Coastguard Worker return 1;
2414*1c60b9acSAndroid Build Coastguard Worker p = lws_mqtt_str_next(&mqtt_vh_payload, NULL);
2415*1c60b9acSAndroid Build Coastguard Worker }
2416*1c60b9acSAndroid Build Coastguard Worker break;
2417*1c60b9acSAndroid Build Coastguard Worker
2418*1c60b9acSAndroid Build Coastguard Worker default:
2419*1c60b9acSAndroid Build Coastguard Worker return 1;
2420*1c60b9acSAndroid Build Coastguard Worker }
2421*1c60b9acSAndroid Build Coastguard Worker
2422*1c60b9acSAndroid Build Coastguard Worker if (lws_write(nwsi, start, lws_ptr_diff_size_t(p, start), LWS_WRITE_BINARY) !=
2423*1c60b9acSAndroid Build Coastguard Worker lws_ptr_diff(p, start))
2424*1c60b9acSAndroid Build Coastguard Worker return 1;
2425*1c60b9acSAndroid Build Coastguard Worker
2426*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->inside_unsubscribe = 1;
2427*1c60b9acSAndroid Build Coastguard Worker
2428*1c60b9acSAndroid Build Coastguard Worker wsi->mqtt->sul_unsuback_wait.cb = lws_mqtt_unsuback_timeout;
2429*1c60b9acSAndroid Build Coastguard Worker __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend],
2430*1c60b9acSAndroid Build Coastguard Worker &wsi->mqtt->sul_unsuback_wait,
2431*1c60b9acSAndroid Build Coastguard Worker 3 * LWS_USEC_PER_SEC);
2432*1c60b9acSAndroid Build Coastguard Worker
2433*1c60b9acSAndroid Build Coastguard Worker return 0;
2434*1c60b9acSAndroid Build Coastguard Worker }
2435*1c60b9acSAndroid Build Coastguard Worker
2436*1c60b9acSAndroid Build Coastguard Worker /*
2437*1c60b9acSAndroid Build Coastguard Worker * This is called when child streams bind to an already-existing and compatible
2438*1c60b9acSAndroid Build Coastguard Worker * MQTT stream
2439*1c60b9acSAndroid Build Coastguard Worker */
2440*1c60b9acSAndroid Build Coastguard Worker
2441*1c60b9acSAndroid Build Coastguard Worker struct lws *
lws_wsi_mqtt_adopt(struct lws * parent_wsi,struct lws * wsi)2442*1c60b9acSAndroid Build Coastguard Worker lws_wsi_mqtt_adopt(struct lws *parent_wsi, struct lws *wsi)
2443*1c60b9acSAndroid Build Coastguard Worker {
2444*1c60b9acSAndroid Build Coastguard Worker /* no more children allowed by parent? */
2445*1c60b9acSAndroid Build Coastguard Worker
2446*1c60b9acSAndroid Build Coastguard Worker if (parent_wsi->mux.child_count + 1 > LWS_MQTT_MAX_CHILDREN) {
2447*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: reached concurrent stream limit\n", __func__);
2448*1c60b9acSAndroid Build Coastguard Worker return NULL;
2449*1c60b9acSAndroid Build Coastguard Worker }
2450*1c60b9acSAndroid Build Coastguard Worker
2451*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CLIENT)
2452*1c60b9acSAndroid Build Coastguard Worker wsi->client_mux_substream = 1;
2453*1c60b9acSAndroid Build Coastguard Worker #endif
2454*1c60b9acSAndroid Build Coastguard Worker
2455*1c60b9acSAndroid Build Coastguard Worker lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid);
2456*1c60b9acSAndroid Build Coastguard Worker
2457*1c60b9acSAndroid Build Coastguard Worker if (lws_ensure_user_space(wsi))
2458*1c60b9acSAndroid Build Coastguard Worker goto bail1;
2459*1c60b9acSAndroid Build Coastguard Worker
2460*1c60b9acSAndroid Build Coastguard Worker lws_mqtt_set_client_established(wsi);
2461*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
2462*1c60b9acSAndroid Build Coastguard Worker
2463*1c60b9acSAndroid Build Coastguard Worker return wsi;
2464*1c60b9acSAndroid Build Coastguard Worker
2465*1c60b9acSAndroid Build Coastguard Worker bail1:
2466*1c60b9acSAndroid Build Coastguard Worker /* undo the insert */
2467*1c60b9acSAndroid Build Coastguard Worker parent_wsi->mux.child_list = wsi->mux.sibling_list;
2468*1c60b9acSAndroid Build Coastguard Worker parent_wsi->mux.child_count--;
2469*1c60b9acSAndroid Build Coastguard Worker
2470*1c60b9acSAndroid Build Coastguard Worker if (wsi->user_space)
2471*1c60b9acSAndroid Build Coastguard Worker lws_free_set_NULL(wsi->user_space);
2472*1c60b9acSAndroid Build Coastguard Worker
2473*1c60b9acSAndroid Build Coastguard Worker wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);
2474*1c60b9acSAndroid Build Coastguard Worker lws_free(wsi);
2475*1c60b9acSAndroid Build Coastguard Worker
2476*1c60b9acSAndroid Build Coastguard Worker return NULL;
2477*1c60b9acSAndroid Build Coastguard Worker }
2478*1c60b9acSAndroid Build Coastguard Worker
2479