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