1 /*******************************************************************************
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 */
MQTTSerialize_connectLength(MQTTPacket_connectData * options)27 int 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 */
MQTTSerialize_connect(unsigned char * buf,int buflen,MQTTPacket_connectData * options)58 int 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
77 ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
78
79 if (options->MQTTVersion == 4)
80 {
81 writeCString(&ptr, "MQTT");
82 writeChar(&ptr, (char) 4);
83 }
84 else
85 {
86 writeCString(&ptr, "MQIsdp");
87 writeChar(&ptr, (char) 3);
88 }
89
90 flags.all = 0;
91 flags.bits.cleansession = options->cleansession;
92 flags.bits.will = (options->willFlag) ? 1 : 0;
93 if (flags.bits.will)
94 {
95 flags.bits.willQoS = options->will.qos;
96 flags.bits.willRetain = options->will.retained;
97 }
98
99 if (options->username.cstring || options->username.lenstring.data)
100 flags.bits.username = 1;
101 if (options->password.cstring || options->password.lenstring.data)
102 flags.bits.password = 1;
103
104 writeChar(&ptr, flags.all);
105 writeInt(&ptr, options->keepAliveInterval);
106 writeMQTTString(&ptr, options->clientID);
107 if (options->willFlag)
108 {
109 writeMQTTString(&ptr, options->will.topicName);
110 writeMQTTString(&ptr, options->will.message);
111 }
112 if (flags.bits.username)
113 writeMQTTString(&ptr, options->username);
114 if (flags.bits.password)
115 writeMQTTString(&ptr, options->password);
116
117 rc = ptr - buf;
118
119 exit: FUNC_EXIT_RC(rc);
120 return rc;
121 }
122
123
124 /**
125 * Deserializes the supplied (wire) buffer into connack data - return code
126 * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
127 * @param connack_rc returned integer value of the connack return code
128 * @param buf the raw buffer data, of the correct length determined by the remaining length field
129 * @param len the length in bytes of the data in the supplied buffer
130 * @return error code. 1 is success, 0 is failure
131 */
MQTTDeserialize_connack(unsigned char * sessionPresent,unsigned char * connack_rc,unsigned char * buf,int buflen)132 int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
133 {
134 MQTTHeader header = {0};
135 unsigned char* curdata = buf;
136 unsigned char* enddata = NULL;
137 int rc = 0;
138 int mylen;
139 MQTTConnackFlags flags = {0};
140
141 FUNC_ENTRY;
142 header.byte = readChar(&curdata);
143 if (header.bits.type != CONNACK)
144 goto exit;
145
146 curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
147 enddata = curdata + mylen;
148 if (enddata - curdata < 2)
149 goto exit;
150
151 flags.all = readChar(&curdata);
152 *sessionPresent = flags.bits.sessionpresent;
153 *connack_rc = readChar(&curdata);
154
155 rc = 1;
156 exit:
157 FUNC_EXIT_RC(rc);
158 return rc;
159 }
160
161
162 /**
163 * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
164 * @param buf the buffer into which the packet will be serialized
165 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
166 * @param packettype the message type
167 * @return serialized length, or error if 0
168 */
MQTTSerialize_zero(unsigned char * buf,int buflen,unsigned char packettype)169 int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
170 {
171 MQTTHeader header = {0};
172 int rc = -1;
173 unsigned char *ptr = buf;
174
175 FUNC_ENTRY;
176 if (buflen < 2)
177 {
178 rc = MQTTPACKET_BUFFER_TOO_SHORT;
179 goto exit;
180 }
181 header.byte = 0;
182 header.bits.type = packettype;
183 writeChar(&ptr, header.byte); /* write header */
184
185 ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
186 rc = ptr - buf;
187 exit:
188 FUNC_EXIT_RC(rc);
189 return rc;
190 }
191
192
193 /**
194 * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
195 * @param buf the buffer into which the packet will be serialized
196 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
197 * @return serialized length, or error if 0
198 */
MQTTSerialize_disconnect(unsigned char * buf,int buflen)199 int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
200 {
201 return MQTTSerialize_zero(buf, buflen, DISCONNECT);
202 }
203
204
205 /**
206 * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
207 * @param buf the buffer into which the packet will be serialized
208 * @param buflen the length in bytes of the supplied buffer, to avoid overruns
209 * @return serialized length, or error if 0
210 */
MQTTSerialize_pingreq(unsigned char * buf,int buflen)211 int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
212 {
213 return MQTTSerialize_zero(buf, buflen, PINGREQ);
214 }
215