From 88a4177e285d65affeb2c2b97e308449a2c0cd4c Mon Sep 17 00:00:00 2001 From: brain Date: Tue, 24 May 2005 04:05:14 +0000 Subject: 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 --- include/commands.h | 4 +++ src/commands.cpp | 88 ++++++++++++++++++++++++++++++------------------------ src/connection.cpp | 40 ++++++++++++++++++------- src/inspircd.cpp | 15 ++++++++++ src/servers.cpp | 12 +++++++- 5 files changed, 108 insertions(+), 51 deletions(-) diff --git a/include/commands.h b/include/commands.h index c12d1b36b..d68c4273e 100644 --- a/include/commands.h +++ b/include/commands.h @@ -121,4 +121,8 @@ bool is_uline(const char* server); */ long duration(const char* str); +/** Server connect creation + */ +void ConnectServer(char* servermask, userrec* user); + #endif 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, irc::StrHa typedef nspace::hash_map, irc::InAddr_HashComp> address_cache; typedef nspace::hash_map, irc::StrHashComp> whowas_hash; typedef std::deque command_table; +typedef std::map 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()) { -- cgit v1.2.3