]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_select.cpp
Calculate hosts on connect so theres no way around a ban on your cloak, even if you...
[user/henk/code/inspircd.git] / src / socketengines / socketengine_select.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #ifndef WINDOWS
16 #include <sys/select.h>
17 #endif // WINDOWS
18 #include "socketengines/socketengine_select.h"
19
20
21 SelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance)
22 {
23         MAX_DESCRIPTORS = FD_SETSIZE;
24         EngineHandle = 0;
25         CurrentSetSize = 0;
26
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()];
32 }
33
34 SelectEngine::~SelectEngine()
35 {
36         delete[] ref;
37         delete[] ev;
38 }
39
40 bool SelectEngine::AddFd(EventHandler* eh)
41 {
42         int fd = eh->GetFd();
43         if ((fd < 0) || (fd > GetMaxFds() - 1))
44                 return false;
45
46         if (GetRemainingFds() <= 1)
47                 return false;
48
49         if (ref[fd])
50                 return false;
51
52         fds[fd] = fd;
53         ref[fd] = eh;
54         CurrentSetSize++;
55
56         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
57         return true;
58 }
59
60 void SelectEngine::WantWrite(EventHandler* eh)
61 {
62         writeable[eh->GetFd()] = true;
63 }
64
65 bool SelectEngine::DelFd(EventHandler* eh, bool force)
66 {
67         int fd = eh->GetFd();
68
69         if ((fd < 0) || (fd > GetMaxFds() - 1))
70                 return false;
71
72         std::map<int,int>::iterator t = fds.find(fd);
73         if (t != fds.end())
74                 fds.erase(t);
75
76         CurrentSetSize--;
77         ref[fd] = NULL;
78
79         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
80         return true;
81 }
82
83 int SelectEngine::GetMaxFds()
84 {
85         return FD_SETSIZE;
86 }
87
88 int SelectEngine::GetRemainingFds()
89 {
90         return GetMaxFds() - CurrentSetSize;
91 }
92
93 int SelectEngine::DispatchEvents()
94 {
95         int result = 0;
96         timeval tval;
97         int sresult = 0;
98         socklen_t codesize;
99         int errcode;
100
101         FD_ZERO(&wfdset);
102         FD_ZERO(&rfdset);
103         FD_ZERO(&errfdset);
104
105         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
106         {
107                 if (ref[a->second]->Readable())
108                         FD_SET (a->second, &rfdset);
109                 else
110                         FD_SET (a->second, &wfdset);
111                 if (writeable[a->second])
112                         FD_SET (a->second, &wfdset);
113
114                 FD_SET (a->second, &errfdset);
115         }
116
117         tval.tv_sec = 1;
118         tval.tv_usec = 0;
119
120         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
121
122         if (sresult > 0)
123         {
124                 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
125                 {
126                         if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))
127                         {
128                                 ev[result++] = ref[a->second];
129                         }
130                 }
131         }
132
133         /** An event handler may remove its own descriptor from the list, therefore it is not
134          * safe to directly iterate over the list and dispatch events there with STL iterators.
135          * Thats a shame because it makes this code slower and more resource intensive, but maybe
136          * the user should stop using select(), as select() smells anyway.
137          */
138         for (int i = 0; i < result; i++)
139         {
140                 if (ev[i])
141                 {
142                         if (FD_ISSET (ev[i]->GetFd(), &errfdset))
143                         {
144                                 ErrorEvents++;
145
146                                 if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
147                                         errcode = errno;
148
149                                 ev[i]->HandleEvent(EVENT_ERROR, errcode);
150
151                                 continue;
152                         }
153                         else
154                         {
155                                 if (writeable[ev[i]->GetFd()])
156                                 {
157                                         WriteEvents++;
158                                         writeable[ev[i]->GetFd()] = false;
159                                         ev[i]->HandleEvent(EVENT_WRITE);
160                                 }
161                                 else
162                                 {
163                                         if (ev[i]->Readable())
164                                         {
165                                                 ReadEvents++;
166                                                 ev[i]->HandleEvent(EVENT_READ);
167                                         }
168                                         else
169                                         {
170                                                 WriteEvents++;
171                                                 ev[i]->HandleEvent(EVENT_WRITE);
172                                         }
173                                 }
174                         }
175                 }
176         }
177
178         return result;
179 }
180
181 std::string SelectEngine::GetName()
182 {
183         return "select";
184 }