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