Annotation of libaitmqtt/src/aitmqtt.c, revision 1.2
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.2 ! misho 6: * $Id: aitmqtt.c,v 1.1.1.1.2.16 2012/06/20 08:15:13 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: #pragma GCC visibility push(hidden)
50:
51: int mqtt_Errno;
52: char mqtt_Error[STRSIZ];
53:
54: #pragma GCC visibility pop
55:
56: // mqtt_GetErrno() Get error code of last operation
57: inline int
58: mqtt_GetErrno()
59: {
60: return mqtt_Errno;
61: }
62:
63: // mqtt_GetError() Get error text of last operation
64: inline const char *
65: mqtt_GetError()
66: {
67: return mqtt_Error;
68: }
69:
70: // mqtt_SetErr() Set error to variables for internal use!!!
71: inline void
72: mqtt_SetErr(int eno, char *estr, ...)
73: {
74: va_list lst;
75:
76: mqtt_Errno = eno;
77: memset(mqtt_Error, 0, sizeof mqtt_Error);
78: va_start(lst, estr);
79: vsnprintf(mqtt_Error, sizeof mqtt_Error, estr, lst);
80: va_end(lst);
81: }
82:
83: #pragma GCC visibility push(hidden)
1.2 ! misho 84: /* _mqtt_readHEADER() read fixed header from MQTT message */
1.1 misho 85: inline struct mqtthdr *
86: _mqtt_readHEADER(mqtt_msg_t * __restrict buf, u_char cmd, int *bytes, int *len)
87: {
88: struct mqtthdr *hdr;
89:
90: if (!buf || !buf->msg_base || !buf->msg_len)
91: return NULL;
92:
93: hdr = (struct mqtthdr*) buf->msg_base;
94: if (hdr->mqtt_msg.type != cmd) {
95: mqtt_SetErr(EINVAL, "Error:: wrong command #%d should be %d",
96: hdr->mqtt_msg.type, cmd);
97: return NULL;
98: }
99:
100: *len = mqtt_decodeLen(hdr->mqtt_len, bytes);
101: return hdr;
102: }
103: #pragma GCC visibility pop
104:
105:
106: /*
107: * mqtt_msgFree() Free MQTT message
108: *
109: * @msg = Message buffer
110: * @all = !=0 Destroy entire message, if MQTT Message allocated with mqtt_msgAlloc()
111: * return: none
112: */
113: inline void
114: mqtt_msgFree(mqtt_msg_t ** __restrict msg, int all)
115: {
116: if (msg && *msg) {
117: if ((*msg)->msg_base) {
118: free((*msg)->msg_base);
119: (*msg)->msg_base = NULL;
120: }
121: if (all) {
122: free(*msg);
123: *msg = NULL;
124: } else
125: (*msg)->msg_len ^= (*msg)->msg_len;
126: }
127: }
128:
129: /*
130: * mqtt_msgAlloc() Allocate memory for MQTT Message
131: *
132: * @len = >0 Allocate buffer with length
133: * return: NULL error or Message, after use must call mqtt_msgFree() with all!=0
134: */
135: inline mqtt_msg_t *
136: mqtt_msgAlloc(u_short len)
137: {
138: mqtt_msg_t *m = NULL;
139:
140: m = malloc(sizeof(mqtt_msg_t));
141: if (!m) {
142: LOGERR;
143: return NULL;
144: } else
145: memset(m, 0, sizeof(mqtt_msg_t));
146:
147: if (len) {
148: m->msg_len = len;
149: m->msg_base = malloc(m->msg_len);
150: if (!m->msg_base) {
151: LOGERR;
152: free(m);
153: return NULL;
154: } else
155: memset(m->msg_base, 0, m->msg_len);
156: }
157:
158: return m;
159: }
160:
161: /*
162: * mqtt_msgRealloc() Reallocate MQTT message buffer
163: *
164: * @msg = MQTT message
165: * @len = new length
166: * return: -1 error or >-1 old buffer length
167: */
168: inline int
169: mqtt_msgRealloc(mqtt_msg_t * __restrict msg, u_short len)
170: {
171: void *p = NULL;
172: int ret = 0;
173:
174: if (!msg)
175: return -1;
176:
1.2 ! misho 177: if (len <= msg->msg_len)
1.1 misho 178: return len;
179:
180: p = realloc(msg->msg_base, len);
181: if (!p) {
182: LOGERR;
183: return -1;
184: }
185:
186: ret = msg->msg_len;
187: msg->msg_len = len;
188: msg->msg_base = p;
189:
190: return ret;
191: }
192:
193: /*
1.2 ! misho 194: * mqtt_msgDup() - Duplicate message buffer
! 195: *
! 196: * @msg = Message
! 197: * return: NULL error or !=NULL duplicated message, after use must call mqtt_msgFree() with all!=0
! 198: */
! 199: inline mqtt_msg_t *
! 200: mqtt_msgDup(mqtt_msg_t * __restrict msg)
! 201: {
! 202: mqtt_msg_t *m = NULL;
! 203:
! 204: m = malloc(sizeof(mqtt_msg_t));
! 205: if (!m) {
! 206: LOGERR;
! 207: return NULL;
! 208: } else
! 209: memset(m, 0, sizeof(mqtt_msg_t));
! 210:
! 211: if (msg->msg_len) {
! 212: m->msg_len = msg->msg_len;
! 213: m->msg_base = malloc(m->msg_len);
! 214: if (!m->msg_base) {
! 215: LOGERR;
! 216: free(m);
! 217: return NULL;
! 218: } else
! 219: memcpy(m->msg_base, msg->msg_base, m->msg_len);
! 220: }
! 221:
! 222: return m;
! 223: }
! 224:
! 225: /*
1.1 misho 226: * mqtt_encodeLen() Encode number to MQTT length field
227: *
228: * @num = number for encode
229: * return: -1 error or >-1 length
230: */
231: inline u_int
232: mqtt_encodeLen(u_int num)
233: {
234: register u_int dig, i;
235: u_int ret = 0;
236:
237: if (num > 268435455)
238: return (u_int) -1;
239:
240: for (i = 0; i < sizeof ret && num > 0; i++) {
241: dig = num % 0x80;
242: num /= 0x80;
243: if (num > 0)
244: dig |= 0x80;
245:
246: *((u_char*) &ret + i) = (u_char) dig;
247: }
248:
249: return ret;
250: }
251:
252: /*
253: * mqtt_decodeLen() Decode length from MQTT packet
254: *
255: * @len = length from MQTT header
256: * @n = sizeof bytes, if !=NULL
257: * return: -1 error, >-1 length of message
258: */
259: inline u_int
260: mqtt_decodeLen(void * __restrict len, int * __restrict n)
261: {
262: register u_int i, dig, mul;
263: u_int ret = 0;
264: u_char *p = (u_char*) len;
265:
266: if (!len)
267: return (u_int) -1;
268:
269: for (mul = 1, i = 0; i < sizeof ret; i++, mul *= 0x80) {
270: dig = p[i];
271: ret += (dig & 0x7f) * mul;
272:
273: if (!(dig & 0x80))
274: break;
275: }
276:
277: if (n)
278: *n = (char) (i & 0x7f) + 1;
279: return ret;
280: }
281:
282: /*
283: * mqtt_sizeLen Return sizeof len field
284: *
285: * @len = length
286: * return: -1 error, >-1 sizeof len in bytes
287: */
288: inline char
289: mqtt_sizeLen(u_int len)
290: {
291: register char i;
292: u_char *p = (u_char*) &len;
293:
294: if (len > 0xffffff7f)
295: return -1;
296:
297: for (i = 0; i < sizeof len; i++)
298: if (!(*(p + i) & 0x80))
299: break;
300:
301: return ++i;
302: }
303:
304: /*
1.2 ! misho 305: * mqtt_pktLen() - Get total packet length
! 306: *
! 307: * @hdr = MQTT packet header
! 308: * return: packet length
! 309: */
! 310: inline u_int
! 311: mqtt_pktLen(struct mqtthdr * __restrict hdr)
! 312: {
! 313: int siz, n = 0;
! 314:
! 315: if (!hdr)
! 316: return 0;
! 317:
! 318: siz = mqtt_decodeLen(hdr->mqtt_len, &n);
! 319: siz += sizeof(struct mqtthdr) + n - 1;
! 320:
! 321: return siz;
! 322: }
! 323:
! 324: /*
! 325: * mqtt_str2subs Create MQTT subscribe variable from string(s)
1.1 misho 326: *
1.2 ! misho 327: * @csStr = null terminated string array
! 328: * @strnum = copy at most number of strings elements
1.1 misho 329: * @qoses = QoS elements applied to subscribe variable,
330: * count of elements must be equal with csStr elements
331: * return: NULL error or != subscribe variables array, must be free after use with mqtt_freeSub()
332: */
333: inline mqtt_subscr_t *
1.2 ! misho 334: mqtt_str2subs(const char **csStr, u_short strnum, u_char *qoses)
1.1 misho 335: {
336: mqtt_subscr_t *v;
337: register int i, items;
338: const char **strs;
339:
340: if (!csStr)
341: return NULL;
1.2 ! misho 342:
! 343: for (items = 0, strs = csStr;
! 344: (!strnum || (strnum && items < strnum)) && *strs;
! 345: items++, strs++);
1.1 misho 346:
347: if (!(v = malloc((items + 1) * sizeof(mqtt_subscr_t)))) {
348: LOGERR;
349: return NULL;
350: } else
351: memset(v, 0, (items + 1) * sizeof(mqtt_subscr_t));
352:
353: for (i = 0; i < items; i++) {
354: v[i].sub_topic.msg_len = strlen(csStr[i]);
355: v[i].sub_topic.msg_base = (u_char*) strdup(csStr[i]);
356: if (qoses && qoses[i] < MQTT_QOS_RESERVED)
357: v[i].sub_ret = qoses[i];
358: }
359:
360: return v;
361: }
362:
363: /*
364: * mqtt_subFree() Free array from subscribe variables
365: *
366: * @subs = Subscribe variables
367: * return: none
368: */
369: inline void
370: mqtt_subFree(mqtt_subscr_t ** __restrict subs)
371: {
372: mqtt_subscr_t *v;
373:
374: if (!subs)
375: return;
376:
377: for (v = *subs; v->sub_topic.msg_base; v++) {
378: free(v->sub_topic.msg_base);
379: v->sub_topic.msg_base = NULL;
380: v->sub_topic.msg_len = 0;
381:
382: if (v->sub_value.msg_base) {
383: free(v->sub_value.msg_base);
384: v->sub_value.msg_base = NULL;
385: v->sub_value.msg_len = 0;
386: }
387: }
388:
389: free(*subs);
390: *subs = NULL;
391: }
392:
393: /*
394: * mqtt_subAlloc() Create array from subscribe variables
395: *
396: * @num = Number of elements
397: * return: NULL error or subscribe array, after use must call mqtt_subFree()
398: */
399: inline mqtt_subscr_t *
400: mqtt_subAlloc(u_short num)
401: {
402: mqtt_subscr_t *s = NULL;
403:
404: s = malloc((num + 1) * sizeof(mqtt_subscr_t));
405: if (!s) {
406: LOGERR;
407: return NULL;
408: } else
409: memset(s, 0, (num + 1) * sizeof(mqtt_subscr_t));
410:
411: return s;
412: }
413:
414: /*
415: * mqtt_subRealloc() Reallocate array from subscribe variables
416: *
417: * @subs = Subscribe array
418: * @num = Number of elements
419: * return: NULL error or subscribe array, after use must call mqtt_subFree()
420: */
421: inline mqtt_subscr_t *
1.2 ! misho 422: mqtt_subRealloc(mqtt_subscr_t ** __restrict subs, u_short num)
1.1 misho 423: {
424: mqtt_subscr_t *s = NULL;
425:
1.2 ! misho 426: if (!subs)
! 427: return NULL;
! 428:
! 429: s = realloc(*subs, (num + 1) * sizeof(mqtt_subscr_t));
1.1 misho 430: if (!s) {
431: LOGERR;
432: return NULL;
1.2 ! misho 433: } else {
! 434: memset(s + num, 0, sizeof(mqtt_subscr_t));
! 435: *subs = s;
! 436: }
! 437:
! 438: return *subs;
! 439: }
! 440:
! 441: /*
! 442: * mqtt_subCopy() - Copy subscription structure to another one
! 443: *
! 444: * @dst = destination subscription
! 445: * @src = source subscription
! 446: * return: =NULL error or !=NULL successful copied a structure
! 447: */
! 448: inline mqtt_subscr_t *
! 449: mqtt_subCopy(mqtt_subscr_t * __restrict dst, mqtt_subscr_t * __restrict src)
! 450: {
! 451: if (!dst || !src)
! 452: return NULL;
! 453:
! 454: if (src->sub_topic.msg_base) {
! 455: dst->sub_topic.msg_base = malloc(src->sub_topic.msg_len + 1);
! 456: if (!dst->sub_topic.msg_base) {
! 457: LOGERR;
! 458: memset(dst, 0, sizeof(mqtt_subscr_t));
! 459: return NULL;
! 460: } else {
! 461: dst->sub_topic.msg_len = src->sub_topic.msg_len;
! 462: ((char*) dst->sub_topic.msg_base)[dst->sub_topic.msg_len] = 0;
! 463: memcpy(dst->sub_topic.msg_base, src->sub_topic.msg_base,
! 464: dst->sub_topic.msg_len);
! 465: }
! 466: } else {
! 467: /*
! 468: if (dst->sub_topic.msg_base)
! 469: free(dst->sub_topic.msg_base);
! 470: */
! 471: dst->sub_topic.msg_base = NULL;
! 472: dst->sub_topic.msg_len = 0;
! 473: }
! 474: if (src->sub_value.msg_base) {
! 475: dst->sub_value.msg_base = malloc(src->sub_value.msg_len + 1);
! 476: if (!dst->sub_value.msg_base) {
! 477: LOGERR;
! 478: if (dst->sub_topic.msg_base)
! 479: free(dst->sub_topic.msg_base);
! 480: memset(dst, 0, sizeof(mqtt_subscr_t));
! 481: return NULL;
! 482: } else {
! 483: dst->sub_value.msg_len = src->sub_value.msg_len;
! 484: ((char*) dst->sub_value.msg_base)[dst->sub_value.msg_len] = 0;
! 485: memcpy(dst->sub_value.msg_base, src->sub_value.msg_base,
! 486: dst->sub_value.msg_len);
! 487: }
! 488: } else {
! 489: /*
! 490: if (dst->sub_value.msg_base)
! 491: free(dst->sub_value.msg_base);
! 492: */
! 493: dst->sub_value.msg_base = NULL;
! 494: dst->sub_value.msg_len = 0;
! 495: }
! 496:
! 497: dst->sub_ret = src->sub_ret;
! 498: return dst;
! 499: }
! 500:
! 501:
! 502: /*
! 503: * mqtt_expandTopic() - Expanding topic to regular expression
! 504: *
! 505: * @csInput = Input topic
! 506: * @psRegEx = Output to regular expression
! 507: * @regexLen = Length of psRegEx
! 508: * @BOL = Begin of Line, if =0 not added
! 509: * @EOL = End of Line, if =0 not appended
! 510: * return: -1 error, 0 nothing expanded or >0 expanded bytes
! 511: */
! 512: int
! 513: mqtt_expandTopic(const char *csInput, char * __restrict psRegEx, int regexLen, u_char BOL, u_char EOL)
! 514: {
! 515: int ret = 0;
! 516: register int i;
! 517: char *pos, *s;
! 518: const char reROM[] = "[](){}^$\\-|?.+*";
! 519:
! 520: if (!csInput || !psRegEx || regexLen < 1)
! 521: return -1;
! 522: else
! 523: memset(psRegEx, 0, regexLen);
! 524:
! 525: /* check # */
! 526: for (i = 0, pos = (char*) csInput; *pos && i < 2; pos++)
! 527: if (*pos == '#')
! 528: i++;
! 529: if (i == 2) {
! 530: mqtt_SetErr(EINVAL, "Syntax error, multiple occurrences of #..#");
! 531: return -1;
! 532: }
! 533: if (i == 1 && (pos = strrchr(csInput, '#')))
! 534: if ((pos != csInput && *(pos - 1) != '/') || *(pos + 1)) {
! 535: mqtt_SetErr(EINVAL, "Syntax error, bad format of #");
! 536: return -1;
! 537: }
! 538: /* check + */
! 539: for (pos = (char*) csInput; *pos && (pos = strchr(pos, '+')); pos++)
! 540: if ((pos != csInput && *(pos - 1) != '/') || (*(pos + 1) && *(pos + 1) != '/')) {
! 541: mqtt_SetErr(EINVAL, "Syntax error, bad format of +");
! 542: return -1;
! 543: }
! 544:
! 545: /* BUILD REGEX */
! 546: s = psRegEx;
! 547: if (BOL) {
! 548: *s++ = '^';
! 549: ret++;
! 550: }
! 551: for (pos = (char*) csInput; s < psRegEx + regexLen && *pos; s++, pos++) {
! 552: if (*pos == '#') {
! 553: strlcat(s, ".*", regexLen - (s - psRegEx));
! 554: s++;
! 555: ret++;
! 556: break;
! 557: }
! 558: if (*pos == '+') {
! 559: if (*(pos + 1)) {
! 560: strlcat(s, ".*", regexLen - (s - psRegEx));
! 561: s++;
! 562: ret++;
! 563: continue;
! 564: } else {
! 565: strlcat(s, ".*/", regexLen - (s - psRegEx));
! 566: ret += 2;
! 567: break;
! 568: }
! 569: }
! 570: for (i = 0; i < sizeof reROM - 1; i++)
! 571: if (*pos == reROM[i] && regexLen - (s - psRegEx) - 1 > 0) {
! 572: *s++ = '\\';
! 573: ret++;
! 574: break;
! 575: }
! 576:
! 577: *s = *pos;
1.1 misho 578: }
1.2 ! misho 579: if (EOL) {
! 580: strlcat(psRegEx, "$", regexLen);
! 581: ret++;
! 582: }
! 583:
! 584: return ret;
! 585: }
! 586:
! 587: /*
! 588: * mqtt_sqlTopic() - Expanding topic to SQL search string
! 589: *
! 590: * @csInput = Input topic
! 591: * @psSQL = Output to SQL search string
! 592: * @sqlLen = Length of psSQL
! 593: * return: -1 error, 0 changed bytes
! 594: */
! 595: int
! 596: mqtt_sqlTopic(const char *csInput, char * __restrict psSQL, int sqlLen)
! 597: {
! 598: int ret = 0;
! 599: register int i;
! 600: char *pos, *s;
! 601:
! 602: if (!csInput || !psSQL || sqlLen < 1)
! 603: return -1;
! 604: else
! 605: memset(psSQL, 0, sqlLen);
1.1 misho 606:
1.2 ! misho 607: /* check # */
! 608: for (i = 0, pos = (char*) csInput; *pos && i < 2; pos++)
! 609: if (*pos == '#')
! 610: i++;
! 611: if (i == 2) {
! 612: mqtt_SetErr(EINVAL, "Syntax error, multiple occurrences of #..#");
! 613: return -1;
! 614: }
! 615: if (i == 1 && (pos = strrchr(csInput, '#')))
! 616: if ((pos != csInput && *(pos - 1) != '/') || *(pos + 1)) {
! 617: mqtt_SetErr(EINVAL, "Syntax error, bad format of #");
! 618: return -1;
! 619: }
! 620: /* check + */
! 621: for (pos = (char*) csInput; *pos && (pos = strchr(pos, '+')); pos++)
! 622: if ((pos != csInput && *(pos - 1) != '/') || (*(pos + 1) && *(pos + 1) != '/')) {
! 623: mqtt_SetErr(EINVAL, "Syntax error, bad format of +");
! 624: return -1;
! 625: }
! 626:
! 627: /* BUILD SEARCH STRING */
! 628: s = psSQL;
! 629: for (pos = (char*) csInput; s < psSQL + sqlLen && *pos; s++, pos++) {
! 630: if (*pos == '#') {
! 631: *s = '%';
! 632: s++;
! 633: ret++;
! 634: break;
! 635: }
! 636: if (*pos == '+') {
! 637: if (*(pos + 1)) {
! 638: *s = '%';
! 639: ret++;
! 640: continue;
! 641: } else {
! 642: strlcat(s, "%/", sqlLen - (s - psSQL));
! 643: ret += 2;
! 644: break;
! 645: }
! 646: }
! 647: /*
! 648: for (i = 0; i < sizeof reROM - 1; i++)
! 649: if (*pos == reROM[i] && regexLen - (s - psRegEx) - 1 > 0) {
! 650: *s++ = '\\';
! 651: ret++;
! 652: break;
! 653: }
! 654: */
! 655:
! 656: *s = *pos;
! 657: }
! 658:
! 659: return ret;
1.1 misho 660: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>