FD_WANT_NO_WRITE = 0x10,
/** Give a write event at all times when writes will not block.
*
- * You probably don't need to use this state; try your write first, and
- * then use FD_WANT_FAST_WRITE.
+ * You probably shouldn't use this state; if it's likely that the write
+ * will not block, try it first, then use FD_WANT_FAST_WRITE if it
+ * fails. If it's likely to block (or you are using polling-style reads)
+ * then use FD_WANT_SINGLE_WRITE.
*/
FD_WANT_POLL_WRITE = 0x20,
/** Give a write event when writes don't block any more
* FD_WANT_FAST_WRITE when writing data to a mostly-unblocked socket.
*/
FD_WANT_EDGE_WRITE = 0x80,
+ /** Request a one-shot poll-style write notification. The socket will
+ * return to the FD_WANT_NO_WRITE state before HandleEvent is called.
+ */
+ FD_WANT_SINGLE_WRITE = 0x100,
/** Mask for all write events */
- FD_WANT_WRITE_MASK = 0xF0,
+ FD_WANT_WRITE_MASK = 0x1F0,
/** Add a trial read. During the next DispatchEvents invocation, this
* will call HandleEvent with EVENT_READ unless reads are known to be
- * blocking. Useful for edge-triggered reads; does nothing if
- * FD_READ_WILL_BLOCK has been set on this EventHandler.
+ * blocking.
*/
- FD_ADD_TRIAL_READ = 0x100,
+ FD_ADD_TRIAL_READ = 0x1000,
/** Assert that reads are known to block. This cancels FD_ADD_TRIAL_READ.
+ * Reset by SE before running EVENT_READ
*/
- FD_READ_WILL_BLOCK = 0x200,
+ FD_READ_WILL_BLOCK = 0x2000,
/** Add a trial write. During the next DispatchEvents invocation, this
* will call HandleEvent with EVENT_WRITE unless writes are known to be
* send() syscall, or to ensure that writes are blocking when attempting
* to use FD_WANT_FAST_WRITE.
*/
- FD_ADD_TRIAL_WRITE = 0x1000,
+ FD_ADD_TRIAL_WRITE = 0x4000,
/** Assert that writes are known to block. This cancels FD_ADD_TRIAL_WRITE.
+ * Reset by SE before running EVENT_WRITE
*/
- FD_WRITE_WILL_BLOCK = 0x2000,
+ FD_WRITE_WILL_BLOCK = 0x8000,
- /** Mask for trial read/write items */
- FD_TRIAL_NOTE_MASK = 0x1100,
- /** Mask for read/write blocking notifications */
- FD_BLOCK_NOTE_MASK = 0x2200
+ /** Mask for trial read/trial write */
+ FD_TRIAL_NOTE_MASK = 0x5000
};
class InspIRCd;
this->state = I_CONNECTING;
- if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_POLL_WRITE))
+ if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE))
return I_ERR_NOMOREFDS;
this->Timeout = new SocketTimeout(this->GetFd(), this, timeout, ServerInstance->Time());
this->OnConnected();
if (GetIOHook())
GetIOHook()->OnStreamSocketConnect(this);
+ else
+ ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE);
}
this->StreamSocket::DoWrite();
}
else if (ret > 0)
{
sendq = sendq.substr(ret);
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (ret == 0)
{
// gnutls_handshake() wants to write() again.
session->status = ISSL_HANDSHAKING_WRITE;
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
}
}
else
}
else if (err == SSL_ERROR_WANT_WRITE)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
return 0;
}
else
else if (ret > 0)
{
buffer = buffer.substr(ret);
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (ret == 0)
if (err == SSL_ERROR_WANT_WRITE)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_SINGLE_WRITE);
return 0;
}
else if (err == SSL_ERROR_WANT_READ)
}
else if (err == SSL_ERROR_WANT_WRITE)
{
- ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_POLL_WRITE);
+ ServerInstance->SE->ChangeEventMask(user, FD_WANT_NO_READ | FD_WANT_SINGLE_WRITE);
session->status = ISSL_HANDSHAKING;
return true;
}
static int mask_to_epoll(int event_mask)
{
int rv = 0;
- if (event_mask & (FD_WANT_POLL_READ | FD_WANT_POLL_WRITE))
+ if (event_mask & (FD_WANT_POLL_READ | FD_WANT_POLL_WRITE | FD_WANT_SINGLE_WRITE))
{
// we need to use standard polling on this FD
if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
rv |= EPOLLIN;
- if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+ if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
rv |= EPOLLOUT;
}
else
eh->HandleEvent(EVENT_ERROR, errcode);
continue;
}
+ int mask = eh->GetEventMask();
+ if (events[j].events & EPOLLIN)
+ mask &= ~FD_READ_WILL_BLOCK;
+ if (events[j].events & EPOLLOUT)
+ {
+ mask &= ~FD_WRITE_WILL_BLOCK;
+ if (mask & FD_WANT_SINGLE_WRITE)
+ {
+ int nm = mask & ~FD_WANT_SINGLE_WRITE;
+ OnSetEvent(eh, mask, nm);
+ mask = nm;
+ }
+ }
+ SetEventMask(eh, mask);
if (events[j].events & EPOLLIN)
{
ReadEvents++;
- SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
eh->HandleEvent(EVENT_READ);
}
if (events[j].events & EPOLLOUT)
{
WriteEvents++;
- SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
eh->HandleEvent(EVENT_WRITE);
}
}
ServerInstance->Logs->Log("SOCKET",DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", *fake_fd, eh->GetFd(), eh);
/* post a write event if there is data to be written */
- if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+ if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
WantWrite(eh);
/* we're all good =) */
return;
/* Post event - write begin */
- if((new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE)) && !eh->GetExt("windows_writeevent", m_writeEvent))
+ if((new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !eh->GetExt("windows_writeevent", m_writeEvent))
{
ULONG_PTR completion_key = (ULONG_PTR)*fake_fd;
Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0);
return false;
}
- if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE)) {
+ if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) {
// ...and sometimes want to write
WantWrite(eh);
}
eh->GetFd(), strerror(errno));
}
}
- if ((new_mask & FD_WANT_EDGE_WRITE) && !(old_mask & FD_WANT_EDGE_WRITE))
+ if ((new_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !(old_mask & (FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)))
{
// new one-shot write
struct kevent ke;
if (ke_list[j].filter == EVFILT_WRITE)
{
WriteEvents++;
- /* When mask is FD_WANT_FAST_WRITE, we set a one-shot
- * write, so we need to clear that bit to detect when it
- * set again.
+ /* When mask is FD_WANT_FAST_WRITE or FD_WANT_SINGLE_WRITE,
+ * we set a one-shot write, so we need to clear that bit
+ * to detect when it set again.
*/
- const int bits_to_clr = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
+ const int bits_to_clr = FD_WANT_SINGLE_WRITE | FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
SetEventMask(eh, eh->GetEventMask() & ~bits_to_clr);
eh->HandleEvent(EVENT_WRITE);
}
int rv = 0;
if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
rv |= POLLIN;
- if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+ if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
rv |= POLLOUT;
return rv;
}
if (events[index].revents & POLLOUT)
{
- SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
+ int mask = eh->GetEventMask();
+ mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE);
+ SetEventMask(eh, mask);
+ events[index].events = mask_to_poll(mask);
eh->HandleEvent(EVENT_WRITE);
}
}
int rv = 0;
if (event_mask & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
rv |= POLLRDNORM;
- if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+ if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
rv |= POLLWRNORM;
return rv;
}
{
int mask = eh->GetEventMask();
if (events[i].portev_events & POLLWRNORM)
- mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE);
+ mask &= ~(FD_WRITE_WILL_BLOCK | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE);
if (events[i].portev_events & POLLRDNORM)
mask &= ~FD_READ_WILL_BLOCK;
// reinsert port for next time around, pretending to be one-shot for writes
int state = eh->GetEventMask();
if (state & (FD_WANT_POLL_READ | FD_WANT_FAST_READ))
FD_SET (i, &rfdset);
- if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE))
+ if (state & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
FD_SET (i, &wfdset);
FD_SET (i, &errfdset);
}
if (FD_ISSET (i, &wfdset))
{
WriteEvents++;
- SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
+ SetEventMask(eh, eh->GetEventMask() & ~(FD_WRITE_WILL_BLOCK | FD_WANT_SINGLE_WRITE));
ev->HandleEvent(EVENT_WRITE);
}
}