]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_select.cpp
Ugly-ish hack to select SocketEngine on windows until I or someone else finds a bette...
[user/henk/code/inspircd.git] / src / socketengines / socketengine_select.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd_config.h"
15 #ifndef CONFIG_USE_IOCP
16
17 #include "inspircd.h"
18 #ifndef WINDOWS
19 #include <sys/select.h>
20 #endif // WINDOWS
21
22 #ifndef __SOCKETENGINE_SELECT__
23 #define __SOCKETENGINE_SELECT__
24
25 #include <vector>
26 #include <string>
27 #include <map>
28 #ifndef WINDOWS
29 #include <sys/select.h>
30 #endif // WINDOWS
31 #include "inspircd.h"
32 #include "socketengine.h"
33
34 /** A specialisation of the SocketEngine class, designed to use traditional select().
35  */
36 class SelectEngine : public SocketEngine
37 {
38 public:
39         /** Create a new SelectEngine
40          */
41         SelectEngine();
42         /** Delete a SelectEngine
43          */
44         virtual ~SelectEngine();
45         virtual bool AddFd(EventHandler* eh, int event_mask);
46         virtual bool DelFd(EventHandler* eh, bool force = false);
47         void OnSetEvent(EventHandler* eh, int, int);
48         virtual int DispatchEvents();
49         virtual std::string GetName();
50 };
51
52 #endif
53
54
55
56 SelectEngine::SelectEngine()
57 {
58         MAX_DESCRIPTORS = FD_SETSIZE;
59         CurrentSetSize = 0;
60
61         ref = new EventHandler* [GetMaxFds()];
62         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
63 }
64
65 SelectEngine::~SelectEngine()
66 {
67         delete[] ref;
68 }
69
70 bool SelectEngine::AddFd(EventHandler* eh, int event_mask)
71 {
72         int fd = eh->GetFd();
73         if ((fd < 0) || (fd > GetMaxFds() - 1))
74                 return false;
75
76         if (ref[fd])
77                 return false;
78
79         ref[fd] = eh;
80         SocketEngine::SetEventMask(eh, event_mask);
81         CurrentSetSize++;
82
83         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
84         return true;
85 }
86
87 bool SelectEngine::DelFd(EventHandler* eh, bool force)
88 {
89         int fd = eh->GetFd();
90
91         if ((fd < 0) || (fd > GetMaxFds() - 1))
92                 return false;
93
94         CurrentSetSize--;
95         ref[fd] = NULL;
96
97         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
98         return true;
99 }
100
101 void SelectEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
102 {
103         // deal with it later
104 }
105
106 int SelectEngine::DispatchEvents()
107 {
108         timeval tval;
109         int sresult = 0;
110         socklen_t codesize = sizeof(int);
111         int errcode = 0;
112
113         fd_set wfdset, rfdset, errfdset;
114         FD_ZERO(&wfdset);
115         FD_ZERO(&rfdset);
116         FD_ZERO(&errfdset);
117
118         /* Populate the select FD sets (this is why select sucks compared to epoll, kqueue, IOCP) */
119         for (unsigned int i = 0; i < FD_SETSIZE; i++)
120         {
121                 EventHandler* eh = ref[i];
122                 if (!eh)
123                         continue;
124                 int state = eh->GetEventMask();
125                 if (state & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
126                         FD_SET (i, &rfdset);
127                 if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
128                         FD_SET (i, &wfdset);
129                 FD_SET (i, &errfdset);
130         }
131
132         /* One second wait */
133         tval.tv_sec = 1;
134         tval.tv_usec = 0;
135
136         sresult = select(FD_SETSIZE, &rfdset, &wfdset, &errfdset, &tval);
137
138         /* Nothing to process this time around */
139         if (sresult < 1)
140                 return 0;
141
142         for (int i = 0; i < FD_SETSIZE; i++)
143         {
144                 EventHandler* ev = ref[i];
145                 if (ev)
146                 {
147                         if (FD_ISSET (i, &errfdset))
148                         {
149                                 ErrorEvents++;
150                                 if (getsockopt(i, SOL_SOCKET, SO_ERROR, (char*)&errcode, &codesize) < 0)
151                                         errcode = errno;
152
153                                 ev->HandleEvent(EVENT_ERROR, errcode);
154                                 continue;
155                         }
156                         else
157                         {
158                                 /* NOTE: This is a pair of seperate if statements as the socket
159                                  * may be in both read and writeable state at the same time.
160                                  * If an error event occurs above it is not worth processing the
161                                  * read and write states even if set.
162                                  */
163                                 if (FD_ISSET (i, &rfdset))
164                                 {
165                                         ReadEvents++;
166                                         SetEventMask(ev, ev->GetEventMask() & ~FD_READ_WILL_BLOCK);
167                                         ev->HandleEvent(EVENT_READ);
168                                 }
169                                 if (FD_ISSET (i, &wfdset))
170                                 {
171                                         WriteEvents++;
172                                         SetEventMask(ev, ev->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
173                                         ev->HandleEvent(EVENT_WRITE);
174                                 }
175                         }
176                 }
177         }
178
179         return sresult;
180 }
181
182 std::string SelectEngine::GetName()
183 {
184         return "select";
185 }
186
187 SocketEngine* CreateSocketEngine()
188 {
189         return new SelectEngine;
190 }
191 #endif