blob: 405c23eef7d091bd03de523cdc6da6cdd0dfd9b7 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001/*******************************************************************************
2 * Copyright (c) 2014 IBM Corp.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * and Eclipse Distribution License v1.0 which accompany this distribution.
7 *
8 * The Eclipse Public License is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 * and the Eclipse Distribution License is available at
11 * http://www.eclipse.org/org/documents/edl-v10.php.
12 *
13 * Contributors:
14 * Ian Craggs - initial API and implementation and/or initial documentation
15 *******************************************************************************/
16
17#include "MQTTPacket.h"
18#include "StackTrace.h"
19
20#include <string.h>
21
22/**
23 * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
24 * @param options the options to be used to build the connect packet
25 * @return the length of buffer needed to contain the serialized version of the packet
26 */
27int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
28{
29 int len = 0;
30
31 FUNC_ENTRY;
32
33 if (options->MQTTVersion == 3)
34 len = 12; /* variable depending on MQTT or MQIsdp */
35 else if (options->MQTTVersion == 4)
36 len = 10;
37
38 len += MQTTstrlen(options->clientID)+2;
39 if (options->willFlag)
40 len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
41 if (options->username.cstring || options->username.lenstring.data)
42 len += MQTTstrlen(options->username)+2;
43 if (options->password.cstring || options->password.lenstring.data)
44 len += MQTTstrlen(options->password)+2;
45
46 FUNC_EXIT_RC(len);
47 return len;
48}
49
50
51/**
52 * Serializes the connect options into the buffer.
53 * @param buf the buffer into which the packet will be serialized
54 * @param len the length in bytes of the supplied buffer
55 * @param options the options to be used to build the connect packet
56 * @return serialized length, or error if 0
57 */
58int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
59{
60 unsigned char *ptr = buf;
61 MQTTHeader header = {0};
62 MQTTConnectFlags flags = {0};
63 int len = 0;
64 int rc = -1;
65
66 FUNC_ENTRY;
67 if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
68 {
69 rc = MQTTPACKET_BUFFER_TOO_SHORT;
70 goto exit;
71 }
72
73 header.byte = 0;
74 header.bits.type = CONNECT;
75 writeChar(&ptr, header.byte); /* write header */
76 ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
77 if (options->MQTTVersion == 4)
78 {
79 writeCString(&ptr, "MQTT");
80 writeChar(&ptr, (char) 4);
81 }
82 else
83 {
84 writeCString(&ptr, "MQIsdp");
85 writeChar(&ptr, (char) 3);
86 }
87
88 flags.all = 0;
89 flags.bits.cleansession = options->cleansession;
90 flags.bits.will = (options->willFlag) ? 1 : 0;
91 if (flags.bits.will)
92 {
93 flags.bits.willQoS = options->will.qos;
94 flags.bits.willRetain = options->will.retained;
95 }
96
97 if (options->username.cstring || options->username.lenstring.data)
98 flags.bits.username = 1;
99 if (options->password.cstring || options->password.lenstring.data)
100 flags.bits.password = 1;
101 writeChar(&ptr, flags.all);
102 writeInt(&ptr, options->keepAliveInterval);
103 writeMQTTString(&ptr, options->clientID);
104 if (options->willFlag)
105 {
106 writeMQTTString(&ptr, options->will.topicName);
107 writeMQTTString(&ptr, options->will.message);
108 }
109 if (flags.bits.username)
110 writeMQTTString(&ptr, options->username);
111 if (flags.bits.password)
112 writeMQTTString(&ptr, options->password);
113
114 rc = ptr - buf;
115
116 exit: FUNC_EXIT_RC(rc);
117 return rc;
118}
119
120
121/**
122 * Deserializes the supplied (wire) buffer into connack data - return code
123 * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
124 * @param connack_rc returned integer value of the connack return code
125 * @param buf the raw buffer data, of the correct length determined by the remaining length field
126 * @param len the length in bytes of the data in the supplied buffer
127 * @return error code. 1 is success, 0 is failure
128 */
129int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
130{
131 MQTTHeader header = {0};
132 unsigned char* curdata = buf;
133 unsigned char* enddata = NULL;
134 int rc = 0;
135 int mylen;
136 MQTTConnackFlags flags = {0};
137
138 FUNC_ENTRY;
139 header.byte = readChar(&curdata);
140 if (header.bits.type != CONNACK)
141 goto exit;
142
143 curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
144 enddata = curdata + mylen;
145 if (enddata - curdata < 2)
146 goto exit;
147
148 flags.all = readChar(&curdata);
149 *sessionPresent = flags.bits.sessionpresent;
150 *connack_rc = readChar(&curdata);
151
152 rc = 1;
153exit:
154 FUNC_EXIT_RC(rc);
155 return rc;
156}
157
158
159/**
160 * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
161 * @param buf the buffer into which the packet will be serialized
162 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
163 * @param packettype the message type
164 * @return serialized length, or error if 0
165 */
166int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
167{
168 MQTTHeader header = {0};
169 int rc = -1;
170 unsigned char *ptr = buf;
171
172 FUNC_ENTRY;
173 if (buflen < 2)
174 {
175 rc = MQTTPACKET_BUFFER_TOO_SHORT;
176 goto exit;
177 }
178 header.byte = 0;
179 header.bits.type = packettype;
180 writeChar(&ptr, header.byte); /* write header */
181
182 ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
183 rc = ptr - buf;
184exit:
185 FUNC_EXIT_RC(rc);
186 return rc;
187}
188
189
190/**
191 * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
192 * @param buf the buffer into which the packet will be serialized
193 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
194 * @return serialized length, or error if 0
195 */
196int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
197{
198 return MQTTSerialize_zero(buf, buflen, DISCONNECT);
199}
200
201
202/**
203 * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
204 * @param buf the buffer into which the packet will be serialized
205 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
206 * @return serialized length, or error if 0
207 */
208int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
209{
210 return MQTTSerialize_zero(buf, buflen, PINGREQ);
211}