* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- * E-mail:
- * <brain@chatspike.net>
- * <Craig@chatspike.net>
- *
- * Written by Craig Edwards, Craig McLure, and others.
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
* This program is free but copyrighted software; see
* the file COPYING for details.
*
this->fd = -1;
this->WaitingForWriteEvent = false;
this->Instance = SI;
+ this->IsIOHooked = false;
}
InspSocket::InspSocket(InspIRCd* SI, int newfd, const char* ip)
strlcpy(this->IP,ip,MAXBUF);
this->WaitingForWriteEvent = false;
this->Instance = SI;
+ this->IsIOHooked = false;
if (this->fd > -1)
this->Instance->SE->AddFd(this);
}
this->Instance = SI;
strlcpy(host,ipaddr.c_str(),MAXBUF);
this->WaitingForWriteEvent = false;
+ this->IsIOHooked = false;
if (listening)
{
if ((this->fd = OpenTCPSocket()) == ERROR)
void InspSocket::WantWrite()
{
- /** XXX:
- * The socket engine may only have each FD in the list ONCE.
- * This means we cant watch for write AND read at the same
- * time. We have to remove the READ fd, to insert the WRITE
- * fd. Once we receive our WRITE event (which WILL ARRIVE,
- * pretty much gauranteed) we switch back to watching for
- * READ events again.
- *
- * This behaviour may be fixed in a later version.
- */
- this->Instance->SE->DelFd(this);
+ this->Instance->SE->WantWrite(this);
this->WaitingForWriteEvent = true;
- if (!this->Instance->SE->AddFd(this))
- {
- this->Close();
- this->fd = -1;
- this->state = I_ERROR;
- this->OnError(I_ERR_NOMOREFDS);
- }
}
void InspSocket::SetQueues(int nfd)
{
if (this->fd > -1)
{
+ if (this->IsIOHooked && Instance->Config->GetIOHook(this))
+ {
+ try
+ {
+ Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ Instance->Log(DEBUG,"Module exception cought: %s",modexcept.GetReason());
+ }
+ }
this->OnClose();
shutdown(this->fd,2);
close(this->fd);
{
if ((fd < 0) || (fd > MAX_DESCRIPTORS))
return NULL;
- int n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
+
+ int n = 0;
+
+ if (this->IsIOHooked)
+ {
+ int result2 = 0;
+ int MOD_RESULT = 0;
+ try
+ {
+ MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf),result2);
+ }
+ catch (ModuleException& modexcept)
+ {
+ Instance->Log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
+ }
+ if (MOD_RESULT < 0)
+ {
+ n = -1;
+ errno = EAGAIN;
+ }
+ else
+ {
+ n = result2;
+ }
+ }
+ else
+ {
+ n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
+ }
+
if ((n > 0) && (n <= (int)sizeof(this->ibuf)))
{
ibuf[n] = 0;
/* Try and append the data to the back of the queue, and send it on its way
*/
outbuffer.push_back(data);
+ this->Instance->SE->WantWrite(this);
return (!this->FlushWriteBuffer());
}
errno = 0;
if ((this->fd > -1) && (this->state == I_CONNECTED))
{
- /* If we have multiple lines, try to send them all,
- * not just the first one -- Brain
- */
- while (outbuffer.size() && (errno != EAGAIN))
+ if (this->IsIOHooked)
{
- /* Send a line */
- int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
- if (result > 0)
+ while (outbuffer.size() && (errno != EAGAIN))
{
- if ((unsigned int)result == outbuffer[0].length())
+ try
{
- /* The whole block was written (usually a line)
- * Pop the block off the front of the queue,
- * dont set errno, because we are clear of errors
- * and want to try and write the next block too.
- */
- outbuffer.pop_front();
+ int result = Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
+ if (result > 0)
+ {
+ if ((unsigned int)result == outbuffer[0].length())
+ {
+ outbuffer.pop_front();
+ }
+ else
+ {
+ std::string temp = outbuffer[0].substr(result);
+ outbuffer[0] = temp;
+ errno = EAGAIN;
+ }
+ }
+ else if ((result == -1) && (errno != EAGAIN))
+ {
+ this->Instance->Log(DEBUG,"Write error on socket: %s",strerror(errno));
+ this->OnError(I_ERR_WRITE);
+ this->state = I_ERROR;
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ return true;
+ }
+ else if (result == 0)
+ {
+ this->Instance->Log(DEBUG,"Write error on socket: EOF");
+ this->OnError(I_ERR_WRITE);
+ this->state = I_ERROR;
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ return true;
+ }
}
- else
+ catch (ModuleException& modexcept)
{
- std::string temp = outbuffer[0].substr(result);
- outbuffer[0] = temp;
- /* We didnt get the whole line out. arses.
- * Try again next time, i guess. Set errno,
- * because we shouldnt be writing any more now,
- * until the socketengine says its safe to do so.
- */
- errno = EAGAIN;
+ Instance->Log(DEBUG,"Module exception caught: %s",modexcept.GetReason());
+ return true;
}
}
- else if ((result == -1) && (errno != EAGAIN))
+ }
+ else
+ {
+ /* If we have multiple lines, try to send them all,
+ * not just the first one -- Brain
+ */
+ while (outbuffer.size() && (errno != EAGAIN))
{
- this->Instance->Log(DEBUG,"Write error on socket: %s",strerror(errno));
- this->OnError(I_ERR_WRITE);
- this->state = I_ERROR;
- this->Instance->SE->DelFd(this);
- this->Close();
- return true;
+ /* Send a line */
+ int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
+ if (result > 0)
+ {
+ if ((unsigned int)result == outbuffer[0].length())
+ {
+ /* The whole block was written (usually a line)
+ * Pop the block off the front of the queue,
+ * dont set errno, because we are clear of errors
+ * and want to try and write the next block too.
+ */
+ outbuffer.pop_front();
+ }
+ else
+ {
+ std::string temp = outbuffer[0].substr(result);
+ outbuffer[0] = temp;
+ /* We didnt get the whole line out. arses.
+ * Try again next time, i guess. Set errno,
+ * because we shouldnt be writing any more now,
+ * until the socketengine says its safe to do so.
+ */
+ errno = EAGAIN;
+ }
+ }
+ else if ((result == -1) && (errno != EAGAIN))
+ {
+ this->Instance->Log(DEBUG,"Write error on socket: %s",strerror(errno));
+ this->OnError(I_ERR_WRITE);
+ this->state = I_ERROR;
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ return true;
+ }
}
}
}
+
+ if ((errno == EAGAIN) && (fd > -1))
+ {
+ this->Instance->SE->WantWrite(this);
+ }
+
return (fd < 0);
}
delete this->sock;
return;
}
- this->sock->FlushWriteBuffer();
}
bool InspSocket::Poll()
return false;
int incoming = -1;
- bool n = true;
if ((fd < 0) || (fd > MAX_DESCRIPTORS))
return false;
if (!this->Instance->SE->AddFd(this))
return false;
}
+ if (Instance->Config->GetIOHook(this))
+ {
+ try
+ {
+ Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
+ }
+ catch (ModuleException& modexcept)
+ {
+ Instance->Log(DEBUG,"Module exception cought: %s",modexcept.GetReason());
+ }
+ }
return this->OnConnected();
break;
case I_LISTENING:
length = sizeof (client);
incoming = accept (this->fd, (sockaddr*)&client,&length);
- this->SetQueues(incoming);
+
#ifdef IPV6
- this->OnIncomingConnection(incoming,(char*)insp_ntoa(client.sin6_addr));
+ this->OnIncomingConnection(incoming, (char*)insp_ntoa(client.sin6_addr));
#else
- this->OnIncomingConnection(incoming,(char*)insp_ntoa(client.sin_addr));
+ this->OnIncomingConnection(incoming, (char*)insp_ntoa(client.sin_addr));
#endif
- return true;
- break;
- case I_CONNECTED:
-
- if (this->WaitingForWriteEvent)
- {
- /* Switch back to read events */
- this->Instance->SE->DelFd(this);
- this->WaitingForWriteEvent = false;
- if (!this->Instance->SE->AddFd(this))
- return false;
- /* Trigger the write event */
- n = this->OnWriteReady();
- }
- else
+ if (this->IsIOHooked)
{
- /* Process the read event */
- n = this->OnDataReady();
+ try
+ {
+#ifdef IPV6
+ Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, insp_ntoa(client.sin6_addr), this->port);
+#else
+ Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, insp_ntoa(client.sin_addr), this->port);
+#endif
+ }
+ catch (ModuleException& modexcept)
+ {
+ Instance->Log(DEBUG,"Module exception cought: %s",modexcept.GetReason());
+ }
}
- /* Flush any pending, but not till after theyre done with the event
- * so there are less write calls involved.
- * Both FlushWriteBuffer AND the return result of OnDataReady must
- * return true for this to be ok.
- */
- if (this->FlushWriteBuffer())
- return false;
- return n;
+
+ this->SetQueues(incoming);
+ return true;
+ break;
+ case I_CONNECTED:
+ /* Process the read event */
+ return this->OnDataReady();
break;
default:
break;
this->Close();
}
-void InspSocket::HandleEvent(EventType et)
+void InspSocket::HandleEvent(EventType et, int errornum)
{
- if (!this->Poll())
+ switch (et)
{
- this->Instance->SE->DelFd(this);
- this->Close();
- delete this;
+ case EVENT_ERROR:
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ delete this;
+ return;
+ break;
+ case EVENT_READ:
+ if (!this->Poll())
+ {
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ delete this;
+ return;
+ }
+ break;
+ case EVENT_WRITE:
+ if (this->WaitingForWriteEvent)
+ {
+ this->WaitingForWriteEvent = false;
+ if (!this->OnWriteReady())
+ {
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ delete this;
+ return;
+ }
+ }
+ if (this->state == I_CONNECTING)
+ {
+ /* This might look wrong as if we should be actually calling
+ * with EVENT_WRITE, but trust me it is correct. There are some
+ * writeability-state things in the read code, because of how
+ * InspSocket used to work regarding write buffering in previous
+ * versions of InspIRCd. - Brain
+ */
+ this->HandleEvent(EVENT_READ);
+ return;
+ }
+ else
+ {
+ Instance->Log(DEBUG,"State=%d CONNECTED=%d", this->state, I_CONNECTED);
+ if (this->FlushWriteBuffer())
+ {
+ this->Instance->SE->DelFd(this);
+ this->Close();
+ delete this;
+ return;
+ }
+ }
+ break;
}
}