--- libaitmqtt/src/cmds.c 2012/05/03 08:21:28 1.1.2.1 +++ libaitmqtt/src/cmds.c 2022/09/15 15:13:31 1.4.2.2 @@ -1,3 +1,175 @@ +/************************************************************************* +* (C) 2011 AITNET ltd - Sofia/Bulgaria - +* by Michael Pounov +* +* $Author: misho $ +* $Id: cmds.c,v 1.4.2.2 2022/09/15 15:13:31 misho Exp $ +* +************************************************************************** +The ELWIX and AITNET software is distributed under the following +terms: + +All of the documentation and software included in the ELWIX and AITNET +Releases is copyrighted by ELWIX - Sofia/Bulgaria + +Copyright 2004 - 2022 + by Michael Pounov . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by Michael Pounov +ELWIX - Embedded LightWeight unIX and its contributors. +4. Neither the name of AITNET nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ #include "global.h" +#pragma GCC visibility push(hidden) + +int +mqtt_wait4data(int sock, u_short ka, short events) +{ + int ret = 0; + struct pollfd pfd; + + if (sock < 3) + return -1; /* error */ + + pfd.fd = sock; + pfd.events = POLLOUT; + if ((ret = poll(&pfd, 1, ka * 1000)) == -1 || + pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + LOGERR; + return -1; /* error */ + } else if (!ret) + return 1; /* timeout */ + + return 0; /* ready */ +} + +#pragma GCC visibility pop + + +/* + * mqtt_KeepAlive() - Keep Alive check routine + * + * @sock = connected socket + * @ka = keep alive timeout + * @tries = tries for receive correct ping response, usually ==1 + * return: -1 error, 0 host is alive, 1 timeout session or 2 broken session + */ +int +mqtt_KeepAlive(int sock, u_short ka, u_char tries) +{ + int ret = 0; + mqtt_msg_t *msg = NULL; + + if (sock < 3) + return -1; /* error */ + + if ((ret = mqtt_wait4data(sock, ka, POLLOUT))) + return ret; + /* ping request */ + if (!(msg = mqtt_msgPINGREQ())) + return -1; /* error */ + if ((ret = send(sock, msg->msg_base, msg->msg_len, MSG_NOSIGNAL)) == -1) { + LOGERR; + goto end; + } else + mqtt_msgFree(&msg, 0); + + while (tries--) { + if ((ret = mqtt_wait4data(sock, ka, POLLIN | POLLPRI))) { + if (ret == -1) + break; + else + continue; + } + /* receive & decode packet */ + msg = mqtt_msgAlloc(BUFSIZ); + if ((ret = recv(sock, msg->msg_base, msg->msg_len, 0)) == -1) { + LOGERR; + break; + } + if (!mqtt_readPINGRESP(msg)) { + ret = 0; /* Host is alive */ + break; + } else + ret = 2; /* Session is broken ... must be disconnect! */ + } +end: + mqtt_msgFree(&msg, 0); + return ret; +} + +/* + * mqtt_WillMessage() - Publish WILL message + * + * @sock = connected socket + * @ka = keep alive timeout + * @topic = will topic + * @data = will message + * return: -1 error, 1 timeout, 2 not ack or 0 ok + */ +int +mqtt_WillMessage(int sock, u_short ka, const char *topic, const char *data) +{ + int ret = 0; + mqtt_msg_t *msg = NULL; + + if (!topic) + return -1; /* error */ + + /* will message */ + if ((ret = mqtt_wait4data(sock, ka, POLLOUT))) + return ret; + msg = mqtt_msgPUBLISH(topic, 0xDEAD, 0, 1, 0, data, data ? strlen(data) : 0); + if (!msg) + return -1; /* error */ + if ((ret = send(sock, msg->msg_base, msg->msg_len, MSG_NOSIGNAL)) == -1) { + LOGERR; + mqtt_msgFree(&msg, 0); + return -1; /* error */ + } else + mqtt_msgFree(&msg, 0); + + /* will ack */ + if ((ret = mqtt_wait4data(sock, ka, POLLIN | POLLPRI))) + return ret; + /* receive & decode packet */ + msg = mqtt_msgAlloc(BUFSIZ); + if ((ret = recv(sock, msg->msg_base, msg->msg_len, 0)) == -1) { + LOGERR; + mqtt_msgFree(&msg, 0); + return -1; /* error */ + } + if (mqtt_readPUBACK(msg)) + ret = 0; /* ok */ + else + ret = 2; /* semi-error */ + + mqtt_msgFree(&msg, 0); + return ret; +}