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