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