00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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 extern serverrec* me[32];
00041
00042 extern bool has_been_netsplit;
00043
00044 std::deque<std::string> xsums;
00045
00046 serverrec::serverrec()
00047 {
00048 strlcpy(name,"",256);
00049 pingtime = 0;
00050 lastping = TIME;
00051 usercount_i = usercount = opercount = version = 0;
00052 hops_away = 1;
00053 signon = TIME;
00054 jupiter = false;
00055 fd = 0;
00056 sync_soon = false;
00057 strlcpy(nickserv,"",NICKMAX);
00058 connectors.clear();
00059 }
00060
00061
00062 serverrec::~serverrec()
00063 {
00064 }
00065
00066 serverrec::serverrec(char* n, long ver, bool jupe)
00067 {
00068 strlcpy(name,n,256);
00069 lastping = TIME;
00070 usercount_i = usercount = opercount = 0;
00071 version = ver;
00072 hops_away = 1;
00073 signon = TIME;
00074 jupiter = jupe;
00075 fd = 0;
00076 sync_soon = false;
00077 strlcpy(nickserv,"",NICKMAX);
00078 connectors.clear();
00079 }
00080
00081 bool serverrec::CreateListener(char* newhost, int p)
00082 {
00083 sockaddr_in host_address;
00084 int flags;
00085 in_addr addy;
00086 int on = 0;
00087 struct linger linger = { 0 };
00088
00089 this->port = p;
00090
00091 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00092 if (fd <= 0)
00093 {
00094 return false;
00095 }
00096
00097 setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
00098 linger.l_onoff = 1;
00099 linger.l_linger = 1;
00100 setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
00101
00102
00103
00104 int sendbuf = 32768;
00105 int recvbuf = 32768;
00106 setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00107 setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00108
00109 memset((void*)&host_address, 0, sizeof(host_address));
00110
00111 host_address.sin_family = AF_INET;
00112
00113 if (!strcmp(newhost,""))
00114 {
00115 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
00116 }
00117 else
00118 {
00119 inet_aton(newhost,&addy);
00120 host_address.sin_addr = addy;
00121 }
00122
00123 host_address.sin_port = htons(p);
00124
00125 if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
00126 {
00127 return false;
00128 }
00129
00130
00131 flags = fcntl(fd, F_GETFL, 0);
00132 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
00133
00134 this->port = p;
00135
00136 listen(this->fd, MaxConn);
00137
00138 return true;
00139 }
00140
00141
00142 bool serverrec::BeginLink(char* targethost, int newport, char* password, char* servername, int myport)
00143 {
00144 char connect[MAXBUF];
00145
00146 ircd_connector connector;
00147 ircd_connector *cn = this->FindHost(servername);
00148
00149
00150 if (cn)
00151 {
00152 WriteOpers("CONNECT aborted: Server %s already exists",servername);
00153 return false;
00154 }
00155
00156
00157 if (this->fd)
00158 {
00159 if (connector.MakeOutboundConnection(targethost,newport))
00160 {
00161
00162
00163 connector.SetServerName(servername);
00164 snprintf(connect,MAXBUF,"S %s %s %lu %s :%s",getservername().c_str(),password,(unsigned long)myport,GetRevision().c_str(),getserverdesc().c_str());
00165 connector.SetState(STATE_NOAUTH_OUTBOUND);
00166 connector.SetHostAndPort(targethost, newport);
00167 this->connectors.push_back(connector);
00168
00169
00170 return this->SendPacket(connect, servername);
00171 }
00172 else
00173 {
00174 connector.SetState(STATE_DISCONNECTED);
00175 WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00176 }
00177 }
00178 return false;
00179 }
00180
00181
00182 bool serverrec::MeshCookie(char* targethost, int newport, unsigned long cookie, char* servername)
00183 {
00184 char connect[MAXBUF];
00185
00186 ircd_connector connector;
00187
00188 WriteOpers("Establishing meshed link to %s:%d",servername,newport);
00189
00190 if (this->fd)
00191 {
00192 if (connector.MakeOutboundConnection(targethost,newport))
00193 {
00194
00195
00196 connector.SetServerName(servername);
00197 snprintf(connect,MAXBUF,"- %lu %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
00198 connector.SetState(STATE_NOAUTH_OUTBOUND);
00199 connector.SetHostAndPort(targethost, newport);
00200 this->connectors.push_back(connector);
00201 return this->SendPacket(connect, servername);
00202 }
00203 else
00204 {
00205 connector.SetState(STATE_DISCONNECTED);
00206 WriteOpers("Could not create outbound connection to %s:%d",targethost,newport);
00207 }
00208 }
00209 return false;
00210 }
00211
00212 bool serverrec::AddIncoming(int newfd, char* targethost, int sourceport)
00213 {
00214 ircd_connector connector;
00215
00216
00217
00218 connector.SetServerName(targethost);
00219 connector.SetDescriptor(newfd);
00220 connector.SetState(STATE_NOAUTH_INBOUND);
00221 int flags = fcntl(newfd, F_GETFL, 0);
00222 fcntl(newfd, F_SETFL, flags | O_NONBLOCK);
00223 int sendbuf = 32768;
00224 int recvbuf = 32768;
00225 setsockopt(newfd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
00226 setsockopt(newfd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
00227 connector.SetHostAndPort(targethost, sourceport);
00228 connector.SetState(STATE_NOAUTH_INBOUND);
00229 log(DEBUG,"serverrec::AddIncoming() Added connection: %s:%d",targethost,sourceport);
00230 this->connectors.push_back(connector);
00231 return true;
00232 }
00233
00234 void serverrec::TerminateLink(char* targethost)
00235 {
00236
00237
00238
00239 }
00240
00241
00242 ircd_connector* serverrec::FindHost(std::string findhost)
00243 {
00244 for (int i = 0; i < this->connectors.size(); i++)
00245 {
00246 if (this->connectors[i].GetServerName() == findhost)
00247 {
00248 return &this->connectors[i];
00249 }
00250 }
00251 return NULL;
00252 }
00253
00254
00255
00256 bool IsRoutable(std::string servername)
00257 {
00258 int c = 0;
00259 for (int x = 0; x < 32; x++)
00260 if (me[x])
00261 {
00262 for (int i = 0; i < me[x]->connectors.size(); i++)
00263 {
00264 if ((me[x]->connectors[i].GetServerName() == servername) && (me[x]->connectors[i].GetState() != STATE_DISCONNECTED))
00265 {
00266 c++;
00267 }
00268 }
00269 }
00270 return (c != 0);
00271 }
00272
00273
00274 void serverrec::FlushWriteBuffers()
00275 {
00276 char buffer[MAXBUF];
00277 for (int i = 0; i < this->connectors.size(); i++)
00278 {
00279
00280 if ((this->connectors[i].GetState() == STATE_NOAUTH_OUTBOUND) && (TIME > this->connectors[i].age+30))
00281 {
00282
00283 WriteOpers("*** Connection to %s timed out",this->connectors[i].GetServerName().c_str());
00284 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00285 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00286 DoSplit(this->connectors[i].GetServerName().c_str());
00287 return;
00288 }
00289 if ((this->connectors[i].GetState() == STATE_NOAUTH_INBOUND) && (TIME > this->connectors[i].age+30))
00290 {
00291 WriteOpers("*** Connection from %s timed out",this->connectors[i].GetServerName().c_str());
00292 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00293 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00294 DoSplit(this->connectors[i].GetServerName().c_str());
00295 return;
00296 }
00297 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00298 {
00299 if (!this->connectors[i].CheckPing())
00300 {
00301 WriteOpers("*** Lost single connection to %s: Ping timeout",this->connectors[i].GetServerName().c_str());
00302 this->connectors[i].CloseConnection();
00303 this->connectors[i].SetState(STATE_DISCONNECTED);
00304 if (!IsRoutable(this->connectors[i].GetServerName()))
00305 {
00306 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00307 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00308 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00309 DoSplit(this->connectors[i].GetServerName().c_str());
00310 }
00311 has_been_netsplit = true;
00312 }
00313 }
00314 if ((this->connectors[i].GetWriteError() !="") && (this->connectors[i].GetState() != STATE_DISCONNECTED))
00315 {
00316
00317 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",this->connectors[i].GetServerName().c_str(),this->connectors[i].GetWriteError().c_str());
00318 this->connectors[i].CloseConnection();
00319 this->connectors[i].SetState(STATE_DISCONNECTED);
00320 if (!IsRoutable(this->connectors[i].GetServerName()))
00321 {
00322 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00323 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00324 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00325 DoSplit(this->connectors[i].GetServerName().c_str());
00326 }
00327 has_been_netsplit = true;
00328 }
00329 if ((this->connectors[i].HasBufferedOutput()) && (this->connectors[i].GetState() != STATE_DISCONNECTED))
00330 {
00331 if (!this->connectors[i].FlushWriteBuf())
00332 {
00333
00334 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",this->connectors[i].GetServerName().c_str(),this->connectors[i].GetWriteError().c_str());
00335 this->connectors[i].CloseConnection();
00336 this->connectors[i].SetState(STATE_DISCONNECTED);
00337 if (!IsRoutable(this->connectors[i].GetServerName()))
00338 {
00339 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00340 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00341 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00342 DoSplit(this->connectors[i].GetServerName().c_str());
00343 }
00344 has_been_netsplit = true;
00345 }
00346 }
00347 }
00348 }
00349
00350 bool serverrec::SendPacket(char *message, const char* sendhost)
00351 {
00352 if ((!message) || (!sendhost))
00353 return true;
00354
00355 ircd_connector* cn = this->FindHost(sendhost);
00356
00357 if (!strchr(message,'\n'))
00358 {
00359 strlcat(message,"\n",MAXBUF);
00360 }
00361
00362 if (cn)
00363 {
00364 log(DEBUG,"main: serverrec::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
00365
00366 if (cn->GetState() == STATE_DISCONNECTED)
00367 {
00368
00369 if (strncmp(message,"R ",2))
00370 {
00371 log(DEBUG,"Not a double reroute");
00372
00373 for (int k = 0; k < this->connectors.size(); k++)
00374 {
00375 log(DEBUG,"Check connector %d: %s",k,this->connectors[k].GetServerName().c_str());
00376
00377 for (int m = 0; m < this->connectors[k].routes.size(); m++)
00378 {
00379 if (!strcasecmp(this->connectors[k].routes[m].c_str(),sendhost))
00380 {
00381 log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
00382 char buffer[MAXBUF];
00383 snprintf(buffer,MAXBUF,"R %s %s",sendhost,message);
00384 this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
00385 return true;
00386 }
00387 }
00388 }
00389 }
00390 char buffer[MAXBUF];
00391 snprintf(buffer,MAXBUF,"& %s",sendhost);
00392 WriteOpers("*** All connections to %s lost.",sendhost);
00393 NetSendToAllExcept(sendhost,buffer);
00394 DoSplit(sendhost);
00395 return false;
00396 }
00397
00398
00399 if (!cn->AddWriteBuf(message))
00400 {
00401
00402 log(DEBUG,"cn->AddWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00403 log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00404 cn->CloseConnection();
00405 cn->SetState(STATE_DISCONNECTED);
00406 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00407
00408 return this->SendPacket(message,sendhost);
00409 }
00410 if (!cn->FlushWriteBuf())
00411 {
00412
00413 log(DEBUG,"cn->FlushWriteBuf() failed for serverrec::SendPacket(): %s",cn->GetWriteError().c_str());
00414 log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
00415 cn->CloseConnection();
00416 cn->SetState(STATE_DISCONNECTED);
00417 WriteOpers("*** Lost single connection to %s, link inactive and retrying: %s",cn->GetServerName().c_str(),cn->GetWriteError().c_str());
00418
00419 return this->SendPacket(message,sendhost);
00420 }
00421 return true;
00422 }
00423 }
00424
00425 bool already_have_sum(std::string sum)
00426 {
00427 for (int i = 0; i < xsums.size(); i++)
00428 {
00429 if (xsums[i] == sum)
00430 {
00431 return true;
00432 }
00433 }
00434 if (xsums.size() >= 128)
00435 {
00436 xsums.pop_front();
00437 }
00438 xsums.push_back(sum);
00439 return false;
00440 }
00441
00442
00443
00444
00445 bool serverrec::RecvPacket(std::deque<std::string> &messages, char* recvhost,std::deque<std::string> &sums)
00446 {
00447 char data[65536],buffer[MAXBUF];
00448 memset(data, 0, 65536);
00449 for (int i = 0; i < this->connectors.size(); i++)
00450 {
00451 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
00452 {
00453
00454 int rcvsize = 0;
00455
00456
00457
00458 pollfd polls;
00459 polls.fd = this->connectors[i].GetDescriptor();
00460 polls.events = POLLIN;
00461 int ret = poll(&polls,1,1);
00462 if (ret <= 0) continue;
00463
00464 rcvsize = recv(this->connectors[i].GetDescriptor(),data,65000,0);
00465 data[rcvsize] = '\0';
00466 if (rcvsize == 0)
00467 {
00468 log(DEBUG,"recv() failed for serverrec::RecvPacket(): EOF");
00469 log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
00470 this->connectors[i].CloseConnection();
00471 this->connectors[i].SetState(STATE_DISCONNECTED);
00472 if (!IsRoutable(this->connectors[i].GetServerName()))
00473 {
00474 WriteOpers("*** Server %s is no longer routable, disconnecting (EOF)",this->connectors[i].GetServerName().c_str());
00475 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00476 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00477 DoSplit(this->connectors[i].GetServerName().c_str());
00478 }
00479 has_been_netsplit = true;
00480 }
00481 if (rcvsize == -1)
00482 {
00483 if (errno != EAGAIN)
00484 {
00485 log(DEBUG,"recv() failed for serverrec::RecvPacket(): %s",strerror(errno));
00486 log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
00487 this->connectors[i].CloseConnection();
00488 this->connectors[i].SetState(STATE_DISCONNECTED);
00489 if (!IsRoutable(this->connectors[i].GetServerName()))
00490 {
00491 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00492 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00493 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00494 DoSplit(this->connectors[i].GetServerName().c_str());
00495 }
00496 has_been_netsplit = true;
00497 }
00498 }
00499 int pushed = 0;
00500 if (rcvsize > 0)
00501 {
00502 if (!this->connectors[i].AddBuffer(data))
00503 {
00504 WriteOpers("*** Read buffer for %s exceeds maximum, closing connection!",this->connectors[i].GetServerName().c_str());
00505 this->connectors[i].CloseConnection();
00506 this->connectors[i].SetState(STATE_DISCONNECTED);
00507 if (!IsRoutable(this->connectors[i].GetServerName()))
00508 {
00509 WriteOpers("*** Server %s is no longer routable, disconnecting.",this->connectors[i].GetServerName().c_str());
00510 snprintf(buffer,MAXBUF,"& %s",this->connectors[i].GetServerName().c_str());
00511 NetSendToAllExcept(this->connectors[i].GetServerName().c_str(),buffer);
00512 DoSplit(this->connectors[i].GetServerName().c_str());
00513 }
00514 has_been_netsplit = true;
00515 }
00516 if (this->connectors[i].BufferIsComplete())
00517 {
00518 this->connectors[i].ResetPing();
00519 while (this->connectors[i].BufferIsComplete())
00520 {
00521 std::string text = this->connectors[i].GetBuffer();
00522 if (text != "")
00523 {
00524 if ((text[0] == ':') && (text.find(" ") != std::string::npos))
00525 {
00526 std::string orig = text;
00527 log(DEBUG,"Original: %s",text.c_str());
00528 std::string sum = text.substr(1,text.find(" ")-1);
00529 text = text.substr(text.find(" ")+1,text.length());
00530 std::string possible_token = text.substr(1,text.find(" ")-1);
00531 if (possible_token.length() > 1)
00532 {
00533 sums.push_back("*");
00534 text = orig;
00535 log(DEBUG,"Non-mesh, non-tokenized string passed up the chain");
00536 }
00537 else
00538 {
00539 log(DEBUG,"Packet sum: '%s'",sum.c_str());
00540 if ((already_have_sum(sum)) && (sum != "*"))
00541 {
00542
00543 continue;
00544 }
00545 sums.push_back(sum.c_str());
00546 }
00547 }
00548 else sums.push_back("*");
00549 messages.push_back(text.c_str());
00550 strlcpy(recvhost,this->connectors[i].GetServerName().c_str(),160);
00551 log(DEBUG,"serverrec::RecvPacket() %d:%s->%s",pushed++,recvhost,text.c_str());
00552 }
00553 }
00554 return true;
00555 }
00556 }
00557 }
00558 }
00559
00560 return false;
00561 }
00562