diff --git a/.gitignore b/.gitignore index 9c409e8..8c695b4 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ test-driver tags /trcomm.h* /testers/testserver* +/testers/testclient* diff --git a/include/Makefile.am b/include/Makefile.am index 937e6a4..38ac4a6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -15,6 +15,7 @@ nobase_include_HEADERS = trcomm.h \ tr/protocol/message_raw.h \ tr/protocol_handler.h \ tr/server.h \ + tr/simple_client.h \ tr/interface/comm_end_point.h \ tr/interface/comm_manager.h \ tr/interface/protocol.h diff --git a/include/tr/interface/comm_manager.h b/include/tr/interface/comm_manager.h index 74f0a43..d4c073e 100644 --- a/include/tr/interface/comm_manager.h +++ b/include/tr/interface/comm_manager.h @@ -31,7 +31,7 @@ #include "tr/comm_end_point.h" typedef TR_EventDone (* fptr_TR_commManagerAddEndpoint)(void *, TR_CommEndPoint); -typedef TR_EventDone (* fptr_TR_commManagerSelect)(void *, TR_Event, int); +typedef TR_EventDone (* fptr_TR_commManagerSelect)(void *, TR_Event, unsigned long); typedef TR_EventDone (* fptr_TR_commManagerPollWrite)(void *, TR_Event); typedef TR_EventDone (* fptr_TR_commManagerPollRead)(void *, TR_Event); typedef TR_EventDone (* fptr_TR_commManagerDisableWrite)(void *, TR_Event); diff --git a/include/tr/server.h b/include/tr/server.h index 9a56213..ce5eb42 100644 --- a/include/tr/server.h +++ b/include/tr/server.h @@ -53,7 +53,7 @@ TR_CLASSVARS_DECL(TR_Server) {}; void TR_serverBindTcp(TR_Server, const char *, int, TR_Protocol); void TR_serverBindUdp(TR_Server, const char *, int, TR_Protocol); -void TR_serverStart(TR_Server, int); +void TR_serverStart(TR_Server, unsigned long); #define TR_serverClassCleanup() \ TR_eventHandlerClassCleanup(TR_ProtocolHandler); \ diff --git a/include/tr/simple_client.h b/include/tr/simple_client.h new file mode 100644 index 0000000..2d2c1bd --- /dev/null +++ b/include/tr/simple_client.h @@ -0,0 +1,70 @@ +/** + * \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 . + */ + +#ifndef __TR_SIMPLE_CLIENT_H__ +#define __TR_SIMPLE_CLIENT_H__ + +#include +#include + +#include "trbase.h" +#include "trevent.h" + +#include "tr/comm_manager.h" +#include "tr/comm_end_point.h" +#include "tr/io_handler.h" +#include "tr/protocol_handler.h" +#include "tr/protocol.h" +#include "tr/proto_message.h" +#include "tr/interface/comm_manager.h" + +TR_CLASS(TR_SimpleClient) { + TR_EXTENDS(TR_EventHandler); + + TR_CommEndPoint endpoint; + TR_CommManager comm_manager; + TR_ProtoMessage request; + TR_ProtoMessage response; + TR_IoHandler io_handler; + TR_ProtocolHandler protocol_handler; + TR_EventDispatcher dispatcher; + int send_issued; + TR_Timer timer; +}; +TR_INSTANCE_INIT(TR_SimpleClient); +TR_CLASSVARS_DECL(TR_SimpleClient) { + TR_CV_EXTENDS(TR_EventHandler); +}; + +TR_ProtoMessage TR_simpleClientIssue( + TR_SimpleClient, TR_ProtoMessage, unsigned long); + +#define TR_simpleClientClassCleanup() \ + TR_eventHandlerClassCleanup(TR_ProtocolHandler); \ + TR_eventHandlerClassCleanup(TR_IoHandler); \ + TR_eventHandlerClassCleanup(TR_CommManagerEpoll); \ + TR_eventHandlerClassCleanup(TR_SimpleClient) + +#endif // __TR_SIMPLE_CLIENT_H__ + +// vim: set ts=4 sw=4: + diff --git a/include/trcomm.h b/include/trcomm.h index e6d26f2..b2691f9 100644 --- a/include/trcomm.h +++ b/include/trcomm.h @@ -17,6 +17,7 @@ #include "tr/protocol/message_raw.h" #include "tr/protocol_handler.h" #include "tr/server.h" +#include "tr/simple_client.h" #include "tr/interface/comm_end_point.h" #include "tr/interface/comm_manager.h" #include "tr/interface/protocol.h" diff --git a/src/Makefile.am b/src/Makefile.am index bb54599..235169a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,8 @@ TRCOMM = cet_accept.c \ server_bind_tcp.c \ server_bind_udp.c \ server_start.c \ + simple_client.c \ + simple_client_issue.c \ i_comm_end_point.c \ i_comm_manager.c \ i_protocol.c diff --git a/src/comm_manager.c b/src/comm_manager.c index 01a0a7e..3f893a4 100644 --- a/src/comm_manager.c +++ b/src/comm_manager.c @@ -40,9 +40,14 @@ commManagerCtor(void * _this, va_list * params) TR_PARENTCALL(TR_CommManager, _this, TR_Class, ctor, params); - this->accept = TR_new(TR_Hash); - this->write = TR_new(TR_Hash); - this->read = TR_new(TR_Hash); + this->accept = TR_new(TR_Hash); + this->write = TR_new(TR_Hash); + this->read = TR_new(TR_Hash); + + this->accept->cleanup_no_free = TRUE; + this->write->cleanup_no_free = TRUE; + this->read->cleanup_no_free = TRUE; + this->n_endpoints = sysconf(_SC_OPEN_MAX); this->endpoints = TR_calloc(sizeof(TR_CommEndPoint), this->n_endpoints); @@ -56,7 +61,7 @@ commManagerDtor(void * _this) TR_CommManager this = _this; nfds_t i; - for (i = 0; i < this->n_endpoints; i++) { + for (i=0; in_endpoints; i++) { TR_delete(this->endpoints[i]); } TR_MEM_FREE(this->endpoints); @@ -85,7 +90,7 @@ TR_commManagerAddEndpointEvt(TR_CommManager this, TR_Event event) return TR_EVENT_DONE; } -TR_EventDone TR_commManagerSelect(void *, TR_Event, int); +TR_EventDone TR_commManagerSelect(void *, TR_Event); TR_EventDone TR_commManagerPollWrite(void *, TR_Event); TR_EventDone TR_commManagerPollRead(void *, TR_Event); TR_EventDone TR_commManagerDisableRead(void *, TR_Event); diff --git a/src/comm_manager_epoll.c b/src/comm_manager_epoll.c index 164034b..72cdfe8 100644 --- a/src/comm_manager_epoll.c +++ b/src/comm_manager_epoll.c @@ -83,7 +83,7 @@ TR_commManagerEpollAddEndpoint(void * _this, TR_CommEndPoint endpoint) static void -TR_commManagerEpollSelect(void * _this, TR_Event event, int timeout) +TR_commManagerEpollSelect(void * _this, TR_Event event, unsigned long timeout) { TR_CommManagerEpoll this = _this; TR_CommManager cmgr = _this; diff --git a/src/comm_manager_poll.c b/src/comm_manager_poll.c index 4bd3e5f..e5bcb16 100644 --- a/src/comm_manager_poll.c +++ b/src/comm_manager_poll.c @@ -61,6 +61,7 @@ commManagerPollDtor(void * _this) TR_CommManagerPoll this = _this; TR_MEM_FREE(this->fds); + TR_PARENTCALL(TR_CommManagerPoll, _this, TR_Class, dtor); } static @@ -75,7 +76,7 @@ TR_commManagerPollAddEndpoint(void * _this, TR_CommEndPoint endpoint) static void -TR_commManagerPollSelect(void * _this, TR_Event event, int timeout) +TR_commManagerPollSelect(void * _this, TR_Event event, unsigned long timeout) { TR_CommManagerPoll this = _this; TR_CommManager cmgr = _this; diff --git a/src/i_comm_manager.c b/src/i_comm_manager.c index 00fc9f4..d6f5344 100644 --- a/src/i_comm_manager.c +++ b/src/i_comm_manager.c @@ -86,19 +86,19 @@ commManagerIssueReadEvents(const void * endpoint, const void * comm_manager) TR_EventDone TR_commManagerSelect(void * _this, TR_Event event) { - TR_CommManager this = _this; - int timeout; // milliseconds - int * timeoutptr = event->data; - TR_EventDispatcher dispatcher = (TR_EventDispatcher)event->subject; + TR_CommManager this = _this; + TR_Timer timer = (TR_Timer)event->data; + TR_EventDispatcher dispatcher = (TR_EventDispatcher)event->subject; + unsigned long timeout; // milliseconds if (! (TR_hashEmpty(this->read) && TR_hashEmpty(this->write) && TR_hashEmpty(this->accept))) { timeout = 0; - } else if (NULL == timeoutptr) { + } else if (NULL == timer) { timeout = TR_eventDispatcherGetDataWaitTime(dispatcher); } else { - timeout = *timeoutptr; + timeout = TR_timerGet(timer, NULL); } TR_CALL(_this, TR_CommManager, select, event, timeout); diff --git a/src/server.c b/src/server.c index adb4ef8..7fda748 100644 --- a/src/server.c +++ b/src/server.c @@ -48,7 +48,7 @@ serverCtor(void * _this, va_list * params) #else this->comm_manager = (TR_CommManager)TR_new(TR_CommManagerPoll); #endif - this->dispatcher = TR_new(TR_EventDispatcher, TR_EVD_SERVER, NULL, 100); + this->dispatcher = TR_new(TR_EventDispatcher, TR_EVD_SERVER, NULL); this->connector = TR_new(TR_Connector); this->io_handler = TR_new(TR_IoHandler); this->protocol_handler = TR_new(TR_ProtocolHandler); diff --git a/src/server_start.c b/src/server_start.c index 8f67861..4a9ed9b 100644 --- a/src/server_start.c +++ b/src/server_start.c @@ -26,9 +26,9 @@ #include "tr/server.h" void -TR_serverStart(TR_Server this, int heartbeat) +TR_serverStart(TR_Server this, unsigned long heartbeat) { - TR_eventDispatcherSetHeartbeat(this->dispatcher, 1000); + TR_eventDispatcherSetHeartbeat(this->dispatcher, heartbeat); TR_eventDispatcherStart(this->dispatcher); } diff --git a/src/simple_client.c b/src/simple_client.c new file mode 100644 index 0000000..dd70237 --- /dev/null +++ b/src/simple_client.c @@ -0,0 +1,160 @@ +/** + * \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 "trio.h" +#include "trevent.h" + +#include "tr/simple_client.h" +#include "tr/comm_end_point.h" +#include "tr/comm_manager.h" +#include "tr/comm_manager_poll.h" +#include "tr/comm_manager_epoll.h" +#include "tr/connector.h" +#include "tr/io_handler.h" +#include "tr/protocol_handler.h" + + +static +int +simpleClientCtor(void * _this, va_list * params) +{ + TR_SimpleClient this = _this; + + this->endpoint = va_arg(*params, TR_CommEndPoint); + +#if 1 + this->comm_manager = (TR_CommManager)TR_new(TR_CommManagerEpoll); +#else + this->comm_manager = (TR_CommManager)TR_new(TR_CommManagerPoll); +#endif + this->dispatcher = TR_new(TR_EventDispatcher, TR_EVD_CLIENT, NULL); + this->io_handler = TR_new(TR_IoHandler); + this->protocol_handler = TR_new(TR_ProtocolHandler); + this->timer = TR_new(TR_Timer, TR_TBASE_MIL, 1000); + + TR_eventDispatcherRegisterHandler( + this->dispatcher, + (TR_EventHandler)this->comm_manager); + TR_eventDispatcherRegisterHandler( + this->dispatcher, + (TR_EventHandler)this->io_handler); + TR_eventDispatcherRegisterHandler( + this->dispatcher, + (TR_EventHandler)this->protocol_handler); + TR_eventDispatcherRegisterHandler( + this->dispatcher, + (TR_EventHandler)this); + + TR_commManagerAddEndpoint(this->comm_manager, this->endpoint); + + return 0; +} + +static +void +simpleClientDtor(void * _this) +{ + TR_SimpleClient this = _this; + + TR_delete(this->protocol_handler); + TR_delete(this->io_handler); + TR_delete(this->comm_manager); + TR_delete(this->dispatcher); + TR_delete(this->timer); +} + +static +TR_EventDone +simpleClientUserAction(void * _this, TR_Event event) +{ + TR_SimpleClient this = _this; + + if (this->send_issued) { + unsigned long missed; + + TR_timerGet(this->timer, &missed); + + if (this->response || missed) { + TR_eventDispatcherStop((TR_EventDispatcher)event->subject); + } else { + TR_eventHandlerIssueEvent( + (TR_EventHandler)_this, + TR_eventSubjectEmit( + event->subject, + TR_DISPATCHER_EVENT_DATA_WAIT, + this->timer)); + } + } else { + TR_eventHandlerIssueEvent( + (TR_EventHandler)_this, + TR_eventSubjectEmit( + (TR_EventSubject)this->endpoint, + TR_CEP_EVENT_MSG_READY, + this->request)); + this->send_issued = TRUE; + } + + return TR_EVENT_DONE; +} + +static +TR_EventDone +simpleClientHandleData(void * _this, TR_Event event) +{ + ((TR_SimpleClient)_this)->response = event->data; + + return TR_EVENT_DONE; +} + +static +void +simpleClientCvInit(TR_class_ptr cls) +{ + TR_EVENT_HANDLER_SET_METHOD( + cls, + TR_EventDispatcher, + TR_DISPATCHER_EVENT_USER_WAIT, + simpleClientUserAction); + TR_EVENT_HANDLER_SET_METHOD( + cls, + TR_CommEndPoint, + TR_CEP_EVENT_NEW_MSG, + simpleClientHandleData); +} + +TR_INSTANCE(TR_Hash, simpleClientEventMethods); +TR_INIT_IFACE(TR_Class, simpleClientCtor, simpleClientDtor, NULL); +TR_CREATE_CLASS( + TR_SimpleClient, + TR_EventHandler, + simpleClientCvInit, + TR_IF(TR_Class)) = { + { &(_simpleClientEventMethods.data) } +}; + +// vim: set ts=4 sw=4: diff --git a/src/simple_client_issue.c b/src/simple_client_issue.c new file mode 100644 index 0000000..bb7affb --- /dev/null +++ b/src/simple_client_issue.c @@ -0,0 +1,50 @@ +/** + * \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 "trbase.h" +#include "trevent.h" + +#include "tr/simple_client.h" +#include "tr/proto_message.h" + +TR_ProtoMessage +TR_simpleClientIssue( + TR_SimpleClient this, + TR_ProtoMessage request, + unsigned long timeout) +{ + TR_ProtoMessage retval; + + TR_timerSetMil(this->timer, timeout); + this->request = request; + this->response = NULL; + this->send_issued = FALSE; + + TR_eventDispatcherStart(((TR_EventHandler)this)->dispatcher[0]); + + retval = this->response; + this->request = this->response = NULL; + + return retval; +} + +// vim: set ts=4 sw=4: diff --git a/testers/build.sh b/testers/build.sh index fda4ed3..8fafec4 100755 --- a/testers/build.sh +++ b/testers/build.sh @@ -5,3 +5,4 @@ LIBS="-lcrypto -lssl -lrt -luuid" gcc ${CFLAGS} -c -o test_handler.o test_handler.c gcc ${CFLAGS} -I/usr/local/include -L/usr/local/lib ${LIBS} -o testserver testserver.c test_handler.o ${TRLIBS} gcc ${CFLAGS} -I/usr/local/include -L/usr/local/lib ${LIBS} -o testserver2 testserver2.c test_handler.o ${TRLIBS} +gcc ${CFLAGS} -I/usr/local/include -L/usr/local/lib ${LIBS} -o testclient testclient.c ${TRLIBS} diff --git a/testers/testclient.c b/testers/testclient.c new file mode 100644 index 0000000..e24db17 --- /dev/null +++ b/testers/testclient.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include "trbase.h" +#include "trcomm.h" +#include "trio.h" +#include "trevent.h" + +#include "test_handler.h" + +TR_INSTANCE(TR_LoggerSyslog, mylogger, {TR_LOGGER_INFO}); +TR_INSTANCE(TR_LoggerStderr, mylogger2, {TR_LOGGER_INFO}); + +int +main (int argc, char * argv[]) +{ + TR_TcpSocket socket; + TR_Connection connection; + TR_SimpleClient client; + TR_Protocol protocol; + TR_ProtoMessageRaw message; + TR_RemoteData data; + + TR_logger = TR_INSTANCE_CAST(TR_Logger, mylogger2); + socket = TR_new(TR_TcpSocket, TR_logger, "192.168.2.13", 5678, 0); + protocol = TR_new(TR_ProtocolRaw); + connection = TR_new(TR_Connection, socket, protocol); + + TR_socketConnect((TR_Socket)socket); + TR_socketNonblock((TR_Socket)socket); + + client = TR_new(TR_SimpleClient, connection); + + message = (TR_ProtoMessageRaw)TR_protoCreateRequest(protocol, (TR_Socket)socket); + data = TR_new(TR_RemoteData, "test", sizeof("test"), (TR_Socket)socket); + message->data = data; + message = (TR_ProtoMessageRaw)TR_simpleClientIssue( + client, + (TR_ProtoMessage)message, + 10000000); + + printf("%s\n", ((TR_SizedData)message->data)->data); + TR_delete(message->data); + TR_delete(message); + + puts("cleanup..."); + + TR_delete(client); + TR_delete(protocol); + + TR_simpleClientClassCleanup(); + + TR_cleanup(); + + return 0; +} + +// vim: set ts=4 sw=4: