/**************************************************************************** * 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 "./msgrequest_p.h" #include #include #include GWEN_INHERIT_FUNCTIONS(AQH_MSG_REQUEST) GWEN_TREE2_FUNCTIONS(AQH_MSG_REQUEST, AQH_MsgRequest) /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void _freeFinishedRequests(AQH_MSG_REQUEST *rq); /* ------------------------------------------------------------------------------------------------ * code * ------------------------------------------------------------------------------------------------ */ AQH_MSG_REQUEST *AQH_MsgRequest_new() { AQH_MSG_REQUEST *rq; GWEN_NEW_OBJECT(AQH_MSG_REQUEST, rq); GWEN_INHERIT_INIT(AQH_MSG_REQUEST, rq); GWEN_TREE2_INIT(AQH_MSG_REQUEST, rq, AQH_MsgRequest); return rq; } void AQH_MsgRequest_free(AQH_MSG_REQUEST *rq) { if (rq) { GWEN_TREE2_FINI(AQH_MSG_REQUEST, rq, AQH_MsgRequest); GWEN_INHERIT_FINI(AQH_MSG_REQUEST, rq); GWEN_Timestamp_free(rq->expiresAt); GWEN_Timestamp_free(rq->createdAt); AQH_Message_free(rq->requestMsg); AQH_Message_List_free(rq->msgList); AQH_Object_free(rq->endpoint); GWEN_FREE_OBJECT(rq); } } int AQH_MsgRequest_GetRequestType(const AQH_MSG_REQUEST *rq) { return rq?rq->requestType:0; } void AQH_MsgRequest_SetRequestType(AQH_MSG_REQUEST *rq, int t) { if (rq) rq->requestType=t; } AQH_MESSAGE *AQH_MsgRequest_GetRequestMsg(const AQH_MSG_REQUEST *rq) { return rq?rq->requestMsg:NULL; } void AQH_MsgRequest_SetRequestMsg(AQH_MSG_REQUEST *rq, AQH_MESSAGE *msg) { if (rq) { AQH_Message_free(rq->requestMsg); rq->requestMsg=msg; } } AQH_OBJECT *AQH_MsgRequest_GetEndpoint(const AQH_MSG_REQUEST *rq) { return rq?rq->endpoint:NULL; } void AQH_MsgRequest_SetEndpoint(AQH_MSG_REQUEST *rq, AQH_OBJECT *ep) { if (rq) { if (ep) AQH_Object_IncRefCount(ep); if (rq->endpoint) AQH_Object_free(ep); rq->endpoint=ep; } } uint32_t AQH_MsgRequest_GetRequestMsgId(const AQH_MSG_REQUEST *rq) { return rq?rq->requestMsgId:0; } void AQH_MsgRequest_SetRequestMsgId(AQH_MSG_REQUEST *rq, uint32_t id) { if (rq) rq->requestMsgId=id; } AQH_MESSAGE_LIST *AQH_MsgRequest_GetMsgList(const AQH_MSG_REQUEST *rq) { return rq?rq->msgList:NULL; } AQH_MESSAGE *AQH_MsgRequest_GetFirstMsgFromList(const AQH_MSG_REQUEST *rq) { return (rq && rq->msgList)?AQH_Message_List_First(rq->msgList):NULL; } void AQH_MsgRequest_AddMsgToList(AQH_MSG_REQUEST *rq, AQH_MESSAGE *msg) { if (rq && msg) { if (rq->msgList==NULL) rq->msgList=AQH_Message_List_new(); AQH_Message_List_Add(msg, rq->msgList); } } const GWEN_TIMESTAMP *AQH_MsgRequest_GetCreatedAt(const AQH_MSG_REQUEST *rq) { return rq?rq->createdAt:NULL; } void AQH_MsgRequest_SetCreatedAt(AQH_MSG_REQUEST *rq, GWEN_TIMESTAMP *ts) { if (rq) { GWEN_Timestamp_free(rq->createdAt); rq->createdAt=ts; } } const GWEN_TIMESTAMP *AQH_MsgRequest_GetExpiresAt(const AQH_MSG_REQUEST *rq) { return rq?rq->expiresAt:NULL; } void AQH_MsgRequest_SetExpiresAt(AQH_MSG_REQUEST *rq, GWEN_TIMESTAMP *ts) { if (rq) { GWEN_Timestamp_free(rq->expiresAt); rq->expiresAt=ts; } } void AQH_MsgRequest_SetTimestamps(AQH_MSG_REQUEST *rq, int expiresInSecs) { if (rq) { GWEN_TIMESTAMP *ts; ts=GWEN_Timestamp_NowInLocalTime(); GWEN_Timestamp_free(rq->createdAt); rq->createdAt=GWEN_Timestamp_dup(ts); GWEN_Timestamp_AddSeconds(ts, expiresInSecs); GWEN_Timestamp_free(rq->expiresAt); rq->expiresAt=ts; } } int AQH_MsgRequest_HandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg) { if (rq && rq->handleResponseFn) return (rq->handleResponseFn)(rq, msg); return AQH_MSG_REQUEST_RESULT_NOT_HANDLED; } void AQH_MsgRequest_SubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason) { if (rq && rq->subRequestFinishedFn) rq->subRequestFinishedFn(rq, subRq, reason); } void AQH_MsgRequest_Abort(AQH_MSG_REQUEST *rq, int reason) { if (rq && rq->abortFn) { rq->abortFn(rq, reason); AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE); } else { AQH_MSG_REQUEST *rqParent; AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE); rqParent=AQH_MsgRequest_Tree2_GetParent(rq); if (rqParent) AQH_MsgRequest_SubRequestFinished(rqParent, rq, AQH_MSG_REQUEST_REASON_ABORTED); } } AQH_MSG_REQUEST_HANDLERESPONSE_FN AQH_MsgRequest_SetHandleResponseFn(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST_HANDLERESPONSE_FN f) { if (rq) { AQH_MSG_REQUEST_HANDLERESPONSE_FN oldFn; oldFn=rq->handleResponseFn; rq->handleResponseFn=f; return oldFn; } return NULL; } AQH_MSG_REQUEST_SUBREQUESTFINISHED_FN AQH_MsgRequest_SetSubRequestFinishedFn(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST_SUBREQUESTFINISHED_FN f) { if (rq) { AQH_MSG_REQUEST_SUBREQUESTFINISHED_FN oldFn; oldFn=rq->subRequestFinishedFn; rq->subRequestFinishedFn=f; return oldFn; } return NULL; } AQH_MSG_REQUEST_ABORT_FN AQH_MsgRequest_SetAbortFn(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST_ABORT_FN f) { if (rq) { AQH_MSG_REQUEST_ABORT_FN oldFn; oldFn=rq->abortFn; rq->abortFn=f; return oldFn; } return NULL; } void *AQH_MsgRequest_GetPrivateData(const AQH_MSG_REQUEST *rq) { return rq?rq->privateData:NULL; } void AQH_MsgRequest_SetPrivateData(AQH_MSG_REQUEST *rq, void *p) { if (rq) rq->privateData=p; } int AQH_MsgRequest_GetResult(const AQH_MSG_REQUEST *rq) { return rq?rq->result:0; } void AQH_MsgRequest_SetResult(AQH_MSG_REQUEST *rq, int result) { if (rq) rq->result=result; } int AQH_MsgRequest_GetState(const AQH_MSG_REQUEST *rq) { return rq?rq->state:0; } void AQH_MsgRequest_SetState(AQH_MSG_REQUEST *rq, int i) { if (rq) rq->state=i; } AQH_MSG_REQUEST *AQH_MsgRequest_Tree2_FindByEndpointAndMsgId(AQH_MSG_REQUEST *rootRq, AQH_OBJECT *ep, uint32_t refMsgId) { if (rootRq) { AQH_MSG_REQUEST *rq; rq=AQH_MsgRequest_Tree2_GetFirstChild(rootRq); while(rq) { if (rq->endpoint==ep && rq->requestMsgId==refMsgId) return rq; rq=AQH_MsgRequest_Tree2_GetBelow(rq); } /* while */ } return NULL; } void AQH_Request_Tree2_CheckTimeouts(AQH_MSG_REQUEST *rootRq) { if (rootRq) { AQH_MSG_REQUEST *rq; GWEN_TIMESTAMP *now; now=GWEN_Timestamp_NowInLocalTime(); rq=AQH_MsgRequest_Tree2_GetFirstChild(rootRq); while(rq) { const GWEN_TIMESTAMP *ts; ts=AQH_MsgRequest_GetExpiresAt(rq); if (GWEN_Timestamp_Compare(now, ts)>=0) { /* timeout */ DBG_INFO(AQH_LOGDOMAIN, "Request timed out, aborting"); AQH_MsgRequest_Abort(rq, AQH_MSG_REQUEST_REASON_TIMEOUT); } rq=AQH_MsgRequest_Tree2_GetBelow(rq); } GWEN_Timestamp_free(now); } } void AQH_Request_Tree2_Cleanup(AQH_MSG_REQUEST *rootRq) { if (rootRq) { AQH_MSG_REQUEST *rq; rq=AQH_MsgRequest_Tree2_GetFirstChild(rootRq); while(rq) { AQH_MSG_REQUEST *nextSubRq; nextSubRq=AQH_MsgRequest_Tree2_GetNext(rq); _freeFinishedRequests(rq); rq=nextSubRq; } } } int AQH_Request_Tree2_HandleIpcMsg(AQH_MSG_REQUEST *rootRq, AQH_OBJECT *srcEp, AQH_MESSAGE *recvdMsg) { if (rootRq) { uint32_t refMsgId; refMsgId=AQH_IpcMessage_GetRefMsgId(recvdMsg); if (refMsgId) { AQH_MSG_REQUEST *rq; rq=AQH_MsgRequest_Tree2_GetFirstChild(rootRq); while(rq) { if (srcEp==AQH_MsgRequest_GetEndpoint(rq) && refMsgId==AQH_MsgRequest_GetRequestMsgId(rq)) { if (AQH_MsgRequest_HandleResponse(rq, recvdMsg)==AQH_MSG_REQUEST_RESULT_HANDLED) return AQH_MSG_REQUEST_RESULT_HANDLED; } rq=AQH_MsgRequest_Tree2_GetBelow(rq); } } else { DBG_INFO(AQH_LOGDOMAIN, "Message has no reference msg id, not a response"); } } return AQH_MSG_REQUEST_RESULT_NOT_HANDLED; } int AQH_Request_Tree2_HandleTtyMsg(AQH_MSG_REQUEST *rootRq, AQH_OBJECT *srcEp, AQH_MESSAGE *recvdMsg) { if (rootRq) { AQH_MSG_REQUEST *rq; rq=AQH_MsgRequest_Tree2_GetFirstChild(rootRq); while(rq) { if (srcEp==AQH_MsgRequest_GetEndpoint(rq)) { if (AQH_MsgRequest_HandleResponse(rq, recvdMsg)==AQH_MSG_REQUEST_RESULT_HANDLED) return AQH_MSG_REQUEST_RESULT_HANDLED; } rq=AQH_MsgRequest_Tree2_GetBelow(rq); } } return AQH_MSG_REQUEST_RESULT_NOT_HANDLED; } void _freeFinishedRequests(AQH_MSG_REQUEST *rq) { AQH_MSG_REQUEST *subRq; subRq=AQH_MsgRequest_Tree2_GetFirstChild(rq); while(subRq) { AQH_MSG_REQUEST *nextSubRq; nextSubRq=AQH_MsgRequest_Tree2_GetNext(subRq); _freeFinishedRequests(subRq); subRq=nextSubRq; } if (AQH_MsgRequest_GetState(rq)==AQH_MSG_REQUEST_STATE_DONE) { DBG_INFO(AQH_LOGDOMAIN, "Deleting request"); AQH_MsgRequest_free(rq); } }