Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

servers.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
00006  *                       E-mail:
00007  *                <brain@chatspike.net>
00008  *                <Craig@chatspike.net>
00009  *     
00010  * Written by Craig Edwards, Craig McLure, and others.
00011  * This program is free but copyrighted software; see
00012  *            the file COPYING for details.
00013  *
00014  * ---------------------------------------------------
00015  */
00016 
00017 using namespace std;
00018 
00019 #include "inspircd_config.h" 
00020 #include "servers.h"
00021 #include "inspircd.h"
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <poll.h>
00025 #include <sys/errno.h>
00026 #include <sys/ioctl.h>
00027 #include <sys/utsname.h>
00028 #include <vector>
00029 #include <string>
00030 #include <deque>
00031 #include <sstream>
00032 #include <map>
00033 #include "inspstring.h"
00034 #include "helperfuncs.h"
00035 #include "connection.h"
00036 
00037 extern time_t TIME;
00038 extern int MaxConn;
00039 
00040 std::deque<std::string> xsums;
00041 
00042 serverrec::serverrec()
00043 {
00044         strlcpy(name,"",256);
00045         pingtime = 0;
00046         lastping = TIME;
00047         usercount_i = usercount = opercount = version = 0;
00048         hops_away = 1;
00049         signon = TIME;
00050         jupiter = false;
00051         fd = 0;
00052         sync_soon = false;
00053         strlcpy(nickserv,"",NICKMAX);
00054         connectors.clear();
00055 }
00056 
00057  
00058 serverrec::~serverrec()
00059 {
00060 }
00061 
00062 serverrec::serverrec(char* n, long ver, bool jupe)
00063 {
00064         strlcpy(name,n,256);
00065         lastping = TIME;
00066         usercount_i = usercount = opercount = 0;
00067         version = ver;
00068         hops_away = 1;
00069         signon = TIME;
00070         jupiter = jupe;
00071         fd = 0;
00072         sync_soon = false;
00073         strlcpy(nickserv,"",NICKMAX);
00074         connectors.clear();
00075 }
00076 
00077 bool serverrec::CreateListener(char* newhost, int p)
00078 {
00079         sockaddr_in host_address;
00080         int flags;
00081         in_addr addy;
00082         int on = 0;
00083         struct linger linger = { 0 };
00084 
00085         this->port = p;
00086 
00087         fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00088         if (fd <= 0)
00089         {
00090                 return false;
00091         }
00092 
00093         setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
00094         linger.l_onoff = 1;
00095         linger.l_linger = 1;
00096         setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
00097 
00098         // attempt to increase socket sendq and recvq as high as its possible
00099         // to get them on linux.
00100         int sendbuf = 32768;
00101         int recvbuf = 32768;
00102         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00103         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00104 
00105         memset((void*)&host_address, 0, sizeof(host_address));
00106 
00107         host_address.sin_family = AF_INET;
00108 
00109         if (!strcmp(newhost,""))
00110         {
00111                 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
00112         }
00113         else
00114         {
00115                 inet_aton(newhost,&addy);
00116                 host_address.sin_addr = addy;
00117         }
00118 
00119         host_address.sin_port = htons(p);
00120 
00121         if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
00122         {
00123                 return false;
00124         }
00125 
00126         // make the socket non-blocking
00127         flags = fcntl(fd, F_GETFL, 0);
00128         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
00129 
00130         this->port = p;
00131 
00132         listen(this->fd, MaxConn);
00133 
00134         return true;
00135 }
00136 
00137 
00138 bool serverrec::BeginLink(char* targethost, int newport, char* password, char* servername, int myport)
00139 {
00140         char connect[MAXBUF];
00141 
00142         ircd_connector connector;
00143         ircd_connector *cn = this->FindHost(servername);
00144 
00145 
00146         if (cn)
00147         {
00148                 WriteOpers("CONNECT aborted: Server %s already exists",servername);
00149                 return false;
00150         }
00151 
00152 
00153         if (this->fd)
00154         {
00155                 if (connector.MakeOutboundConnection(targethost,newport))
00156                 {
00157                         // targethost has been turned into an ip...
00158                         // we dont want this as the server name.
00159                         connector.SetServerName(servername);
00160                         snprintf(connect,MAXBUF,"S %s %s %lu %s :%s",getservername().c_str(),password,(unsigned long)myport,GetRevision().c_str(),getserverdesc().c_str());
00161                         connector.SetState(STATE_NOAUTH_OUTBOUND);
00162                         connector.SetHostAndPort(targethost, newport);
00163                         this->connectors.push_back(connector);
00164                         return this->SendPacket(connect, servername);
00165                 }
00166                 else
00167                 {
00168                         connector.SetState(STATE_DISCONNECTED);
00169                         WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00170                 }
00171         }
00172         return false;
00173 }
00174 
00175 
00176 bool serverrec::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername)
00177 {
00178         char connect[MAXBUF];
00179 
00180         ircd_connector connector;
00181 
00182         WriteOpers("Establishing meshed link to %s:%d",servername,newport);
00183 
00184         if (this->fd)
00185         {
00186                 if (connector.MakeOutboundConnection(targethost,newport))
00187                 {
00188                         // targethost has been turned into an ip...
00189                         // we dont want this as the server name.
00190                         connector.SetServerName(servername);
00191                         snprintf(connect,MAXBUF,"- %lu %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
00192                         connector.SetState(STATE_NOAUTH_OUTBOUND);
00193                         connector.SetHostAndPort(targethost, newport);
00194                         connector.SetState(STATE_CONNECTED);
00195                         this->connectors.push_back(connector);
00196                         return this->SendPacket(connect, servername);
00197                 }
00198                 else
00199                 {
00200                         connector.SetState(STATE_DISCONNECTED);
00201                         WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00202                 }
00203         }
00204         return false;
00205 }
00206 
00207 bool serverrec::AddIncoming(int newfd, char* targethost, int sourceport)
00208 {
00209         ircd_connector connector;
00210 
00211         // targethost has been turned into an ip...
00212         // we dont want this as the server name.
00213         connector.SetServerName(targethost);
00214         connector.SetDescriptor(newfd);
00215         connector.SetState(STATE_NOAUTH_INBOUND);
00216         int flags = fcntl(newfd, F_GETFL, 0);
00217         fcntl(newfd, F_SETFL, flags | O_NONBLOCK);
00218         int sendbuf = 32768;
00219         int recvbuf = 32768;
00220         setsockopt(newfd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00221         setsockopt(newfd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00222         connector.SetHostAndPort(targethost, sourceport);
00223         connector.SetState(STATE_NOAUTH_INBOUND);
00224         log(DEBUG,"serverrec::AddIncoming() Added connection: %s:%d",targethost,sourceport);
00225         this->connectors.push_back(connector);
00226         return true;
00227 }
00228 
00229 void serverrec::TerminateLink(char* targethost)
00230 {
00231         // this locates the targethost in the serverrec::connectors vector of the class,
00232         // and terminates it by sending it an SQUIT token and closing its descriptor.
00233         // TerminateLink with a null string causes a terminate of ALL links
00234 }
00235 
00236 // Returns a pointer to the connector for 'host'
00237 ircd_connector* serverrec::FindHost(std::string findhost)
00238 {
00239         for (int i = 0; i < this->connectors.size(); i++)
00240         {
00241                 if (this->connectors[i].GetServerName() == findhost)
00242                 {
00243                         return &this->connectors[i];
00244                 }
00245         }
00246         return NULL;
00247 }
00248 
00249 void serverrec::FlushWriteBuffers()
00250 {
00251         for (int i = 0; i < this->connectors.size(); i++)
00252         {
00253                 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00254                 {
00255                         if (!this->connectors[i].CheckPing())
00256                         {
00257                                 WriteOpers("*** Lost single connection to %s: Ping timeout",this->connectors[i].GetServerName().c_str());
00258                                 this->connectors[i].CloseConnection();
00259                                 this->connectors[i].SetState(STATE_DISCONNECTED);
00260                         }
00261                 }
00262                 if (this->connectors[i].HasBufferedOutput())
00263                 {
00264                         if (!this->connectors[i].FlushWriteBuf())
00265                         {
00266                                 // if we're here the write() caused an error, we cannot proceed
00267                                 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",this->connectors[i].GetServerName().c_str(),this->connectors[i].GetWriteError().c_str());
00268                                 this->connectors[i].CloseConnection();
00269                                 this->connectors[i].SetState(STATE_DISCONNECTED);
00270                         }
00271                 }
00272         }
00273 }
00274 
00275 bool serverrec::SendPacket(char *message, const char* sendhost)
00276 {
00277         if ((!message) || (!sendhost))
00278                 return true;
00279 
00280         ircd_connector* cn = this->FindHost(sendhost);
00281 
00282         if (!strchr(message,'\n'))
00283         {
00284                 strlcat(message,"\n",MAXBUF);
00285         }
00286 
00287         if (cn)
00288         {
00289                 log(DEBUG,"main: serverrec::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
00290 
00291                 if (cn->GetState() == STATE_DISCONNECTED)
00292                 {
00293                         // fix: can only route one hop to avoid a loop
00294                         if (strncmp(message,"R ",2))
00295                         {
00296                                 log(DEBUG,"Not a double reroute");
00297                                 // this route is down, we must re-route the packet through an available point in the mesh.
00298                                 for (int k = 0; k < this->connectors.size(); k++)
00299                                 {
00300                                         log(DEBUG,"Check connector %d: %s",k,this->connectors[k].GetServerName().c_str());
00301                                         // search for another point in the mesh which can 'reach' where we want to go
00302                                         for (int m = 0; m < this->connectors[k].routes.size(); m++)
00303                                         {
00304                                                 if (!strcasecmp(this->connectors[k].routes[m].c_str(),sendhost))
00305                                                 {
00306                                                         log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
00307                                                         char buffer[MAXBUF];
00308                                                         snprintf(buffer,MAXBUF,"R %s %s",sendhost,message);
00309                                                         this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
00310                                                         return true;
00311                                                 }
00312                                         }
00313                                 }
00314                         }
00315                         char buffer[MAXBUF];
00316                         snprintf(buffer,MAXBUF,"& %s",sendhost);
00317                         WriteOpers("*** All connections to %s lost.",sendhost);
00318                         NetSendToAllExcept(sendhost,buffer);
00319                         DoSplit(sendhost);
00320                         return false;
00321                 }
00322 
00323                 // returns false if the packet could not be sent (e.g. target host down)
00324                 if (!cn->AddWriteBuf(message))
00325                 {
00326                         // if we're here, there was an error pending, and the send cannot proceed
00327                         log(DEBUG,"cn->AddWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00328                         log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00329                         cn->CloseConnection();
00330                         cn->SetState(STATE_DISCONNECTED);
00331                         WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00332                         // retry the packet along a new route so either arrival OR failure are gauranteed (bugfix)
00333                         return this->SendPacket(message,sendhost);
00334                 }
00335                 if (!cn->FlushWriteBuf())
00336                 {
00337                         // if we're here the write() caused an error, we cannot proceed
00338                         log(DEBUG,"cn->FlushWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00339                         log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00340                         cn->CloseConnection();
00341                         cn->SetState(STATE_DISCONNECTED);
00342                         WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00343                         // retry the packet along a new route so either arrival OR failure are gauranteed
00344                         return this->SendPacket(message,sendhost);
00345                 }
00346                 return true;
00347         }
00348 }
00349 
00350 bool already_have_sum(std::string sum)
00351 {
00352         for (int i = 0; i < xsums.size(); i++)
00353         {
00354                 if (xsums[i] == sum)
00355                 {
00356                         return true;
00357                 }
00358         }
00359         if (xsums.size() >= 128)
00360         {
00361                 xsums.pop_front();
00362         }
00363         xsums.push_back(sum);
00364         return false;
00365 }
00366 
00367 // receives a packet from any where there is data waiting, first come, first served
00368 // fills the message and host values with the host where the data came from.
00369 
00370 bool serverrec::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums)
00371 {
00372         char data[65536];
00373         memset(data, 0, 65536);
00374         for (int i = 0; i < this->connectors.size(); i++)
00375         {
00376                 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00377                 {
00378                         // returns false if the packet could not be sent (e.g. target host down)
00379                         int rcvsize = 0;
00380 
00381                         // check if theres any data on this socket
00382                         // if not, continue onwards to the next.
00383                         pollfd polls;
00384                         polls.fd = this->connectors[i].GetDescriptor();
00385                         polls.events = POLLIN;
00386                         int ret = poll(&polls,1,1);
00387                         if (ret <= 0) continue;
00388 
00389                         rcvsize = recv(this->connectors[i].GetDescriptor(),data,65000,0);
00390                         data[rcvsize] = '\0';
00391                         if (rcvsize == -1)
00392                         {
00393                                 if (errno != EAGAIN)
00394                                 {
00395                                         log(DEBUG,"recv() failed for serverrec::RecvPacket(): %s",strerror(errno));
00396                                         log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
00397                                         this->connectors[i].CloseConnection();
00398                                         this->connectors[i].SetState(STATE_DISCONNECTED);
00399                                 }
00400                         }
00401                         int pushed = 0;
00402                         if (rcvsize > 0)
00403                         {
00404                                 if (!this->connectors[i].AddBuffer(data))
00405                                 {
00406                                         WriteOpers("*** Read buffer for %s exceeds maximum, closing connection!",this->connectors[i].GetServerName().c_str());
00407                                         this->connectors[i].CloseConnection();
00408                                         this->connectors[i].SetState(STATE_DISCONNECTED);
00409                                 }
00410                                 if (this->connectors[i].BufferIsComplete())
00411                                 {
00412                                         this->connectors[i].ResetPing();
00413                                         while (this->connectors[i].BufferIsComplete())
00414                                         {
00415                                                 std::string text = this->connectors[i].GetBuffer();
00416                                                 if (text != "")
00417                                                 {
00418                                                         if ((text[0] == ':') && (text.find(" ") != std::string::npos))
00419                                                         {
00420                                                                 std::string orig = text;
00421                                                                 log(DEBUG,"Original: %s",text.c_str());
00422                                                                 std::string sum = text.substr(1,text.find(" ")-1);
00423                                                                 text = text.substr(text.find(" ")+1,text.length());
00424                                                                 std::string possible_token = text.substr(1,text.find(" ")-1);
00425                                                                 if (possible_token.length() > 1)
00426                                                                 {
00427                                                                         sums.push_back("*");
00428                                                                         text = orig;
00429                                                                         log(DEBUG,"Non-mesh, non-tokenized string passed up the chain");
00430                                                                 }
00431                                                                 else
00432                                                                 {
00433                                                                         log(DEBUG,"Packet sum: '%s'",sum.c_str());
00434                                                                         if ((already_have_sum(sum)) && (sum != "*"))
00435                                                                         {
00436                                                                                 // we don't accept dupes
00437                                                                                 continue;
00438                                                                         }
00439                                                                         sums.push_back(sum.c_str());
00440                                                                 }
00441                                                         }
00442                                                         else sums.push_back("*");
00443                                                         messages.push_back(text.c_str());
00444                                                         strlcpy(recvhost,this->connectors[i].GetServerName().c_str(),160);
00445                                                         log(DEBUG,"serverrec::RecvPacket() %d:%s->%s",pushed++,recvhost,text.c_str());
00446                                                 }
00447                                         }
00448                                         return true;
00449                                 }
00450                         }
00451                 }
00452         }
00453         // nothing new yet -- message and host will be undefined
00454         return false;
00455 }
00456 

Generated on Tue May 24 02:30:06 2005 for InspIRCd by doxygen 1.3.3