xref: /aosp_15_r20/external/curl/lib/mqtt.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Björn Stenberg, <[email protected]>
10*6236dae4SAndroid Build Coastguard Worker  *
11*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
12*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
13*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
14*6236dae4SAndroid Build Coastguard Worker  *
15*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
17*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
18*6236dae4SAndroid Build Coastguard Worker  *
19*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
21*6236dae4SAndroid Build Coastguard Worker  *
22*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
23*6236dae4SAndroid Build Coastguard Worker  *
24*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
25*6236dae4SAndroid Build Coastguard Worker 
26*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_MQTT
29*6236dae4SAndroid Build Coastguard Worker 
30*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
31*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
32*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
33*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
34*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
35*6236dae4SAndroid Build Coastguard Worker #include "mqtt.h"
36*6236dae4SAndroid Build Coastguard Worker #include "select.h"
37*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
38*6236dae4SAndroid Build Coastguard Worker #include "url.h"
39*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
40*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
41*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
42*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
43*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
44*6236dae4SAndroid Build Coastguard Worker #include "rand.h"
45*6236dae4SAndroid Build Coastguard Worker 
46*6236dae4SAndroid Build Coastguard Worker /* The last #include file should be: */
47*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_CONNECT   0x10
50*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_CONNACK   0x20
51*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_PUBLISH   0x30
52*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_SUBSCRIBE 0x82
53*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_SUBACK    0x90
54*6236dae4SAndroid Build Coastguard Worker #define MQTT_MSG_DISCONNECT 0xe0
55*6236dae4SAndroid Build Coastguard Worker 
56*6236dae4SAndroid Build Coastguard Worker #define MQTT_CONNACK_LEN 2
57*6236dae4SAndroid Build Coastguard Worker #define MQTT_SUBACK_LEN 3
58*6236dae4SAndroid Build Coastguard Worker #define MQTT_CLIENTID_LEN 12 /* "curl0123abcd" */
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker /*
61*6236dae4SAndroid Build Coastguard Worker  * Forward declarations.
62*6236dae4SAndroid Build Coastguard Worker  */
63*6236dae4SAndroid Build Coastguard Worker 
64*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
65*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_done(struct Curl_easy *data,
66*6236dae4SAndroid Build Coastguard Worker                           CURLcode status, bool premature);
67*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_doing(struct Curl_easy *data, bool *done);
68*6236dae4SAndroid Build Coastguard Worker static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn,
69*6236dae4SAndroid Build Coastguard Worker                         curl_socket_t *sock);
70*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_setup_conn(struct Curl_easy *data,
71*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn);
72*6236dae4SAndroid Build Coastguard Worker 
73*6236dae4SAndroid Build Coastguard Worker /*
74*6236dae4SAndroid Build Coastguard Worker  * MQTT protocol handler.
75*6236dae4SAndroid Build Coastguard Worker  */
76*6236dae4SAndroid Build Coastguard Worker 
77*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_mqtt = {
78*6236dae4SAndroid Build Coastguard Worker   "mqtt",                             /* scheme */
79*6236dae4SAndroid Build Coastguard Worker   mqtt_setup_conn,                    /* setup_connection */
80*6236dae4SAndroid Build Coastguard Worker   mqtt_do,                            /* do_it */
81*6236dae4SAndroid Build Coastguard Worker   mqtt_done,                          /* done */
82*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* do_more */
83*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* connect_it */
84*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* connecting */
85*6236dae4SAndroid Build Coastguard Worker   mqtt_doing,                         /* doing */
86*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* proto_getsock */
87*6236dae4SAndroid Build Coastguard Worker   mqtt_getsock,                       /* doing_getsock */
88*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* domore_getsock */
89*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* perform_getsock */
90*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* disconnect */
91*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* write_resp */
92*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* write_resp_hd */
93*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* connection_check */
94*6236dae4SAndroid Build Coastguard Worker   ZERO_NULL,                          /* attach connection */
95*6236dae4SAndroid Build Coastguard Worker   PORT_MQTT,                          /* defport */
96*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_MQTT,                     /* protocol */
97*6236dae4SAndroid Build Coastguard Worker   CURLPROTO_MQTT,                     /* family */
98*6236dae4SAndroid Build Coastguard Worker   PROTOPT_NONE                        /* flags */
99*6236dae4SAndroid Build Coastguard Worker };
100*6236dae4SAndroid Build Coastguard Worker 
mqtt_setup_conn(struct Curl_easy * data,struct connectdata * conn)101*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_setup_conn(struct Curl_easy *data,
102*6236dae4SAndroid Build Coastguard Worker                                 struct connectdata *conn)
103*6236dae4SAndroid Build Coastguard Worker {
104*6236dae4SAndroid Build Coastguard Worker   /* allocate the HTTP-specific struct for the Curl_easy, only to survive
105*6236dae4SAndroid Build Coastguard Worker      during this request */
106*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq;
107*6236dae4SAndroid Build Coastguard Worker   (void)conn;
108*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(data->req.p.mqtt == NULL);
109*6236dae4SAndroid Build Coastguard Worker 
110*6236dae4SAndroid Build Coastguard Worker   mq = calloc(1, sizeof(struct MQTT));
111*6236dae4SAndroid Build Coastguard Worker   if(!mq)
112*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
113*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV);
114*6236dae4SAndroid Build Coastguard Worker   data->req.p.mqtt = mq;
115*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
116*6236dae4SAndroid Build Coastguard Worker }
117*6236dae4SAndroid Build Coastguard Worker 
mqtt_send(struct Curl_easy * data,char * buf,size_t len)118*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_send(struct Curl_easy *data,
119*6236dae4SAndroid Build Coastguard Worker                           char *buf, size_t len)
120*6236dae4SAndroid Build Coastguard Worker {
121*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
122*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
123*6236dae4SAndroid Build Coastguard Worker   size_t n;
124*6236dae4SAndroid Build Coastguard Worker   result = Curl_xfer_send(data, buf, len, FALSE, &n);
125*6236dae4SAndroid Build Coastguard Worker   if(result)
126*6236dae4SAndroid Build Coastguard Worker     return result;
127*6236dae4SAndroid Build Coastguard Worker   Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
128*6236dae4SAndroid Build Coastguard Worker   if(len != n) {
129*6236dae4SAndroid Build Coastguard Worker     size_t nsend = len - n;
130*6236dae4SAndroid Build Coastguard Worker     char *sendleftovers = Curl_memdup(&buf[n], nsend);
131*6236dae4SAndroid Build Coastguard Worker     if(!sendleftovers)
132*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
133*6236dae4SAndroid Build Coastguard Worker     mq->sendleftovers = sendleftovers;
134*6236dae4SAndroid Build Coastguard Worker     mq->nsend = nsend;
135*6236dae4SAndroid Build Coastguard Worker   }
136*6236dae4SAndroid Build Coastguard Worker   else {
137*6236dae4SAndroid Build Coastguard Worker     mq->sendleftovers = NULL;
138*6236dae4SAndroid Build Coastguard Worker     mq->nsend = 0;
139*6236dae4SAndroid Build Coastguard Worker   }
140*6236dae4SAndroid Build Coastguard Worker   return result;
141*6236dae4SAndroid Build Coastguard Worker }
142*6236dae4SAndroid Build Coastguard Worker 
143*6236dae4SAndroid Build Coastguard Worker /* Generic function called by the multi interface to figure out what socket(s)
144*6236dae4SAndroid Build Coastguard Worker    to wait for and for what actions during the DOING and PROTOCONNECT
145*6236dae4SAndroid Build Coastguard Worker    states */
mqtt_getsock(struct Curl_easy * data,struct connectdata * conn,curl_socket_t * sock)146*6236dae4SAndroid Build Coastguard Worker static int mqtt_getsock(struct Curl_easy *data,
147*6236dae4SAndroid Build Coastguard Worker                         struct connectdata *conn,
148*6236dae4SAndroid Build Coastguard Worker                         curl_socket_t *sock)
149*6236dae4SAndroid Build Coastguard Worker {
150*6236dae4SAndroid Build Coastguard Worker   (void)data;
151*6236dae4SAndroid Build Coastguard Worker   sock[0] = conn->sock[FIRSTSOCKET];
152*6236dae4SAndroid Build Coastguard Worker   return GETSOCK_READSOCK(FIRSTSOCKET);
153*6236dae4SAndroid Build Coastguard Worker }
154*6236dae4SAndroid Build Coastguard Worker 
mqtt_encode_len(char * buf,size_t len)155*6236dae4SAndroid Build Coastguard Worker static int mqtt_encode_len(char *buf, size_t len)
156*6236dae4SAndroid Build Coastguard Worker {
157*6236dae4SAndroid Build Coastguard Worker   int i;
158*6236dae4SAndroid Build Coastguard Worker 
159*6236dae4SAndroid Build Coastguard Worker   for(i = 0; (len > 0) && (i < 4); i++) {
160*6236dae4SAndroid Build Coastguard Worker     unsigned char encoded;
161*6236dae4SAndroid Build Coastguard Worker     encoded = len % 0x80;
162*6236dae4SAndroid Build Coastguard Worker     len /= 0x80;
163*6236dae4SAndroid Build Coastguard Worker     if(len)
164*6236dae4SAndroid Build Coastguard Worker       encoded |= 0x80;
165*6236dae4SAndroid Build Coastguard Worker     buf[i] = (char)encoded;
166*6236dae4SAndroid Build Coastguard Worker   }
167*6236dae4SAndroid Build Coastguard Worker 
168*6236dae4SAndroid Build Coastguard Worker   return i;
169*6236dae4SAndroid Build Coastguard Worker }
170*6236dae4SAndroid Build Coastguard Worker 
171*6236dae4SAndroid Build Coastguard Worker /* add the passwd to the CONNECT packet */
add_passwd(const char * passwd,const size_t plen,char * pkt,const size_t start,int remain_pos)172*6236dae4SAndroid Build Coastguard Worker static int add_passwd(const char *passwd, const size_t plen,
173*6236dae4SAndroid Build Coastguard Worker                        char *pkt, const size_t start, int remain_pos)
174*6236dae4SAndroid Build Coastguard Worker {
175*6236dae4SAndroid Build Coastguard Worker   /* magic number that need to be set properly */
176*6236dae4SAndroid Build Coastguard Worker   const size_t conn_flags_pos = remain_pos + 8;
177*6236dae4SAndroid Build Coastguard Worker   if(plen > 0xffff)
178*6236dae4SAndroid Build Coastguard Worker     return 1;
179*6236dae4SAndroid Build Coastguard Worker 
180*6236dae4SAndroid Build Coastguard Worker   /* set password flag */
181*6236dae4SAndroid Build Coastguard Worker   pkt[conn_flags_pos] |= 0x40;
182*6236dae4SAndroid Build Coastguard Worker 
183*6236dae4SAndroid Build Coastguard Worker   /* length of password provided */
184*6236dae4SAndroid Build Coastguard Worker   pkt[start] = (char)((plen >> 8) & 0xFF);
185*6236dae4SAndroid Build Coastguard Worker   pkt[start + 1] = (char)(plen & 0xFF);
186*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[start + 2], passwd, plen);
187*6236dae4SAndroid Build Coastguard Worker   return 0;
188*6236dae4SAndroid Build Coastguard Worker }
189*6236dae4SAndroid Build Coastguard Worker 
190*6236dae4SAndroid Build Coastguard Worker /* add user to the CONNECT packet */
add_user(const char * username,const size_t ulen,unsigned char * pkt,const size_t start,int remain_pos)191*6236dae4SAndroid Build Coastguard Worker static int add_user(const char *username, const size_t ulen,
192*6236dae4SAndroid Build Coastguard Worker                     unsigned char *pkt, const size_t start, int remain_pos)
193*6236dae4SAndroid Build Coastguard Worker {
194*6236dae4SAndroid Build Coastguard Worker   /* magic number that need to be set properly */
195*6236dae4SAndroid Build Coastguard Worker   const size_t conn_flags_pos = remain_pos + 8;
196*6236dae4SAndroid Build Coastguard Worker   if(ulen > 0xffff)
197*6236dae4SAndroid Build Coastguard Worker     return 1;
198*6236dae4SAndroid Build Coastguard Worker 
199*6236dae4SAndroid Build Coastguard Worker   /* set username flag */
200*6236dae4SAndroid Build Coastguard Worker   pkt[conn_flags_pos] |= 0x80;
201*6236dae4SAndroid Build Coastguard Worker   /* length of username provided */
202*6236dae4SAndroid Build Coastguard Worker   pkt[start] = (unsigned char)((ulen >> 8) & 0xFF);
203*6236dae4SAndroid Build Coastguard Worker   pkt[start + 1] = (unsigned char)(ulen & 0xFF);
204*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[start + 2], username, ulen);
205*6236dae4SAndroid Build Coastguard Worker   return 0;
206*6236dae4SAndroid Build Coastguard Worker }
207*6236dae4SAndroid Build Coastguard Worker 
208*6236dae4SAndroid Build Coastguard Worker /* add client ID to the CONNECT packet */
add_client_id(const char * client_id,const size_t client_id_len,char * pkt,const size_t start)209*6236dae4SAndroid Build Coastguard Worker static int add_client_id(const char *client_id, const size_t client_id_len,
210*6236dae4SAndroid Build Coastguard Worker                          char *pkt, const size_t start)
211*6236dae4SAndroid Build Coastguard Worker {
212*6236dae4SAndroid Build Coastguard Worker   if(client_id_len != MQTT_CLIENTID_LEN)
213*6236dae4SAndroid Build Coastguard Worker     return 1;
214*6236dae4SAndroid Build Coastguard Worker   pkt[start] = 0x00;
215*6236dae4SAndroid Build Coastguard Worker   pkt[start + 1] = MQTT_CLIENTID_LEN;
216*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN);
217*6236dae4SAndroid Build Coastguard Worker   return 0;
218*6236dae4SAndroid Build Coastguard Worker }
219*6236dae4SAndroid Build Coastguard Worker 
220*6236dae4SAndroid Build Coastguard Worker /* Set initial values of CONNECT packet */
init_connpack(char * packet,char * remain,int remain_pos)221*6236dae4SAndroid Build Coastguard Worker static int init_connpack(char *packet, char *remain, int remain_pos)
222*6236dae4SAndroid Build Coastguard Worker {
223*6236dae4SAndroid Build Coastguard Worker   /* Fixed header starts */
224*6236dae4SAndroid Build Coastguard Worker   /* packet type */
225*6236dae4SAndroid Build Coastguard Worker   packet[0] = MQTT_MSG_CONNECT;
226*6236dae4SAndroid Build Coastguard Worker   /* remaining length field */
227*6236dae4SAndroid Build Coastguard Worker   memcpy(&packet[1], remain, remain_pos);
228*6236dae4SAndroid Build Coastguard Worker   /* Fixed header ends */
229*6236dae4SAndroid Build Coastguard Worker 
230*6236dae4SAndroid Build Coastguard Worker   /* Variable header starts */
231*6236dae4SAndroid Build Coastguard Worker   /* protocol length */
232*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 1] = 0x00;
233*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 2] = 0x04;
234*6236dae4SAndroid Build Coastguard Worker   /* protocol name */
235*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 3] = 'M';
236*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 4] = 'Q';
237*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 5] = 'T';
238*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 6] = 'T';
239*6236dae4SAndroid Build Coastguard Worker   /* protocol level */
240*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 7] = 0x04;
241*6236dae4SAndroid Build Coastguard Worker   /* CONNECT flag: CleanSession */
242*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 8] = 0x02;
243*6236dae4SAndroid Build Coastguard Worker   /* keep-alive 0 = disabled */
244*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 9] = 0x00;
245*6236dae4SAndroid Build Coastguard Worker   packet[remain_pos + 10] = 0x3c;
246*6236dae4SAndroid Build Coastguard Worker   /* end of variable header */
247*6236dae4SAndroid Build Coastguard Worker   return remain_pos + 10;
248*6236dae4SAndroid Build Coastguard Worker }
249*6236dae4SAndroid Build Coastguard Worker 
mqtt_connect(struct Curl_easy * data)250*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_connect(struct Curl_easy *data)
251*6236dae4SAndroid Build Coastguard Worker {
252*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
253*6236dae4SAndroid Build Coastguard Worker   int pos = 0;
254*6236dae4SAndroid Build Coastguard Worker   int rc = 0;
255*6236dae4SAndroid Build Coastguard Worker   /* remain length */
256*6236dae4SAndroid Build Coastguard Worker   int remain_pos = 0;
257*6236dae4SAndroid Build Coastguard Worker   char remain[4] = {0};
258*6236dae4SAndroid Build Coastguard Worker   size_t packetlen = 0;
259*6236dae4SAndroid Build Coastguard Worker   size_t payloadlen = 0;
260*6236dae4SAndroid Build Coastguard Worker   size_t start_user = 0;
261*6236dae4SAndroid Build Coastguard Worker   size_t start_pwd = 0;
262*6236dae4SAndroid Build Coastguard Worker   char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
263*6236dae4SAndroid Build Coastguard Worker   const size_t clen = strlen("curl");
264*6236dae4SAndroid Build Coastguard Worker   char *packet = NULL;
265*6236dae4SAndroid Build Coastguard Worker 
266*6236dae4SAndroid Build Coastguard Worker   /* extracting username from request */
267*6236dae4SAndroid Build Coastguard Worker   const char *username = data->state.aptr.user ?
268*6236dae4SAndroid Build Coastguard Worker     data->state.aptr.user : "";
269*6236dae4SAndroid Build Coastguard Worker   const size_t ulen = strlen(username);
270*6236dae4SAndroid Build Coastguard Worker   /* extracting password from request */
271*6236dae4SAndroid Build Coastguard Worker   const char *passwd = data->state.aptr.passwd ?
272*6236dae4SAndroid Build Coastguard Worker     data->state.aptr.passwd : "";
273*6236dae4SAndroid Build Coastguard Worker   const size_t plen = strlen(passwd);
274*6236dae4SAndroid Build Coastguard Worker 
275*6236dae4SAndroid Build Coastguard Worker   payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
276*6236dae4SAndroid Build Coastguard Worker   /* The plus 2 are for the MSB and LSB describing the length of the string to
277*6236dae4SAndroid Build Coastguard Worker    * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
278*6236dae4SAndroid Build Coastguard Worker   if(ulen)
279*6236dae4SAndroid Build Coastguard Worker     payloadlen += 2;
280*6236dae4SAndroid Build Coastguard Worker   if(plen)
281*6236dae4SAndroid Build Coastguard Worker     payloadlen += 2;
282*6236dae4SAndroid Build Coastguard Worker 
283*6236dae4SAndroid Build Coastguard Worker   /* getting how much occupy the remain length */
284*6236dae4SAndroid Build Coastguard Worker   remain_pos = mqtt_encode_len(remain, payloadlen + 10);
285*6236dae4SAndroid Build Coastguard Worker 
286*6236dae4SAndroid Build Coastguard Worker   /* 10 length of variable header and 1 the first byte of the fixed header */
287*6236dae4SAndroid Build Coastguard Worker   packetlen = payloadlen + 10 + remain_pos + 1;
288*6236dae4SAndroid Build Coastguard Worker 
289*6236dae4SAndroid Build Coastguard Worker   /* allocating packet */
290*6236dae4SAndroid Build Coastguard Worker   if(packetlen > 268435455)
291*6236dae4SAndroid Build Coastguard Worker     return CURLE_WEIRD_SERVER_REPLY;
292*6236dae4SAndroid Build Coastguard Worker   packet = malloc(packetlen);
293*6236dae4SAndroid Build Coastguard Worker   if(!packet)
294*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
295*6236dae4SAndroid Build Coastguard Worker   memset(packet, 0, packetlen);
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker   /* set initial values for the CONNECT packet */
298*6236dae4SAndroid Build Coastguard Worker   pos = init_connpack(packet, remain, remain_pos);
299*6236dae4SAndroid Build Coastguard Worker 
300*6236dae4SAndroid Build Coastguard Worker   result = Curl_rand_alnum(data, (unsigned char *)&client_id[clen],
301*6236dae4SAndroid Build Coastguard Worker                            MQTT_CLIENTID_LEN - clen + 1);
302*6236dae4SAndroid Build Coastguard Worker   /* add client id */
303*6236dae4SAndroid Build Coastguard Worker   rc = add_client_id(client_id, strlen(client_id), packet, pos + 1);
304*6236dae4SAndroid Build Coastguard Worker   if(rc) {
305*6236dae4SAndroid Build Coastguard Worker     failf(data, "Client ID length mismatched: [%zu]", strlen(client_id));
306*6236dae4SAndroid Build Coastguard Worker     result = CURLE_WEIRD_SERVER_REPLY;
307*6236dae4SAndroid Build Coastguard Worker     goto end;
308*6236dae4SAndroid Build Coastguard Worker   }
309*6236dae4SAndroid Build Coastguard Worker   infof(data, "Using client id '%s'", client_id);
310*6236dae4SAndroid Build Coastguard Worker 
311*6236dae4SAndroid Build Coastguard Worker   /* position where starts the user payload */
312*6236dae4SAndroid Build Coastguard Worker   start_user = pos + 3 + MQTT_CLIENTID_LEN;
313*6236dae4SAndroid Build Coastguard Worker   /* position where starts the password payload */
314*6236dae4SAndroid Build Coastguard Worker   start_pwd = start_user + ulen;
315*6236dae4SAndroid Build Coastguard Worker   /* if username was provided, add it to the packet */
316*6236dae4SAndroid Build Coastguard Worker   if(ulen) {
317*6236dae4SAndroid Build Coastguard Worker     start_pwd += 2;
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker     rc = add_user(username, ulen,
320*6236dae4SAndroid Build Coastguard Worker                   (unsigned char *)packet, start_user, remain_pos);
321*6236dae4SAndroid Build Coastguard Worker     if(rc) {
322*6236dae4SAndroid Build Coastguard Worker       failf(data, "Username is too large: [%zu]", ulen);
323*6236dae4SAndroid Build Coastguard Worker       result = CURLE_WEIRD_SERVER_REPLY;
324*6236dae4SAndroid Build Coastguard Worker       goto end;
325*6236dae4SAndroid Build Coastguard Worker     }
326*6236dae4SAndroid Build Coastguard Worker   }
327*6236dae4SAndroid Build Coastguard Worker 
328*6236dae4SAndroid Build Coastguard Worker   /* if passwd was provided, add it to the packet */
329*6236dae4SAndroid Build Coastguard Worker   if(plen) {
330*6236dae4SAndroid Build Coastguard Worker     rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
331*6236dae4SAndroid Build Coastguard Worker     if(rc) {
332*6236dae4SAndroid Build Coastguard Worker       failf(data, "Password is too large: [%zu]", plen);
333*6236dae4SAndroid Build Coastguard Worker       result = CURLE_WEIRD_SERVER_REPLY;
334*6236dae4SAndroid Build Coastguard Worker       goto end;
335*6236dae4SAndroid Build Coastguard Worker     }
336*6236dae4SAndroid Build Coastguard Worker   }
337*6236dae4SAndroid Build Coastguard Worker 
338*6236dae4SAndroid Build Coastguard Worker   if(!result)
339*6236dae4SAndroid Build Coastguard Worker     result = mqtt_send(data, packet, packetlen);
340*6236dae4SAndroid Build Coastguard Worker 
341*6236dae4SAndroid Build Coastguard Worker end:
342*6236dae4SAndroid Build Coastguard Worker   if(packet)
343*6236dae4SAndroid Build Coastguard Worker     free(packet);
344*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(data->state.aptr.user);
345*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(data->state.aptr.passwd);
346*6236dae4SAndroid Build Coastguard Worker   return result;
347*6236dae4SAndroid Build Coastguard Worker }
348*6236dae4SAndroid Build Coastguard Worker 
mqtt_disconnect(struct Curl_easy * data)349*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_disconnect(struct Curl_easy *data)
350*6236dae4SAndroid Build Coastguard Worker {
351*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
352*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
353*6236dae4SAndroid Build Coastguard Worker   result = mqtt_send(data, (char *)"\xe0\x00", 2);
354*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(mq->sendleftovers);
355*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&mq->recvbuf);
356*6236dae4SAndroid Build Coastguard Worker   return result;
357*6236dae4SAndroid Build Coastguard Worker }
358*6236dae4SAndroid Build Coastguard Worker 
mqtt_recv_atleast(struct Curl_easy * data,size_t nbytes)359*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes)
360*6236dae4SAndroid Build Coastguard Worker {
361*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
362*6236dae4SAndroid Build Coastguard Worker   size_t rlen = Curl_dyn_len(&mq->recvbuf);
363*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
364*6236dae4SAndroid Build Coastguard Worker 
365*6236dae4SAndroid Build Coastguard Worker   if(rlen < nbytes) {
366*6236dae4SAndroid Build Coastguard Worker     unsigned char readbuf[1024];
367*6236dae4SAndroid Build Coastguard Worker     ssize_t nread;
368*6236dae4SAndroid Build Coastguard Worker 
369*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
370*6236dae4SAndroid Build Coastguard Worker     result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
371*6236dae4SAndroid Build Coastguard Worker     if(result)
372*6236dae4SAndroid Build Coastguard Worker       return result;
373*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(nread >= 0);
374*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread))
375*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
376*6236dae4SAndroid Build Coastguard Worker     rlen = Curl_dyn_len(&mq->recvbuf);
377*6236dae4SAndroid Build Coastguard Worker   }
378*6236dae4SAndroid Build Coastguard Worker   return (rlen >= nbytes) ? CURLE_OK : CURLE_AGAIN;
379*6236dae4SAndroid Build Coastguard Worker }
380*6236dae4SAndroid Build Coastguard Worker 
mqtt_recv_consume(struct Curl_easy * data,size_t nbytes)381*6236dae4SAndroid Build Coastguard Worker static void mqtt_recv_consume(struct Curl_easy *data, size_t nbytes)
382*6236dae4SAndroid Build Coastguard Worker {
383*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
384*6236dae4SAndroid Build Coastguard Worker   size_t rlen = Curl_dyn_len(&mq->recvbuf);
385*6236dae4SAndroid Build Coastguard Worker   if(rlen <= nbytes)
386*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_reset(&mq->recvbuf);
387*6236dae4SAndroid Build Coastguard Worker   else
388*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_tail(&mq->recvbuf, rlen - nbytes);
389*6236dae4SAndroid Build Coastguard Worker }
390*6236dae4SAndroid Build Coastguard Worker 
mqtt_verify_connack(struct Curl_easy * data)391*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_verify_connack(struct Curl_easy *data)
392*6236dae4SAndroid Build Coastguard Worker {
393*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
394*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
395*6236dae4SAndroid Build Coastguard Worker   char *ptr;
396*6236dae4SAndroid Build Coastguard Worker 
397*6236dae4SAndroid Build Coastguard Worker   result = mqtt_recv_atleast(data, MQTT_CONNACK_LEN);
398*6236dae4SAndroid Build Coastguard Worker   if(result)
399*6236dae4SAndroid Build Coastguard Worker     goto fail;
400*6236dae4SAndroid Build Coastguard Worker 
401*6236dae4SAndroid Build Coastguard Worker   /* verify CONNACK */
402*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_CONNACK_LEN);
403*6236dae4SAndroid Build Coastguard Worker   ptr = Curl_dyn_ptr(&mq->recvbuf);
404*6236dae4SAndroid Build Coastguard Worker   Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_CONNACK_LEN);
405*6236dae4SAndroid Build Coastguard Worker 
406*6236dae4SAndroid Build Coastguard Worker   if(ptr[0] != 0x00 || ptr[1] != 0x00) {
407*6236dae4SAndroid Build Coastguard Worker     failf(data, "Expected %02x%02x but got %02x%02x",
408*6236dae4SAndroid Build Coastguard Worker           0x00, 0x00, ptr[0], ptr[1]);
409*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_reset(&mq->recvbuf);
410*6236dae4SAndroid Build Coastguard Worker     result = CURLE_WEIRD_SERVER_REPLY;
411*6236dae4SAndroid Build Coastguard Worker     goto fail;
412*6236dae4SAndroid Build Coastguard Worker   }
413*6236dae4SAndroid Build Coastguard Worker   mqtt_recv_consume(data, MQTT_CONNACK_LEN);
414*6236dae4SAndroid Build Coastguard Worker fail:
415*6236dae4SAndroid Build Coastguard Worker   return result;
416*6236dae4SAndroid Build Coastguard Worker }
417*6236dae4SAndroid Build Coastguard Worker 
mqtt_get_topic(struct Curl_easy * data,char ** topic,size_t * topiclen)418*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_get_topic(struct Curl_easy *data,
419*6236dae4SAndroid Build Coastguard Worker                                char **topic, size_t *topiclen)
420*6236dae4SAndroid Build Coastguard Worker {
421*6236dae4SAndroid Build Coastguard Worker   char *path = data->state.up.path;
422*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_URL_MALFORMAT;
423*6236dae4SAndroid Build Coastguard Worker   if(strlen(path) > 1) {
424*6236dae4SAndroid Build Coastguard Worker     result = Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA);
425*6236dae4SAndroid Build Coastguard Worker     if(!result && (*topiclen > 0xffff)) {
426*6236dae4SAndroid Build Coastguard Worker       failf(data, "Too long MQTT topic");
427*6236dae4SAndroid Build Coastguard Worker       result = CURLE_URL_MALFORMAT;
428*6236dae4SAndroid Build Coastguard Worker     }
429*6236dae4SAndroid Build Coastguard Worker   }
430*6236dae4SAndroid Build Coastguard Worker   else
431*6236dae4SAndroid Build Coastguard Worker     failf(data, "No MQTT topic found. Forgot to URL encode it?");
432*6236dae4SAndroid Build Coastguard Worker 
433*6236dae4SAndroid Build Coastguard Worker   return result;
434*6236dae4SAndroid Build Coastguard Worker }
435*6236dae4SAndroid Build Coastguard Worker 
mqtt_subscribe(struct Curl_easy * data)436*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_subscribe(struct Curl_easy *data)
437*6236dae4SAndroid Build Coastguard Worker {
438*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
439*6236dae4SAndroid Build Coastguard Worker   char *topic = NULL;
440*6236dae4SAndroid Build Coastguard Worker   size_t topiclen;
441*6236dae4SAndroid Build Coastguard Worker   unsigned char *packet = NULL;
442*6236dae4SAndroid Build Coastguard Worker   size_t packetlen;
443*6236dae4SAndroid Build Coastguard Worker   char encodedsize[4];
444*6236dae4SAndroid Build Coastguard Worker   size_t n;
445*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
446*6236dae4SAndroid Build Coastguard Worker 
447*6236dae4SAndroid Build Coastguard Worker   result = mqtt_get_topic(data, &topic, &topiclen);
448*6236dae4SAndroid Build Coastguard Worker   if(result)
449*6236dae4SAndroid Build Coastguard Worker     goto fail;
450*6236dae4SAndroid Build Coastguard Worker 
451*6236dae4SAndroid Build Coastguard Worker   conn->proto.mqtt.packetid++;
452*6236dae4SAndroid Build Coastguard Worker 
453*6236dae4SAndroid Build Coastguard Worker   packetlen = topiclen + 5; /* packetid + topic (has a two byte length field)
454*6236dae4SAndroid Build Coastguard Worker                                + 2 bytes topic length + QoS byte */
455*6236dae4SAndroid Build Coastguard Worker   n = mqtt_encode_len((char *)encodedsize, packetlen);
456*6236dae4SAndroid Build Coastguard Worker   packetlen += n + 1; /* add one for the control packet type byte */
457*6236dae4SAndroid Build Coastguard Worker 
458*6236dae4SAndroid Build Coastguard Worker   packet = malloc(packetlen);
459*6236dae4SAndroid Build Coastguard Worker   if(!packet) {
460*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
461*6236dae4SAndroid Build Coastguard Worker     goto fail;
462*6236dae4SAndroid Build Coastguard Worker   }
463*6236dae4SAndroid Build Coastguard Worker 
464*6236dae4SAndroid Build Coastguard Worker   packet[0] = MQTT_MSG_SUBSCRIBE;
465*6236dae4SAndroid Build Coastguard Worker   memcpy(&packet[1], encodedsize, n);
466*6236dae4SAndroid Build Coastguard Worker   packet[1 + n] = (conn->proto.mqtt.packetid >> 8) & 0xff;
467*6236dae4SAndroid Build Coastguard Worker   packet[2 + n] = conn->proto.mqtt.packetid & 0xff;
468*6236dae4SAndroid Build Coastguard Worker   packet[3 + n] = (topiclen >> 8) & 0xff;
469*6236dae4SAndroid Build Coastguard Worker   packet[4 + n ] = topiclen & 0xff;
470*6236dae4SAndroid Build Coastguard Worker   memcpy(&packet[5 + n], topic, topiclen);
471*6236dae4SAndroid Build Coastguard Worker   packet[5 + n + topiclen] = 0; /* QoS zero */
472*6236dae4SAndroid Build Coastguard Worker 
473*6236dae4SAndroid Build Coastguard Worker   result = mqtt_send(data, (char *)packet, packetlen);
474*6236dae4SAndroid Build Coastguard Worker 
475*6236dae4SAndroid Build Coastguard Worker fail:
476*6236dae4SAndroid Build Coastguard Worker   free(topic);
477*6236dae4SAndroid Build Coastguard Worker   free(packet);
478*6236dae4SAndroid Build Coastguard Worker   return result;
479*6236dae4SAndroid Build Coastguard Worker }
480*6236dae4SAndroid Build Coastguard Worker 
481*6236dae4SAndroid Build Coastguard Worker /*
482*6236dae4SAndroid Build Coastguard Worker  * Called when the first byte was already read.
483*6236dae4SAndroid Build Coastguard Worker  */
mqtt_verify_suback(struct Curl_easy * data)484*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_verify_suback(struct Curl_easy *data)
485*6236dae4SAndroid Build Coastguard Worker {
486*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
487*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
488*6236dae4SAndroid Build Coastguard Worker   struct mqtt_conn *mqtt = &conn->proto.mqtt;
489*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
490*6236dae4SAndroid Build Coastguard Worker   char *ptr;
491*6236dae4SAndroid Build Coastguard Worker 
492*6236dae4SAndroid Build Coastguard Worker   result = mqtt_recv_atleast(data, MQTT_SUBACK_LEN);
493*6236dae4SAndroid Build Coastguard Worker   if(result)
494*6236dae4SAndroid Build Coastguard Worker     goto fail;
495*6236dae4SAndroid Build Coastguard Worker 
496*6236dae4SAndroid Build Coastguard Worker   /* verify SUBACK */
497*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(Curl_dyn_len(&mq->recvbuf) >= MQTT_SUBACK_LEN);
498*6236dae4SAndroid Build Coastguard Worker   ptr = Curl_dyn_ptr(&mq->recvbuf);
499*6236dae4SAndroid Build Coastguard Worker   Curl_debug(data, CURLINFO_HEADER_IN, ptr, MQTT_SUBACK_LEN);
500*6236dae4SAndroid Build Coastguard Worker 
501*6236dae4SAndroid Build Coastguard Worker   if(((unsigned char)ptr[0]) != ((mqtt->packetid >> 8) & 0xff) ||
502*6236dae4SAndroid Build Coastguard Worker      ((unsigned char)ptr[1]) != (mqtt->packetid & 0xff) ||
503*6236dae4SAndroid Build Coastguard Worker      ptr[2] != 0x00) {
504*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_reset(&mq->recvbuf);
505*6236dae4SAndroid Build Coastguard Worker     result = CURLE_WEIRD_SERVER_REPLY;
506*6236dae4SAndroid Build Coastguard Worker     goto fail;
507*6236dae4SAndroid Build Coastguard Worker   }
508*6236dae4SAndroid Build Coastguard Worker   mqtt_recv_consume(data, MQTT_SUBACK_LEN);
509*6236dae4SAndroid Build Coastguard Worker fail:
510*6236dae4SAndroid Build Coastguard Worker   return result;
511*6236dae4SAndroid Build Coastguard Worker }
512*6236dae4SAndroid Build Coastguard Worker 
mqtt_publish(struct Curl_easy * data)513*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_publish(struct Curl_easy *data)
514*6236dae4SAndroid Build Coastguard Worker {
515*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
516*6236dae4SAndroid Build Coastguard Worker   char *payload = data->set.postfields;
517*6236dae4SAndroid Build Coastguard Worker   size_t payloadlen;
518*6236dae4SAndroid Build Coastguard Worker   char *topic = NULL;
519*6236dae4SAndroid Build Coastguard Worker   size_t topiclen;
520*6236dae4SAndroid Build Coastguard Worker   unsigned char *pkt = NULL;
521*6236dae4SAndroid Build Coastguard Worker   size_t i = 0;
522*6236dae4SAndroid Build Coastguard Worker   size_t remaininglength;
523*6236dae4SAndroid Build Coastguard Worker   size_t encodelen;
524*6236dae4SAndroid Build Coastguard Worker   char encodedbytes[4];
525*6236dae4SAndroid Build Coastguard Worker   curl_off_t postfieldsize = data->set.postfieldsize;
526*6236dae4SAndroid Build Coastguard Worker 
527*6236dae4SAndroid Build Coastguard Worker   if(!payload) {
528*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(data, "mqtt_publish without payload, return bad arg"));
529*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_FUNCTION_ARGUMENT;
530*6236dae4SAndroid Build Coastguard Worker   }
531*6236dae4SAndroid Build Coastguard Worker   if(postfieldsize < 0)
532*6236dae4SAndroid Build Coastguard Worker     payloadlen = strlen(payload);
533*6236dae4SAndroid Build Coastguard Worker   else
534*6236dae4SAndroid Build Coastguard Worker     payloadlen = (size_t)postfieldsize;
535*6236dae4SAndroid Build Coastguard Worker 
536*6236dae4SAndroid Build Coastguard Worker   result = mqtt_get_topic(data, &topic, &topiclen);
537*6236dae4SAndroid Build Coastguard Worker   if(result)
538*6236dae4SAndroid Build Coastguard Worker     goto fail;
539*6236dae4SAndroid Build Coastguard Worker 
540*6236dae4SAndroid Build Coastguard Worker   remaininglength = payloadlen + 2 + topiclen;
541*6236dae4SAndroid Build Coastguard Worker   encodelen = mqtt_encode_len(encodedbytes, remaininglength);
542*6236dae4SAndroid Build Coastguard Worker 
543*6236dae4SAndroid Build Coastguard Worker   /* add the control byte and the encoded remaining length */
544*6236dae4SAndroid Build Coastguard Worker   pkt = malloc(remaininglength + 1 + encodelen);
545*6236dae4SAndroid Build Coastguard Worker   if(!pkt) {
546*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
547*6236dae4SAndroid Build Coastguard Worker     goto fail;
548*6236dae4SAndroid Build Coastguard Worker   }
549*6236dae4SAndroid Build Coastguard Worker 
550*6236dae4SAndroid Build Coastguard Worker   /* assemble packet */
551*6236dae4SAndroid Build Coastguard Worker   pkt[i++] = MQTT_MSG_PUBLISH;
552*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[i], encodedbytes, encodelen);
553*6236dae4SAndroid Build Coastguard Worker   i += encodelen;
554*6236dae4SAndroid Build Coastguard Worker   pkt[i++] = (topiclen >> 8) & 0xff;
555*6236dae4SAndroid Build Coastguard Worker   pkt[i++] = (topiclen & 0xff);
556*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[i], topic, topiclen);
557*6236dae4SAndroid Build Coastguard Worker   i += topiclen;
558*6236dae4SAndroid Build Coastguard Worker   memcpy(&pkt[i], payload, payloadlen);
559*6236dae4SAndroid Build Coastguard Worker   i += payloadlen;
560*6236dae4SAndroid Build Coastguard Worker   result = mqtt_send(data, (char *)pkt, i);
561*6236dae4SAndroid Build Coastguard Worker 
562*6236dae4SAndroid Build Coastguard Worker fail:
563*6236dae4SAndroid Build Coastguard Worker   free(pkt);
564*6236dae4SAndroid Build Coastguard Worker   free(topic);
565*6236dae4SAndroid Build Coastguard Worker   return result;
566*6236dae4SAndroid Build Coastguard Worker }
567*6236dae4SAndroid Build Coastguard Worker 
mqtt_decode_len(unsigned char * buf,size_t buflen,size_t * lenbytes)568*6236dae4SAndroid Build Coastguard Worker static size_t mqtt_decode_len(unsigned char *buf,
569*6236dae4SAndroid Build Coastguard Worker                               size_t buflen, size_t *lenbytes)
570*6236dae4SAndroid Build Coastguard Worker {
571*6236dae4SAndroid Build Coastguard Worker   size_t len = 0;
572*6236dae4SAndroid Build Coastguard Worker   size_t mult = 1;
573*6236dae4SAndroid Build Coastguard Worker   size_t i;
574*6236dae4SAndroid Build Coastguard Worker   unsigned char encoded = 128;
575*6236dae4SAndroid Build Coastguard Worker 
576*6236dae4SAndroid Build Coastguard Worker   for(i = 0; (i < buflen) && (encoded & 128); i++) {
577*6236dae4SAndroid Build Coastguard Worker     encoded = buf[i];
578*6236dae4SAndroid Build Coastguard Worker     len += (encoded & 127) * mult;
579*6236dae4SAndroid Build Coastguard Worker     mult *= 128;
580*6236dae4SAndroid Build Coastguard Worker   }
581*6236dae4SAndroid Build Coastguard Worker 
582*6236dae4SAndroid Build Coastguard Worker   if(lenbytes)
583*6236dae4SAndroid Build Coastguard Worker     *lenbytes = i;
584*6236dae4SAndroid Build Coastguard Worker 
585*6236dae4SAndroid Build Coastguard Worker   return len;
586*6236dae4SAndroid Build Coastguard Worker }
587*6236dae4SAndroid Build Coastguard Worker 
588*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
589*6236dae4SAndroid Build Coastguard Worker static const char *statenames[]={
590*6236dae4SAndroid Build Coastguard Worker   "MQTT_FIRST",
591*6236dae4SAndroid Build Coastguard Worker   "MQTT_REMAINING_LENGTH",
592*6236dae4SAndroid Build Coastguard Worker   "MQTT_CONNACK",
593*6236dae4SAndroid Build Coastguard Worker   "MQTT_SUBACK",
594*6236dae4SAndroid Build Coastguard Worker   "MQTT_SUBACK_COMING",
595*6236dae4SAndroid Build Coastguard Worker   "MQTT_PUBWAIT",
596*6236dae4SAndroid Build Coastguard Worker   "MQTT_PUB_REMAIN",
597*6236dae4SAndroid Build Coastguard Worker 
598*6236dae4SAndroid Build Coastguard Worker   "NOT A STATE"
599*6236dae4SAndroid Build Coastguard Worker };
600*6236dae4SAndroid Build Coastguard Worker #endif
601*6236dae4SAndroid Build Coastguard Worker 
602*6236dae4SAndroid Build Coastguard Worker /* The only way to change state */
mqstate(struct Curl_easy * data,enum mqttstate state,enum mqttstate nextstate)603*6236dae4SAndroid Build Coastguard Worker static void mqstate(struct Curl_easy *data,
604*6236dae4SAndroid Build Coastguard Worker                     enum mqttstate state,
605*6236dae4SAndroid Build Coastguard Worker                     enum mqttstate nextstate) /* used if state == FIRST */
606*6236dae4SAndroid Build Coastguard Worker {
607*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
608*6236dae4SAndroid Build Coastguard Worker   struct mqtt_conn *mqtt = &conn->proto.mqtt;
609*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
610*6236dae4SAndroid Build Coastguard Worker   infof(data, "%s (from %s) (next is %s)",
611*6236dae4SAndroid Build Coastguard Worker         statenames[state],
612*6236dae4SAndroid Build Coastguard Worker         statenames[mqtt->state],
613*6236dae4SAndroid Build Coastguard Worker         (state == MQTT_FIRST) ? statenames[nextstate] : "");
614*6236dae4SAndroid Build Coastguard Worker #endif
615*6236dae4SAndroid Build Coastguard Worker   mqtt->state = state;
616*6236dae4SAndroid Build Coastguard Worker   if(state == MQTT_FIRST)
617*6236dae4SAndroid Build Coastguard Worker     mqtt->nextstate = nextstate;
618*6236dae4SAndroid Build Coastguard Worker }
619*6236dae4SAndroid Build Coastguard Worker 
620*6236dae4SAndroid Build Coastguard Worker 
mqtt_read_publish(struct Curl_easy * data,bool * done)621*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
622*6236dae4SAndroid Build Coastguard Worker {
623*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
624*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
625*6236dae4SAndroid Build Coastguard Worker   ssize_t nread;
626*6236dae4SAndroid Build Coastguard Worker   size_t remlen;
627*6236dae4SAndroid Build Coastguard Worker   struct mqtt_conn *mqtt = &conn->proto.mqtt;
628*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
629*6236dae4SAndroid Build Coastguard Worker   unsigned char packet;
630*6236dae4SAndroid Build Coastguard Worker 
631*6236dae4SAndroid Build Coastguard Worker   switch(mqtt->state) {
632*6236dae4SAndroid Build Coastguard Worker MQTT_SUBACK_COMING:
633*6236dae4SAndroid Build Coastguard Worker   case MQTT_SUBACK_COMING:
634*6236dae4SAndroid Build Coastguard Worker     result = mqtt_verify_suback(data);
635*6236dae4SAndroid Build Coastguard Worker     if(result)
636*6236dae4SAndroid Build Coastguard Worker       break;
637*6236dae4SAndroid Build Coastguard Worker 
638*6236dae4SAndroid Build Coastguard Worker     mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
639*6236dae4SAndroid Build Coastguard Worker     break;
640*6236dae4SAndroid Build Coastguard Worker 
641*6236dae4SAndroid Build Coastguard Worker   case MQTT_SUBACK:
642*6236dae4SAndroid Build Coastguard Worker   case MQTT_PUBWAIT:
643*6236dae4SAndroid Build Coastguard Worker     /* we are expecting PUBLISH or SUBACK */
644*6236dae4SAndroid Build Coastguard Worker     packet = mq->firstbyte & 0xf0;
645*6236dae4SAndroid Build Coastguard Worker     if(packet == MQTT_MSG_PUBLISH)
646*6236dae4SAndroid Build Coastguard Worker       mqstate(data, MQTT_PUB_REMAIN, MQTT_NOSTATE);
647*6236dae4SAndroid Build Coastguard Worker     else if(packet == MQTT_MSG_SUBACK) {
648*6236dae4SAndroid Build Coastguard Worker       mqstate(data, MQTT_SUBACK_COMING, MQTT_NOSTATE);
649*6236dae4SAndroid Build Coastguard Worker       goto MQTT_SUBACK_COMING;
650*6236dae4SAndroid Build Coastguard Worker     }
651*6236dae4SAndroid Build Coastguard Worker     else if(packet == MQTT_MSG_DISCONNECT) {
652*6236dae4SAndroid Build Coastguard Worker       infof(data, "Got DISCONNECT");
653*6236dae4SAndroid Build Coastguard Worker       *done = TRUE;
654*6236dae4SAndroid Build Coastguard Worker       goto end;
655*6236dae4SAndroid Build Coastguard Worker     }
656*6236dae4SAndroid Build Coastguard Worker     else {
657*6236dae4SAndroid Build Coastguard Worker       result = CURLE_WEIRD_SERVER_REPLY;
658*6236dae4SAndroid Build Coastguard Worker       goto end;
659*6236dae4SAndroid Build Coastguard Worker     }
660*6236dae4SAndroid Build Coastguard Worker 
661*6236dae4SAndroid Build Coastguard Worker     /* -- switched state -- */
662*6236dae4SAndroid Build Coastguard Worker     remlen = mq->remaining_length;
663*6236dae4SAndroid Build Coastguard Worker     infof(data, "Remaining length: %zu bytes", remlen);
664*6236dae4SAndroid Build Coastguard Worker     if(data->set.max_filesize &&
665*6236dae4SAndroid Build Coastguard Worker        (curl_off_t)remlen > data->set.max_filesize) {
666*6236dae4SAndroid Build Coastguard Worker       failf(data, "Maximum file size exceeded");
667*6236dae4SAndroid Build Coastguard Worker       result = CURLE_FILESIZE_EXCEEDED;
668*6236dae4SAndroid Build Coastguard Worker       goto end;
669*6236dae4SAndroid Build Coastguard Worker     }
670*6236dae4SAndroid Build Coastguard Worker     Curl_pgrsSetDownloadSize(data, remlen);
671*6236dae4SAndroid Build Coastguard Worker     data->req.bytecount = 0;
672*6236dae4SAndroid Build Coastguard Worker     data->req.size = remlen;
673*6236dae4SAndroid Build Coastguard Worker     mq->npacket = remlen; /* get this many bytes */
674*6236dae4SAndroid Build Coastguard Worker     FALLTHROUGH();
675*6236dae4SAndroid Build Coastguard Worker   case MQTT_PUB_REMAIN: {
676*6236dae4SAndroid Build Coastguard Worker     /* read rest of packet, but no more. Cap to buffer size */
677*6236dae4SAndroid Build Coastguard Worker     char buffer[4*1024];
678*6236dae4SAndroid Build Coastguard Worker     size_t rest = mq->npacket;
679*6236dae4SAndroid Build Coastguard Worker     if(rest > sizeof(buffer))
680*6236dae4SAndroid Build Coastguard Worker       rest = sizeof(buffer);
681*6236dae4SAndroid Build Coastguard Worker     result = Curl_xfer_recv(data, buffer, rest, &nread);
682*6236dae4SAndroid Build Coastguard Worker     if(result) {
683*6236dae4SAndroid Build Coastguard Worker       if(CURLE_AGAIN == result) {
684*6236dae4SAndroid Build Coastguard Worker         infof(data, "EEEE AAAAGAIN");
685*6236dae4SAndroid Build Coastguard Worker       }
686*6236dae4SAndroid Build Coastguard Worker       goto end;
687*6236dae4SAndroid Build Coastguard Worker     }
688*6236dae4SAndroid Build Coastguard Worker     if(!nread) {
689*6236dae4SAndroid Build Coastguard Worker       infof(data, "server disconnected");
690*6236dae4SAndroid Build Coastguard Worker       result = CURLE_PARTIAL_FILE;
691*6236dae4SAndroid Build Coastguard Worker       goto end;
692*6236dae4SAndroid Build Coastguard Worker     }
693*6236dae4SAndroid Build Coastguard Worker 
694*6236dae4SAndroid Build Coastguard Worker     /* if QoS is set, message contains packet id */
695*6236dae4SAndroid Build Coastguard Worker     result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread);
696*6236dae4SAndroid Build Coastguard Worker     if(result)
697*6236dae4SAndroid Build Coastguard Worker       goto end;
698*6236dae4SAndroid Build Coastguard Worker 
699*6236dae4SAndroid Build Coastguard Worker     mq->npacket -= nread;
700*6236dae4SAndroid Build Coastguard Worker     if(!mq->npacket)
701*6236dae4SAndroid Build Coastguard Worker       /* no more PUBLISH payload, back to subscribe wait state */
702*6236dae4SAndroid Build Coastguard Worker       mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
703*6236dae4SAndroid Build Coastguard Worker     break;
704*6236dae4SAndroid Build Coastguard Worker   }
705*6236dae4SAndroid Build Coastguard Worker   default:
706*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(NULL); /* illegal state */
707*6236dae4SAndroid Build Coastguard Worker     result = CURLE_WEIRD_SERVER_REPLY;
708*6236dae4SAndroid Build Coastguard Worker     goto end;
709*6236dae4SAndroid Build Coastguard Worker   }
710*6236dae4SAndroid Build Coastguard Worker end:
711*6236dae4SAndroid Build Coastguard Worker   return result;
712*6236dae4SAndroid Build Coastguard Worker }
713*6236dae4SAndroid Build Coastguard Worker 
mqtt_do(struct Curl_easy * data,bool * done)714*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
715*6236dae4SAndroid Build Coastguard Worker {
716*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
717*6236dae4SAndroid Build Coastguard Worker   *done = FALSE; /* unconditionally */
718*6236dae4SAndroid Build Coastguard Worker 
719*6236dae4SAndroid Build Coastguard Worker   result = mqtt_connect(data);
720*6236dae4SAndroid Build Coastguard Worker   if(result) {
721*6236dae4SAndroid Build Coastguard Worker     failf(data, "Error %d sending MQTT CONNECT request", result);
722*6236dae4SAndroid Build Coastguard Worker     return result;
723*6236dae4SAndroid Build Coastguard Worker   }
724*6236dae4SAndroid Build Coastguard Worker   mqstate(data, MQTT_FIRST, MQTT_CONNACK);
725*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
726*6236dae4SAndroid Build Coastguard Worker }
727*6236dae4SAndroid Build Coastguard Worker 
mqtt_done(struct Curl_easy * data,CURLcode status,bool premature)728*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_done(struct Curl_easy *data,
729*6236dae4SAndroid Build Coastguard Worker                           CURLcode status, bool premature)
730*6236dae4SAndroid Build Coastguard Worker {
731*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
732*6236dae4SAndroid Build Coastguard Worker   (void)status;
733*6236dae4SAndroid Build Coastguard Worker   (void)premature;
734*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(mq->sendleftovers);
735*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&mq->recvbuf);
736*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
737*6236dae4SAndroid Build Coastguard Worker }
738*6236dae4SAndroid Build Coastguard Worker 
mqtt_doing(struct Curl_easy * data,bool * done)739*6236dae4SAndroid Build Coastguard Worker static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
740*6236dae4SAndroid Build Coastguard Worker {
741*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
742*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
743*6236dae4SAndroid Build Coastguard Worker   struct mqtt_conn *mqtt = &conn->proto.mqtt;
744*6236dae4SAndroid Build Coastguard Worker   struct MQTT *mq = data->req.p.mqtt;
745*6236dae4SAndroid Build Coastguard Worker   ssize_t nread;
746*6236dae4SAndroid Build Coastguard Worker   unsigned char recvbyte;
747*6236dae4SAndroid Build Coastguard Worker 
748*6236dae4SAndroid Build Coastguard Worker   *done = FALSE;
749*6236dae4SAndroid Build Coastguard Worker 
750*6236dae4SAndroid Build Coastguard Worker   if(mq->nsend) {
751*6236dae4SAndroid Build Coastguard Worker     /* send the remainder of an outgoing packet */
752*6236dae4SAndroid Build Coastguard Worker     char *ptr = mq->sendleftovers;
753*6236dae4SAndroid Build Coastguard Worker     result = mqtt_send(data, mq->sendleftovers, mq->nsend);
754*6236dae4SAndroid Build Coastguard Worker     free(ptr);
755*6236dae4SAndroid Build Coastguard Worker     if(result)
756*6236dae4SAndroid Build Coastguard Worker       return result;
757*6236dae4SAndroid Build Coastguard Worker   }
758*6236dae4SAndroid Build Coastguard Worker 
759*6236dae4SAndroid Build Coastguard Worker   infof(data, "mqtt_doing: state [%d]", (int) mqtt->state);
760*6236dae4SAndroid Build Coastguard Worker   switch(mqtt->state) {
761*6236dae4SAndroid Build Coastguard Worker   case MQTT_FIRST:
762*6236dae4SAndroid Build Coastguard Worker     /* Read the initial byte only */
763*6236dae4SAndroid Build Coastguard Worker     result = Curl_xfer_recv(data, (char *)&mq->firstbyte, 1, &nread);
764*6236dae4SAndroid Build Coastguard Worker     if(result)
765*6236dae4SAndroid Build Coastguard Worker       break;
766*6236dae4SAndroid Build Coastguard Worker     else if(!nread) {
767*6236dae4SAndroid Build Coastguard Worker       failf(data, "Connection disconnected");
768*6236dae4SAndroid Build Coastguard Worker       *done = TRUE;
769*6236dae4SAndroid Build Coastguard Worker       result = CURLE_RECV_ERROR;
770*6236dae4SAndroid Build Coastguard Worker       break;
771*6236dae4SAndroid Build Coastguard Worker     }
772*6236dae4SAndroid Build Coastguard Worker     Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
773*6236dae4SAndroid Build Coastguard Worker     /* remember the first byte */
774*6236dae4SAndroid Build Coastguard Worker     mq->npacket = 0;
775*6236dae4SAndroid Build Coastguard Worker     mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
776*6236dae4SAndroid Build Coastguard Worker     FALLTHROUGH();
777*6236dae4SAndroid Build Coastguard Worker   case MQTT_REMAINING_LENGTH:
778*6236dae4SAndroid Build Coastguard Worker     do {
779*6236dae4SAndroid Build Coastguard Worker       result = Curl_xfer_recv(data, (char *)&recvbyte, 1, &nread);
780*6236dae4SAndroid Build Coastguard Worker       if(result || !nread)
781*6236dae4SAndroid Build Coastguard Worker         break;
782*6236dae4SAndroid Build Coastguard Worker       Curl_debug(data, CURLINFO_HEADER_IN, (char *)&recvbyte, 1);
783*6236dae4SAndroid Build Coastguard Worker       mq->pkt_hd[mq->npacket++] = recvbyte;
784*6236dae4SAndroid Build Coastguard Worker     } while((recvbyte & 0x80) && (mq->npacket < 4));
785*6236dae4SAndroid Build Coastguard Worker     if(!result && nread && (recvbyte & 0x80))
786*6236dae4SAndroid Build Coastguard Worker       /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
787*6236dae4SAndroid Build Coastguard Worker          127 * 128^3 bytes. server tried to send more */
788*6236dae4SAndroid Build Coastguard Worker       result = CURLE_WEIRD_SERVER_REPLY;
789*6236dae4SAndroid Build Coastguard Worker     if(result)
790*6236dae4SAndroid Build Coastguard Worker       break;
791*6236dae4SAndroid Build Coastguard Worker     mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
792*6236dae4SAndroid Build Coastguard Worker     mq->npacket = 0;
793*6236dae4SAndroid Build Coastguard Worker     if(mq->remaining_length) {
794*6236dae4SAndroid Build Coastguard Worker       mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
795*6236dae4SAndroid Build Coastguard Worker       break;
796*6236dae4SAndroid Build Coastguard Worker     }
797*6236dae4SAndroid Build Coastguard Worker     mqstate(data, MQTT_FIRST, MQTT_FIRST);
798*6236dae4SAndroid Build Coastguard Worker 
799*6236dae4SAndroid Build Coastguard Worker     if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
800*6236dae4SAndroid Build Coastguard Worker       infof(data, "Got DISCONNECT");
801*6236dae4SAndroid Build Coastguard Worker       *done = TRUE;
802*6236dae4SAndroid Build Coastguard Worker     }
803*6236dae4SAndroid Build Coastguard Worker     break;
804*6236dae4SAndroid Build Coastguard Worker   case MQTT_CONNACK:
805*6236dae4SAndroid Build Coastguard Worker     result = mqtt_verify_connack(data);
806*6236dae4SAndroid Build Coastguard Worker     if(result)
807*6236dae4SAndroid Build Coastguard Worker       break;
808*6236dae4SAndroid Build Coastguard Worker 
809*6236dae4SAndroid Build Coastguard Worker     if(data->state.httpreq == HTTPREQ_POST) {
810*6236dae4SAndroid Build Coastguard Worker       result = mqtt_publish(data);
811*6236dae4SAndroid Build Coastguard Worker       if(!result) {
812*6236dae4SAndroid Build Coastguard Worker         result = mqtt_disconnect(data);
813*6236dae4SAndroid Build Coastguard Worker         *done = TRUE;
814*6236dae4SAndroid Build Coastguard Worker       }
815*6236dae4SAndroid Build Coastguard Worker       mqtt->nextstate = MQTT_FIRST;
816*6236dae4SAndroid Build Coastguard Worker     }
817*6236dae4SAndroid Build Coastguard Worker     else {
818*6236dae4SAndroid Build Coastguard Worker       result = mqtt_subscribe(data);
819*6236dae4SAndroid Build Coastguard Worker       if(!result) {
820*6236dae4SAndroid Build Coastguard Worker         mqstate(data, MQTT_FIRST, MQTT_SUBACK);
821*6236dae4SAndroid Build Coastguard Worker       }
822*6236dae4SAndroid Build Coastguard Worker     }
823*6236dae4SAndroid Build Coastguard Worker     break;
824*6236dae4SAndroid Build Coastguard Worker 
825*6236dae4SAndroid Build Coastguard Worker   case MQTT_SUBACK:
826*6236dae4SAndroid Build Coastguard Worker   case MQTT_PUBWAIT:
827*6236dae4SAndroid Build Coastguard Worker   case MQTT_PUB_REMAIN:
828*6236dae4SAndroid Build Coastguard Worker     result = mqtt_read_publish(data, done);
829*6236dae4SAndroid Build Coastguard Worker     break;
830*6236dae4SAndroid Build Coastguard Worker 
831*6236dae4SAndroid Build Coastguard Worker   default:
832*6236dae4SAndroid Build Coastguard Worker     failf(data, "State not handled yet");
833*6236dae4SAndroid Build Coastguard Worker     *done = TRUE;
834*6236dae4SAndroid Build Coastguard Worker     break;
835*6236dae4SAndroid Build Coastguard Worker   }
836*6236dae4SAndroid Build Coastguard Worker 
837*6236dae4SAndroid Build Coastguard Worker   if(result == CURLE_AGAIN)
838*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OK;
839*6236dae4SAndroid Build Coastguard Worker   return result;
840*6236dae4SAndroid Build Coastguard Worker }
841*6236dae4SAndroid Build Coastguard Worker 
842*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_MQTT */
843