/** * \file * * \author Georg Hopp * * \copyright * Copyright © 2014 Georg Hopp * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "trbase.h" #include "trevent.h" #include "trio.h" #include "tr/io_handler.h" #include "tr/comm_end_point.h" #include "tr/interface/comm_end_point.h" static int ioHandlerCtor(void * _this, va_list * params) { TR_PARENTCALL(TR_IoHandler, _this, TR_Class, ctor, params); return 0; } static void ioHandlerDtor(void * _this) {} static TR_EventDone ioHandlerRead(void * _this, TR_Event event) { TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject; TR_Event revent; TR_RemoteData data; switch (TR_commEndPointRead(endpoint, &data)) { case FALSE: // EAGAIN revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_READ_BLOCK, NULL); break; case -1: // error revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_CLOSE, NULL); break; default: case -2: // remote close revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_SHUT_READ, NULL); break; case -3: // read limit return TR_EVENT_DONE; case TRUE: if (event->subject->fin) { TR_delete(data); return TR_EVENT_DONE; } revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_NEW_DATA, data); break; } TR_eventHandlerIssueEvent((TR_EventHandler)_this, revent); return TR_EVENT_DONE; } static TR_EventDone ioHandlerWrite(void * _this, TR_Event event) { TR_Event revent = NULL; TR_CommEndPoint endpoint = (TR_CommEndPoint)event->subject; size_t written; switch (TR_cepWriteBuffered(endpoint, &written)) { case FALSE: // EAGAIN revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_WRITE_BLOCK, NULL); break; case -1: // FAILURE revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_CLOSE, NULL); break; case -2: // remote close revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_SHUT_WRITE, NULL); break; case -3: // remote end not ready break; case -4: // no more data to send revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_DATA_END, NULL); break; default: // TODO This still looks wrong... if (TRUE == endpoint->do_close) { revent = TR_eventSubjectEmit( event->subject, TR_CEP_EVENT_CLOSE, NULL); } } endpoint->write_buffer_size -= written; if (revent) { TR_eventHandlerIssueEvent((TR_EventHandler)_this, revent); } return TR_EVENT_DONE; } static void ioHandlerCvInit(TR_class_ptr cls) { TR_EVENT_HANDLER_SET_METHOD( cls, TR_CommEndPoint, TR_CEP_EVENT_DO_READ, ioHandlerRead); TR_EVENT_HANDLER_SET_METHOD( cls, TR_CommEndPoint, TR_CEP_EVENT_DO_WRITE, ioHandlerWrite); } TR_INIT_HANDLER(TR_IoHandler); TR_INIT_IFACE(TR_Class, ioHandlerCtor, ioHandlerDtor, NULL); TR_CREATE_CLASS( TR_IoHandler, TR_EventHandler, ioHandlerCvInit, TR_IF(TR_Class)) = { { TR_HANDLER_CVARS(TR_IoHandler) } }; // vim: set ts=4 sw=4: