summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-24 04:05:14 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2005-05-24 04:05:14 +0000
commit88a4177e285d65affeb2c2b97e308449a2c0cd4c (patch)
tree42361db8c02d39f2d9d495da590a28fd00c4e03a /src
parent66f0cd6469d2643858c2fcd14726d362696bd68d (diff)
Nonblocking connect() for outbound server links (why was this blocking anyway)
Changed /map to show authenticating servers with a * similar to hybrid git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@1485 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src')
-rw-r--r--src/commands.cpp88
-rw-r--r--src/connection.cpp40
-rw-r--r--src/inspircd.cpp15
-rw-r--r--src/servers.cpp12
4 files changed, 104 insertions, 51 deletions
diff --git a/src/commands.cpp b/src/commands.cpp
index b66ad514c..612444cb0 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -1513,50 +1513,60 @@ void handle_stats(char **parameters, int pcnt, userrec *user)
}
-void handle_connect(char **parameters, int pcnt, userrec *user)
+
+void ConnectServer(char* servermask,userrec* user)
{
- char Link_ServerName[1024];
- char Link_IPAddr[1024];
- char Link_Port[1024];
- char Link_Pass[1024];
- int LinkPort;
- bool found = false;
+ char Link_ServerName[1024];
+ char Link_IPAddr[1024];
+ char Link_Port[1024];
+ char Link_Pass[1024];
+ int LinkPort;
+ bool found = false;
- for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
- {
- if (!found)
- {
- ConfValue("link","name",i,Link_ServerName,&config_f);
- ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
- ConfValue("link","port",i,Link_Port,&config_f);
- ConfValue("link","sendpass",i,Link_Pass,&config_f);
- log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass);
- LinkPort = atoi(Link_Port);
- if (match(Link_ServerName,parameters[0])) {
- found = true;
- break;
- }
- }
- }
-
- if (!found) {
- WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,parameters[0]);
- return;
- }
-
- // TODO: Perform a check here to stop a server being linked twice!
+ for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
+ {
+ if (!found)
+ {
+ ConfValue("link","name",i,Link_ServerName,&config_f);
+ ConfValue("link","ipaddr",i,Link_IPAddr,&config_f);
+ ConfValue("link","port",i,Link_Port,&config_f);
+ ConfValue("link","sendpass",i,Link_Pass,&config_f);
+ LinkPort = atoi(Link_Port);
+ if (match(Link_ServerName,servermask)) {
+ found = true;
+ break;
+ }
+ }
+ }
- WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port);
+ if (!found) {
+ if (user)
+ WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,servermask);
+ return;
+ }
- if (me[defaultRoute])
- {
- me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass,Link_ServerName,me[defaultRoute]->port);
- return;
- }
- else
+ if (user)
{
- WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it.",user->nick);
+ WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port);
}
+ else WriteOpers("*** Autoconnecting to %s (%s) port %s...",Link_ServerName,Link_IPAddr,Link_Port);
+
+ if (me[defaultRoute])
+ {
+ me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass,Link_ServerName,me[defaultRoute]->port);
+ return;
+ }
+ else
+ {
+ if (user)
+ WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it.",user->nick);
+ }
+}
+
+
+void handle_connect(char **parameters, int pcnt, userrec *user)
+{
+ ConnectServer(parameters[0],user);
}
void handle_squit(char **parameters, int pcnt, userrec *user)
@@ -1652,7 +1662,7 @@ void handle_map(char **parameters, int pcnt, userrec *user)
{
for (int k = 0; k < me[j]->connectors.size(); k++)
{
- snprintf(line,MAXBUF,"006 %s :%c-%s",user->nick,islast(me[j]->connectors[k].GetServerName().c_str()),me[j]->connectors[k].GetServerName().c_str());
+ snprintf(line,MAXBUF,"006 %s :%c%c%s",user->nick,islast(me[j]->connectors[k].GetServerName().c_str()),me[j]->connectors[k].GetState() == STATE_CONNECTED ? '-' : '*',me[j]->connectors[k].GetServerName().c_str());
while (strlen(line) < 50)
strcat(line," ");
WriteServ(user->fd,"%s%d (%.2f%%)",line,map_count(me[j]->connectors[k].GetServerName().c_str()),(float)(((float)map_count(me[j]->connectors[k].GetServerName().c_str())/(float)registered_usercount())*100));
diff --git a/src/connection.cpp b/src/connection.cpp
index 9fb5070dd..31080615d 100644
--- a/src/connection.cpp
+++ b/src/connection.cpp
@@ -194,11 +194,14 @@ bool ircd_connector::CheckPing()
}
else
{
- this->SetWriteError("Ping timeout");
- this->CloseConnection();
- this->SetState(STATE_DISCONNECTED);
- WriteOpers("*** Ping timeout on link to %s (more routes may remain)",this->GetServerName().c_str());
- return false;
+ if (this->GetState() == STATE_CONNECTED)
+ {
+ this->SetWriteError("Ping timeout");
+ this->CloseConnection();
+ this->SetState(STATE_DISCONNECTED);
+ WriteOpers("*** Ping timeout on link to %s (more routes may remain)",this->GetServerName().c_str());
+ return false;
+ }
}
}
}
@@ -214,6 +217,18 @@ void ircd_connector::ResetPing()
bool ircd_connector::FlushWriteBuf()
{
log(DEBUG,"connector::FlushWriteBuf()");
+ if (this->GetState() == STATE_NOAUTH_OUTBOUND)
+ {
+ // if the outbound socket hasnt connected yet... return true and don't
+ // actually do anything until it IS connected. This should probably
+ // have a timeout somewhere, 10 secs should suffice. ;-)
+ pollfd polls;
+ polls.fd = this->fd;
+ polls.events = POLLOUT;
+ int ret = poll(&polls,1,1);
+ if (ret < 1)
+ return true;
+ }
if (sendq.length())
{
char* tb = (char*)this->sendq.c_str();
@@ -269,14 +284,17 @@ bool ircd_connector::MakeOutboundConnection(char* newhost, int newport)
this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (this->fd >= 0)
{
- if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)))
- {
- WriteOpers("connect() failed for %s",host);
- RemoveServer(this->servername.c_str());
- return false;
- }
int flags = fcntl(this->fd, F_GETFL, 0);
fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
+ if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)) == -1)
+ {
+ if (errno != EINPROGRESS)
+ {
+ WriteOpers("connect() failed for %s",host);
+ RemoveServer(this->servername.c_str());
+ return false;
+ }
+ }
int sendbuf = 32768;
int recvbuf = 32768;
setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index 712e26f5e..577741377 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -124,6 +124,7 @@ typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, irc::StrHa
typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, irc::InAddr_HashComp> address_cache;
typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, irc::StrHashComp> whowas_hash;
typedef std::deque<command_t> command_table;
+typedef std::map<std::string,time_t> autoconnects;
// This table references users by file descriptor.
// its an array to make it VERY fast, as all lookups are referenced
@@ -140,6 +141,7 @@ user_hash clientlist;
chan_hash chanlist;
whowas_hash whowas;
command_table cmdlist;
+autoconnects autoconns;
file_cache MOTD;
file_cache RULES;
address_cache IP;
@@ -398,6 +400,19 @@ void ReadConfig(bool bail, userrec* user)
read_xline_defaults();
log(DEFAULT,"Applying K lines, Q lines and Z lines...");
apply_lines();
+
+ for (int i = 0; i < ConfValueEnum("link",&config_f); i++)
+ {
+ char Link_ServerName[MAXBUF],Link_AConn[MAXBUF];
+ ConfValue("link","name",i,Link_ServerName,&config_f);
+ ConfValue("link","autoconnect",i,Link_AConn,&config_f);
+ if (strcmp(Link_AConn,""))
+ {
+ autoconns[std::string(Link_ServerName)] = atoi(Link_AConn) + time(NULL);
+ }
+ }
+
+
log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
if (!bail)
{
diff --git a/src/servers.cpp b/src/servers.cpp
index 38f9cfb5f..7ae90e41b 100644
--- a/src/servers.cpp
+++ b/src/servers.cpp
@@ -161,6 +161,8 @@ bool serverrec::BeginLink(char* targethost, int newport, char* password, char* s
connector.SetState(STATE_NOAUTH_OUTBOUND);
connector.SetHostAndPort(targethost, newport);
this->connectors.push_back(connector);
+ // this packet isn't actually sent until the socket connects -- the STATE_NOAUTH_OUTBOUND state
+ // queues outbound data until the socket is polled as writeable (e.g. the connection is established)
return this->SendPacket(connect, servername);
}
else
@@ -250,7 +252,15 @@ void serverrec::FlushWriteBuffers()
{
for (int i = 0; i < this->connectors.size(); i++)
{
- if (this->connectors[i].GetState() != STATE_DISCONNECTED)
+ // don't try and ping a NOAUTH_OUTBOUND state, its not authed yet!
+ if (this->connectors[i].GetState() != STATE_NOAUTH_OUTBOUND)
+ {
+ // however if we reach this timer its connected timed out :)
+ WriteOpers("*** Connection to %s timed out",this->connectors[i].GetServerName().c_str());
+ DoSplit(this->connectors[i].GetServerName().c_str());
+ return;
+ }
+ else if (this->connectors[i].GetState() != STATE_DISCONNECTED)
{
if (!this->connectors[i].CheckPing())
{