1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/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()
23 MAX_DESCRIPTORS = FD_SETSIZE;
27 writeable.assign(GetMaxFds(), false);
28 ref = new EventHandler* [GetMaxFds()];
29 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
32 SelectEngine::~SelectEngine()
37 bool SelectEngine::AddFd(EventHandler* eh, bool writeFirst)
40 if ((fd < 0) || (fd > GetMaxFds() - 1))
43 if (GetRemainingFds() <= 1)
53 writeable[eh->GetFd()] = writeFirst;
55 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
59 void SelectEngine::WantWrite(EventHandler* eh)
61 writeable[eh->GetFd()] = true;
64 bool SelectEngine::DelFd(EventHandler* eh, bool force)
68 if ((fd < 0) || (fd > GetMaxFds() - 1))
71 std::set<int>::iterator t = fds.find(fd);
78 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
82 int SelectEngine::GetMaxFds()
87 int SelectEngine::GetRemainingFds()
89 return GetMaxFds() - CurrentSetSize;
92 int SelectEngine::DispatchEvents()
96 socklen_t codesize = sizeof(int);
103 /* Populate the select FD set (this is why select sucks compared to epoll, kqueue, IOCP) */
104 for (std::set<int>::iterator a = fds.begin(); a != fds.end(); a++)
106 /* Explicitly one-time writeable */
108 FD_SET (*a, &wfdset);
110 FD_SET (*a, &rfdset);
112 /* All sockets must receive error notifications regardless */
113 FD_SET (*a, &errfdset);
116 /* One second waits */
120 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
122 /* Nothing to process this time around */
126 std::vector<int> copy(fds.begin(), fds.end());
127 for (std::vector<int>::iterator a = copy.begin(); a != copy.end(); a++)
129 EventHandler* ev = ref[*a];
132 if (FD_ISSET (ev->GetFd(), &errfdset))
135 if (getsockopt(ev->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
138 ev->HandleEvent(EVENT_ERROR, errcode);
143 /* NOTE: This is a pair of seperate if statements as the socket
144 * may be in both read and writeable state at the same time.
145 * If an error event occurs above it is not worth processing the
146 * read and write states even if set.
148 if (FD_ISSET (ev->GetFd(), &wfdset))
151 writeable[ev->GetFd()] = false;
152 ev->HandleEvent(EVENT_WRITE);
154 if (FD_ISSET (ev->GetFd(), &rfdset))
157 ev->HandleEvent(EVENT_READ);
166 std::string SelectEngine::GetName()