1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: conn.c,v 1.3.12.5 2022/09/15 21:06:05 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2022
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * mqtt_msgCONNECT() Create CONNECT message
51: *
52: * @csConnID = ConnectID
53: * @Version = MQTT version, if =0 default version is 3.1.1
54: * @KASec = Keep alive timeout, if =0 default timeout for MQTT
55: * @csUser = Username if !=NULL
56: * @csPass = Password for Username, only if csUser is set
57: * @csWillTopic = Will Topic if !=NULL Will Flags set into message
58: * @csWillMessage = Will Message, may be NULL
59: * @ClrSess = Clear Session subscriptions after disconnect
60: * @WillQOS = Will QOS if csWillTopic is set
61: * @WillRetain = Will Retain Will Message if csWillTopic is set
62: * return: NULL error or allocated CONNECT message
63: */
64: mqtt_msg_t *
65: mqtt_msgCONNECT(const char *csConnID, u_char Version, u_short KASec,
66: const char *csUser, const char *csPass,
67: const char *csWillTopic, const char *csWillMessage,
68: u_char ClrSess, u_char WillQOS, u_char WillRetain)
69: {
70: int len, siz = 0;
71: u_int n, *l;
72: mqtt_msg_t *msg = NULL;
73: struct mqtthdr *hdr;
74: mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass;
75: mqtthdr_connflgs_t *flags;
76: mqtt_len_t *ka;
77: void *data;
78:
79: if (!csConnID)
80: return NULL;
81: if (strlen(csConnID) >= MQTT_CONNID_MAX) {
82: mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max %d bytes)",
83: MQTT_CONNID_MAX - 1);
84: return NULL;
85: }
86: if (Version && (Version < MQTT_PROTO_VER_3 || Version > MQTT_PROTO_VER_5)) {
87: mqtt_SetErr(EINVAL, "Unsupported version");
88: return NULL;
89: }
90: if (csUser && strlen(csUser) >= MQTT_CRED_MAX) {
91: mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max %d bytes)",
92: MQTT_CRED_MAX - 1);
93: return NULL;
94: }
95: if (csPass && strlen(csPass) >= MQTT_CRED_MAX) {
96: mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max %d bytes)",
97: MQTT_CRED_MAX - 1);
98: return NULL;
99: }
100: if (WillQOS > MQTT_QOS_EXACTLY) {
101: mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value");
102: return NULL;
103: }
104:
105: /* calculate message size */
106: len = 10; /* connect arguments: MQTT(6)+Version(1)+ConnFlags(1)+KeepAlive(2) */
107: len += sizeof(mqtt_len_t) + strlen(csConnID); /* connect id */
108: if (csUser && *csUser) { /* user/pass */
109: len += sizeof(mqtt_len_t) + strlen(csUser);
110: if (csPass)
111: len += sizeof(mqtt_len_t) + strlen(csPass);
112: }
113: if (csWillTopic && *csWillTopic) { /* will messages */
114: len += sizeof(mqtt_len_t) + strlen(csWillTopic);
115: len += sizeof(mqtt_len_t) + (csWillMessage ? strlen(csWillMessage) : 0);
116: }
117:
118: /* calculate header size */
119: siz = sizeof(struct mqtthdr); /* mqtt fixed header */
120: n = mqtt_encodeLen(len); /* message size */
121: siz += mqtt_sizeLen(n) - 1; /* length size */
122:
123: if (!(msg = mqtt_msgAlloc(siz + len)))
124: return NULL;
125: else {
126: data = msg->msg_base;
127: hdr = (struct mqtthdr *) data;
128: }
129:
130: /* fixed header */
131: hdr->mqtt_msg.type = MQTT_TYPE_CONNECT;
132: l = (u_int*) hdr->mqtt_len;
133: *l = n;
134: data += siz;
135:
136: /* variable header */
137: var = (mqtthdr_var_t*) data;
138: var->var_sb.val = htons(strlen(MQTT_PROTO_STR));
139: memcpy(var->var_data, MQTT_PROTO_STR, ntohs(var->var_sb.val));
140: data += MQTTHDR_VAR_SIZEOF(var);
141:
142: /* protocol version */
143: *(u_char*) data++ = Version ? Version : MQTT_PROTO_VER_311;
144:
145: /* CONNECT header */
146: flags = (mqtthdr_connflgs_t*) data++;
147: flags->clean_sess = ClrSess ? 1 : 0;
148: if (csUser && *csUser) {
149: flags->username = 1;
150: flags->password = csPass ? 1 : 0;
151: } else {
152: flags->username = 0;
153: flags->password = 0;
154: }
155: if (csWillTopic && *csWillTopic) {
156: flags->will_flg = 1;
157: flags->will_qos = WillQOS;
158: flags->will_retain = WillRetain ? 1 : 0;
159: } else {
160: flags->will_flg = 0;
161: flags->will_qos = 0;
162: flags->will_retain = 0;
163: }
164:
165: /* keep alive */
166: ka = (mqtt_len_t*) data;
167: ka->val = KASec ? htons(KASec) : htons(MQTT_KEEPALIVE);
168: data += sizeof(mqtt_len_t);
169:
170: /* ConnID */
171: cid = (mqtthdr_var_t*) data;
172: cid->var_sb.val = htons(strlen(csConnID));
173: memcpy(cid->var_data, csConnID, ntohs(cid->var_sb.val));
174: data += MQTTHDR_VAR_SIZEOF(cid);
175:
176: /* If Will Flags setup */
177: if (csWillTopic && *csWillTopic) {
178: topic = (mqtthdr_var_t*) data;
179: topic->var_sb.val = htons(strlen(csWillTopic));
180: memcpy(topic->var_data, csWillTopic, ntohs(topic->var_sb.val));
181: data += MQTTHDR_VAR_SIZEOF(topic);
182:
183: wmsg = (mqtthdr_var_t*) data;
184: if (csWillMessage && *csWillMessage) {
185: wmsg->var_sb.val = htons(strlen(csWillMessage));
186: memcpy(wmsg->var_data, csWillMessage, ntohs(wmsg->var_sb.val));
187: } else
188: wmsg->var_sb.val = 0;
189: data += MQTTHDR_VAR_SIZEOF(wmsg);
190: }
191:
192: /* If defined Username & Password */
193: if (csUser && *csUser) {
194: user = (mqtthdr_var_t*) data;
195: user->var_sb.val = htons(strlen(csUser));
196: memcpy(user->var_data, csUser, ntohs(user->var_sb.val));
197: data += MQTTHDR_VAR_SIZEOF(user);
198:
199: if (csPass && *csPass) {
200: pass = (mqtthdr_var_t*) data;
201: pass->var_sb.val = htons(strlen(csPass));
202: memcpy(pass->var_data, csPass, ntohs(pass->var_sb.val));
203: data += MQTTHDR_VAR_SIZEOF(pass);
204: }
205: }
206:
207: return msg;
208: }
209:
210: /*
211: * mqtt_msgCONNACK() Create CONNACK message
212: *
213: * @retcode = Return code
214: * return: NULL error or allocated CONNACK message
215: */
216: mqtt_msg_t *
217: mqtt_msgCONNACK(u_char retcode)
218: {
219: struct mqtthdr *hdr;
220: mqtthdr_connack_t *ack;
221: mqtt_msg_t *msg = NULL;
222:
223: if (retcode > MQTT_RETCODE_DENIED) {
224: mqtt_SetErr(EINVAL, "Invalid retcode");
225: return NULL;
226: }
227:
228: if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t))))
229: return NULL;
230: else {
231: hdr = (struct mqtthdr *) msg->msg_base;
232: ack = (mqtthdr_connack_t*) (msg->msg_base + sizeof(struct mqtthdr));
233: }
234:
235: /* fixed header */
236: hdr->mqtt_msg.type = MQTT_TYPE_CONNACK;
237: *hdr->mqtt_len = sizeof(mqtthdr_connack_t);
238:
239: /* CONNACK header */
240: ack->reserved = 0;
241: ack->retcode = retcode;
242:
243: return msg;
244: }
245:
246: static mqtt_msg_t *
247: _mqtt_msgSIMPLE_(u_char cmd)
248: {
249: struct mqtthdr *hdr;
250: mqtt_msg_t *msg = NULL;
251:
252: if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr))))
253: return NULL;
254: else
255: hdr = (struct mqtthdr *) msg->msg_base;
256:
257: /* fixed header */
258: hdr->mqtt_msg.type = cmd;
259: *hdr->mqtt_len = 0;
260:
261: return msg;
262: }
263:
264: /*
265: * mqtt_msgPINGREQ() Create PINGREQ message
266: *
267: * return: NULL error or allocated message
268: */
269: mqtt_msg_t *
270: mqtt_msgPINGREQ()
271: {
272: return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGREQ);
273: }
274:
275: /*
276: * mqtt_msgPINGRESP() Create PINGRESP message
277: *
278: * return: NULL error or allocated message
279: */
280: mqtt_msg_t *
281: mqtt_msgPINGRESP()
282: {
283: return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGRESP);
284: }
285:
286: /*
287: * mqtt_msgDISCONNECT() Create DISCONNECT message
288: *
289: * return: NULL error or allocated message
290: */
291: mqtt_msg_t *
292: mqtt_msgDISCONNECT()
293: {
294: return _mqtt_msgSIMPLE_(MQTT_TYPE_DISCONNECT);
295: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>