1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 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*));
31 ev = new EventHandler* [GetMaxFds()];
34 SelectEngine::~SelectEngine()
40 bool SelectEngine::AddFd(EventHandler* eh)
43 if ((fd < 0) || (fd > GetMaxFds() - 1))
46 if (GetRemainingFds() <= 1)
56 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
60 void SelectEngine::WantWrite(EventHandler* eh)
62 writeable[eh->GetFd()] = true;
65 bool SelectEngine::DelFd(EventHandler* eh, bool force)
69 if ((fd < 0) || (fd > GetMaxFds() - 1))
72 std::map<int,int>::iterator t = fds.find(fd);
79 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
83 int SelectEngine::GetMaxFds()
88 int SelectEngine::GetRemainingFds()
90 return GetMaxFds() - CurrentSetSize;
93 int SelectEngine::DispatchEvents()
104 /* Populate the select FD set (this is why select sucks compared to epoll, kqueue, IOCP) */
105 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
107 if (ref[a->second]->Readable())
108 /* Read notifications */
109 FD_SET (a->second, &rfdset);
111 /* Write notifications */
112 FD_SET (a->second, &wfdset);
114 /* Explicitly one-time writeable */
115 if (writeable[a->second])
116 FD_SET (a->second, &wfdset);
118 /* All sockets must receive error notifications regardless */
119 FD_SET (a->second, &errfdset);
122 /* One second waits */
126 sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
128 /* Nothing to process this time around */
132 /* Safe assumption (as of 1.1 anyway) that a socket can't remove itself from the list in the middle of the loop */
133 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
135 EventHandler* ev = ref[a->second];
138 if (FD_ISSET (ev->GetFd(), &errfdset))
141 if (getsockopt(ev->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
144 ev->HandleEvent(EVENT_ERROR, errcode);
149 /* NOTE: This is a pair of seperate if statements as the socket
150 * may be in both read and writeable state at the same time.
151 * If an error event occurs above it is not worth processing the
152 * read and write states even if set.
154 if (FD_ISSET (ev->GetFd(), &wfdset))
157 writeable[ev->GetFd()] = false;
158 ev->HandleEvent(EVENT_WRITE);
160 if (FD_ISSET (ev->GetFd(), &rfdset))
163 ev->HandleEvent(EVENT_READ);
172 std::string SelectEngine::GetName()