]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_ports.cpp
Fix Doxygen syntax errors.
[user/henk/code/inspircd.git] / src / socketengines / socketengine_ports.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include "inspircd.h"
22 #include "exitcodes.h"
23 #include <port.h>
24
25 #ifndef SOCKETENGINE_PORTS
26 #define SOCKETENGINE_PORTS
27
28 #ifndef __sun
29 # error You need Solaris 10 or later to make use of this code.
30 #endif
31
32 #include <vector>
33 #include <string>
34 #include <map>
35 #include "inspircd_config.h"
36 #include "inspircd.h"
37 #include "socketengine.h"
38 #include <port.h>
39
40 /** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
41  */
42 class PortsEngine : public SocketEngine
43 {
44 private:
45         /** These are used by epoll() to hold socket events
46          */
47         port_event_t* events;
48 public:
49         /** Create a new PortsEngine
50          */
51         PortsEngine();
52         /** Delete a PortsEngine
53          */
54         virtual ~PortsEngine();
55         virtual bool AddFd(EventHandler* eh, int event_mask);
56         void OnSetEvent(EventHandler* eh, int old_event, int new_event);
57         virtual void DelFd(EventHandler* eh);
58         virtual int DispatchEvents();
59         virtual std::string GetName();
60         virtual void WantWrite(EventHandler* eh);
61 };
62
63 #endif
64
65
66 #include <ulimit.h>
67
68 PortsEngine::PortsEngine()
69 {
70         int max = ulimit(4, 0);
71         if (max > 0)
72         {
73                 MAX_DESCRIPTORS = max;
74         }
75         else
76         {
77                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
78                 printf("ERROR: Can't determine maximum number of open sockets!\n");
79                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
80         }
81         EngineHandle = port_create();
82
83         if (EngineHandle == -1)
84         {
85                 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
86                 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now.");
87                 printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
88                 printf("ERROR: This is a fatal error, exiting now.\n");
89                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
90         }
91         CurrentSetSize = 0;
92
93         ref = new EventHandler* [GetMaxFds()];
94         events = new port_event_t[GetMaxFds()];
95         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
96 }
97
98 PortsEngine::~PortsEngine()
99 {
100         this->Close(EngineHandle);
101         delete[] ref;
102         delete[] events;
103 }
104
105 static int mask_to_events(int event_mask)
106 {
107         int rv = 0;
108         if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
109                 rv |= POLLRDNORM;
110         if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
111                 rv |= POLLWRNORM;
112         return rv;
113 }
114
115 bool PortsEngine::AddFd(EventHandler* eh, int event_mask)
116 {
117         int fd = eh->GetFd();
118         if ((fd < 0) || (fd > GetMaxFds() - 1))
119                 return false;
120
121         if (ref[fd])
122                 return false;
123
124         ref[fd] = eh;
125         SocketEngine::SetEventMask(eh, event_mask);
126         port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
127
128         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
129         CurrentSetSize++;
130         return true;
131 }
132
133 void PortsEngine::WantWrite(EventHandler* eh, int old_mask, int new_mask)
134 {
135         if (mask_to_events(new_mask) != mask_to_events(old_mask))
136                 port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
137 }
138
139 void PortsEngine::DelFd(EventHandler* eh)
140 {
141         int fd = eh->GetFd();
142         if ((fd < 0) || (fd > GetMaxFds() - 1))
143                 return;
144
145         port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
146
147         CurrentSetSize--;
148         ref[fd] = NULL;
149
150         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
151         return true;
152 }
153
154 int PortsEngine::DispatchEvents()
155 {
156         struct timespec poll_time;
157
158         poll_time.tv_sec = 1;
159         poll_time.tv_nsec = 0;
160
161         unsigned int nget = 1; // used to denote a retrieve request.
162         int i = port_getn(EngineHandle, this->events, GetMaxFds() - 1, &nget, &poll_time);
163         ServerInstance->UpdateTime();
164
165         // first handle an error condition
166         if (i == -1)
167                 return i;
168
169         TotalEvents += nget;
170
171         for (i = 0; i < nget; i++)
172         {
173                 switch (this->events[i].portev_source)
174                 {
175                         case PORT_SOURCE_FD:
176                         {
177                                 int fd = this->events[i].portev_object;
178                                 EventHandler* eh = ref[fd];
179                                 if (eh)
180                                 {
181                                         int mask = eh->GetEventMask();
182                                         if (events[i].portev_events & POLLWRNORM)
183                                                 mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
184                                         if (events[i].portev_events & POLLRDNORM)
185                                                 mask &= ~FD_READ_WILL_BLOCK;
186                                         // reinsert port for next time around, pretending to be one-shot for writes
187                                         SetEventMask(ev, mask);
188                                         port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
189                                         if (events[i].portev_events & POLLRDNORM)
190                                         {
191                                                 ReadEvents++;
192                                                 eh->HandleEvent(EVENT_READ);
193                                                 if (eh != ref[fd])
194                                                         continue;
195                                         }
196                                         if (events[i].portev_events & POLLWRNORM)
197                                         {
198                                                 WriteEvents++;
199                                                 eh->HandleEvent(EVENT_WRITE);
200                                         }
201                                 }
202                         }
203                         default:
204                         break;
205                 }
206         }
207
208         return i;
209 }
210
211 std::string PortsEngine::GetName()
212 {
213         return "ports";
214 }
215
216 SocketEngine* CreateSocketEngine()
217 {
218         return new PortsEngine;
219 }