]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengine_select.cpp
80c8646af4eb4933316290b1beccce943343603e
[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         ServerInstance->Log(DEBUG,"SelectEngine::SelectEngine()");
22         EngineHandle = 0;
23         CurrentSetSize = 0;
24         memset(writeable, 0, sizeof(writeable));
25 }
26
27 SelectEngine::~SelectEngine()
28 {
29         ServerInstance->Log(DEBUG,"SelectEngine::~SelectEngine()");
30 }
31
32 bool SelectEngine::AddFd(EventHandler* eh)
33 {
34         int fd = eh->GetFd();
35         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
36         {
37                 ServerInstance->Log(DEBUG,"ERROR: FD of %d added above max of %d",fd,MAX_DESCRIPTORS);
38                 return false;
39         }
40         if (GetRemainingFds() <= 1)
41         {
42                 ServerInstance->Log(DEBUG,"ERROR: System out of file descriptors!");
43                 return false;
44         }
45
46         fds[fd] = fd;
47
48         if (ref[fd])
49                 return false;
50
51         ref[fd] = eh;
52         ServerInstance->Log(DEBUG,"Add socket %d",fd);
53
54         CurrentSetSize++;
55         return true;
56 }
57
58 void SelectEngine::WantWrite(EventHandler* eh)
59 {
60         writeable[eh->GetFd()] = true;
61 }
62
63 bool SelectEngine::DelFd(EventHandler* eh)
64 {
65         int fd = eh->GetFd();
66
67         ServerInstance->Log(DEBUG,"SelectEngine::DelFd(%d)",fd);
68
69         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
70                 return false;
71
72         std::map<int,int>::iterator t = fds.find(fd);
73         if (t != fds.end())
74         {
75                 fds.erase(t);
76                 ServerInstance->Log(DEBUG,"Deleted fd %d",fd);
77         }
78
79         CurrentSetSize--;
80         ref[fd] = NULL;
81         return true;
82 }
83
84 int SelectEngine::GetMaxFds()
85 {
86         return FD_SETSIZE;
87 }
88
89 int SelectEngine::GetRemainingFds()
90 {
91         return FD_SETSIZE - CurrentSetSize;
92 }
93
94 int SelectEngine::DispatchEvents()
95 {
96         int result = 0;
97         timeval tval;
98         int sresult = 0;
99         EventHandler* ev[MAX_DESCRIPTORS];
100         socklen_t codesize;
101         int errcode;
102
103         FD_ZERO(&wfdset);
104         FD_ZERO(&rfdset);
105         FD_ZERO(&errfdset);
106
107         for (std::map<int,int>::iterator a = fds.begin(); a != fds.end(); a++)
108         {
109                 if (ref[a->second]->Readable())
110                         FD_SET (a->second, &rfdset);
111                 else
112                         FD_SET (a->second, &wfdset);
113                 if (writeable[a->second])
114                         FD_SET (a->second, &wfdset);
115
116                 FD_SET (a->second, &errfdset);
117         }
118         tval.tv_sec = 0;
119         tval.tv_usec = 50L;
120         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
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                                 if (ev[i])
144                                 {
145                                         if (getsockopt(ev[i]->GetFd(), SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0)
146                                                 errcode = errno;
147
148                                         ev[i]->HandleEvent(EVENT_ERROR, errcode);
149                                 }
150                                 continue;
151                         }
152                         if (ev[i])
153                         {
154                                 ServerInstance->Log(DEBUG,"Handle %s event on fd %d",writeable[ev[i]->GetFd()] || !ev[i]->Readable() ? "write" : "read", ev[i]->GetFd());
155                                 if (writeable[ev[i]->GetFd()])
156                                 {
157                                         if (ev[i])
158                                                 ev[i]->HandleEvent(EVENT_WRITE);
159                                         writeable[ev[i]->GetFd()] = false;
160                 
161                                 }
162                                 else
163                                 {
164                                         if (ev[i])
165                                                 ev[i]->HandleEvent(ev[i]->Readable() ? EVENT_READ : EVENT_WRITE);
166                                 }
167                         }
168                 }
169         }
170
171         return result;
172 }
173
174 std::string SelectEngine::GetName()
175 {
176         return "select";
177 }