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