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;
71 ServerInstance->Logs->Log("SOCKET", DEFAULT, "ERROR: Can't determine maximum number of open sockets!");
72 printf("ERROR: Can't determine maximum number of open sockets!\n");
73 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
75 EngineHandle = port_create();
77 if (EngineHandle == -1)
79 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: Could not initialize socket engine: %s", strerror(errno));
80 ServerInstance->Logs->Log("SOCKET",SPARSE,"ERROR: This is a fatal error, exiting now.");
81 printf("ERROR: Could not initialize socket engine: %s\n", strerror(errno));
82 printf("ERROR: This is a fatal error, exiting now.\n");
83 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
87 ref = new EventHandler* [GetMaxFds()];
88 events = new port_event_t[GetMaxFds()];
89 memset(ref, 0, GetMaxFds() * sizeof(EventHandler*));
92 PortsEngine::~PortsEngine()
94 this->Close(EngineHandle);
99 static int mask_to_events(int event_mask)
102 if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
104 if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
109 bool PortsEngine::AddFd(EventHandler* eh, int event_mask)
111 int fd = eh->GetFd();
112 if ((fd < 0) || (fd > GetMaxFds() - 1))
119 SocketEngine::SetEventMask(eh, event_mask);
120 port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(event_mask), eh);
122 ServerInstance->Logs->Log("SOCKET",DEBUG,"New file descriptor: %d", fd);
127 void PortsEngine::WantWrite(EventHandler* eh, int old_mask, int new_mask)
129 if (mask_to_events(new_mask) != mask_to_events(old_mask))
130 port_associate(EngineHandle, PORT_SOURCE_FD, eh->GetFd(), mask_to_events(new_mask), eh);
133 void PortsEngine::DelFd(EventHandler* eh)
135 int fd = eh->GetFd();
136 if ((fd < 0) || (fd > GetMaxFds() - 1))
139 port_dissociate(EngineHandle, PORT_SOURCE_FD, fd);
144 ServerInstance->Logs->Log("SOCKET",DEBUG,"Remove file descriptor: %d", fd);
148 int PortsEngine::DispatchEvents()
150 struct timespec poll_time;
152 poll_time.tv_sec = 1;
153 poll_time.tv_nsec = 0;
155 unsigned int nget = 1; // used to denote a retrieve request.
156 int i = port_getn(EngineHandle, this->events, GetMaxFds() - 1, &nget, &poll_time);
157 ServerInstance->UpdateTime();
159 // first handle an error condition
165 for (i = 0; i < nget; i++)
167 switch (this->events[i].portev_source)
171 int fd = this->events[i].portev_object;
172 EventHandler* eh = ref[fd];
175 int mask = eh->GetEventMask();
176 if (events[i].portev_events & POLLWRNORM)
177 mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
178 if (events[i].portev_events & POLLRDNORM)
179 mask &= ~FD_READ_WILL_BLOCK;
180 // reinsert port for next time around, pretending to be one-shot for writes
181 SetEventMask(ev, mask);
182 port_associate(EngineHandle, PORT_SOURCE_FD, fd, mask_to_events(mask), eh);
183 if (events[i].portev_events & POLLRDNORM)
186 eh->HandleEvent(EVENT_READ);
190 if (events[i].portev_events & POLLWRNORM)
193 eh->HandleEvent(EVENT_WRITE);
205 std::string PortsEngine::GetName()
210 SocketEngine* CreateSocketEngine()
212 return new PortsEngine;