1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2010 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
15 #include "exitcodes.h"
18 #ifndef __SOCKETENGINE_PORTS__
19 #define __SOCKETENGINE_PORTS__
22 # error You need Solaris 10 or later to make use of this code.
28 #include "inspircd_config.h"
30 #include "socketengine.h"
33 /** A specialisation of the SocketEngine class, designed to use solaris 10 I/O completion ports
35 class PortsEngine : public SocketEngine
38 /** These are used by epoll() to hold socket events
42 /** Create a new PortsEngine
43 * @param Instance The creator of this object
46 /** Delete a PortsEngine
48 virtual ~PortsEngine();
49 virtual bool AddFd(EventHandler* eh, int event_mask);
50 void OnSetEvent(EventHandler* eh, int old_event, int new_event);
51 virtual void DelFd(EventHandler* eh);
52 virtual int DispatchEvents();
53 virtual std::string GetName();
54 virtual void WantWrite(EventHandler* eh);
62 PortsEngine::PortsEngine()
64 int max = ulimit(4, 0);
67 MAX_DESCRIPTORS = max;
72 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
73 printf("ERROR: Can't determine maximum number of open sockets!\n");
74 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
76 EngineHandle = port_create();
78 if (EngineHandle == -1)
80 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
81 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now.");
82 printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
83 printf("ERROR: This is a fatal error, exiting now.\n");
84 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
88 ref = new EventHandler* [GetMaxFds()];
89 events = new port_event_t[GetMaxFds()];
90 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
93 PortsEngine::~PortsEngine()
95 this->Close(EngineHandle);
100 static int mask_to_events(int event_mask)
103 if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
105 if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
110 bool PortsEngine::AddFd(EventHandler* eh, int event_mask)
112 int fd = eh->GetFd();
113 if ((fd < 0) || (fd > GetMaxFds() - 1))
120 SocketEngine::SetEventMask(eh, event_mask);
121 port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
123 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
128 void PortsEngine::WantWrite(EventHandler* eh, int old_mask, int new_mask)
130 if (mask_to_events(new_mask) != mask_to_events(old_mask))
131 port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
134 void PortsEngine::DelFd(EventHandler* eh)
136 int fd = eh->GetFd();
137 if ((fd < 0) || (fd > GetMaxFds() - 1))
140 port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
145 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
149 int PortsEngine::DispatchEvents()
151 struct timespec poll_time;
153 poll_time.tv_sec = 1;
154 poll_time.tv_nsec = 0;
156 unsigned int nget = 1; // used to denote a retrieve request.
157 int i = port_getn(EngineHandle, this->events, GetMaxFds() - 1, &nget, &poll_time);
158 ServerInstance->UpdateTime();
160 // first handle an error condition
166 for (i = 0; i < nget; i++)
168 switch (this->events[i].portev_source)
172 int fd = this->events[i].portev_object;
173 EventHandler* eh = ref[fd];
176 int mask = eh->GetEventMask();
177 if (events[i].portev_events & POLLWRNORM)
178 mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
179 if (events[i].portev_events & POLLRDNORM)
180 mask &= ~FD_READ_WILL_BLOCK;
181 // reinsert port for next time around, pretending to be one-shot for writes
182 SetEventMask(ev, mask);
183 port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
184 if (events[i].portev_events & POLLRDNORM)
187 eh->HandleEvent(EVENT_READ);
191 if (events[i].portev_events & POLLWRNORM)
194 eh->HandleEvent(EVENT_WRITE);
206 std::string PortsEngine::GetName()
211 SocketEngine* CreateSocketEngine()
213 return new PortsEngine;