]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_ports.cpp
Merge pull request #1407 from genius3000/master+update_helpop_extbans
[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
24 #ifndef __sun
25 # error You need Solaris 10 or later to make use of this code.
26 #endif
27
28 #include "inspircd.h"
29 #include <port.h>
30 #include <iostream>
31 #include <ulimit.h>
32
33 /** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
34  */
35 namespace
36 {
37         /** These are used by ports to hold socket events
38          */
39         std::vector<port_event_t> events(16);
40         int EngineHandle;
41 }
42
43 /** Initialize ports engine
44  */
45 void SocketEngine::Init()
46 {
47         // MAX_DESCRIPTORS is mainly used for display purposes, no problem if ulimit() fails and returns a negative number
48         MAX_DESCRIPTORS = ulimit(4, 0);
49
50         EngineHandle = port_create();
51
52         if (EngineHandle == -1)
53         {
54                 ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: Could not initialize socket engine: %s", strerror(errno));
55                 ServerInstance->Logs->Log("SOCKET", LOG_SPARSE, "ERROR: This is a fatal error, exiting now.");
56                 std::cout << "ERROR: Could not initialize socket engine: " << strerror(errno) << std::endl;
57                 std::cout << "ERROR: This is a fatal error, exiting now." << std::endl;
58                 ServerInstance->QuickExit(EXIT_STATUS_SOCKETENGINE);
59         }
60 }
61
62 /** Shutdown the ports engine
63  */
64 void SocketEngine::Deinit()
65 {
66         SocketEngine::Close(EngineHandle);
67 }
68
69 void SocketEngine::RecoverFromFork()
70 {
71 }
72
73 static int mask_to_events(int event_mask)
74 {
75         int rv = 0;
76         if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
77                 rv |= POLLRDNORM;
78         if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
79                 rv |= POLLWRNORM;
80         return rv;
81 }
82
83 bool SocketEngine::AddFd(EventHandler* eh, int event_mask)
84 {
85         int fd = eh->GetFd();
86         if (fd < 0)
87                 return false;
88
89         if (!SocketEngine::AddFdRef(eh))
90                 return false;
91
92         eh->SetEventMask(event_mask);
93         port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
94
95         ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd);
96         ResizeDouble(events);
97
98         return true;
99 }
100
101 void SocketEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
102 {
103         if (mask_to_events(new_mask) != mask_to_events(old_mask))
104                 port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
105 }
106
107 void SocketEngine::DelFd(EventHandler* eh)
108 {
109         int fd = eh->GetFd();
110         if (fd < 0)
111                 return;
112
113         port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
114
115         SocketEngine::DelFdRef(eh);
116
117         ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "Remove file descriptor: %d", fd);
118 }
119
120 int SocketEngine::DispatchEvents()
121 {
122         struct timespec poll_time;
123
124         poll_time.tv_sec = 1;
125         poll_time.tv_nsec = 0;
126
127         unsigned int nget = 1; // used to denote a retrieve request.
128         int ret = port_getn(EngineHandle, &events[0], events.size(), &nget, &poll_time);
129         ServerInstance->UpdateTime();
130
131         // first handle an error condition
132         if (ret == -1)
133                 return -1;
134
135         stats.TotalEvents += nget;
136
137         unsigned int i;
138         for (i = 0; i < nget; i++)
139         {
140                 port_event_t& ev = events[i];
141
142                 if (ev.portev_source != PORT_SOURCE_FD)
143                         continue;
144
145                 // Copy these in case the vector gets resized and ev invalidated
146                 const int fd = ev.portev_object;
147                 const int portev_events = ev.portev_events;
148                 EventHandler* eh = static_cast<EventHandler*>(ev.portev_user);
149                 if (eh->GetFd() < 0)
150                         continue;
151
152                 int mask = eh->GetEventMask();
153                 if (portev_events & POLLWRNORM)
154                         mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
155                 if (portev_events & POLLRDNORM)
156                         mask &= ~FD_READ_WILL_BLOCK;
157                 // reinsert port for next time around, pretending to be one-shot for writes
158                 eh->SetEventMask(mask);
159                 port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
160                 if (portev_events & POLLRDNORM)
161                 {
162                         eh->OnEventHandlerRead();
163                         if (eh != GetRef(fd))
164                                 continue;
165                 }
166                 if (portev_events & POLLWRNORM)
167                 {
168                         eh->OnEventHandlerWrite();
169                 }
170         }
171
172         return (int)i;
173 }