• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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