]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_select.cpp
Remote /MAP (that now doesn't confuse clients ;p)
[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         EngineHandle = 0;
24         CurrentSetSize = 0;
25
26         writeable = new bool [GetMaxFds()];
27         memset(writeable, 0, sizeof(writeable));
28         ref = new EventHandler* [GetMaxFds()];
29         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
30         ev = new EventHandler* [GetMaxFds()];
31 }
32
33 SelectEngine::~SelectEngine()
34 {
35         delete[] ref;
36         delete[] ev;
37 }
38
39 bool SelectEngine::AddFd(EventHandler* eh)
40 {
41         int fd = eh->GetFd();
42         if ((fd < 0) || (fd > GetMaxFds() - 1))
43                 return false;
44
45         if (GetRemainingFds() <= 1)
46                 return false;
47
48         if (ref[fd])
49                 return false;
50
51         fds[fd] = fd;
52         ref[fd] = eh;
53         CurrentSetSize++;
54
55         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
56         return true;
57 }
58
59 void SelectEngine::WantWrite(EventHandler* eh)
60 {
61         writeable[eh->GetFd()] = true;
62 }
63
64 bool SelectEngine::DelFd(EventHandler* eh, bool force)
65 {
66         int fd = eh->GetFd();
67
68         if ((fd < 0) || (fd > GetMaxFds() - 1))
69                 return false;
70
71         std::map<int,int>::iterator t = fds.find(fd);
72         if (t != fds.end())
73                 fds.erase(t);
74
75         CurrentSetSize--;
76         ref[fd] = NULL;
77
78         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
79         return true;
80 }
81
82 int SelectEngine::GetMaxFds()
83 {
84         return FD_SETSIZE;
85 }
86
87 int SelectEngine::GetRemainingFds()
88 {
89         return GetMaxFds() - CurrentSetSize;
90 }
91
92 int SelectEngine::DispatchEvents()
93 {
94         int result = 0;
95         timeval tval;
96         int sresult = 0;
97         socklen_t codesize;
98         int errcode;
99
100         FD_ZERO(&wfdset);
101         FD_ZERO(&rfdset);
102         FD_ZERO(&errfdset);
103
104         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
105         {
106                 if (ref[a->second]->Readable())
107                         FD_SET (a->second, &rfdset);
108                 else
109                         FD_SET (a->second, &wfdset);
110                 if (writeable[a->second])
111                         FD_SET (a->second, &wfdset);
112
113                 FD_SET (a->second, &errfdset);
114         }
115
116         tval.tv_sec = 1;
117         tval.tv_usec = 0;
118
119         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
120
121         if (sresult > 0)
122         {
123                 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
124                 {
125                         if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))
126                         {
127                                 ev[result++] = ref[a->second];
128                         }
129                 }
130         }
131
132         /** An event handler may remove its own descriptor from the list, therefore it is not
133          * safe to directly iterate over the list and dispatch events there with STL iterators.
134          * Thats a shame because it makes this code slower and more resource intensive, but maybe
135          * the user should stop using select(), as select() smells anyway.
136          */
137         for (int i = 0; i < result; i++)
138         {
139                 if (ev[i])
140                 {
141                         if (FD_ISSET (ev[i]->GetFd(), &errfdset))
142                         {
143                                 ErrorEvents++;
144
145                                 if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
146                                         errcode = errno;
147
148                                 ev[i]->HandleEvent(EVENT_ERROR, errcode);
149
150                                 continue;
151                         }
152                         else
153                         {
154                                 if (writeable[ev[i]->GetFd()])
155                                 {
156                                         WriteEvents++;
157                                         writeable[ev[i]->GetFd()] = false;
158                                         ev[i]->HandleEvent(EVENT_WRITE);
159                                 }
160                                 else
161                                 {
162                                         if (ev[i]->Readable())
163                                         {
164                                                 ReadEvents++;
165                                                 ev[i]->HandleEvent(EVENT_READ);
166                                         }
167                                         else
168                                         {
169                                                 WriteEvents++;
170                                                 ev[i]->HandleEvent(EVENT_WRITE);
171                                         }
172                                 }
173                         }
174                 }
175         }
176
177         return result;
178 }
179
180 std::string SelectEngine::GetName()
181 {
182         return "select";
183 }