]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine_select.cpp
Check is off by one, this wont break anything but will cut a character off the set...
[user/henk/code/inspircd.git] / src / socketengine_select.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 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 #include <sys/select.h>
16 #include "socketengine_select.h"
17
18
19 SelectEngine::SelectEngine(InspIRCd* Instance) : SocketEngine(Instance)
20 {
21         EngineHandle = 0;
22         CurrentSetSize = 0;
23         memset(writeable, 0, sizeof(writeable));
24 }
25
26 SelectEngine::~SelectEngine()
27 {
28 }
29
30 bool SelectEngine::AddFd(EventHandler* eh)
31 {
32         int fd = eh->GetFd();
33         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
34                 return false;
35
36         if (GetRemainingFds() <= 1)
37                 return false;
38
39         if (ref[fd])
40                 return false;
41
42         fds[fd] = fd;
43         ref[fd] = eh;
44         CurrentSetSize++;
45
46         ServerInstance->Log(DEBUG,"New file descriptor: %d", fd);
47         return true;
48 }
49
50 void SelectEngine::WantWrite(EventHandler* eh)
51 {
52         writeable[eh->GetFd()] = true;
53 }
54
55 bool SelectEngine::DelFd(EventHandler* eh, bool force)
56 {
57         int fd = eh->GetFd();
58
59         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
60                 return false;
61
62         std::map<int,int>::iterator t = fds.find(fd);
63         if (t != fds.end())
64                 fds.erase(t);
65
66         CurrentSetSize--;
67         ref[fd] = NULL;
68
69         ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
70         return true;
71 }
72
73 int SelectEngine::GetMaxFds()
74 {
75         return FD_SETSIZE;
76 }
77
78 int SelectEngine::GetRemainingFds()
79 {
80         return FD_SETSIZE - CurrentSetSize;
81 }
82
83 int SelectEngine::DispatchEvents()
84 {
85         int result = 0;
86         timeval tval;
87         int sresult = 0;
88         EventHandler* ev[MAX_DESCRIPTORS];
89         socklen_t codesize;
90         int errcode;
91
92         FD_ZERO(&wfdset);
93         FD_ZERO(&rfdset);
94         FD_ZERO(&errfdset);
95
96         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
97         {
98                 if (ref[a->second]->Readable())
99                         FD_SET (a->second, &rfdset);
100                 else
101                         FD_SET (a->second, &wfdset);
102                 if (writeable[a->second])
103                         FD_SET (a->second, &wfdset);
104
105                 FD_SET (a->second, &errfdset);
106         }
107         tval.tv_sec = 1;
108         tval.tv_usec = 0;
109         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
110         if (sresult > 0)
111         {
112                 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
113                 {
114                         if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))
115                         {
116                                 ev[result++] = ref[a->second];
117                         }
118                 }
119         }
120
121         /** An event handler may remove its own descriptor from the list, therefore it is not
122          * safe to directly iterate over the list and dispatch events there with STL iterators.
123          * Thats a shame because it makes this code slower and more resource intensive, but maybe
124          * the user should stop using select(), as select() smells anyway.
125          */
126         for (int i = 0; i < result; i++)
127         {
128                 if (ev[i])
129                 {
130                         if (FD_ISSET (ev[i]->GetFd(), &errfdset))
131                         {
132                                 if (ev[i])
133                                 {
134                                         if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
135                                                 errcode = errno;
136
137                                         ev[i]->HandleEvent(EVENT_ERROR, errcode);
138                                 }
139                                 continue;
140                         }
141                         if (ev[i])
142                         {
143                                 if (writeable[ev[i]->GetFd()])
144                                 {
145                                         writeable[ev[i]->GetFd()] = false;
146                                         if (ev[i])
147                                                 ev[i]->HandleEvent(EVENT_WRITE);
148                                 }
149                                 else
150                                 {
151                                         if (ev[i])
152                                                 ev[i]->HandleEvent(ev[i]->Readable() ? EVENT_READ : EVENT_WRITE);
153                                 }
154                         }
155                 }
156         }
157
158         return result;
159 }
160
161 std::string SelectEngine::GetName()
162 {
163         return "select";
164 }