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