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