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 * ---------------------------------------------------
17 #include <connection.h>
20 #include <sys/errno.h>
21 #include <sys/ioctl.h>
22 #include <sys/utsname.h>
28 #include "inspstring.h"
33 extern std::vector<Module*> modules;
34 extern std::vector<ircd_module*> factory;
40 connection::connection()
46 bool connection::CreateListener(char* host, int p)
48 sockaddr_in host_address;
52 struct linger linger = { 0 };
56 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
62 setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
65 setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
67 // attempt to increase socket sendq and recvq as high as its possible
68 // to get them on linux.
71 setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
72 setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
74 memset((void*)&host_address, 0, sizeof(host_address));
76 host_address.sin_family = AF_INET;
80 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
84 inet_aton(host,&addy);
85 host_address.sin_addr = addy;
88 host_address.sin_port = htons(p);
90 if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
95 // make the socket non-blocking
96 flags = fcntl(fd, F_GETFL, 0);
97 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
106 char* ircd_connector::GetServerIP()
111 int ircd_connector::GetServerPort()
116 bool ircd_connector::SetHostAndPort(char* host, int port)
118 strncpy(this->host,host,160);
123 bool ircd_connector::SetHostAddress(char* host, int port)
125 strncpy(this->host,host,160);
127 memset((void*)&addr, 0, sizeof(addr));
128 addr.sin_family = AF_INET;
129 inet_aton(host,&addr.sin_addr);
130 addr.sin_port = htons(port);
134 void ircd_connector::SetServerPort(int p)
139 bool ircd_connector::MakeOutboundConnection(char* host, int port)
141 log(DEBUG,"MakeOutboundConnection: Original param: %s",host);
142 hostent* hoste = gethostbyname(host);
145 log(DEBUG,"MakeOutboundConnection: gethostbyname was NULL, setting %s",host);
146 this->SetHostAddress(host,port);
147 SetHostAndPort(host,port);
151 struct in_addr* ia = (in_addr*)hoste->h_addr;
152 log(DEBUG,"MakeOutboundConnection: gethostbyname was valid, setting %s",inet_ntoa(*ia));
153 this->SetHostAddress(inet_ntoa(*ia),port);
154 SetHostAndPort(inet_ntoa(*ia),port);
157 this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
160 if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)))
162 WriteOpers("connect() failed for %s",host);
163 RemoveServer(this->servername.c_str());
166 int flags = fcntl(this->fd, F_GETFL, 0);
167 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
170 setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
171 setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
176 WriteOpers("socket() failed!");
177 RemoveServer(this->servername.c_str());
184 bool connection::BeginLink(char* targethost, int port, char* password, char* servername, int myport)
186 char connect[MAXBUF];
188 ircd_connector connector;
189 ircd_connector *cn = this->FindHost(servername);
194 WriteOpers("CONNECT aborted: Server %s already exists",servername);
201 if (connector.MakeOutboundConnection(targethost,port))
203 // targethost has been turned into an ip...
204 // we dont want this as the server name.
205 connector.SetServerName(servername);
206 snprintf(connect,MAXBUF,"S %s %s %d %d :%s",getservername().c_str(),password,myport,GetRevision(),getserverdesc().c_str());
207 connector.SetState(STATE_NOAUTH_OUTBOUND);
208 connector.SetHostAndPort(targethost, port);
209 this->connectors.push_back(connector);
210 return this->SendPacket(connect, servername);
214 connector.SetState(STATE_DISCONNECTED);
215 WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
221 bool connection::MeshCookie(char* targethost, int port, long cookie, char* servername)
223 char connect[MAXBUF];
225 ircd_connector connector;
227 WriteOpers("Establishing meshed link to %s:%d",servername,port);
231 if (connector.MakeOutboundConnection(targethost,port))
233 // targethost has been turned into an ip...
234 // we dont want this as the server name.
235 connector.SetServerName(servername);
236 snprintf(connect,MAXBUF,"- %d %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
237 connector.SetState(STATE_NOAUTH_OUTBOUND);
238 connector.SetHostAndPort(targethost, port);
239 connector.SetState(STATE_CONNECTED);
240 this->connectors.push_back(connector);
241 return this->SendPacket(connect, servername);
245 connector.SetState(STATE_DISCONNECTED);
246 WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
252 bool connection::AddIncoming(int fd, char* targethost, int sourceport)
254 char connect[MAXBUF];
256 ircd_connector connector;
258 // targethost has been turned into an ip...
259 // we dont want this as the server name.
260 connector.SetServerName(targethost);
261 connector.SetDescriptor(fd);
262 connector.SetState(STATE_NOAUTH_INBOUND);
263 int flags = fcntl(fd, F_GETFL, 0);
264 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
267 setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf));
268 setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
269 connector.SetHostAndPort(targethost, sourceport);
270 connector.SetState(STATE_NOAUTH_INBOUND);
271 log(DEBUG,"connection::AddIncoming() Added connection: %s:%d",targethost,sourceport);
272 this->connectors.push_back(connector);
276 void connection::TerminateLink(char* targethost)
278 // this locates the targethost in the connection::connectors vector of the class,
279 // and terminates it by sending it an SQUIT token and closing its descriptor.
280 // TerminateLink with a null string causes a terminate of ALL links
284 // Returns a pointer to the connector for 'host'
285 ircd_connector* connection::FindHost(std::string host)
287 for (int i = 0; i < this->connectors.size(); i++)
289 if (this->connectors[i].GetServerName() == host)
291 return &this->connectors[i];
297 std::string ircd_connector::GetServerName()
299 return this->servername;
302 std::string ircd_connector::GetDescription()
304 return this->description;
307 void ircd_connector::SetServerName(std::string serv)
309 this->servername = serv;
312 void ircd_connector::SetDescription(std::string desc)
314 this->description = desc;
318 int ircd_connector::GetDescriptor()
323 int ircd_connector::GetState()
329 void ircd_connector::SetState(int state)
332 if (state == STATE_DISCONNECTED)
334 NetSendMyRoutingTable();
338 void ircd_connector::CloseConnection()
340 int flags = fcntl(this->fd, F_GETFL, 0);
341 fcntl(this->fd, F_SETFL, flags ^ O_NONBLOCK);
343 flags = fcntl(this->fd, F_GETFL, 0);
344 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
347 void ircd_connector::SetDescriptor(int fd)
352 bool connection::SendPacket(char *message, const char* host)
354 if ((!message) || (!host))
357 ircd_connector* cn = this->FindHost(host);
359 if (!strchr(message,'\n'))
361 strlcat(message,"\n",MAXBUF);
366 log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
368 if (cn->GetState() == STATE_DISCONNECTED)
370 log(DEBUG,"Main route to %s is down, seeking alternative",host);
371 // fix: can only route one hop to avoid a loop
372 if (strlcat(message,"R ",2))
374 // this route is down, we must re-route the packet through an available point in the mesh.
375 for (int k = 0; k < this->connectors.size(); k++)
377 // search for another point in the mesh which can 'reach' where we want to go
378 for (int m = 0; m < this->connectors[k].routes.size(); m++)
380 if (!strcasecmp(this->connectors[k].routes[m].c_str(),host))
382 log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
384 snprintf(buffer,MAXBUF,"R %s %s",host,message);
385 this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
392 snprintf(buffer,MAXBUF,"& %s",host);
393 NetSendToAllExcept(host,buffer);
394 log(DEBUG,"There are no routes to %s, we're gonna boot the server off!",host);
399 // returns false if the packet could not be sent (e.g. target host down)
400 if (send(cn->GetDescriptor(),message,strlen(message),0)<0)
402 log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno));
403 log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
404 cn->CloseConnection();
405 cn->SetState(STATE_DISCONNECTED);
406 // retry the packet along a new route so either arrival OR failure are gauranteed (bugfix)
407 return this->SendPacket(message,host);
413 // receives a packet from any where there is data waiting, first come, first served
414 // fills the message and host values with the host where the data came from.
416 bool connection::RecvPacket(std::deque<std::string> &messages, char* host)
419 memset(data, 0, 32767);
420 for (int i = 0; i < this->connectors.size(); i++)
422 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
424 // returns false if the packet could not be sent (e.g. target host down)
426 rcvsize = recv(this->connectors[i].GetDescriptor(),data,32767,0);
431 log(DEBUG,"recv() failed for Connection::RecvPacket(): %s",strerror(errno));
432 log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
433 this->connectors[i].CloseConnection();
434 this->connectors[i].SetState(STATE_DISCONNECTED);
439 char* l = strtok(data,"\n");
442 char sanitized[32767];
443 memset(sanitized, 0, 32767);
445 for (int pt = 0; pt < strlen(l); pt++)
449 sanitized[ptt++] = l[pt];
452 sanitized[ptt] = '\0';
453 if (strlen(sanitized))
455 messages.push_back(sanitized);
456 strlcpy(host,this->connectors[i].GetServerName().c_str(),160);
457 log(DEBUG,"main: Connection::RecvPacket() got '%s' from %s",sanitized,host);
460 l = strtok(NULL,"\n");
466 // nothing new yet -- message and host will be undefined
470 long connection::GenKey()
472 return (random()*time(NULL));