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