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(InspIRCd* Instance) : SocketEngine(Instance)
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)
40 if ((fd < 0) || (fd > GetMaxFds() - 1))
43 if (GetRemainingFds() <= 1)
53 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
57 void SelectEngine::WantWrite(EventHandler* eh)
59 writeable[eh->GetFd()] = true;
62 bool SelectEngine::DelFd(EventHandler* eh, bool force)
66 if ((fd < 0) || (fd > GetMaxFds() - 1))
69 std::set<int>::iterator t = fds.find(fd);
76 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
80 int SelectEngine::GetMaxFds()
85 int SelectEngine::GetRemainingFds()
87 return GetMaxFds() - CurrentSetSize;
90 int SelectEngine::DispatchEvents()
94 socklen_t codesize = sizeof(int);
101 /* Populate the select FD set (this is why select sucks compared to epoll, kqueue, IOCP) */
102 for (std::set<int>::iterator a = fds.begin(); a != fds.end(); a++)
104 if (ref[*a]->Readable())
105 /* Read notifications */
106 FD_SET (*a, &rfdset);
108 /* Write notifications */
109 FD_SET (*a, &wfdset);
111 /* Explicitly one-time writeable */
113 FD_SET (*a, &wfdset);
115 /* All sockets must receive error notifications regardless */
116 FD_SET (*a, &errfdset);
119 /* One second waits */
123 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
125 /* Nothing to process this time around */
129 std::vector<int> copy(fds.begin(), fds.end());
130 for (std::vector<int>::iterator a = copy.begin(); a != copy.end(); a++)
132 EventHandler* ev = ref[*a];
135 if (FD_ISSET (ev->GetFd(), &errfdset))
138 if (getsockopt(ev->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
141 ev->HandleEvent(EVENT_ERROR, errcode);
146 /* NOTE: This is a pair of seperate if statements as the socket
147 * may be in both read and writeable state at the same time.
148 * If an error event occurs above it is not worth processing the
149 * read and write states even if set.
151 if (FD_ISSET (ev->GetFd(), &wfdset))
154 writeable[ev->GetFd()] = false;
155 ev->HandleEvent(EVENT_WRITE);
157 if (FD_ISSET (ev->GetFd(), &rfdset))
160 ev->HandleEvent(EVENT_READ);
169 std::string SelectEngine::GetName()