Annotation of libaitmqtt/src/conn.c, revision 1.1.1.1.2.1
1.1 misho 1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.1.1.1.2.1! misho 6: * $Id: conn.c,v 1.1.1.1 2012/01/26 13:07:33 misho Exp $
1.1 misho 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:
1.1.1.1.2.1! misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.1 misho 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: * @buf = Message buffer
53: * @csConnID = ConnectID
54: * @kasec = Keep alive timeout
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: -1 error or >-1 message size for send
63: */
64: int
65: mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const char *csConnID,
66: u_short kasec, 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 siz = 0;
71: struct mqtthdr *hdr;
72: mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass;
73: mqtthdr_protover_t *proto;
74: mqtthdr_connflgs_t *flags;
75: mqtt_len_t *ka;
76:
77: if (!buf || !csConnID)
78: return -1;
79: if (strlen(csConnID) > 23) {
1.1.1.1.2.1! misho 80: mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max 23 bytes)");
1.1 misho 81: return -1;
82: }
83: if (csUser && strlen(csUser) > 12) {
1.1.1.1.2.1! misho 84: mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max 12 bytes)");
1.1 misho 85: return -1;
86: }
87: if (csPass && strlen(csPass) > 12) {
1.1.1.1.2.1! misho 88: mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max 12 bytes)");
1.1 misho 89: return -1;
90: }
91: if (WillQOS > MQTT_QOS_EXACTLY) {
1.1.1.1.2.1! misho 92: mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value");
1.1 misho 93: return -1;
94: }
95:
96: if (mqtt_msgRealloc(buf, BUFSIZ) == -1)
97: return -1;
98: else {
99: hdr = (struct mqtthdr *) (buf->msg_base + siz);
100: siz += sizeof(struct mqtthdr);
101: var = (mqtthdr_var_t*) (buf->msg_base + siz);
102: siz += 8;
103: proto = buf->msg_base + siz;
104: siz++;
105: flags = (mqtthdr_connflgs_t*) (buf->msg_base + siz);
106: siz++;
107: ka = (mqtt_len_t*) (buf->msg_base + siz);
108: siz += sizeof(mqtt_len_t);
109: }
110:
111: /* fixed header */
112: MQTTHDR_MSGINIT(hdr);
113: hdr->mqtt_msg.type = MQTT_TYPE_CONNECT;
114: *hdr->mqtt_len = 0;
115:
116: /* variable header */
117: var->var_sb.sb.l = 6;
118: memcpy(var->var_data, MQTT_CONN_STR, 6);
119:
120: *proto = MQTT_PROTO_VER;
121:
122: /* CONNECT header */
123: flags->clean_sess = ClrSess ? 1 : 0;
124: if (csUser && *csUser) {
125: flags->username = 1;
126: flags->password = csPass ? 1 : 0;
127: } else {
128: flags->username = 0;
129: flags->password = 0;
130: }
131: if (csWillTopic && *csWillTopic) {
132: flags->will_flg = 1;
133: flags->will_qos = WillQOS;
134: flags->will_retain = WillRetain ? 1 : 0;
135: } else {
136: flags->will_flg = 0;
137: flags->will_qos = 0;
138: flags->will_retain = 0;
139: }
140:
141: ka->val = kasec ? htons(kasec) : htons(MQTT_KEEPALIVE);
142:
143: /* ConnID */
144: cid = (mqtthdr_var_t*) (buf->msg_base + siz);
145: cid->var_sb.val = htons(strlen(csConnID));
146: siz += MQTTHDR_VAR_SIZEOF(cid);
147: memcpy(cid->var_data, csConnID, ntohs(cid->var_sb.val));
148:
149: /* If Will Flags setup */
150: if (csWillTopic && *csWillTopic) {
151: topic = (mqtthdr_var_t*) (buf->msg_base + siz);
152: topic->var_sb.val = htons(strlen(csWillTopic));
153: memcpy(topic->var_data, csWillTopic, ntohs(topic->var_sb.val));
154: siz += MQTTHDR_VAR_SIZEOF(topic);
155:
156: wmsg = (mqtthdr_var_t*) (buf->msg_base + siz);
157: if (csWillMessage && *csWillMessage) {
158: wmsg->var_sb.val = htons(strlen(csWillMessage));
159: memcpy(wmsg->var_data, csWillMessage, ntohs(wmsg->var_sb.val));
160: } else
161: wmsg->var_sb.val = 0;
162: siz += MQTTHDR_VAR_SIZEOF(wmsg);
163: }
164:
165: /* If defined Username & Password */
166: if (csUser && *csUser) {
167: user = (mqtthdr_var_t*) (buf->msg_base + siz);
168: user->var_sb.val = htons(strlen(csUser));
169: memcpy(user->var_data, csUser, ntohs(user->var_sb.val));
170: siz += MQTTHDR_VAR_SIZEOF(user);
171:
172: if (csPass && *csPass) {
173: pass = (mqtthdr_var_t*) (buf->msg_base + siz);
174: pass->var_sb.val = htons(strlen(csPass));
175: memcpy(pass->var_data, csPass, ntohs(pass->var_sb.val));
176: siz += MQTTHDR_VAR_SIZEOF(pass);
177: }
178: }
179:
180: *hdr->mqtt_len = mqtt_encodeLen(siz - sizeof(struct mqtthdr));
181: mqtt_msgRealloc(buf, siz);
182: return siz;
183: }
184:
185: /*
186: * mqtt_msgCONNACK() Create CONNACK message
187: *
188: * @buf = Message buffer
189: * @retcode = Return code
190: * return: -1 error or >-1 message size for send
191: */
192: int
193: mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char retcode)
194: {
195: int siz = 0;
196: struct mqtthdr *hdr;
197: mqtthdr_connack_t *ack;
198:
199: if (!buf)
200: return -1;
201: if (retcode > MQTT_RETCODE_DENIED) {
1.1.1.1.2.1! misho 202: mqtt_SetErr(EINVAL, "Invalid retcode");
1.1 misho 203: return -1;
204: }
205:
206: if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t)) == -1)
207: return -1;
208: else {
209: hdr = (struct mqtthdr *) (buf->msg_base + siz);
210: siz += sizeof(struct mqtthdr);
211: ack = (mqtthdr_connack_t*) (buf->msg_base + siz);
212: siz += sizeof(mqtthdr_connack_t);
213: }
214:
215: /* fixed header */
216: MQTTHDR_MSGINIT(hdr);
217: hdr->mqtt_msg.type = MQTT_TYPE_CONNACK;
218: *hdr->mqtt_len = sizeof(mqtthdr_connack_t);
219:
220: /* CONNACK header */
221: ack->reserved = 0;
222: ack->retcode = retcode;
223:
224: return siz;
225: }
226:
227: static int
228: _mqtt_msgSIMPLE_(mqtt_msg_t * __restrict buf, u_char cmd)
229: {
230: int siz = 0;
231: struct mqtthdr *hdr;
232:
233: if (!buf)
234: return -1;
235:
236: if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr)) == -1)
237: return -1;
238: else {
239: hdr = (struct mqtthdr *) (buf->msg_base + siz);
240: siz += sizeof(struct mqtthdr);
241: }
242:
243: /* fixed header */
244: MQTTHDR_MSGINIT(hdr);
245: hdr->mqtt_msg.type = cmd;
246: *hdr->mqtt_len = 0;
247:
248: return siz;
249: }
250:
251: /*
252: * mqtt_msgPINGREQ() Create PINGREQ message
253: *
254: * @buf = Message buffer
255: * return: -1 error or >-1 message size for send
256: */
257: int
258: mqtt_msgPINGREQ(mqtt_msg_t * __restrict buf)
259: {
260: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGREQ);
261: }
262:
263: /*
264: * mqtt_msgPINGRESP() Create PINGRESP message
265: *
266: * @buf = Message buffer
267: * return: -1 error or >-1 message size for send
268: */
269: int
270: mqtt_msgPINGRESP(mqtt_msg_t * __restrict buf)
271: {
272: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGRESP);
273: }
274:
275: /*
276: * mqtt_msgDISCONNECT() Create DISCONNECT message
277: *
278: * @buf = Message buffer
279: * return: -1 error or >-1 message size for send
280: */
281: int
282: mqtt_msgDISCONNECT(mqtt_msg_t * __restrict buf)
283: {
284: return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_DISCONNECT);
285: }
286:
287: /* ============= decode ============ */
288:
289: /*
290: * mqtt_readCONNECT() Read elements from CONNECT message
291: *
292: * @buf = Message buffer
293: * @kasec = Keep Alive in seconds for current connection
294: * @psConnID = ConnectID
295: * @connLen = ConnectID length
296: * @psUser = Username if !=NULL
297: * @userLen = Username length
298: * @psPass = Password for Username, only if csUser is set
299: * @passLen = Password length
300: * @psWillTopic = Will Topic if !=NULL Will Flags set into message and must be free()
301: * @psWillMessage = Will Message, may be NULL if !NULL must be free() after use!
302: * return: .reserved == 1 is error or == 0 connection flags & msg ok
303: */
304: mqtthdr_connack_t
305: mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short *kasec, char * __restrict psConnID, int connLen,
306: char * __restrict psUser, int userLen, char * __restrict psPass, int passLen,
307: char ** __restrict psWillTopic, char ** __restrict psWillMessage)
308: {
309: mqtthdr_connflgs_t flg = { MQTT_CONNFLGS_INIT };
310: mqtthdr_connack_t cack = { 1, MQTT_RETCODE_DENIED };
311: struct mqtthdr *hdr;
312: mqtthdr_var_t *var;
313: mqtt_len_t *ka;
314: mqtthdr_protover_t *proto;
315: int len, ret;
316: caddr_t pos;
317:
318: if (!buf || !buf->msg_base || !buf->msg_len || !psConnID || !connLen)
319: return cack;
320:
321: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNECT, &ret, &len);
322: if (!hdr)
323: return cack;
324: if (len < 12) {
1.1.1.1.2.1! misho 325: mqtt_SetErr(EINVAL, "Short message length %d", len);
1.1 misho 326: return cack;
327: } else {
328: pos = buf->msg_base + ret + 1;
329: var = (mqtthdr_var_t*) pos;
330: }
331: /* check init string & protocol */
332: if (var->var_sb.sb.l != 6 || strncmp((char*) var->var_data, MQTT_CONN_STR, 6)) {
1.1.1.1.2.1! misho 333: mqtt_SetErr(EINVAL, "Invalid init string %.6s(%d)",
1.1 misho 334: var->var_data, var->var_sb.sb.l);
335: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
336: return cack;
337: } else {
338: pos += var->var_sb.sb.l + sizeof(mqtt_len_t);
339: proto = (mqtthdr_protover_t*) pos;
340: }
341: if (*proto != MQTT_PROTO_VER) {
1.1.1.1.2.1! misho 342: mqtt_SetErr(EINVAL, "Invalid protocol version %d", *pos);
1.1 misho 343: cack.retcode = MQTT_RETCODE_REFUSE_VER;
344: return cack;
345: } else
346: pos++;
347: flg = *(mqtthdr_connflgs_t*) pos;
348: pos++;
349: ka = (mqtt_len_t*) pos;
350: *kasec = ntohs(ka->val);
351: pos += sizeof(mqtt_len_t);
352:
353: len -= pos - (caddr_t) var;
354:
355: /* get ConnID */
356: var = (mqtthdr_var_t*) pos;
357: len -= MQTTHDR_VAR_SIZEOF(var);
358: if (len < 0 || var->var_sb.sb.l > 23) {
1.1.1.1.2.1! misho 359: mqtt_SetErr(EINVAL, "Unexpected EOM at Connection ID %d", len);
1.1 misho 360: cack.retcode = MQTT_RETCODE_REFUSE_ID;
361: return cack;
362: } else {
363: memset(psConnID, 0, connLen--);
364: memcpy(psConnID, var->var_data, ntohs(var->var_sb.val) > connLen ? connLen : ntohs(var->var_sb.val));
365: pos += MQTTHDR_VAR_SIZEOF(var);
366: }
367:
368: /* get Willz */
369: if (flg.will_flg) {
370: var = (mqtthdr_var_t*) pos;
371: len -= MQTTHDR_VAR_SIZEOF(var);
372: if (len < 0) {
1.1.1.1.2.1! misho 373: mqtt_SetErr(EINVAL, "Unexpected EOM at Will Topic %d", len);
1.1 misho 374: cack.retcode = MQTT_RETCODE_REFUSE_ID;
375: return cack;
376: } else {
377: if (psWillTopic) {
378: *psWillTopic = malloc(ntohs(var->var_sb.val) + 1);
379: if (!*psWillTopic) {
380: LOGERR;
381: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
382: return cack;
383: } else
384: memset(*psWillTopic, 0, ntohs(var->var_sb.val) + 1);
385: memcpy(*psWillTopic, var->var_data, ntohs(var->var_sb.val));
386: }
387: pos += MQTTHDR_VAR_SIZEOF(var);
388: }
389:
390: var = (mqtthdr_var_t*) pos;
391: len -= MQTTHDR_VAR_SIZEOF(var);
392: if (len < 0) {
1.1.1.1.2.1! misho 393: mqtt_SetErr(EINVAL, "Unexpected EOM at Will Message %d", len);
1.1 misho 394: cack.retcode = MQTT_RETCODE_REFUSE_ID;
395: return cack;
396: } else {
397: if (psWillMessage) {
398: *psWillMessage = malloc(ntohs(var->var_sb.val) + 1);
399: if (!*psWillMessage) {
400: LOGERR;
401: cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL;
402: return cack;
403: } else
404: memset(*psWillMessage, 0, ntohs(var->var_sb.val) + 1);
405: memcpy(*psWillMessage, var->var_data, ntohs(var->var_sb.val));
406: }
407: pos += MQTTHDR_VAR_SIZEOF(var);
408: }
409: }
410:
411: /* get User/Pass */
412: if (flg.username) {
413: var = (mqtthdr_var_t*) pos;
414: len -= MQTTHDR_VAR_SIZEOF(var);
415: if (len < 0 || var->var_sb.sb.l > 12) {
1.1.1.1.2.1! misho 416: mqtt_SetErr(EINVAL, "Unexpected EOM at Username %d", len);
1.1 misho 417: cack.retcode = MQTT_RETCODE_REFUSE_USERPASS;
418: return cack;
419: } else {
420: if (psUser && userLen) {
421: memset(psUser, 0, userLen--);
422: memcpy(psUser, var->var_data,
423: ntohs(var->var_sb.val) > userLen ? userLen : ntohs(var->var_sb.val));
424: }
425: pos += MQTTHDR_VAR_SIZEOF(var);
426: }
427: }
428: if (flg.password) {
429: var = (mqtthdr_var_t*) pos;
430: len -= MQTTHDR_VAR_SIZEOF(var);
431: if (len < 0 || var->var_sb.sb.l > 12) {
1.1.1.1.2.1! misho 432: mqtt_SetErr(EINVAL, "Unexpected EOM at Password %d", len);
1.1 misho 433: cack.retcode = MQTT_RETCODE_REFUSE_USERPASS;
434: return cack;
435: } else {
436: if (psPass && passLen) {
437: memset(psPass, 0, passLen--);
438: memcpy(psPass, var->var_data,
439: ntohs(var->var_sb.val) > passLen ? passLen : ntohs(var->var_sb.val));
440: }
441: pos += MQTTHDR_VAR_SIZEOF(var);
442: }
443: }
444:
445: flg.reserved = 0;
446: cack.reserved = flg.flags;
447: cack.retcode = MQTT_RETCODE_ACCEPTED;
448: return cack;
449: }
450:
451: /*
452: * mqtt_readCONNACK() Read CONNACK message
453: *
454: * @buf = Message buffer
455: * return: -1 error or >-1 CONNECT message return code
456: */
457: u_char
458: mqtt_readCONNACK(mqtt_msg_t * __restrict buf)
459: {
460: int len, ret;
461: struct mqtthdr *hdr;
462: mqtthdr_connack_t *ack;
463: caddr_t pos;
464:
465: if (!buf || !buf->msg_base || !buf->msg_len)
466: return (u_char) -1;
467:
468: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNACK, &ret, &len);
469: if (!hdr)
470: return (u_char) -1;
471: if (len < sizeof(mqtthdr_connack_t)) {
1.1.1.1.2.1! misho 472: mqtt_SetErr(EINVAL, "Short message length %d", len);
1.1 misho 473: return (u_char) -1;
474: } else {
475: pos = buf->msg_base + ret + 1;
476: ack = (mqtthdr_connack_t*) pos;
477: }
478:
479: if (ack->retcode > MQTT_RETCODE_DENIED) {
1.1.1.1.2.1! misho 480: mqtt_SetErr(EINVAL, "Invalid retcode %u", ack->retcode);
1.1 misho 481: return (u_char) -1;
482: }
483:
484: return ack->retcode;
485: }
486:
487: /*
488: * mqtt_readDISCONNECT() Read DISCONNECT message
489: *
490: * @buf = Message buffer
491: * return: -1 error, 0 ok, >0 undefined result
492: */
493: int
494: mqtt_readDISCONNECT(mqtt_msg_t * __restrict buf)
495: {
496: int len, ret;
497: struct mqtthdr *hdr;
498:
499: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_DISCONNECT, &ret, &len);
500: if (!hdr || ret != 1)
501: return -1;
502:
503: return len;
504: }
505:
506: /*
507: * mqtt_readPINGREQ() Read PINGREQ message
508: *
509: * @buf = Message buffer
510: * return: -1 error, 0 ok, >0 undefined result
511: */
512: int
513: mqtt_readPINGREQ(mqtt_msg_t * __restrict buf)
514: {
515: int len, ret;
516: struct mqtthdr *hdr;
517:
518: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGREQ, &ret, &len);
519: if (!hdr || ret != 1)
520: return -1;
521:
522: return len;
523: }
524:
525: /*
526: * mqtt_readPINGRESP() Read PINGRESP message
527: *
528: * @buf = Message buffer
529: * return: -1 error, 0 ok, >0 undefined result
530: */
531: int
532: mqtt_readPINGRESP(mqtt_msg_t * __restrict buf)
533: {
534: int len, ret;
535: struct mqtthdr *hdr;
536:
537: hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGRESP, &ret, &len);
538: if (!hdr || ret != 1)
539: return -1;
540:
541: return len;
542: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>