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