From 4438a03ef6a66dee9e99955f14a86f8e538de6e8 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 29 Oct 2015 17:44:59 +0100 Subject: [PATCH] Change socket hashtables for read, accept and write to set --- README.md | 27 +++++++++++++ include/tr/comm_manager.h | 6 +-- include/tr/connect_entry_point.h | 2 - src/Makefile.am | 3 +- src/cet_accept.c | 34 ----------------- src/comm_manager.c | 14 +++---- src/comm_manager_epoll.c | 6 +-- src/comm_manager_poll.c | 6 +-- src/comm_manager_shutdown_read.c | 2 +- src/comm_manager_shutdown_write.c | 2 +- src/connector.c | 10 +++++ src/i_comm_manager.c | 61 ++++++++++++------------------ src/server_bind_tcp.c | 2 +- src/server_bind_udp.c | 3 +- testers/Makefile | 10 +++-- testers/NOTES.md | 1 + testers/testclient.c | 14 +++++-- testers/testset | Bin 0 -> 15440 bytes testers/testset.c | 36 ++++++++++++++++++ 19 files changed, 139 insertions(+), 100 deletions(-) delete mode 100644 src/cet_accept.c create mode 100644 testers/NOTES.md create mode 100755 testers/testset create mode 100644 testers/testset.c diff --git a/README.md b/README.md index cdb7d0e..b39eb21 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,30 @@ Socket communication layer build upon libtrevent. ## BUGS + +## MULTIPLE WORKER + +### Stream sockets + +For stream socket some new classes might be neede: + + * A connector derivate that does not create a TR_CON_EVENT_NEW_CON + event but instead hands over the socket to one of its worker processes. + + * Another connector no doing TR_socketAccept but instead get the + docket via its socket pair. This one then might isse TR_CON_EVENT_NEW_CON + +### Datagram sockets + +Currently there is no clear plan to parallelize the communication +on datagram sockets. + +As we only have one socket for all communication it makes no sense +to share it between multiple processes. This neccicarily will lead +to race condition. + +One possible way might be to share the socket with all worker, but +do the read only in the master worker. When a packet has arraive +it will be handed over to the worker via shared memory. This might +be done as an event message. The worker then will process the packet +and send a respone. diff --git a/include/tr/comm_manager.h b/include/tr/comm_manager.h index 3aac5e7..717c531 100644 --- a/include/tr/comm_manager.h +++ b/include/tr/comm_manager.h @@ -35,9 +35,9 @@ TR_CLASS(TR_CommManager) { TR_EXTENDS(TR_EventHandler); TR_CommEndPoint * endpoints; - TR_Hash accept; - TR_Hash write; - TR_Hash read; + TR_Set accept; + TR_Set write; + TR_Set read; size_t n_endpoints; size_t max_handle; }; diff --git a/include/tr/connect_entry_point.h b/include/tr/connect_entry_point.h index 7ff019f..8da8a34 100644 --- a/include/tr/connect_entry_point.h +++ b/include/tr/connect_entry_point.h @@ -41,8 +41,6 @@ TR_CLASSVARS_DECL(TR_ConnEntryPoint) { #define TR_CET_EVENT_ACC_READY (TR_CEP_EVENT_MAX + 1) #define TR_CET_EVENT_MAX ((size_t)TR_CET_EVENT_ACC_READY) -TR_TcpSocket TR_cetAccept(TR_ConnEntryPoint); - #endif // __TR_CONNECT_ENTRY_POINT_H__ // vim: set ts=4 sw=4: diff --git a/src/Makefile.am b/src/Makefile.am index f4d2d0d..b08bb7a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,8 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects AM_CFLAGS += -I../include/ -std=c99 AM_LDFLAGS += -TRCOMM = cet_accept.c \ - cep_write_buffered.c \ +TRCOMM = cep_write_buffered.c \ comm_end_point_read.c \ comm_end_point.c \ conn_entry_point.c \ diff --git a/src/cet_accept.c b/src/cet_accept.c deleted file mode 100644 index bfa19ae..0000000 --- a/src/cet_accept.c +++ /dev/null @@ -1,34 +0,0 @@ -/** - * \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 "trio.h" - -#include "tr/comm_end_point.h" -#include "tr/connect_entry_point.h" - -TR_TcpSocket -TR_cetAccept(TR_ConnEntryPoint cet) -{ - return TR_socketAccept((TR_TcpSocket)((TR_CommEndPoint)cet)->transport); -} - -// vim: set ts=4 sw=4: diff --git a/src/comm_manager.c b/src/comm_manager.c index 9988bc3..d06a259 100644 --- a/src/comm_manager.c +++ b/src/comm_manager.c @@ -40,13 +40,13 @@ 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_Set); + this->write = TR_new(TR_Set); + this->read = TR_new(TR_Set); - this->accept->cleanup_no_free = TRUE; - this->write->cleanup_no_free = TRUE; - this->read->cleanup_no_free = TRUE; + this->accept->free_msgs = 0; + this->write->free_msgs = 0; + this->read->free_msgs = 0; this->n_endpoints = sysconf(_SC_OPEN_MAX); this->endpoints = TR_calloc(sizeof(TR_CommEndPoint), this->n_endpoints); @@ -76,7 +76,7 @@ TR_commManagerEnableWrite(void * _this, TR_Event event) { TR_CommManager this = _this; - TR_hashAdd(this->write, event->subject); + TR_setAdd(this->write, event->subject); return TR_EVENT_DONE; } diff --git a/src/comm_manager_epoll.c b/src/comm_manager_epoll.c index add5124..fb64514 100644 --- a/src/comm_manager_epoll.c +++ b/src/comm_manager_epoll.c @@ -101,10 +101,10 @@ TR_commManagerEpollSelect(void * _this, TR_Event event, unsigned long timeout) if ((events[i].events & EPOLLIN) == EPOLLIN) { if (TR_INSTANCE_OF(TR_TcpSocket, endpoint->transport) && ((TR_TcpSocket)endpoint->transport)->listen) { - TR_hashAdd(cmgr->accept, endpoint); + TR_setAdd(cmgr->accept, endpoint); } else { if (! event->subject->fin) { - TR_hashAdd(cmgr->read, endpoint); + TR_setAdd(cmgr->read, endpoint); } } @@ -116,7 +116,7 @@ TR_commManagerEpollSelect(void * _this, TR_Event event, unsigned long timeout) if ((events[i].events & EPOLLOUT) == EPOLLOUT) { if (! event->subject->fin) { - TR_hashAdd(cmgr->write, endpoint); + TR_setAdd(cmgr->write, endpoint); } this->events[handle] &= ~EPOLLOUT; _event.data.ptr = endpoint; diff --git a/src/comm_manager_poll.c b/src/comm_manager_poll.c index 5c31aa7..925471f 100644 --- a/src/comm_manager_poll.c +++ b/src/comm_manager_poll.c @@ -97,10 +97,10 @@ TR_commManagerPollSelect(void * _this, TR_Event event, unsigned long timeout) if ((this->fds[i].revents & POLLIN) == POLLIN) { if (TR_INSTANCE_OF(TR_TcpSocket, endpoint->transport) && ((TR_TcpSocket)endpoint->transport)->listen) { - TR_hashAdd(cmgr->accept, endpoint); + TR_setAdd(cmgr->accept, endpoint); } else { if (! event->subject->fin) { - TR_hashAdd(cmgr->read, endpoint); + TR_setAdd(cmgr->read, endpoint); } } this->fds[endpoint->transport->handle].events &= ~POLLIN; @@ -108,7 +108,7 @@ TR_commManagerPollSelect(void * _this, TR_Event event, unsigned long timeout) if ((this->fds[i].revents & POLLOUT) == POLLOUT) { if (! event->subject->fin) { - TR_hashAdd(cmgr->write, endpoint); + TR_setAdd(cmgr->write, endpoint); } this->fds[endpoint->transport->handle].events &= ~(POLLOUT|POLLHUP); diff --git a/src/comm_manager_shutdown_read.c b/src/comm_manager_shutdown_read.c index f3866d4..fd2be7e 100644 --- a/src/comm_manager_shutdown_read.c +++ b/src/comm_manager_shutdown_read.c @@ -47,7 +47,7 @@ TR_commManagerShutdownRead(void * _this, TR_Event event) TR_ISSUE_IO_SHUT_WRITE_EVENT(this, event->subject); } - TR_hashDeleteByVal(this->read, TR_hashableGetHash(event->subject)); + TR_setDelete(this->read, event->subject); return TR_EVENT_DONE; } diff --git a/src/comm_manager_shutdown_write.c b/src/comm_manager_shutdown_write.c index 4ba2f41..173aed5 100644 --- a/src/comm_manager_shutdown_write.c +++ b/src/comm_manager_shutdown_write.c @@ -39,7 +39,7 @@ TR_commManagerShutdownWrite(void * _this, TR_Event event) TR_ISSUE_IO_CLOSE_EVENT(this, event->subject); - TR_hashDeleteByVal(this->write, TR_hashableGetHash(event->subject)); + TR_setDelete(this->write, event->subject); return TR_EVENT_DONE; } diff --git a/src/connector.c b/src/connector.c index e696226..7c91137 100644 --- a/src/connector.c +++ b/src/connector.c @@ -72,6 +72,16 @@ connectorAccept(void * _this, TR_Event event) (TR_EventSubject)new_con, TR_CON_EVENT_NEW_CON, NULL)); + /* + * TODO The break is fatal when using edge triggered events... + * so either make sure to only use level trigged events with + * the accept socket or remove the break... + * Currently I think the break can be removed... + * + * TODO Prevent malicious or broken clients from doing a connection + * bomb here... well, doing this might mean that the break needs to be + * here. + */ if (++count > 100) break; socket = TR_socketAccept((TR_TcpSocket)connection->transport); } diff --git a/src/i_comm_manager.c b/src/i_comm_manager.c index 5f295f3..0f769ff 100644 --- a/src/i_comm_manager.c +++ b/src/i_comm_manager.c @@ -52,37 +52,16 @@ TR_commManagerAddEndpoint(void * _this, TR_CommEndPoint endpoint) if (TR_INSTANCE_OF(TR_TcpSocket, endpoint->transport) && ((TR_TcpSocket)endpoint->transport)->listen) { - TR_hashAdd(this->accept, endpoint); + TR_setAdd(this->accept, endpoint); TR_ISSUE_IO_ACC_EVENT(this, endpoint); } else { - TR_hashAdd(this->read, endpoint); + TR_setAdd(this->read, endpoint); TR_ISSUE_IO_READ_EVENT(this, endpoint); } TR_CALL(_this, TR_CommManager, addEndpoint, endpoint); } -static -void -commManagerIssueAcceptEvents(const void * endpoint, const void * comm_manager) -{ - TR_ISSUE_IO_ACC_EVENT(comm_manager, endpoint); -} - -static -void -commManagerIssueWriteEvents(const void * endpoint, const void * comm_manager) -{ - TR_ISSUE_IO_WRITE_EVENT(comm_manager, endpoint); -} - -static -void -commManagerIssueReadEvents(const void * endpoint, const void * comm_manager) -{ - TR_ISSUE_IO_READ_EVENT(comm_manager, endpoint); -} - TR_EventDone TR_commManagerSelect(void * _this, TR_Event event) { @@ -90,13 +69,23 @@ TR_commManagerSelect(void * _this, TR_Event event) TR_Timer timer = (TR_Timer)event->data; TR_EventDispatcher dispatcher = (TR_EventDispatcher)event->subject; unsigned long timeout; // milliseconds - unsigned long io_triggerd; - io_triggerd = TR_hashEach(this->write, this, commManagerIssueWriteEvents); - io_triggerd += TR_hashEach(this->accept, this, commManagerIssueAcceptEvents); - io_triggerd += TR_hashEach(this->read, this, commManagerIssueReadEvents); +#define IO_TRIGGERED \ + (TR_setSize(this->write) || \ + TR_setSize(this->accept) || \ + TR_setSize(this->read)) + + TR_iterableForeach(this->write) { + TR_ISSUE_IO_WRITE_EVENT(this, TR_iterableCurrent(this->write)); + } + TR_iterableForeach(this->accept) { + TR_ISSUE_IO_ACC_EVENT(this, TR_iterableCurrent(this->accept)); + } + TR_iterableForeach(this->read) { + TR_ISSUE_IO_READ_EVENT(this, TR_iterableCurrent(this->read)); + } - if (io_triggerd) { + if (IO_TRIGGERED) { timeout = 0; } else if (NULL == timer) { timeout = TR_eventDispatcherGetDataWaitTime(dispatcher); @@ -114,7 +103,7 @@ TR_commManagerPollWrite(void * _this, TR_Event event) { TR_CommManager this = _this; - TR_hashDeleteByVal(this->write, TR_hashableGetHash(event->subject)); + TR_setDelete(this->write, event->subject); if (! TR_socketFinWr(((TR_CommEndPoint)event->subject)->transport)) { TR_CALL(_this, TR_CommManager, pollWrite, event); } @@ -130,9 +119,9 @@ TR_commManagerPollRead(void * _this, TR_Event event) if (TR_INSTANCE_OF(TR_TcpSocket, endpoint->transport) && ((TR_TcpSocket)endpoint->transport)->listen) { - TR_hashDeleteByVal(this->accept, TR_hashableGetHash(event->subject)); + TR_setDelete(this->accept, event->subject); } else { - TR_hashDeleteByVal(this->read, TR_hashableGetHash(event->subject)); + TR_setDelete(this->read, event->subject); } if (! TR_socketFinRd(endpoint->transport)) { @@ -146,7 +135,7 @@ TR_EventDone TR_commManagerDisableRead(void * _this, TR_Event event) { TR_CommManager this = _this; - TR_hashDeleteByVal(this->read, TR_hashableGetHash(event->subject)); + TR_setDelete(this->read, event->subject); TR_CALL(_this, TR_CommManager, disableRead, event); return TR_EVENT_DONE; @@ -157,9 +146,9 @@ TR_commManagerDisableWrite(void * _this, TR_Event event) { TR_CommManager this = _this; - TR_hashDeleteByVal(this->write, TR_hashableGetHash(event->subject)); + TR_setDelete(this->write, event->subject); if (! event->subject->fin) { - TR_hashAdd(this->read, event->subject); + TR_setAdd(this->read, event->subject); } TR_CALL(_this, TR_CommManager, disableWrite, event); @@ -186,8 +175,8 @@ TR_commManagerClose(void * _this, TR_Event event) TR_eventSubjectFinalize((TR_EventSubject)this->endpoints[handle]); TR_CALL(_this, TR_CommManager, disableWrite, event); TR_CALL(_this, TR_CommManager, disableRead, event); - TR_hashDeleteByVal(this->write, TR_hashableGetHash(endpoint)); - TR_hashDeleteByVal(this->read, TR_hashableGetHash(endpoint)); + TR_setDelete(this->write, endpoint); + TR_setDelete(this->read, endpoint); } TR_CALL(_this, TR_CommManager, close, event); diff --git a/src/server_bind_tcp.c b/src/server_bind_tcp.c index 6a88801..4d52108 100644 --- a/src/server_bind_tcp.c +++ b/src/server_bind_tcp.c @@ -41,7 +41,7 @@ TR_serverBindTcp( TR_serverAddEndpoint( this, - TR_new(TR_ConnEntryPoint, socket, proto, 2048)); + TR_new(TR_ConnEntryPoint, socket, proto, CEP_DEFAULT_READ_SIZE)); } // vim: set ts=4 sw=4: diff --git a/src/server_bind_udp.c b/src/server_bind_udp.c index f6ee331..18cb463 100644 --- a/src/server_bind_udp.c +++ b/src/server_bind_udp.c @@ -40,7 +40,8 @@ TR_serverBindUdp( port, 0); TR_serverAddEndpoint( - this, TR_new(TR_DatagramEntryPoint, socket, proto, 2048)); + this, TR_new( + TR_DatagramEntryPoint, socket, proto, CEP_DEFAULT_READ_SIZE)); } // vim: set ts=4 sw=4: diff --git a/testers/Makefile b/testers/Makefile index 2ae3781..3442750 100755 --- a/testers/Makefile +++ b/testers/Makefile @@ -14,7 +14,8 @@ LIBS = $(TRLIBS) \ PROGRAMS = testserver2 \ testtcp \ testudp \ - testiterator + testiterator \ + testset all: $(PROGRAMS) @@ -27,11 +28,14 @@ testtcp: testclient.o testudp: testclient.o $(CC) $(LDFLAGS) -std=c99 $(LIBS) -o $@ $< +testudp.o: testclient.c + $(CC) $(CFLAGS) -DUDP=1 -std=c99 -c -o $@ $< + testiterator: testiterator.o $(CC) $(LDFLAGS) -std=c99 $(LIBS) -o $@ $< -testudp.o: testclient.c - $(CC) $(CFLAGS) -DUDP=1 -std=c99 -c -o $@ $< +testset: testset.o + $(CC) $(LDFLAGS) -std=c99 $(LIBS) -o $@ $< %.o: %.c $(CC) $(CFLAGS) -std=c99 -c -o $@ $< diff --git a/testers/NOTES.md b/testers/NOTES.md new file mode 100644 index 0000000..20216ac --- /dev/null +++ b/testers/NOTES.md @@ -0,0 +1 @@ +The testclient throws a segfault when interruption on a waiting connect. diff --git a/testers/testclient.c b/testers/testclient.c index e66e480..2849964 100644 --- a/testers/testclient.c +++ b/testers/testclient.c @@ -34,11 +34,19 @@ main (int argc, char * argv[]) protocol = TR_new(TR_ProtocolRaw); #if UDP socket = TR_new(TR_UdpSocket, TR_logger, "127.0.0.1", 5678, 0); - connection = TR_new(TR_DatagramService, socket, protocol, 2048); + connection = TR_new( + TR_DatagramService, + socket, + protocol, + CEP_DEFAULT_READ_SIZE); TR_socketOpen((TR_Socket)socket); #else socket = TR_new(TR_TcpSocket, TR_logger, "127.0.0.1", 5678, 0); - connection = TR_new(TR_Connection, socket, protocol, 2048); + connection = TR_new( + TR_Connection, + socket, + protocol, + CEP_DEFAULT_READ_SIZE); TR_socketConnect((TR_Socket)socket); #endif @@ -56,7 +64,7 @@ main (int argc, char * argv[]) message = (TR_ProtoMessageRaw)TR_simpleClientIssue( client, (TR_ProtoMessage)message, - 1000); + 100000); if (! message) break; #if 0 diff --git a/testers/testset b/testers/testset new file mode 100755 index 0000000000000000000000000000000000000000..a592bcce21c175221c27b91c05e9eded19433f21 GIT binary patch literal 15440 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 literal 0 HcmV?d00001 diff --git a/testers/testset.c b/testers/testset.c new file mode 100644 index 0000000..64c1d5b --- /dev/null +++ b/testers/testset.c @@ -0,0 +1,36 @@ +#include + +#include "trbase.h" +#include "trdata.h" + +int +main (int argc, char * argv[]) +{ + TR_Set set = TR_new(TR_Set); + + set->free_msgs = 0; + + TR_setAdd(set, "a"); + TR_setAdd(set, "b"); + TR_setAdd(set, "c"); + + TR_iterableForeach(set) { + printf("%s\n", (char *)TR_iterableCurrent(set)); + } + + TR_setDelete(set, "a"); + TR_setDelete(set, "b"); + TR_setAdd(set, "b"); + TR_setAdd(set, "a"); + + TR_iterableForeach(set) { + printf("%s\n", (char *)TR_iterableCurrent(set)); + } + + TR_delete(set); + TR_cleanup(); + + return 0; +} + +// vim: set ts=4 sw=4: