From 95cb4e93c33580e69b6d984cf841277439211b52 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 18 Apr 2023 23:26:19 +0200 Subject: [PATCH] tools: added aqhome-tool. First command implemented is PING. --- apps/0BUILD | 1 + apps/aqhome-tool/0BUILD | 64 +++++++++ apps/aqhome-tool/main.c | 153 +++++++++++++++++++++ apps/aqhome-tool/ping.c | 288 ++++++++++++++++++++++++++++++++++++++++ apps/aqhome-tool/ping.h | 20 +++ 5 files changed, 526 insertions(+) create mode 100644 apps/aqhome-tool/0BUILD create mode 100644 apps/aqhome-tool/main.c create mode 100644 apps/aqhome-tool/ping.c create mode 100644 apps/aqhome-tool/ping.h diff --git a/apps/0BUILD b/apps/0BUILD index cb2e91d..4fc63a3 100644 --- a/apps/0BUILD +++ b/apps/0BUILD @@ -4,6 +4,7 @@ aqhomed + aqhome-tool diff --git a/apps/aqhome-tool/0BUILD b/apps/aqhome-tool/0BUILD new file mode 100644 index 0000000..ac83941 --- /dev/null +++ b/apps/aqhome-tool/0BUILD @@ -0,0 +1,64 @@ + + + + + + + + $(gwenhywfar_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + + + + --include=$(builddir) + --include=$(srcdir) + + + $(visibility_cflags) + + + + + + + + + + + + + + + + + + ping.h + + + + $(local/typefiles) + main.c + ping.c + + + + aqhome + + + + $(gwenhywfar_libs) + + + + + + + + + + + + + + diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c new file mode 100644 index 0000000..8852533 --- /dev/null +++ b/apps/aqhome-tool/main.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./ping.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + + + + + +int main(int argc, char **argv) +{ + GWEN_DB_NODE *dbArgs; + int rv; + GWEN_GUI *gui; + const char *s; + const char *cmd; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "charset", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + 0, /* short option */ + "charset", /* long option */ + I18S("Specify the output character set"), /* short description */ + I18S("Specify the output character set") /* long description */ + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", + I18S("Show this help screen."), + I18S("Show this help screen.") + } + }; + const GWEN_FUNCS cmdDefArray[]= { + GWEN_FE_DAH("ping", AQH_Tool_Ping, I18N("Ping a given node on the network")), + GWEN_FE_END(), + }; + const GWEN_FUNCS *func; + + rv=GWEN_Init(); + if (rv) { + fprintf(stderr, "ERROR: Unable to init Gwen.\n"); + return 2; + } + + gui=GWEN_Gui_CGui_new(); + GWEN_Gui_SetGui(gui); + + + GWEN_Logger_Open(0, "aqhome-tool", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User); + GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); + GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); + + rv=AQH_Init(); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + dbArgs=GWEN_DB_Group_new("arguments"); + rv=GWEN_Args_Check(argc, argv, 1, GWEN_ARGS_MODE_ALLOW_FREEPARAM | GWEN_ARGS_MODE_STOP_AT_FREEPARAM, args, dbArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments main\n"); + return 1; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + GWEN_Buffer_AppendArgs(ubuf, + I18N("This is version %s.\nUsage: %s [GLOBAL OPTIONS] COMMAND [LOCAL OPTIONS]\n\nGlobal Options:\n"), + AQHOME_VERSION_STRING, + argv[0]); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + GWEN_Buffer_AppendString(ubuf, "\n"); + + fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + + fprintf(stderr, "%s\n", I18N("\nCommands:\n\n")); + GWEN_Funcs_Usage_With_Help(cmdDefArray); + + return 0; + } + if (rv) { + argc-=rv-1; + argv+=rv-1; + } + + s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL); + if (s && *s) + GWEN_Gui_SetCharSet(gui, s); + + cmd=GWEN_DB_GetCharValue(dbArgs, "params", 0, 0); + if (!cmd) { + fprintf(stderr, "ERROR: Command needed.\n"); + return 1; + } + + func=GWEN_Funcs_Find(cmdDefArray, cmd); + if (func!=NULL) { + rv=GWEN_Funcs_Call_DB_NODE_Args(func, dbArgs, argc, argv); + } + else { + fprintf(stderr, "ERROR: Unknown command \"%s\".\n", cmd); + rv=1; + } + + GWEN_Fini(); + AQH_Fini(); + + return rv; + +} + + + + diff --git a/apps/aqhome-tool/ping.c b/apps/aqhome-tool/ping.c new file mode 100644 index 0000000..a665a91 --- /dev/null +++ b/apps/aqhome-tool/ping.c @@ -0,0 +1,288 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "./ping.h" + +#include "aqhome/ipc/msg_ipc_setaccmsggrps.h" +#include "aqhome/ipc/msg_ipc_ping.h" +#include "aqhome/ipc/msg_ipc_forward.h" +#include "aqhome/ipc/endpoint_ipc_tcpc.h" +#include "aqhome/msg/msg_node.h" + +#include +#include +#include +#include +#include + +#include +#include + + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + + + +static int _doPing(GWEN_DB_NODE *dbArgs); +static int _sendAcceptedMsgGroups(GWEN_MSG_ENDPOINT *epTcp); +static int _sendPing(GWEN_MSG_ENDPOINT *epTcp, int nodeAddr); +static GWEN_MSG *_waitForSpecificNodeMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, + int msgCode, + int nodeAddr, + int timeoutInSeconds); +static GWEN_MSG_ENDPOINT *_setupIpcEndpoint(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs); + + + +int AQH_Tool_Ping(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + GWEN_DB_NODE *dbLocalArgs; + int rv; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "tcpAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "t", /* short option */ + "tcpaddress", /* long option */ + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)"), + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "tcpPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "P", /* short option */ + "tcpport", /* long option */ + I18S("Specify the TCP port to listen on"), + I18S("Specify the TCP port to listen on") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "nodeAddr", /* name */ + 1, /* minnum */ + 1, /* maxnum */ + "n", /* short option */ + "nodeaddr", /* long option */ + I18S("Specify bus addr of the node to ping"), + I18S("Specify bus addr of the node to ping") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "timeout", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "T", /* short option */ + NULL, /* long option */ + I18S("Specify timeout in seconds for PONG response"), + I18S("Specify timeout in seconds for PONG response") + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", /* long option */ + "Show this help screen", /* short description */ + "Show this help screen" /* long description */ + } + }; + + dbLocalArgs=GWEN_DB_GetGroup(dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local"); + rv=GWEN_Args_Check(argc, argv, 1, + GWEN_ARGS_MODE_ALLOW_FREEPARAM, + args, + dbLocalArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments\n"); + return 1; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + return 0; + } + + return _doPing(dbLocalArgs); +} + + + +int _doPing(GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT_MGR *emgr; + GWEN_MSG_ENDPOINT *epTcp; + int rv; + int nodeAddr; + int timeoutInSeconds; + GWEN_MSG *msg; + + emgr=GWEN_MsgEndpointMgr_new(); + + epTcp=_setupIpcEndpoint(emgr, dbArgs); + if (epTcp==NULL) { + DBG_ERROR(NULL, "ERROR creating TCP connection"); + return 2; + } + GWEN_MsgEndpointMgr_AddEndpoint(emgr, epTcp); + + nodeAddr=GWEN_DB_GetIntValue(dbArgs, "nodeAddr", 0, 0); + timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + + rv=_sendAcceptedMsgGroups(epTcp); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + rv=_sendPing(epTcp, nodeAddr); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return 2; + } + + msg=_waitForSpecificNodeMessage(emgr, epTcp, AQH_MSG_TYPE_PONG, nodeAddr, timeoutInSeconds); + if (msg==NULL) { + DBG_INFO(NULL, "No PONG response received."); + GWEN_MsgEndpointMgr_free(emgr); + return 2; + } + + DBG_INFO(NULL, "PONG response received"); + GWEN_MsgEndpointMgr_free(emgr); + return 0; +} + + + +GWEN_MSG *_waitForSpecificNodeMessage(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_MSG_ENDPOINT *epTcp, + int msgCode, + int nodeAddr, + int timeoutInSeconds) +{ + time_t startTime; + + startTime=time(NULL); + + for (;;) { + GWEN_MSG *msg; + time_t now; + + GWEN_MsgEndpointMgr_RunAllEndpoints(emgr); + GWEN_MsgEndpointMgr_IoLoopOnce(emgr); + msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp); + if (msg) { + if (GWEN_IpcMsg_GetCode(msg)==AQH_MSGTYPE_IPC_FORWARD) { + GWEN_MSG *nodeMsg; + + DBG_INFO(NULL, "Received IPC FORWARD message"); + nodeMsg=AQH_ForwardIpcMsg_GetCopyOfNodeMsg(msg); + if (nodeMsg) { + DBG_ERROR(AQH_LOGDOMAIN, + "Received node msg from %d (%d)", + AQH_NodeMsg_GetSourceAddress(nodeMsg), + AQH_NodeMsg_GetMsgType(nodeMsg)); + if (AQH_NodeMsg_GetMsgType(nodeMsg)==msgCode && + AQH_NodeMsg_GetSourceAddress(nodeMsg)==nodeAddr) { + GWEN_Msg_free(msg); + return nodeMsg; + } + } + } + GWEN_Msg_free(msg); + } + now=time(NULL); + if (now-startTime>timeoutInSeconds) { + DBG_INFO(NULL, "Timeout"); + break; + } + } + + return NULL; +} + + + +int _sendAcceptedMsgGroups(GWEN_MSG_ENDPOINT *epTcp) +{ + GWEN_MSG *msgOut; + + msgOut=AQH_SetAcceptedMsgGroupsIpcMsg_new(AQH_MSGTYPE_IPC_SETACCMSGGRPS, AQH_MSG_TYPEGROUP_ALL); + if (msgOut==NULL) { + DBG_ERROR(NULL, "Error creating message"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); + return 0; +} + + + +int _sendPing(GWEN_MSG_ENDPOINT *epTcp, int nodeAddr) +{ + GWEN_MSG *msgOut; + + msgOut=AQH_PingIpcMsg_new(AQH_MSGTYPE_IPC_PING, nodeAddr); + if (msgOut==NULL) { + DBG_ERROR(NULL, "Error creating message"); + return GWEN_ERROR_GENERIC; + } + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); + return 0; +} + + + + + + +GWEN_MSG_ENDPOINT *_setupIpcEndpoint(GWEN_MSG_ENDPOINT_MGR *emgr, GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT *epTcp; + const char *tcpAddress; + int tcpPort; + + tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, "127.0.0.1"); + tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, 45454); + + DBG_INFO(NULL, "Setup tcp client endpoint to %s:%d", tcpAddress, tcpPort); + epTcp=AQH_IpcTcpClientEndpoint_new(tcpAddress, tcpPort, "aqhome-tool-IPC", 0); + if (epTcp==NULL) { + DBG_ERROR(NULL, "Error creating endpoint TCPc"); + return NULL; + } + + return epTcp; +} + + + + + + + diff --git a/apps/aqhome-tool/ping.h b/apps/aqhome-tool/ping.h new file mode 100644 index 0000000..f7cb436 --- /dev/null +++ b/apps/aqhome-tool/ping.h @@ -0,0 +1,20 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOME_TOOL_PING_H +#define AQHOME_TOOL_PING_H + + +#include + + +int AQH_Tool_Ping(GWEN_DB_NODE *dbArgs, int argc, char **argv); + + +#endif +