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 * ---------------------------------------------------
15 #include "exitcodes.h"
16 #include "socketengines/socketengine_poll.h"
19 #include <sys/sysctl.h>
22 PollEngine::PollEngine(InspIRCd* Instance) : SocketEngine(Instance)
24 // Poll requires no special setup (which is nice).
28 ref = new EventHandler* [GetMaxFds()];
29 events = new struct pollfd[GetMaxFds()];
31 memset(events, 0, GetMaxFds() * sizeof(struct pollfd));
32 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
35 PollEngine::~PollEngine()
37 // No destruction required, either.
42 bool PollEngine::AddFd(EventHandler* eh)
45 if ((fd < 0) || (fd > GetMaxFds() - 1))
47 ServerInstance->Logs->Log("SOCKET",DEBUG,"AddFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
51 if (GetRemainingFds() <= 1)
53 ServerInstance->Logs->Log("SOCKET",DEBUG,"No remaining FDs cannot add fd: %d", fd);
57 if (fd_mappings.find(fd) != fd_mappings.end())
59 ServerInstance->Logs->Log("SOCKET",DEBUG,"Attempt to add duplicate fd: %d", fd);
63 unsigned int index = CurrentSetSize;
65 fd_mappings[fd] = index;
67 events[index].fd = fd;
70 events[index].events = POLLIN;
74 events[index].events = POLLOUT;
77 ServerInstance->Logs->Log("SOCKET", DEBUG,"New file descriptor: %d (%d; index %d)", fd, events[fd].events, index);
82 EventHandler* PollEngine::GetRef(int fd)
84 std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
85 if (it == fd_mappings.end())
87 return ref[it->second];
90 void PollEngine::WantWrite(EventHandler* eh)
92 std::map<int, unsigned int>::iterator it = fd_mappings.find(eh->GetFd());
93 if (it == fd_mappings.end())
95 ServerInstance->Logs->Log("SOCKET",DEBUG,"WantWrite() on unknown fd: %d", eh->GetFd());
99 events[it->second].events = POLLIN | POLLOUT;
102 bool PollEngine::DelFd(EventHandler* eh, bool force)
104 int fd = eh->GetFd();
105 if ((fd < 0) || (fd > MAX_DESCRIPTORS))
107 ServerInstance->Logs->Log("SOCKET", DEBUG, "DelFd out of range: (fd: %d, max: %d)", fd, GetMaxFds());
111 std::map<int, unsigned int>::iterator it = fd_mappings.find(fd);
112 if (it == fd_mappings.end())
114 ServerInstance->Logs->Log("SOCKET",DEBUG,"DelFd() on unknown fd: %d", fd);
118 unsigned int index = it->second;
119 unsigned int last_index = CurrentSetSize - 1;
120 int last_fd = events[last_index].fd;
122 if (index != last_index)
124 // We need to move the last fd we got into this gap (gaps are evil!)
126 // So update the mapping for the last fd to its new position
127 fd_mappings[last_fd] = index;
129 // move last_fd from last_index into index
130 events[index].fd = last_fd;
131 events[index].events = events[last_index].events;
133 ref[index] = ref[last_index];
136 // Now remove all data for the last fd we got into out list.
137 // Above code made sure this always is right
138 fd_mappings.erase(it);
139 events[last_index].fd = 0;
140 events[last_index].events = 0;
141 ref[last_index] = NULL;
145 ServerInstance->Logs->Log("SOCKET", DEBUG, "Remove file descriptor: %d (index: %d) "
146 "(Filled gap with: %d (index: %d))", fd, index, last_fd, last_index);
150 int PollEngine::GetMaxFds()
154 return MAX_DESCRIPTORS;
156 int max = ulimit(4, 0);
159 MAX_DESCRIPTORS = max;
165 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets: %s", strerror(errno));
166 printf("ERROR: Can't determine maximum number of open sockets: %s\n", strerror(errno));
167 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
171 if (!MAX_DESCRIPTORS)
173 int mib[2], maxfiles;
177 mib[1] = KERN_MAXFILES;
178 len = sizeof(maxfiles);
179 sysctl(mib, 2, &maxfiles, &len, NULL, 0);
180 MAX_DESCRIPTORS = maxfiles;
183 return MAX_DESCRIPTORS;
187 int PollEngine::GetRemainingFds()
189 return MAX_DESCRIPTORS - CurrentSetSize;
192 int PollEngine::DispatchEvents()
194 int i = poll(events, CurrentSetSize, 1000);
196 socklen_t codesize = sizeof(int);
202 for (index = 0; index < CurrentSetSize && processed != i; index++)
204 if (events[index].revents)
207 if (events[index].revents & POLLHUP)
210 ref[index]->HandleEvent(EVENT_ERROR, 0);
214 if (events[index].revents & POLLERR)
217 int fd = events[index].fd;
220 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
223 ref[index]->HandleEvent(EVENT_ERROR, errcode);
227 if (events[index].revents & POLLOUT)
229 // Switch to wanting read again
230 // event handlers have to request to write again if they need it
231 events[index].events = POLLIN;
234 ref[index]->HandleEvent(EVENT_WRITE);
237 if (events[index].revents & POLLIN)
240 ref[index]->HandleEvent(EVENT_READ);
248 std::string PollEngine::GetName()