]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_select.cpp
Header update: 2007 -> 2008
[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 #include <sys/select.h>
16 #include "socketengines/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         fds[fd] = 0;
69
70         ServerInstance->Log(DEBUG,"Remove file descriptor: %d", fd);
71         return true;
72 }
73
74 int SelectEngine::GetMaxFds()
75 {
76         return FD_SETSIZE;
77 }
78
79 int SelectEngine::GetRemainingFds()
80 {
81         return FD_SETSIZE - CurrentSetSize;
82 }
83
84 int SelectEngine::DispatchEvents()
85 {
86         int result = 0;
87         timeval tval;
88         int sresult = 0;
89         EventHandler* ev[MAX_DESCRIPTORS];
90         socklen_t codesize;
91         int errcode;
92
93         FD_ZERO(&wfdset);
94         FD_ZERO(&rfdset);
95         FD_ZERO(&errfdset);
96
97         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
98         {
99                 if (ref[a->second]->Readable())
100                         FD_SET (a->second, &rfdset);
101                 else
102                         FD_SET (a->second, &wfdset);
103                 if (writeable[a->second])
104                         FD_SET (a->second, &wfdset);
105
106                 FD_SET (a->second, &errfdset);
107         }
108         tval.tv_sec = 1;
109         tval.tv_usec = 0;
110         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
111         if (sresult > 0)
112         {
113                 for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
114                 {
115                         if ((FD_ISSET (a->second, &rfdset)) || (FD_ISSET (a->second, &wfdset)) || FD_ISSET (a->second, &errfdset))
116                         {
117                                 ev[result++] = ref[a->second];
118                         }
119                 }
120         }
121
122         /** An event handler may remove its own descriptor from the list, therefore it is not
123          * safe to directly iterate over the list and dispatch events there with STL iterators.
124          * Thats a shame because it makes this code slower and more resource intensive, but maybe
125          * the user should stop using select(), as select() smells anyway.
126          */
127         for (int i = 0; i < result; i++)
128         {
129                 if (ev[i])
130                 {
131                         if (FD_ISSET (ev[i]->GetFd(), &errfdset))
132                         {
133                                 if (ev[i])
134                                 {
135                                         if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
136                                                 errcode = errno;
137
138                                         ev[i]->HandleEvent(EVENT_ERROR, errcode);
139                                 }
140                                 continue;
141                         }
142                         if (ev[i])
143                         {
144                                 if (writeable[ev[i]->GetFd()])
145                                 {
146                                         writeable[ev[i]->GetFd()] = false;
147                                         if (ev[i])
148                                                 ev[i]->HandleEvent(EVENT_WRITE);
149                                 }
150                                 else
151                                 {
152                                         if (ev[i])
153                                                 ev[i]->HandleEvent(ev[i]->Readable() ? EVENT_READ : EVENT_WRITE);
154                                 }
155                         }
156                 }
157         }
158
159         return result;
160 }
161
162 std::string SelectEngine::GetName()
163 {
164         return "select";
165 }