/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 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 "./client_p.h" #include "../utils.h" #include "aqhome/aqhome.h" #include "aqhome/msg/ipc/m_ipc.h" #include "aqhome/msg/ipc/m_ipc_tag16.h" #include "aqhome/msg/ipc/m_ipc_result.h" #include "aqhome/msg/ipc/data/m_ipcd.h" #include "aqhome/msg/ipc/data/m_ipcd_connect.h" #include "aqhome/ipc2/endpoint.h" #include #include #include #include GWEN_INHERIT(AQH_OBJECT, AQH_TOOL_CLIENT) static void GWENHYWFAR_CB _freeData(void *bp, void *p); static int _sendWaitHandle(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo); static int _waitAndHandle(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo, uint32_t msgId); static int _exchangeConnect(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo, uint32_t flags); static AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId); static int _handleResponseMessage(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, int first); AQH_OBJECT *AQH_ToolClient_new(AQH_EVENT_LOOP *eventLoop, GWEN_DB_NODE *dbGlobalArgs, const GWEN_ARGS *argDescrs) { AQH_OBJECT *o; AQH_TOOL_CLIENT *xo; o=AQH_Object_new(eventLoop); GWEN_NEW_OBJECT(AQH_TOOL_CLIENT, xo); GWEN_INHERIT_SETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o, xo, _freeData); xo->dbGlobalArgs=dbGlobalArgs; xo->args=argDescrs; return o; } void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) { AQH_TOOL_CLIENT *xo; xo=(AQH_TOOL_CLIENT*)p; AQH_Object_free(xo->ipcEndpoint); GWEN_FREE_OBJECT(xo); } int AQH_ToolClient_ReadLocalArgs(AQH_OBJECT *o, int argc, char **argv) { if (o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) { int rv; GWEN_DB_Group_free(xo->dbLocalArgs); xo->dbLocalArgs=GWEN_DB_GetGroup(xo->dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local"); rv=GWEN_Args_Check(argc, argv, 1, GWEN_ARGS_MODE_ALLOW_FREEPARAM, xo->args, xo->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(xo->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 1; } xo->timeoutInSeconds=GWEN_DB_GetIntValue(xo->dbLocalArgs, "timeout", 0, 5); AQH_MergeConfigFileIntoConfig(xo->dbLocalArgs, "ConfigFile"); return 0; } } return 1; } void AQH_ToolClient_SetCreateRequestMessageFn(AQH_OBJECT *o, AQH_TOOLCLIENT_CREATEREQUESTMESSAGE_FN f) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) xo->createRequestMessageFn=f; } void AQH_ToolClient_SetHandleResponseMessageFn(AQH_OBJECT *o, AQH_TOOLCLIENT_HANDLERESPONSEMESSAGE_FN f) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) xo->handleResponseMessageFn=f; } GWEN_DB_NODE *AQH_ToolClient_GetDbGlobalArgs(const AQH_OBJECT *o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) return xo->dbGlobalArgs; return NULL; } GWEN_DB_NODE *AQH_ToolClient_GetDbLocalArgs(const AQH_OBJECT *o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) return xo->dbLocalArgs; return NULL; } uint32_t AQH_ToolClient_GetFlags(const AQH_OBJECT *o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) return xo->flags; return 0; } void AQH_ToolClient_SetFlags(AQH_OBJECT *o, uint32_t f) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) xo->flags=f; } void AQH_ToolClient_AddFlags(AQH_OBJECT *o, uint32_t f) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) xo->flags|=f; } void AQH_ToolClient_SubFlags(AQH_OBJECT *o, uint32_t f) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) xo->flags&=~f; } int AQH_ToolClient_Run(AQH_OBJECT *o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) { int rv; xo->ipcEndpoint=Utils2_SetupBrokerClientEndpoint(AQH_Object_GetEventLoop(o), xo->dbLocalArgs, 0); if (xo->ipcEndpoint==NULL) { DBG_ERROR(NULL, "ERROR creating TCP connection"); return 2; } rv=_exchangeConnect(o, xo, xo->flags); if (rv!=AQH_MSGDATA_RESULT_SUCCESS) { DBG_ERROR(NULL, "Connect response: %d", rv); return 2; } return _sendWaitHandle(o, xo); } return GWEN_ERROR_INVALID; } int AQH_ToolClient_Watch(AQH_OBJECT *o) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) { int rv; xo->ipcEndpoint=Utils2_SetupBrokerClientEndpoint(AQH_Object_GetEventLoop(o), xo->dbLocalArgs, 0); if (xo->ipcEndpoint==NULL) { DBG_ERROR(NULL, "ERROR creating TCP connection"); return 2; } rv=_exchangeConnect(o, xo, xo->flags); if (rv!=AQH_MSGDATA_RESULT_SUCCESS) { DBG_ERROR(NULL, "Connect response: %d", rv); return 2; } return _waitAndHandle(o, xo, 0); } return GWEN_ERROR_INVALID; } int AQH_ToolClient_HandleResultMsg(GWEN_UNUSED const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, GWEN_UNUSED int first) { int result; result=AQH_IpcMessageResult_GetResult(tagList); if (result!=AQH_MSGDATA_RESULT_SUCCESS) { char *text; text=AQH_IpcMessageResult_GetText(tagList); DBG_ERROR(NULL, "ERROR: %d (%s)", result, text?text:""); return 3; } return 0; } int _sendWaitHandle(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo) { AQH_MESSAGE *msgOut; uint32_t msgId; msgId=AQH_Endpoint_GetNextMessageId(xo->ipcEndpoint); msgOut=_createRequestMessage(o, msgId); if (msgOut==NULL) { DBG_ERROR(NULL, "Error creating outbound message"); return 2; } AQH_Endpoint_AddMsgOut(xo->ipcEndpoint, msgOut); return _waitAndHandle(o, xo, msgId); } int _waitAndHandle(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo, uint32_t msgId) { AQH_EVENT_LOOP *eventLoop; int first=1; eventLoop=AQH_Object_GetEventLoop(o); for (;;) { AQH_MESSAGE *msgIn; msgIn=Utils2_WaitForResponseMsg(eventLoop, xo->ipcEndpoint, msgId, xo->timeoutInSeconds); if (msgIn) { GWEN_TAG16_LIST *tagList; tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0); if (tagList) { int rv; rv=_handleResponseMessage(o, msgIn, tagList, first); GWEN_Tag16_List_free(tagList); AQH_Message_free(msgIn); first=0; if (rv<0) { DBG_ERROR(NULL, "here (%d)", rv); return 3; } else if (rv==1) { DBG_ERROR(NULL, "Done."); return 0; } } } } /* for */ return 1; } int _exchangeConnect(AQH_OBJECT *o, AQH_TOOL_CLIENT *xo, uint32_t flags) { AQH_EVENT_LOOP *eventLoop; AQH_MESSAGE *msgOut; uint32_t msgId; const char *clientId; const char *userId; const char *passw; clientId=GWEN_DB_GetCharValue(xo->dbLocalArgs, "brokerClientId", 0, "aqhome-tool"); userId=GWEN_DB_GetCharValue(xo->dbLocalArgs, "userId", 0, NULL); passw=GWEN_DB_GetCharValue(xo->dbLocalArgs, "password", 0, NULL); eventLoop=AQH_Object_GetEventLoop(o); msgId=AQH_Endpoint_GetNextMessageId(xo->ipcEndpoint); msgOut=AQH_IpcdMessageConnect_new(AQH_MSGTYPE_IPC_DATA_CONNECT_REQ, msgId, 0, clientId, userId, passw, flags); AQH_Endpoint_AddMsgOut(xo->ipcEndpoint, msgOut); for (;;) { AQH_MESSAGE *msgIn; msgIn=Utils2_WaitForResponseMsg(eventLoop, xo->ipcEndpoint, msgId, xo->timeoutInSeconds); if (msgIn) { GWEN_TAG16_LIST *tagList; tagList=AQH_IpcMessageTag16_ParsePayload(msgIn, 0); if (tagList) { int code; code=AQH_IpcMessage_GetCode(msgIn); if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { int result; result=AQH_IpcMessageResult_GetResult(tagList); GWEN_Tag16_List_free(tagList); AQH_Message_free(msgIn); return result; } else { DBG_ERROR(NULL, "Unexpected message received (%x)", code); GWEN_Tag16_List_free(tagList); AQH_Message_free(msgIn); return AQH_MSGDATA_RESULT_ERROR_GENERIC; } GWEN_Tag16_List_free(tagList); } AQH_Message_free(msgIn); } } /* for */ return AQH_MSGDATA_RESULT_ERROR_GENERIC; } AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) { if (xo->createRequestMessageFn) return xo->createRequestMessageFn(o, msgId); } return NULL; } int _handleResponseMessage(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, int first) { AQH_TOOL_CLIENT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_TOOL_CLIENT, o); if (xo) { if (xo->handleResponseMessageFn) return xo->handleResponseMessageFn(o, msg, tagList, first); else { uint16_t code; code=AQH_IpcMessage_GetCode(msg); if (code==AQH_MSGTYPE_IPC_DATA_RESULT) return AQH_ToolClient_HandleResultMsg(msg, tagList, first); else { DBG_INFO(NULL, "Unexpected message \"%d\"", code); return 3; } } } return 0; }