]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/connection.cpp
Fixes to class connection to make it work!
[user/henk/code/inspircd.git] / src / connection.cpp
1 #include <connection.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <sys/errno.h>
5 #include <sys/ioctl.h>
6 #include <sys/utsname.h>
7 #include <vector>
8 #include <string>
9 #include <deque>
10 #include "inspircd.h"
11 #include "modules.h"
12
13 using namespace std;
14
15 extern std::vector<Module*> modules;
16 extern std::vector<ircd_module*> factory;
17
18 extern int MODCOUNT;
19
20 packet::packet()
21 {
22 }
23
24 packet::~packet()
25 {
26 }
27
28 connection::connection()
29 {
30         fd = 0;
31 }
32
33
34 bool connection::CreateListener(char* host, int p)
35 {
36         sockaddr_in host_address;
37         int flags;
38         in_addr addy;
39         int on = 0;
40         struct linger linger = { 0 };
41         
42         this->port = p;
43         
44         fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
45         if (fd <= 0)
46         {
47                 return false;
48         }
49
50         memset((void*)&host_address, 0, sizeof(host_address));
51
52         host_address.sin_family = AF_INET;
53
54         if (!strcmp(host,""))
55         {
56                 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
57         }
58         else
59         {
60                 inet_aton(host,&addy);
61                 host_address.sin_addr = addy;
62         }
63
64         host_address.sin_port = htons(p);
65
66         if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
67         {
68                 return false;
69         }
70
71         // make the socket non-blocking
72         flags = fcntl(fd, F_GETFL, 0);
73         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
74
75         this->port = p;
76
77         setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
78         linger.l_onoff = 1;
79         linger.l_linger = 0;
80         setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
81         
82         // attempt to increase socket sendq and recvq as high as its possible
83         // to get them on linux.
84         int sendbuf = 32768;
85         int recvbuf = 32768;
86         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
87         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
88         
89         listen(this->fd,5);
90
91         return true;
92 }
93
94 char* ircd_connector::GetServerIP()
95 {
96         return this->host;
97 }
98
99 int ircd_connector::GetServerPort()
100 {
101         return this->port;
102 }
103
104 bool ircd_connector::SetHostAndPort(char* host, int port)
105 {
106         strncpy(this->host,host,160);
107         this->port = port;
108         return true;
109 }
110
111 bool ircd_connector::SetHostAddress(char* host, int port)
112 {
113         strncpy(this->host,host,160);
114         this->port = port;
115         memset((void*)&addr, 0, sizeof(addr));
116         addr.sin_family = AF_INET;
117         inet_aton(host,&addr.sin_addr);
118         addr.sin_port = htons(port);
119         return true;
120 }
121
122 void ircd_connector::SetServerPort(int p)
123 {
124         this->port = p;
125 }
126
127
128 bool ircd_connector::MakeOutboundConnection(char* host, int port)
129 {
130         hostent* hoste = gethostbyname(host);
131         if (!hoste)
132         {
133                 WriteOpers("Failed to look up hostname for %s, using as an ip address",host);
134                 this->SetHostAddress(host,port);
135                 SetHostAndPort(host,port);
136         }
137         else
138         {
139                 WriteOpers("Found hostname for %s",host);
140                 this->SetHostAddress(hoste->h_addr,port);
141                 SetHostAndPort(hoste->h_addr,port);
142         }
143
144         this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
145         if (this->fd >= 0)
146         {
147                 if(connect(this->fd, (sockaddr*)&addr,sizeof(addr)))
148                 {
149                         WriteOpers("connect() failed for %s",host);
150                         return false;
151                 }
152                 int flags = fcntl(this->fd, F_GETFL, 0);
153                 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
154                 int sendbuf = 32768;
155                 int recvbuf = 32768;
156                 setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
157                 setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
158                 return true;
159         }
160         else
161         {
162                 WriteOpers("socket() failed!");
163         }
164
165         return false;
166 }
167
168
169 bool connection::BeginLink(char* targethost, int port, char* password, char* servername, int myport)
170 {
171         char connect[MAXBUF];
172         
173         ircd_connector connector;
174         
175         if (this->fd)
176         {
177                 if (connector.MakeOutboundConnection(targethost,port))
178                 {
179                         // targethost has been turned into an ip...
180                         // we dont want this as the server name.
181                         connector.SetServerName(servername);
182                         sprintf(connect,"S %s %s %d :%s",getservername().c_str(),password,myport,getserverdesc().c_str());
183                         connector.SetState(STATE_NOAUTH_OUTBOUND);
184                         connector.SetHostAndPort(targethost, port);
185                         this->connectors.push_back(connector);
186                         return this->SendPacket(connect, servername);
187                 }
188                 else
189                 {
190                         connector.SetState(STATE_DISCONNECTED);
191                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
192                 }
193         }
194         return false;
195 }
196
197 bool connection::MeshCookie(char* targethost, int port, long cookie, char* servername)
198 {
199         char connect[MAXBUF];
200         
201         ircd_connector connector;
202         
203         WriteOpers("Establishing meshed link to %s:%d",servername,port);
204
205         if (this->fd)
206         {
207                 if (connector.MakeOutboundConnection(targethost,port))
208                 {
209                         // targethost has been turned into an ip...
210                         // we dont want this as the server name.
211                         connector.SetServerName(servername);
212                         sprintf(connect,"- %d %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
213                         connector.SetState(STATE_NOAUTH_OUTBOUND);
214                         connector.SetHostAndPort(targethost, port);
215                         connector.SetState(STATE_CONNECTED);
216                         this->connectors.push_back(connector);
217                         return this->SendPacket(connect, servername);
218                 }
219                 else
220                 {
221                         connector.SetState(STATE_DISCONNECTED);
222                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
223                 }
224         }
225         return false;
226 }
227
228 bool connection::AddIncoming(int fd, char* targethost, int sourceport)
229 {
230         char connect[MAXBUF];
231         
232         ircd_connector connector;
233         
234         // targethost has been turned into an ip...
235         // we dont want this as the server name.
236         connector.SetServerName(targethost);
237         connector.SetDescriptor(fd);
238         connector.SetState(STATE_NOAUTH_INBOUND);
239         int flags = fcntl(fd, F_GETFL, 0);
240         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
241         int sendbuf = 32768;
242         int recvbuf = 32768;
243         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
244         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
245         connector.SetHostAndPort(targethost, sourceport);
246         connector.SetState(STATE_NOAUTH_INBOUND);
247         log(DEBUG,"connection::AddIncoming() Added connection: %s:%d",targethost,sourceport);
248         this->connectors.push_back(connector);
249         return true;
250 }
251
252 void connection::TerminateLink(char* targethost)
253 {
254         // this locates the targethost in the connection::connectors vector of the class,
255         // and terminates it by sending it an SQUIT token and closing its descriptor.
256         // TerminateLink with a null string causes a terminate of ALL links
257 }
258
259
260 // Returns a pointer to the connector for 'host'
261 ircd_connector* connection::FindHost(std::string host)
262 {
263         for (int i = 0; i < this->connectors.size(); i++)
264         {
265                 if (this->connectors[i].GetServerName() == host)
266                 {
267                         return &this->connectors[i];
268                 }
269         }
270         return NULL;
271 }
272
273 std::string ircd_connector::GetServerName()
274 {
275         return this->servername;
276 }
277
278 std::string ircd_connector::GetDescription()
279 {
280         return this->description;
281 }
282
283 void ircd_connector::SetServerName(std::string serv)
284 {
285         this->servername = serv;
286 }
287
288 void ircd_connector::SetDescription(std::string desc)
289 {
290         this->servername = desc;
291 }
292
293
294 int ircd_connector::GetDescriptor()
295 {
296         return this->fd;
297 }
298
299 int ircd_connector::GetState()
300 {
301         return this->state;
302 }
303
304
305 void ircd_connector::SetState(int state)
306 {
307         this->state = state;
308         if (state == STATE_DISCONNECTED)
309         {
310                 NetSendMyRoutingTable();
311         }
312 }
313
314 void ircd_connector::CloseConnection()
315 {
316         int flags = fcntl(this->fd, F_GETFL, 0);
317         fcntl(this->fd, F_SETFL, flags ^ O_NONBLOCK);
318         close(this->fd);
319         flags = fcntl(this->fd, F_GETFL, 0);
320         fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
321 }
322
323 void ircd_connector::SetDescriptor(int fd)
324 {
325         this->fd = fd;
326 }
327
328 bool connection::SendPacket(char *message, const char* host)
329 {
330         ircd_connector* cn = this->FindHost(host);
331         
332         if (!strchr(message,'\n'))
333         {
334                 strncat(message,"\n",MAXBUF);
335         }
336
337         if (cn)
338         {
339                 log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
340                 
341                 if (cn->GetState() == STATE_DISCONNECTED)
342                 {
343                         log(DEBUG,"Main route to %s is down, seeking alternative",host);
344                         // this route is down, we must re-route the packet through an available point in the mesh.
345                         for (int k = 0; k < this->connectors.size(); k++)
346                         {
347                                 // search for another point in the mesh which can 'reach' where we want to go
348                                 for (int m = 0; m < this->connectors[k].routes.size(); m++)
349                                 {
350                                         if (!strcasecmp(this->connectors[k].routes[m].c_str(),host))
351                                         {
352                                                 log(DEBUG,"Found alternative route for packet: %s",this->connectors[k].GetServerName().c_str());
353                                                 char buffer[MAXBUF];
354                                                 snprintf(buffer,MAXBUF,"R %s %s",host,message);
355                                                 this->SendPacket(buffer,this->connectors[k].GetServerName().c_str());
356                                                 return true;
357                                         }
358                                 }
359                         }
360                         char buffer[MAXBUF];
361                         snprintf(buffer,MAXBUF,"& %s",host);
362                         NetSendToAllExcept(host,buffer);
363                         log(DEBUG,"There are no routes to %s, we're gonna boot the server off!",host);
364                         DoSplit(host);
365                         return false;
366                 }
367
368                 // returns false if the packet could not be sent (e.g. target host down)
369                 if (send(cn->GetDescriptor(),message,strlen(message),0)<0)
370                 {
371                         log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno));
372                         log(DEBUG,"Disabling connector: %s",cn->GetServerName().c_str());
373                         cn->CloseConnection();
374                         cn->SetState(STATE_DISCONNECTED);
375                         return false;
376                 }
377                 return true;
378         }
379 }
380
381 // receives a packet from any where there is data waiting, first come, first served
382 // fills the message and host values with the host where the data came from.
383
384 bool connection::RecvPacket(std::deque<std::string> &messages, char* host)
385 {
386         char data[32767];
387         memset(data, 0, 32767);
388         for (int i = 0; i < this->connectors.size(); i++)
389         {
390                 if (this->connectors[i].GetState() != STATE_DISCONNECTED)
391                 {
392                         // returns false if the packet could not be sent (e.g. target host down)
393                         int rcvsize = 0;
394                         rcvsize = recv(this->connectors[i].GetDescriptor(),data,32767,0);
395                         if (rcvsize == -1)
396                         {
397                                 if (errno != EAGAIN)
398                                 {
399                                         log(DEBUG,"recv() failed for Connection::RecvPacket(): %s",strerror(errno));
400                                         log(DEBUG,"Disabling connector: %s",this->connectors[i].GetServerName().c_str());
401                                         this->connectors[i].CloseConnection();
402                                         this->connectors[i].SetState(STATE_DISCONNECTED);
403                                 }
404                         }
405                         if (rcvsize > 0)
406                         {
407                                 char* l = strtok(data,"\n");
408                                 while (l)
409                                 {
410                                         char sanitized[32767];
411                                         memset(sanitized, 0, 32767);
412                                         int ptt = 0;
413                                         for (int pt = 0; pt < strlen(l); pt++)
414                                         {
415                                                 if (l[pt] != '\r')
416                                                 {
417                                                         sanitized[ptt++] = l[pt];
418                                                 }
419                                         }
420                                         sanitized[ptt] = '\0';
421                                         if (strlen(sanitized))
422                                         {
423                                                 messages.push_back(sanitized);
424                                                 strncpy(host,this->connectors[i].GetServerName().c_str(),160);
425                                                 log(DEBUG,"main: Connection::RecvPacket() got '%s' from %s",sanitized,host);
426                                                 
427                                         }
428                                         l = strtok(NULL,"\n");
429                                 }
430                                 return true;
431                         }
432                 }
433         }
434         // nothing new yet -- message and host will be undefined
435         return false;
436 }
437
438 long connection::GenKey()
439 {
440         srand(time(NULL));
441         return (random()*time(NULL));
442 }
443