]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_ports.cpp
Replace printf(_c) with iostream
[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 #include <iostream>
40
41 /** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
42  */
43 class PortsEngine : public SocketEngine
44 {
45 private:
46         /** These are used by epoll() to hold socket events
47          */
48         port_event_t* events;
49 public:
50         /** Create a new PortsEngine
51          */
52         PortsEngine();
53         /** Delete a PortsEngine
54          */
55         virtual ~PortsEngine();
56         virtual bool AddFd(EventHandler* eh, int event_mask);
57         void OnSetEvent(EventHandler* eh, int old_event, int new_event);
58         virtual void DelFd(EventHandler* eh);
59         virtual int DispatchEvents();
60         virtual std::string GetName();
61         virtual void WantWrite(EventHandler* eh);
62 };
63
64 #endif
65
66
67 #include <ulimit.h>
68
69 PortsEngine::PortsEngine()
70 {
71         int max = ulimit(4, 0);
72         if (max > 0)
73         {
74                 MAX_DESCRIPTORS = max;
75         }
76         else
77         {
78                 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
79                 std::cout << "ERROR: Can't determine maximum number of open sockets!" << std::endl;
80                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
81         }
82         EngineHandle = port_create();
83
84         if (EngineHandle == -1)
85         {
86                 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
87                 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now.");
88                 std::cout << "ERROR: Could not initialize socket engine: " << strerror(errno) << std::endl;
89                 std::cout << "ERROR: This is a fatal error, exiting now." << std::endl;
90                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
91         }
92         CurrentSetSize = 0;
93
94         ref = new EventHandler* [GetMaxFds()];
95         events = new port_event_t[GetMaxFds()];
96         memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
97 }
98
99 PortsEngine::~PortsEngine()
100 {
101         this->Close(EngineHandle);
102         delete[] ref;
103         delete[] events;
104 }
105
106 static int mask_to_events(int event_mask)
107 {
108         int rv = 0;
109         if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
110                 rv |= POLLRDNORM;
111         if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
112                 rv |= POLLWRNORM;
113         return rv;
114 }
115
116 bool PortsEngine::AddFd(EventHandler* eh, int event_mask)
117 {
118         int fd = eh->GetFd();
119         if ((fd < 0) || (fd > GetMaxFds() - 1))
120                 return false;
121
122         if (ref[fd])
123                 return false;
124
125         ref[fd] = eh;
126         SocketEngine::SetEventMask(eh, event_mask);
127         port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
128
129         ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
130         CurrentSetSize++;
131         return true;
132 }
133
134 void PortsEngine::WantWrite(EventHandler* eh, int old_mask, int new_mask)
135 {
136         if (mask_to_events(new_mask) != mask_to_events(old_mask))
137                 port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
138 }
139
140 void PortsEngine::DelFd(EventHandler* eh)
141 {
142         int fd = eh->GetFd();
143         if ((fd < 0) || (fd > GetMaxFds() - 1))
144                 return;
145
146         port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
147
148         CurrentSetSize--;
149         ref[fd] = NULL;
150
151         ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
152         return true;
153 }
154
155 int PortsEngine::DispatchEvents()
156 {
157         struct timespec poll_time;
158
159         poll_time.tv_sec = 1;
160         poll_time.tv_nsec = 0;
161
162         unsigned int nget = 1; // used to denote a retrieve request.
163         int i = port_getn(EngineHandle, this->events, GetMaxFds() - 1, &nget, &poll_time);
164         ServerInstance->UpdateTime();
165
166         // first handle an error condition
167         if (i == -1)
168                 return i;
169
170         TotalEvents += nget;
171
172         for (i = 0; i < nget; i++)
173         {
174                 switch (this->events[i].portev_source)
175                 {
176                         case PORT_SOURCE_FD:
177                         {
178                                 int fd = this->events[i].portev_object;
179                                 EventHandler* eh = ref[fd];
180                                 if (eh)
181                                 {
182                                         int mask = eh->GetEventMask();
183                                         if (events[i].portev_events & POLLWRNORM)
184                                                 mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
185                                         if (events[i].portev_events & POLLRDNORM)
186                                                 mask &= ~FD_READ_WILL_BLOCK;
187                                         // reinsert port for next time around, pretending to be one-shot for writes
188                                         SetEventMask(ev, mask);
189                                         port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
190                                         if (events[i].portev_events & POLLRDNORM)
191                                         {
192                                                 ReadEvents++;
193                                                 eh->HandleEvent(EVENT_READ);
194                                                 if (eh != ref[fd])
195                                                         continue;
196                                         }
197                                         if (events[i].portev_events & POLLWRNORM)
198                                         {
199                                                 WriteEvents++;
200                                                 eh->HandleEvent(EVENT_WRITE);
201                                         }
202                                 }
203                         }
204                         default:
205                         break;
206                 }
207         }
208
209         return i;
210 }
211
212 std::string PortsEngine::GetName()
213 {
214         return "ports";
215 }
216
217 SocketEngine* CreateSocketEngine()
218 {
219         return new PortsEngine;
220 }