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