1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
16 #include <sys/select.h>
18 #include "socketengines/socketengine_select.h"
21 SelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance)
23 MAX_DESCRIPTORS = FD_SETSIZE;
27 writeable = new bool [GetMaxFds()];
28 memset(writeable, 0, sizeof(writeable));
29 ref = new EventHandler* [GetMaxFds()];
30 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
33 SelectEngine::~SelectEngine()
38 bool SelectEngine::AddFd(EventHandler* eh)
41 if ((fd < 0) || (fd > GetMaxFds() - 1))
44 if (GetRemainingFds() <= 1)
54 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
58 void SelectEngine::WantWrite(EventHandler* eh)
60 writeable[eh->GetFd()] = true;
63 bool SelectEngine::DelFd(EventHandler* eh, bool force)
67 if ((fd < 0) || (fd > GetMaxFds() - 1))
70 std::map<int,int>::iterator t = fds.find(fd);
77 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
81 int SelectEngine::GetMaxFds()
86 int SelectEngine::GetRemainingFds()
88 return GetMaxFds() - CurrentSetSize;
91 int SelectEngine::DispatchEvents()
95 socklen_t codesize = sizeof(int);
102 /* Populate the select FD set (this is why select sucks compared to epoll, kqueue, IOCP) */
103 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
105 if (ref[a->second]->Readable())
106 /* Read notifications */
107 FD_SET (a->second, &rfdset);
109 /* Write notifications */
110 FD_SET (a->second, &wfdset);
112 /* Explicitly one-time writeable */
113 if (writeable[a->second])
114 FD_SET (a->second, &wfdset);
116 /* All sockets must receive error notifications regardless */
117 FD_SET (a->second, &errfdset);
120 /* One second waits */
124 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
126 /* Nothing to process this time around */
130 /* Safe assumption (as of 1.1 anyway) that a socket can't remove itself from the list in the middle of the loop */
131 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
133 EventHandler* ev = ref[a->second];
136 if (FD_ISSET (ev->GetFd(), &errfdset))
139 if (getsockopt(ev->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
142 ev->HandleEvent(EVENT_ERROR, errcode);
147 /* NOTE: This is a pair of seperate if statements as the socket
148 * may be in both read and writeable state at the same time.
149 * If an error event occurs above it is not worth processing the
150 * read and write states even if set.
152 if (FD_ISSET (ev->GetFd(), &wfdset))
155 writeable[ev->GetFd()] = false;
156 ev->HandleEvent(EVENT_WRITE);
158 if (FD_ISSET (ev->GetFd(), &rfdset))
161 ev->HandleEvent(EVENT_READ);
170 std::string SelectEngine::GetName()