/src/mosquitto/lib/property_mosq.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 2018-2021 Roger Light <roger@atchoo.org> |
3 | | |
4 | | All rights reserved. This program and the accompanying materials |
5 | | are made available under the terms of the Eclipse Public License 2.0 |
6 | | and Eclipse Distribution License v1.0 which accompany this distribution. |
7 | | |
8 | | The Eclipse Public License is available at |
9 | | https://www.eclipse.org/legal/epl-2.0/ |
10 | | and the Eclipse Distribution License is available at |
11 | | http://www.eclipse.org/org/documents/edl-v10.php. |
12 | | |
13 | | SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
14 | | |
15 | | Contributors: |
16 | | Roger Light - initial implementation and documentation. |
17 | | */ |
18 | | |
19 | | #include "config.h" |
20 | | |
21 | | #include <errno.h> |
22 | | #include <string.h> |
23 | | |
24 | | #ifndef WIN32 |
25 | | # include <strings.h> |
26 | | #endif |
27 | | |
28 | | #include "logging_mosq.h" |
29 | | #include "mosquitto/mqtt_protocol.h" |
30 | | #include "packet_mosq.h" |
31 | | #include "property_common.h" |
32 | | #include "property_mosq.h" |
33 | | |
34 | | |
35 | | static int property__read(struct mosquitto__packet_in *packet, uint32_t *len, mosquitto_property *property) |
36 | 19.8M | { |
37 | 19.8M | int rc; |
38 | 19.8M | uint32_t property_identifier; |
39 | 19.8M | uint8_t byte; |
40 | 19.8M | uint8_t byte_count; |
41 | 19.8M | uint16_t uint16; |
42 | 19.8M | uint32_t uint32; |
43 | 19.8M | uint32_t varint; |
44 | 19.8M | char *str1, *str2; |
45 | 19.8M | uint16_t slen1, slen2; |
46 | | |
47 | 19.8M | if(!property){ |
48 | 0 | return MOSQ_ERR_INVAL; |
49 | 0 | } |
50 | | |
51 | 19.8M | rc = packet__read_varint(packet, &property_identifier, NULL); |
52 | 19.8M | if(rc){ |
53 | 943 | return rc; |
54 | 943 | } |
55 | 19.8M | *len -= mosquitto_varint_bytes(property_identifier); |
56 | | |
57 | 19.8M | memset(property, 0, sizeof(mosquitto_property)); |
58 | | |
59 | 19.8M | property->identifier = (int32_t)property_identifier; |
60 | | |
61 | 19.8M | switch(property_identifier){ |
62 | 4.56M | case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR: |
63 | 8.78M | case MQTT_PROP_REQUEST_PROBLEM_INFORMATION: |
64 | 9.59M | case MQTT_PROP_REQUEST_RESPONSE_INFORMATION: |
65 | 10.3M | case MQTT_PROP_MAXIMUM_QOS: |
66 | 11.8M | case MQTT_PROP_RETAIN_AVAILABLE: |
67 | 13.0M | case MQTT_PROP_WILDCARD_SUB_AVAILABLE: |
68 | 14.3M | case MQTT_PROP_SUBSCRIPTION_ID_AVAILABLE: |
69 | 15.2M | case MQTT_PROP_SHARED_SUB_AVAILABLE: |
70 | 15.2M | rc = packet__read_byte(packet, &byte); |
71 | 15.2M | if(rc){ |
72 | 578 | return rc; |
73 | 578 | } |
74 | 15.2M | *len -= 1; /* byte */ |
75 | 15.2M | property->value.i8 = byte; |
76 | 15.2M | property->property_type = MQTT_PROP_TYPE_BYTE; |
77 | 15.2M | break; |
78 | | |
79 | 382k | case MQTT_PROP_SERVER_KEEP_ALIVE: |
80 | 603k | case MQTT_PROP_RECEIVE_MAXIMUM: |
81 | 873k | case MQTT_PROP_TOPIC_ALIAS_MAXIMUM: |
82 | 965k | case MQTT_PROP_TOPIC_ALIAS: |
83 | 965k | rc = packet__read_uint16(packet, &uint16); |
84 | 965k | if(rc){ |
85 | 307 | return rc; |
86 | 307 | } |
87 | 965k | *len -= 2; /* uint16 */ |
88 | 965k | property->value.i16 = uint16; |
89 | 965k | property->property_type = MQTT_PROP_TYPE_INT16; |
90 | 965k | break; |
91 | | |
92 | 250k | case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL: |
93 | 368k | case MQTT_PROP_SESSION_EXPIRY_INTERVAL: |
94 | 374k | case MQTT_PROP_WILL_DELAY_INTERVAL: |
95 | 497k | case MQTT_PROP_MAXIMUM_PACKET_SIZE: |
96 | 497k | rc = packet__read_uint32(packet, &uint32); |
97 | 497k | if(rc){ |
98 | 311 | return rc; |
99 | 311 | } |
100 | 497k | *len -= 4; /* uint32 */ |
101 | 497k | property->value.i32 = uint32; |
102 | 497k | property->property_type = MQTT_PROP_TYPE_INT32; |
103 | 497k | break; |
104 | | |
105 | 1.18M | case MQTT_PROP_SUBSCRIPTION_IDENTIFIER: |
106 | 1.18M | rc = packet__read_varint(packet, &varint, &byte_count); |
107 | 1.18M | if(rc){ |
108 | 38 | return rc; |
109 | 38 | } |
110 | 1.18M | *len -= byte_count; |
111 | 1.18M | property->value.varint = varint; |
112 | 1.18M | property->property_type = MQTT_PROP_TYPE_VARINT; |
113 | 1.18M | break; |
114 | | |
115 | 207k | case MQTT_PROP_CONTENT_TYPE: |
116 | 333k | case MQTT_PROP_RESPONSE_TOPIC: |
117 | 506k | case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER: |
118 | 512k | case MQTT_PROP_AUTHENTICATION_METHOD: |
119 | 521k | case MQTT_PROP_RESPONSE_INFORMATION: |
120 | 534k | case MQTT_PROP_SERVER_REFERENCE: |
121 | 583k | case MQTT_PROP_REASON_STRING: |
122 | 583k | rc = packet__read_string(packet, &str1, &slen1); |
123 | 583k | if(rc){ |
124 | 953 | return rc; |
125 | 953 | } |
126 | 582k | *len = (*len) - 2 - slen1; /* uint16, string len */ |
127 | 582k | property->value.s.v = str1; |
128 | 582k | property->value.s.len = slen1; |
129 | 582k | property->property_type = MQTT_PROP_TYPE_STRING; |
130 | 582k | break; |
131 | | |
132 | 856k | case MQTT_PROP_AUTHENTICATION_DATA: |
133 | 1.31M | case MQTT_PROP_CORRELATION_DATA: |
134 | 1.31M | rc = packet__read_binary(packet, (uint8_t **)&str1, &slen1); |
135 | 1.31M | if(rc){ |
136 | 404 | return rc; |
137 | 404 | } |
138 | 1.31M | *len = (*len) - 2 - slen1; /* uint16, binary len */ |
139 | 1.31M | property->value.bin.v = str1; |
140 | 1.31M | property->value.bin.len = slen1; |
141 | 1.31M | property->property_type = MQTT_PROP_TYPE_BINARY; |
142 | 1.31M | break; |
143 | | |
144 | 11.8k | case MQTT_PROP_USER_PROPERTY: |
145 | 11.8k | rc = packet__read_string(packet, &str1, &slen1); |
146 | 11.8k | if(rc){ |
147 | 86 | return rc; |
148 | 86 | } |
149 | 11.8k | *len = (*len) - 2 - slen1; /* uint16, string len */ |
150 | | |
151 | 11.8k | rc = packet__read_string(packet, &str2, &slen2); |
152 | 11.8k | if(rc){ |
153 | 86 | mosquitto_FREE(str1); |
154 | 86 | return rc; |
155 | 86 | } |
156 | 11.7k | *len = (*len) - 2 - slen2; /* uint16, string len */ |
157 | | |
158 | 11.7k | property->name.v = str1; |
159 | 11.7k | property->name.len = slen1; |
160 | 11.7k | property->value.s.v = str2; |
161 | 11.7k | property->value.s.len = slen2; |
162 | 11.7k | property->property_type = MQTT_PROP_TYPE_STRING_PAIR; |
163 | 11.7k | break; |
164 | | |
165 | 1.05k | default: |
166 | 1.05k | #ifdef WITH_BROKER |
167 | 1.05k | log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property_identifier); |
168 | 1.05k | #endif |
169 | 1.05k | return MOSQ_ERR_MALFORMED_PACKET; |
170 | 19.8M | } |
171 | | |
172 | 19.8M | return MOSQ_ERR_SUCCESS; |
173 | 19.8M | } |
174 | | |
175 | | |
176 | | int property__read_all(int command, struct mosquitto__packet_in *packet, mosquitto_property **properties) |
177 | 14.4k | { |
178 | 14.4k | int rc; |
179 | 14.4k | uint32_t proplen; |
180 | 14.4k | mosquitto_property *p, *tail = NULL; |
181 | | |
182 | 14.4k | rc = packet__read_varint(packet, &proplen, NULL); |
183 | 14.4k | if(rc){ |
184 | 143 | return rc; |
185 | 143 | } |
186 | | |
187 | 14.2k | *properties = NULL; |
188 | | |
189 | | /* The order of properties must be preserved for some types, so keep the |
190 | | * same order for all */ |
191 | 19.8M | while(proplen > 0){ |
192 | 19.8M | p = mosquitto_calloc(1, sizeof(mosquitto_property)); |
193 | 19.8M | if(!p){ |
194 | 0 | mosquitto_property_free_all(properties); |
195 | 0 | return MOSQ_ERR_NOMEM; |
196 | 0 | } |
197 | | |
198 | 19.8M | rc = property__read(packet, &proplen, p); |
199 | 19.8M | if(rc){ |
200 | 4.75k | mosquitto_FREE(p); |
201 | 4.75k | mosquitto_property_free_all(properties); |
202 | 4.75k | return rc; |
203 | 4.75k | } |
204 | | |
205 | 19.8M | if(!(*properties)){ |
206 | 10.8k | *properties = p; |
207 | 19.7M | }else{ |
208 | 19.7M | tail->next = p; |
209 | 19.7M | } |
210 | 19.8M | tail = p; |
211 | | |
212 | 19.8M | } |
213 | | |
214 | 9.50k | rc = mosquitto_property_check_all(command, *properties); |
215 | 9.50k | if(rc){ |
216 | 978 | mosquitto_property_free_all(properties); |
217 | 978 | return rc; |
218 | 978 | } |
219 | 8.52k | return MOSQ_ERR_SUCCESS; |
220 | 9.50k | } |
221 | | |
222 | | |
223 | | static int property__write(struct mosquitto__packet *packet, const mosquitto_property *property) |
224 | 1.33k | { |
225 | 1.33k | int rc; |
226 | | |
227 | 1.33k | rc = packet__write_varint(packet, (uint32_t)mosquitto_property_identifier(property)); |
228 | 1.33k | if(rc){ |
229 | 0 | return rc; |
230 | 0 | } |
231 | | |
232 | 1.33k | switch(property->property_type){ |
233 | 1.33k | case MQTT_PROP_TYPE_BYTE: |
234 | 1.33k | packet__write_byte(packet, property->value.i8); |
235 | 1.33k | break; |
236 | | |
237 | 0 | case MQTT_PROP_TYPE_INT16: |
238 | 0 | packet__write_uint16(packet, property->value.i16); |
239 | 0 | break; |
240 | | |
241 | 0 | case MQTT_PROP_TYPE_INT32: |
242 | 0 | packet__write_uint32(packet, property->value.i32); |
243 | 0 | break; |
244 | | |
245 | 0 | case MQTT_PROP_TYPE_VARINT: |
246 | 0 | return packet__write_varint(packet, property->value.varint); |
247 | | |
248 | 0 | case MQTT_PROP_TYPE_STRING: |
249 | 0 | packet__write_string(packet, property->value.s.v, property->value.s.len); |
250 | 0 | break; |
251 | | |
252 | 0 | case MQTT_PROP_TYPE_BINARY: |
253 | 0 | packet__write_uint16(packet, property->value.bin.len); |
254 | 0 | packet__write_bytes(packet, property->value.bin.v, property->value.bin.len); |
255 | 0 | break; |
256 | | |
257 | 0 | case MQTT_PROP_TYPE_STRING_PAIR: |
258 | 0 | packet__write_string(packet, property->name.v, property->name.len); |
259 | 0 | packet__write_string(packet, property->value.s.v, property->value.s.len); |
260 | 0 | break; |
261 | | |
262 | 0 | default: |
263 | 0 | #ifdef WITH_BROKER |
264 | 0 | log__printf(NULL, MOSQ_LOG_DEBUG, "Unsupported property type: %d", property->identifier); |
265 | 0 | #endif |
266 | 0 | return MOSQ_ERR_INVAL; |
267 | 1.33k | } |
268 | | |
269 | 1.33k | return MOSQ_ERR_SUCCESS; |
270 | 1.33k | } |
271 | | |
272 | | |
273 | | int property__write_all(struct mosquitto__packet *packet, const mosquitto_property *properties, bool write_len) |
274 | 1.53k | { |
275 | 1.53k | int rc; |
276 | 1.53k | const mosquitto_property *p; |
277 | | |
278 | 1.53k | if(write_len){ |
279 | 1.53k | rc = packet__write_varint(packet, mosquitto_property_get_length_all(properties)); |
280 | 1.53k | if(rc){ |
281 | 0 | return rc; |
282 | 0 | } |
283 | 1.53k | } |
284 | | |
285 | 1.53k | p = properties; |
286 | 2.87k | while(p){ |
287 | 1.33k | rc = property__write(packet, p); |
288 | 1.33k | if(rc){ |
289 | 0 | return rc; |
290 | 0 | } |
291 | 1.33k | p = p->next; |
292 | 1.33k | } |
293 | | |
294 | 1.53k | return MOSQ_ERR_SUCCESS; |
295 | 1.53k | } |