--- libaitmqtt/src/conn.c 2012/06/28 11:06:17 1.3 +++ libaitmqtt/src/conn.c 2022/09/14 14:32:48 1.3.12.3 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: conn.c,v 1.3 2012/06/28 11:06:17 misho Exp $ +* $Id: conn.c,v 1.3.12.3 2022/09/14 14:32:48 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -12,7 +12,7 @@ terms: All of the documentation and software included in the ELWIX and AITNET Releases is copyrighted by ELWIX - Sofia/Bulgaria -Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Copyright 2004 - 2022 by Michael Pounov . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -49,9 +49,9 @@ SUCH DAMAGE. /* * mqtt_msgCONNECT() Create CONNECT message * - * @buf = Message buffer * @csConnID = ConnectID - * @kasec = Keep alive timeout, if =0 default timeout for MQTT + * @Version = MQTT version, if =0 default version is 3.1.1 + * @KASec = Keep alive timeout, if =0 default timeout for MQTT * @csUser = Username if !=NULL * @csPass = Password for Username, only if csUser is set * @csWillTopic = Will Topic if !=NULL Will Flags set into message @@ -59,44 +59,51 @@ SUCH DAMAGE. * @ClrSess = Clear Session subscriptions after disconnect * @WillQOS = Will QOS if csWillTopic is set * @WillRetain = Will Retain Will Message if csWillTopic is set - * return: -1 error or >-1 message size for send + * return: NULL error or allocated CONNECT message */ -int -mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const char *csConnID, - u_short kasec, const char *csUser, const char *csPass, +mqtt_msg_t * +mqtt_msgCONNECT(const char *csConnID, u_char Version, u_short KASec, + const char *csUser, const char *csPass, const char *csWillTopic, const char *csWillMessage, u_char ClrSess, u_char WillQOS, u_char WillRetain) { int len, siz = 0; u_int n, *l; + mqtt_msg_t *msg = NULL; struct mqtthdr *hdr; mqtthdr_var_t *var, *cid, *topic, *wmsg, *user, *pass; - mqtthdr_protover_t *proto; mqtthdr_connflgs_t *flags; mqtt_len_t *ka; void *data; - if (!buf || !csConnID) - return -1; - if (strlen(csConnID) > 23) { - mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max 23 bytes)"); - return -1; + if (!csConnID) + return NULL; + if (strlen(csConnID) >= MQTT_CONNID_MAX) { + mqtt_SetErr(EINVAL, "Invalid argument ConnID is too long (max %d bytes)", + MQTT_CONNID_MAX - 1); + return NULL; } - if (csUser && strlen(csUser) > 12) { - mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max 12 bytes)"); - return -1; + if (Version && (Version < MQTT_PROTO_VER_3 || Version > MQTT_PROTO_VER_5)) { + mqtt_SetErr(EINVAL, "Unsupported version"); + return NULL; } - if (csPass && strlen(csPass) > 12) { - mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max 12 bytes)"); - return -1; + if (csUser && strlen(csUser) >= MQTT_CRED_MAX) { + mqtt_SetErr(EINVAL, "Invalid argument Username is too long (max %d bytes)", + MQTT_CRED_MAX - 1); + return NULL; } + if (csPass && strlen(csPass) >= MQTT_CRED_MAX) { + mqtt_SetErr(EINVAL, "Invalid argument Password is too long (max %d bytes)", + MQTT_CRED_MAX - 1); + return NULL; + } if (WillQOS > MQTT_QOS_EXACTLY) { mqtt_SetErr(EINVAL, "Invalid argument WillQOS - unknown QOS value"); - return -1; + return NULL; } /* calculate message size */ - len = 10 + sizeof(mqtt_len_t); /* connect arguments */ + len = 10; /* connect arguments: MQTT(6)+Version(1)+ConnFlags(1)+KeepAlive(2) */ len += sizeof(mqtt_len_t) + strlen(csConnID); /* connect id */ if (csUser && *csUser) { /* user/pass */ len += sizeof(mqtt_len_t) + strlen(csUser); @@ -113,15 +120,14 @@ mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha n = mqtt_encodeLen(len); /* message size */ siz += mqtt_sizeLen(n) - 1; /* length size */ - if (mqtt_msgRealloc(buf, siz + len) == -1) - return -1; + if (!(msg = mqtt_msgAlloc(siz + len))) + return NULL; else { - data = buf->msg_base; + data = msg->msg_base; hdr = (struct mqtthdr *) data; } /* fixed header */ - MQTTHDR_MSGINIT(hdr); hdr->mqtt_msg.type = MQTT_TYPE_CONNECT; l = (u_int*) hdr->mqtt_len; *l = n; @@ -129,13 +135,12 @@ mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha /* variable header */ var = (mqtthdr_var_t*) data; - var->var_sb.val = htons(strlen(MQTT_CONN_STR)); - memcpy(var->var_data, MQTT_CONN_STR, ntohs(var->var_sb.val)); + var->var_sb.val = htons(strlen(MQTT_PROTO_STR)); + memcpy(var->var_data, MQTT_PROTO_STR, ntohs(var->var_sb.val)); data += MQTTHDR_VAR_SIZEOF(var); /* protocol version */ - proto = (mqtthdr_protover_t*) data++; - *proto = MQTT_PROTO_VER; + *(u_char*) data++ = Version ? Version : MQTT_PROTO_VER_311; /* CONNECT header */ flags = (mqtthdr_connflgs_t*) data++; @@ -159,7 +164,7 @@ mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha /* keep alive */ ka = (mqtt_len_t*) data; - ka->val = kasec ? htons(kasec) : htons(MQTT_KEEPALIVE); + ka->val = KASec ? htons(KASec) : htons(MQTT_KEEPALIVE); data += sizeof(mqtt_len_t); /* ConnID */ @@ -199,41 +204,35 @@ mqtt_msgCONNECT(mqtt_msg_t * __restrict buf, const cha } } - return siz + len; + return msg; } /* * mqtt_msgCONNACK() Create CONNACK message * - * @buf = Message buffer * @retcode = Return code - * return: -1 error or >-1 message size for send + * return: NULL error or allocated CONNACK message */ -int -mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char retcode) +mqtt_msg_t * +mqtt_msgCONNACK(u_char retcode) { - int siz = 0; struct mqtthdr *hdr; mqtthdr_connack_t *ack; + mqtt_msg_t *msg = NULL; - if (!buf) - return -1; if (retcode > MQTT_RETCODE_DENIED) { mqtt_SetErr(EINVAL, "Invalid retcode"); - return -1; + return NULL; } - if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t)) == -1) - return -1; + if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr) + sizeof(mqtthdr_connack_t)))) + return NULL; else { - hdr = (struct mqtthdr *) (buf->msg_base + siz); - siz += sizeof(struct mqtthdr); - ack = (mqtthdr_connack_t*) (buf->msg_base + siz); - siz += sizeof(mqtthdr_connack_t); + hdr = (struct mqtthdr *) msg->msg_base; + ack = (mqtthdr_connack_t*) msg->msg_base + sizeof(struct mqtthdr); } /* fixed header */ - MQTTHDR_MSGINIT(hdr); hdr->mqtt_msg.type = MQTT_TYPE_CONNACK; *hdr->mqtt_len = sizeof(mqtthdr_connack_t); @@ -241,88 +240,107 @@ mqtt_msgCONNACK(mqtt_msg_t * __restrict buf, u_char re ack->reserved = 0; ack->retcode = retcode; - return siz; + return msg; } -static int -_mqtt_msgSIMPLE_(mqtt_msg_t * __restrict buf, u_char cmd) +static mqtt_msg_t * +_mqtt_msgSIMPLE_(u_char cmd) { - int siz = 0; struct mqtthdr *hdr; + mqtt_msg_t *msg = NULL; - if (!buf) - return -1; + if (!(msg = mqtt_msgAlloc(sizeof(struct mqtthdr)))) + return NULL; + else + hdr = (struct mqtthdr *) msg->msg_base; - if (mqtt_msgRealloc(buf, sizeof(struct mqtthdr)) == -1) - return -1; - else { - hdr = (struct mqtthdr *) (buf->msg_base + siz); - siz += sizeof(struct mqtthdr); - } - /* fixed header */ - MQTTHDR_MSGINIT(hdr); hdr->mqtt_msg.type = cmd; *hdr->mqtt_len = 0; - return siz; + return msg; } /* * mqtt_msgPINGREQ() Create PINGREQ message * - * @buf = Message buffer - * return: -1 error or >-1 message size for send + * return: NULL error or allocated message */ -int -mqtt_msgPINGREQ(mqtt_msg_t * __restrict buf) +mqtt_msg_t * +mqtt_msgPINGREQ() { - return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGREQ); + return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGREQ); } /* * mqtt_msgPINGRESP() Create PINGRESP message * - * @buf = Message buffer - * return: -1 error or >-1 message size for send + * return: NULL error or allocated message */ -int -mqtt_msgPINGRESP(mqtt_msg_t * __restrict buf) +mqtt_msg_t * +mqtt_msgPINGRESP() { - return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_PINGRESP); + return _mqtt_msgSIMPLE_(MQTT_TYPE_PINGRESP); } /* * mqtt_msgDISCONNECT() Create DISCONNECT message * - * @buf = Message buffer - * return: -1 error or >-1 message size for send + * return: NULL error or allocated message */ -int -mqtt_msgDISCONNECT(mqtt_msg_t * __restrict buf) +mqtt_msg_t * +mqtt_msgDISCONNECT() { - return _mqtt_msgSIMPLE_(buf, MQTT_TYPE_DISCONNECT); + return _mqtt_msgSIMPLE_(MQTT_TYPE_DISCONNECT); } /* ============= decode ============ */ +//#pragma GCC visibility push(hidden) +/* _mqtt_readHEADER() read fixed header from MQTT message */ +static struct mqtthdr * +_mqtt_readHEADER(mqtt_msg_t * __restrict buf, u_char cmd, int *len, caddr_t *next) +{ + struct mqtthdr *hdr; + int bytes; + + if (!buf || !buf->msg_base || !buf->msg_len) + return NULL; + + hdr = (struct mqtthdr*) buf->msg_base; + if (hdr->mqtt_msg.type != cmd) { + mqtt_SetErr(EINVAL, "Error:: wrong command #%d should be %d", + hdr->mqtt_msg.type, cmd); + return NULL; + } + + if (len) + *len = mqtt_decodeLen(hdr->mqtt_len, &bytes); + + if (next) + *next = buf->msg_base + bytes + 1; + + return hdr; +} +//#pragma GCC visibility pop + /* * mqtt_readCONNECT() Read elements from CONNECT message * * @buf = Message buffer - * @kasec = Keep Alive in seconds for current connection + * @KASec = Keep Alive in seconds for current connection * @psConnID = ConnectID * @connLen = ConnectID length * @psUser = Username if !=NULL * @userLen = Username length * @psPass = Password for Username, only if csUser is set * @passLen = Password length - * @psWillTopic = Will Topic if !=NULL Will Flags set into message and must be free() - * @psWillMessage = Will Message, may be NULL if !NULL must be free() after use! + * @psWillTopic = Will Topic if !=NULL Will Flags set into message and must be e_free() + * @psWillMessage = Will Message, may be NULL if !NULL must be e_free() after use! * return: .reserved == 1 is error or == 0 connection flags & msg ok */ mqtthdr_connack_t -mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short *kasec, char * __restrict psConnID, int connLen, +mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short *KASec, char * __restrict psConnID, int connLen, char * __restrict psUser, int userLen, char * __restrict psPass, int passLen, char ** __restrict psWillTopic, char ** __restrict psWillMessage) { @@ -331,43 +349,47 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short struct mqtthdr *hdr; mqtthdr_var_t *var; mqtt_len_t *ka; - mqtthdr_protover_t *proto; - int len, ret; + int len; caddr_t pos; if (!buf || !buf->msg_base || !buf->msg_len || !psConnID || !connLen) return cack; - hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNECT, &ret, &len); + hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNECT, &len, &pos); if (!hdr) return cack; if (len < 12) { mqtt_SetErr(EINVAL, "Short message length %d", len); return cack; - } else { - pos = buf->msg_base + ret + 1; + } else var = (mqtthdr_var_t*) pos; - } + /* check init string & protocol */ - if (var->var_sb.sb.l != 6 || strncmp((char*) var->var_data, MQTT_CONN_STR, 6)) { + if (var->var_sb.sb.l == 4 && !strcmp((char*) var->var_data, MQTT_PROTO_STR)) + pos += var->var_sb.sb.l + sizeof(mqtt_len_t); + else if (var->var_sb.sb.l == 6 || strcmp((char*) var->var_data, MQTT_CONN_STR)) + pos += var->var_sb.sb.l + sizeof(mqtt_len_t); + else { mqtt_SetErr(EINVAL, "Invalid init string %.6s(%d)", var->var_data, var->var_sb.sb.l); cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; return cack; - } else { - pos += var->var_sb.sb.l + sizeof(mqtt_len_t); - proto = (mqtthdr_protover_t*) pos; } - if (*proto != MQTT_PROTO_VER) { - mqtt_SetErr(EINVAL, "Invalid protocol version %d", *pos); - cack.retcode = MQTT_RETCODE_REFUSE_VER; - return cack; - } else - pos++; + switch (*pos) { + case MQTT_PROTO_VER_3: + case MQTT_PROTO_VER_311: + case MQTT_PROTO_VER_5: + pos++; + break; + default: + mqtt_SetErr(EINVAL, "Invalid protocol version %d", *pos); + cack.retcode = MQTT_RETCODE_REFUSE_VER; + return cack; + } flg = *(mqtthdr_connflgs_t*) pos; pos++; ka = (mqtt_len_t*) pos; - *kasec = ntohs(ka->val); + *KASec = ntohs(ka->val); pos += sizeof(mqtt_len_t); len -= pos - (caddr_t) var; @@ -375,13 +397,14 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short /* get ConnID */ var = (mqtthdr_var_t*) pos; len -= MQTTHDR_VAR_SIZEOF(var); - if (len < 0 || var->var_sb.sb.l > 23) { + if (len < 0 || var->var_sb.sb.l >= MQTT_CONNID_MAX) { mqtt_SetErr(EINVAL, "Unexpected EOM at Connection ID %d", len); cack.retcode = MQTT_RETCODE_REFUSE_ID; return cack; } else { memset(psConnID, 0, connLen--); - memcpy(psConnID, var->var_data, ntohs(var->var_sb.val) > connLen ? connLen : ntohs(var->var_sb.val)); + memcpy(psConnID, var->var_data, + ntohs(var->var_sb.val) > connLen ? connLen : ntohs(var->var_sb.val)); pos += MQTTHDR_VAR_SIZEOF(var); } @@ -395,7 +418,7 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short return cack; } else { if (psWillTopic) { - *psWillTopic = malloc(ntohs(var->var_sb.val) + 1); + *psWillTopic = e_malloc(ntohs(var->var_sb.val) + 1); if (!*psWillTopic) { LOGERR; cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; @@ -411,13 +434,15 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short len -= MQTTHDR_VAR_SIZEOF(var); if (len < 0) { mqtt_SetErr(EINVAL, "Unexpected EOM at Will Message %d", len); + e_free(psWillTopic); cack.retcode = MQTT_RETCODE_REFUSE_ID; return cack; } else { if (psWillMessage) { - *psWillMessage = malloc(ntohs(var->var_sb.val) + 1); + *psWillMessage = e_malloc(ntohs(var->var_sb.val) + 1); if (!*psWillMessage) { LOGERR; + e_free(psWillTopic); cack.retcode = MQTT_RETCODE_REFUSE_UNAVAIL; return cack; } else @@ -434,6 +459,12 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short len -= MQTTHDR_VAR_SIZEOF(var); if (len < 0 || var->var_sb.sb.l > 12) { mqtt_SetErr(EINVAL, "Unexpected EOM at Username %d", len); + if (flg.will_flg) { + if (psWillTopic) + e_free(psWillTopic); + if (psWillMessage) + e_free(psWillMessage); + } cack.retcode = MQTT_RETCODE_REFUSE_USERPASS; return cack; } else { @@ -450,6 +481,12 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short len -= MQTTHDR_VAR_SIZEOF(var); if (len < 0 || var->var_sb.sb.l > 12) { mqtt_SetErr(EINVAL, "Unexpected EOM at Password %d", len); + if (flg.will_flg) { + if (psWillTopic) + e_free(psWillTopic); + if (psWillMessage) + e_free(psWillMessage); + } cack.retcode = MQTT_RETCODE_REFUSE_USERPASS; return cack; } else { @@ -477,7 +514,7 @@ mqtt_readCONNECT(mqtt_msg_t * __restrict buf, u_short u_char mqtt_readCONNACK(mqtt_msg_t * __restrict buf) { - int len, ret; + int len; struct mqtthdr *hdr; mqtthdr_connack_t *ack; caddr_t pos; @@ -485,16 +522,14 @@ mqtt_readCONNACK(mqtt_msg_t * __restrict buf) if (!buf || !buf->msg_base || !buf->msg_len) return (u_char) -1; - hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNACK, &ret, &len); + hdr = _mqtt_readHEADER(buf, MQTT_TYPE_CONNACK, &len, &pos); if (!hdr) return (u_char) -1; if (len < sizeof(mqtthdr_connack_t)) { mqtt_SetErr(EINVAL, "Short message length %d", len); return (u_char) -1; - } else { - pos = buf->msg_base + ret + 1; + } else ack = (mqtthdr_connack_t*) pos; - } if (ack->retcode > MQTT_RETCODE_DENIED) { mqtt_SetErr(EINVAL, "Invalid retcode %u", ack->retcode); @@ -513,11 +548,9 @@ mqtt_readCONNACK(mqtt_msg_t * __restrict buf) int mqtt_readDISCONNECT(mqtt_msg_t * __restrict buf) { - int len, ret; - struct mqtthdr *hdr; + int len; - hdr = _mqtt_readHEADER(buf, MQTT_TYPE_DISCONNECT, &ret, &len); - if (!hdr || ret != 1) + if (!_mqtt_readHEADER(buf, MQTT_TYPE_DISCONNECT, &len, NULL)) return -1; return len; @@ -532,11 +565,9 @@ mqtt_readDISCONNECT(mqtt_msg_t * __restrict buf) int mqtt_readPINGREQ(mqtt_msg_t * __restrict buf) { - int len, ret; - struct mqtthdr *hdr; + int len; - hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGREQ, &ret, &len); - if (!hdr || ret != 1) + if (!_mqtt_readHEADER(buf, MQTT_TYPE_PINGREQ, &len, NULL)) return -1; return len; @@ -551,11 +582,9 @@ mqtt_readPINGREQ(mqtt_msg_t * __restrict buf) int mqtt_readPINGRESP(mqtt_msg_t * __restrict buf) { - int len, ret; - struct mqtthdr *hdr; + int len; - hdr = _mqtt_readHEADER(buf, MQTT_TYPE_PINGRESP, &ret, &len); - if (!hdr || ret != 1) + if (!_mqtt_readHEADER(buf, MQTT_TYPE_PINGRESP, &len, NULL)) return -1; return len;