/**************************************************************************** * 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 "./fdobject_p.h" #include #include #include //#include #include #include #include GWEN_INHERIT(AQH_OBJECT, AQH_FDOBJECT) /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void GWENHYWFAR_CB _freeData(void *bp, void *p); static void _cbEnable(AQH_OBJECT *o); static void _cbDisable(AQH_OBJECT *o); static int _cbFlush(AQH_OBJECT *o); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ AQH_OBJECT *AQH_FdObject_new(AQH_EVENT_LOOP *eventLoop, int fd, int mode) { AQH_OBJECT *o; AQH_FDOBJECT *xo; o=AQH_Object_new(eventLoop); GWEN_NEW_OBJECT(AQH_FDOBJECT, xo); GWEN_INHERIT_SETDATA(AQH_OBJECT, AQH_FDOBJECT, o, xo, _freeData); xo->fd=fd; xo->fdMode=mode; xo->flushFn=_cbFlush; AQH_Object_SetEnableFn(o, _cbEnable); AQH_Object_SetDisableFn(o, _cbDisable); return o; } void GWENHYWFAR_CB _freeData(void *bp, void *p) { AQH_FDOBJECT *xo; xo=(AQH_FDOBJECT*)p; AQH_Object_Disable((AQH_OBJECT*)bp); if (xo->fd>=0) close(xo->fd); xo->fd=-1; GWEN_FREE_OBJECT(xo); } AQH_FDOBJECT_STARTMSG_FN AQH_FdObject_SetStartMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_STARTMSG_FN f) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { AQH_FDOBJECT_STARTMSG_FN oldFn; oldFn=xo->startMsgFn; xo->startMsgFn=f; return oldFn; } return NULL; } AQH_FDOBJECT_ENDMSG_FN AQH_FdObject_SetEndMsgFn(AQH_OBJECT *o, AQH_FDOBJECT_ENDMSG_FN f) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { AQH_FDOBJECT_ENDMSG_FN oldFn; oldFn=xo->endMsgFn; xo->endMsgFn=f; return oldFn; } return NULL; } AQH_FDOBJECT_FLUSH_FN AQH_FdObject_SetFlushFn(AQH_OBJECT *o, AQH_FDOBJECT_FLUSH_FN f) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { AQH_FDOBJECT_FLUSH_FN oldFn; oldFn=xo->flushFn; xo->flushFn=f; return oldFn; } return NULL; } int AQH_FdObject_GetFdMode(const AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) return xo->fdMode; } return 0; } void AQH_FdObject_SetFdMode(AQH_OBJECT *o, int i) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) xo->fdMode=i; } } int AQH_FdObject_GetFd(const AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) return xo->fd; } return -1; } int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer) { if (o && ptrBuffer && lenBuffer) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { if (xo->fd!=-1) { ssize_t rv; rv=read(xo->fd, ptrBuffer, lenBuffer); if (rv==0) { DBG_INFO(AQH_LOGDOMAIN, "EOF met"); return 0; } else if (rv>0) { /* data received */ DBG_DEBUG(AQH_LOGDOMAIN, "Received %d bytes", (int) rv); // GWEN_Text_LogString((const char*) ptrBuffer, rv, NULL, GWEN_LoggerLevel_Error); return (int) rv; } else { if (errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN) { /* temporarily no data, try again */ return GWEN_ERROR_TRY_AGAIN; } else { DBG_INFO(AQH_LOGDOMAIN, "Error on read(%d): %s (%d)", xo->fd, strerror(errno), errno); close(xo->fd); xo->fd=-1; return GWEN_ERROR_IO; } } } else { DBG_ERROR(AQH_LOGDOMAIN, "Previous error, not reading."); return GWEN_ERROR_IO; } } } return GWEN_ERROR_INVALID; } int AQH_FdObject_FlushInput(AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo && xo->flushFn) { int rv; rv=xo->flushFn(o); if (rv<0) { if (xo->fd!=-1) { DBG_ERROR(AQH_LOGDOMAIN, "Error on flush, closing."); close(xo->fd); xo->fd=-1; } } return rv; } } return 0; } int AQH_FdObject_Write(AQH_OBJECT *o, const uint8_t *ptrBuffer, uint32_t lenBuffer) { if (o && ptrBuffer && lenBuffer) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { if (xo->fd!=-1) { ssize_t rv; rv=write(xo->fd, ptrBuffer, lenBuffer); if (rv<0) { if (errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN) { /* temporarily no data, try again */ return GWEN_ERROR_TRY_AGAIN; } else { DBG_ERROR(AQH_LOGDOMAIN, "Error on write: %s (%d)", strerror(errno), errno); close(xo->fd); xo->fd=-1; return GWEN_ERROR_IO; } } else { /* data received */ return (int) rv; } } else { DBG_ERROR(AQH_LOGDOMAIN, "Previous error, not writing."); return GWEN_ERROR_IO; } } } return GWEN_ERROR_INVALID; } int AQH_FdObject_StartMsg(AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo && xo->startMsgFn) return xo->startMsgFn(o); } return 0; } void AQH_FdObject_EndMsg(AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo && xo->endMsgFn) xo->endMsgFn(o); } } void _cbEnable(AQH_OBJECT *o) { if (o && !(AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { AQH_EVENT_LOOP *eventLoop; eventLoop=AQH_Object_GetEventLoop(o); if (eventLoop) { AQH_EventLoop_AddFdObject(eventLoop, o); AQH_Object_AddFlags(o, AQH_OBJECT_FLAGS_ENABLED); } } } void _cbDisable(AQH_OBJECT *o) { if (o && (AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_ENABLED)) { AQH_EVENT_LOOP *eventLoop; eventLoop=AQH_Object_GetEventLoop(o); if (eventLoop) { AQH_EventLoop_DelFdObject(eventLoop, o); AQH_Object_SubFlags(o, AQH_OBJECT_FLAGS_ENABLED); } } } int _cbFlush(AQH_OBJECT *o) { if (o) { AQH_FDOBJECT *xo; xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_FDOBJECT, o); if (xo) { if (xo->fd!=-1) { ssize_t rv; ssize_t bytesRead=0; uint8_t tbuf[16]; do { rv=read(xo->fd, tbuf, sizeof(tbuf)); if (rv>0) bytesRead+=rv; } while(rv>=0); if (rv==0) { DBG_INFO(AQH_LOGDOMAIN, "EOF met"); return GWEN_ERROR_EOF; } else if (rv<0) { if (errno!=EINTR && errno!=EWOULDBLOCK && errno!=EAGAIN) { DBG_ERROR(AQH_LOGDOMAIN, "Error on read: %s (%d)", strerror(errno), errno); return GWEN_ERROR_IO; } } return (bytesRead>0)?1:0; } else { DBG_ERROR(AQH_LOGDOMAIN, "Previous error, not reading."); return GWEN_ERROR_IO; } } } return GWEN_ERROR_INVALID; }