#include "inspstring.h"
#include "helperfuncs.h"
#include "socketengine.h"
+#include "message.h"
extern InspIRCd* ServerInstance;
this->ClosePending = false;
}
-InspSocket::InspSocket(int newfd, char* ip)
+InspSocket::InspSocket(int newfd, const char* ip)
{
this->fd = newfd;
this->state = I_CONNECTED;
strlcpy(this->IP,ip,MAXBUF);
this->ClosePending = false;
- ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
- socket_ref[this->fd] = this;
+ if (this->fd > -1)
+ {
+ ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
+ socket_ref[this->fd] = this;
+ }
}
InspSocket::InspSocket(const std::string &ahost, int aport, bool listening, unsigned long maxtime) : fd(-1)
else
{
this->state = I_LISTENING;
- ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
- socket_ref[this->fd] = this;
+ if (this->fd > -1)
+ {
+ ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
+ socket_ref[this->fd] = this;
+ }
log(DEBUG,"New socket now in I_LISTENING state");
return;
}
}
}
+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->WaitingForWriteEvent = true;
+ ServerInstance->SE->DelFd(this->fd);
+ ServerInstance->SE->AddFd(this->fd,false,X_ESTAB_MODULE);
+}
+
void InspSocket::SetQueues(int nfd)
{
// attempt to increase socket sendq and recvq as high as its possible
return true;
}
+/* Most irc servers require you to specify the ip you want to bind to.
+ * If you dont specify an IP, they rather dumbly bind to the first IP
+ * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP
+ * addresses we've bound server ports to, and we try and bind our outbound
+ * connections to the first usable non-loopback and non-any IP we find.
+ * This is easier to configure when you have a lot of links and a lot
+ * of servers to configure.
+ */
+bool InspSocket::BindAddr()
+{
+ insp_inaddr n;
+ ConfigReader Conf;
+
+ log(DEBUG,"In InspSocket::BindAddr()");
+ for (int j =0; j < Conf.Enumerate("bind"); j++)
+ {
+ std::string Type = Conf.ReadValue("bind","type",j);
+ std::string IP = Conf.ReadValue("bind","address",j);
+ if (Type == "servers")
+ {
+ if ((IP != "*") && (IP != "127.0.0.1") && (IP != ""))
+ {
+ insp_sockaddr s;
+ char resolved_addr[MAXBUF];
+
+ if (!inet_aton(IP.c_str(),&n))
+ {
+ /* If they gave a hostname, bind to the IP it resolves to */
+ log(DEBUG,"Resolving host %s",IP.c_str());
+ if (CleanAndResolve(resolved_addr, IP.c_str(), true))
+ {
+ log(DEBUG,"Resolved host %s to %s",IP.c_str(),resolved_addr);
+ IP = resolved_addr;
+ }
+ }
+
+ if (inet_aton(IP.c_str(),&n))
+ {
+ log(DEBUG,"Found an IP to bind to: %s",IP.c_str());
+ s.sin_addr = n;
+ s.sin_family = AF_INET;
+ if (bind(this->fd,(struct sockaddr*)&s,sizeof(s)) < 0)
+ {
+ log(DEBUG,"Cant bind()");
+ this->state = I_ERROR;
+ this->OnError(I_ERR_BIND);
+ this->fd = -1;
+ return false;
+ }
+ log(DEBUG,"bind() reports outbound fd bound to ip %s",IP.c_str());
+ return true;
+ }
+ else
+ {
+ log(DEBUG,"Address '%s' was not an IP address",IP.c_str());
+ }
+ }
+ }
+ }
+ log(DEBUG,"Found no suitable IPs to bind, binding INADDR_ANY");
+ return true;
+}
+
bool InspSocket::DoConnect()
{
log(DEBUG,"In DoConnect()");
return false;
}
+ if (!this->BindAddr())
+ return false;
+
log(DEBUG,"Part 2 DoConnect() %s",this->IP);
inet_aton(this->IP,&addy);
addr.sin_family = AF_INET;
}
}
this->state = I_CONNECTING;
- ServerInstance->SE->AddFd(this->fd,false,X_ESTAB_MODULE);
- socket_ref[this->fd] = this;
- this->SetQueues(this->fd);
+ if (this->fd > -1)
+ {
+ ServerInstance->SE->AddFd(this->fd,false,X_ESTAB_MODULE);
+ socket_ref[this->fd] = this;
+ this->SetQueues(this->fd);
+ }
log(DEBUG,"Returning true from InspSocket::DoConnect");
return true;
}
/* Our socket was in write-state, so delete it and re-add it
* in read-state.
*/
- ServerInstance->SE->DelFd(this->fd);
- ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
+ if (this->fd > -1)
+ {
+ ServerInstance->SE->DelFd(this->fd);
+ ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
+ }
return this->OnConnected();
break;
case I_LISTENING:
return true;
break;
case I_CONNECTED:
- n = this->OnDataReady();
+
+ if (this->WaitingForWriteEvent)
+ {
+ /* Switch back to read events */
+ ServerInstance->SE->DelFd(this->fd);
+ ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
+ /* Trigger the write event */
+ n = this->OnWriteReady();
+ }
+ else
+ {
+ /* Process the read event */
+ n = this->OnDataReady();
+ }
/* 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
int InspSocket::OnDisconnect() { return 0; }
int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
bool InspSocket::OnDataReady() { return true; }
+bool InspSocket::OnWriteReady() { return true; }
void InspSocket::OnTimeout() { return; }
void InspSocket::OnClose() { return; }