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