1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
20 #include "connection.h"
24 #include <sys/errno.h>
25 #include <sys/ioctl.h>
26 #include <sys/utsname.h>
32 #include "inspstring.h"
33 #include "helperfuncs.h"
35 extern char ServerName[MAXBUF];
36 extern serverrec* me[32];
37 extern bool has_been_netsplit;
38 extern std::vector<Module*> modules;
39 extern std::vector<ircd_module*> factory;
47 * The InspIRCd mesh network is maintained by a tree of objects which reference *themselves*.
48 * Every local server has an array of 32 *serverrecs, known as me[]. Each of these represents
49 * a local listening port, and is not null if the user has opened a listening port on the server.
50 * It is assumed nobody will ever want to open more than 32 listening server ports at any one
51 * time (i mean come on, why would you want more, the ircd works fine with ONE).
52 * Each me[] entry has multiple classes within it of type ircd_connector. These are stored in a vector
53 * and each represents a server linked via this socket. If the connection was created outbound,
54 * the connection is bound to the default ip address by using me[defaultRoute] (defaultRoute being
55 * a global variable which indicates the default server to make connections on). If the connection
56 * was created inbound, it is attached to the port the connection came in on. There may be as many
57 * ircd_connector objects as needed in each me[] entry. Each ircd_connector implements the specifics
58 * of an ircd connection in the mesh, however each ircd may have multiple ircd_connector connections
59 * to it, to maintain the mesh link.
62 char* xsumtable = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
64 // creates a random id for a line for detection of duplicate messages
65 std::string CreateSum()
70 for(int q = 1; q < 8; q++)
71 sum[q] = xsumtable[rand()%52];
75 connection::connection()
81 ircd_connector::ircd_connector()
91 char* ircd_connector::GetServerIP()
96 int ircd_connector::GetServerPort()
101 bool ircd_connector::SetHostAndPort(char* newhost, int newport)
103 strncpy(this->host,newhost,160);
104 this->port = newport;
108 bool ircd_connector::SetHostAddress(char* newhost, int newport)
110 strncpy(this->host,newhost,160);
111 this->port = newport;
112 memset((void*)&addr, 0, sizeof(addr));
113 addr.sin_family = AF_INET;
114 inet_aton(host,&addr.sin_addr);
115 addr.sin_port = htons(port);
119 void ircd_connector::SetServerPort(int p)
124 bool ircd_connector::AddBuffer(std::string a)
127 for (unsigned int i = 0; i < a.length(); i++)
131 std::stringstream stream(ircdbuffer);
133 log(DEBUG,"AddBuffer: %s",b.c_str());
134 ircdbuffer = stream.str();
135 return (ircdbuffer.length() < 1048576);
138 bool ircd_connector::BufferIsComplete()
140 for (unsigned int i = 0; i < ircdbuffer.length(); i++)
141 if (ircdbuffer[i] == '\n')
146 void ircd_connector::ClearBuffer()
151 std::string ircd_connector::GetBuffer()
153 // Fix by Brain 28th Apr 2005
154 // seems my stringstream code isnt liked by linux
155 // EVEN THOUGH IT IS CORRECT! Fixed by using a different
156 // (SLOWER) algorithm...
157 char* line = (char*)ircdbuffer.c_str();
158 std::string ret = "";
159 while ((*line != '\n') && (strlen(line)))
164 if ((*line == '\n') || (*line == '\r'))
170 bool ircd_connector::AddWriteBuf(std::string data)
172 log(DEBUG,"connector::AddWriteBuf(%s)",data.c_str());
173 if (this->GetWriteError() != "")
175 if (this->GetState() == STATE_DISCONNECTED)
177 std::stringstream stream;
178 stream << sendq << data;
179 sendq = stream.str();
180 return (sendq.length() < 1048576);
183 bool ircd_connector::HasBufferedOutput()
185 return (sendq.length() > 0);
188 bool ircd_connector::CheckPing()
190 if (TIME > this->nextping)
194 this->AddWriteBuf("?\n");
195 this->nextping = TIME+120;
196 this->replied = false;
201 if (this->GetState() == STATE_CONNECTED)
203 this->SetWriteError("Ping timeout");
204 this->CloseConnection();
205 this->SetState(STATE_DISCONNECTED);
206 WriteOpers("*** Ping timeout on link to %s (more routes may remain)",this->GetServerName().c_str());
207 has_been_netsplit = true;
215 void ircd_connector::ResetPing()
217 log(DEBUG,"Reset ping counter");
218 this->replied = true;
219 this->nextping = TIME+120;
222 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
223 bool ircd_connector::FlushWriteBuf()
226 if ((this->GetState() == STATE_NOAUTH_OUTBOUND) || (this->GetState() == STATE_COOKIE_OUTBOUND))
228 // if the outbound socket hasnt connected yet... return true and don't
229 // actually do anything until it IS connected. This should probably
230 // have a timeout somewhere, 10 secs should suffice. ;-)
233 polls.events = POLLOUT;
234 int ret = poll(&polls,1,1);
237 // this falls through and sends any waiting data, which can put it into the
239 if (this->GetState() == STATE_COOKIE_OUTBOUND)
241 log(DEBUG,"Moving cookie_outbound into STATE_CONNECTED state");
242 this->SetState(STATE_CONNECTED);
243 for (int t = 0; t < 32; t++) if (me[t]) for (unsigned int l = 0; l < me[t]->connectors.size(); l++)
245 if (me[t]->connectors[l].GetDescription() != "")
247 snprintf(buffer,MAXBUF,"%s = %s :%s\r\n",CreateSum().c_str(),me[t]->connectors[l].GetServerName().c_str(),me[t]->connectors[l].GetDescription().c_str());
248 this->AddWriteBuf(buffer);
252 snprintf(buffer,MAXBUF,"%s v %s %s\r\n",CreateSum().c_str(),ServerName,GetVersionString().c_str());
253 this->AddWriteBuf(buffer);
255 if ((sendq.length()) && (this->GetState() != STATE_DISCONNECTED))
257 char* tb = (char*)this->sendq.c_str();
258 int n_sent = write(this->fd,tb,this->sendq.length());
263 this->SetWriteError(strerror(errno));
268 log(DEBUG,"Wrote %d chars to socket",n_sent);
279 void ircd_connector::SetWriteError(std::string error)
281 if (this->WriteError == "")
282 this->WriteError = error;
285 std::string ircd_connector::GetWriteError()
287 return this->WriteError;
291 bool ircd_connector::MakeOutboundConnection(char* newhost, int newport)
293 log(DEBUG,"MakeOutboundConnection: Original param: %s",newhost);
295 hostent* hoste = gethostbyname(newhost);
298 log(DEBUG,"MakeOutboundConnection: gethostbyname was NULL, setting %s",newhost);
299 this->SetHostAddress(newhost,newport);
300 SetHostAndPort(newhost,newport);
304 struct in_addr* ia = (in_addr*)hoste->h_addr;
305 log(DEBUG,"MakeOutboundConnection: gethostbyname was valid, setting %s",inet_ntoa(*ia));
306 this->SetHostAddress(inet_ntoa(*ia),newport);
307 SetHostAndPort(inet_ntoa(*ia),newport);
310 this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
313 int flags = fcntl(this->fd, F_GETFL, 0);
314 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
315 if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)) == -1)
317 if (errno != EINPROGRESS)
319 WriteOpers("connect() failed for %s",host);
320 RemoveServer(this->servername.c_str());
326 setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
327 setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
332 WriteOpers("socket() failed!");
333 RemoveServer(this->servername.c_str());
340 void ircd_connector::SetVersionString(std::string newversion)
342 log(DEBUG,"Set version of %s to %s",this->servername.c_str(),newversion.c_str());
343 this->version = newversion;
346 std::string ircd_connector::GetVersionString()
348 return this->version;
352 std::string ircd_connector::GetServerName()
354 return this->servername;
357 std::string ircd_connector::GetDescription()
359 return this->description;
362 void ircd_connector::SetServerName(std::string serv)
364 this->servername = serv;
367 void ircd_connector::SetDescription(std::string desc)
369 this->description = desc;
373 int ircd_connector::GetDescriptor()
378 int ircd_connector::GetState()
384 void ircd_connector::SetState(int newstate)
386 this->state = newstate;
387 if (state == STATE_DISCONNECTED)
389 NetSendMyRoutingTable();
393 void ircd_connector::CloseConnection()
395 log(DEBUG,"Closing connection");
398 this->ircdbuffer = "";
399 shutdown(this->fd,2);
403 void ircd_connector::SetDescriptor(int newfd)