]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/connection.cpp
Mesh tweaks (wasnt sending the ip in the + packet)
[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                         this->connectors.push_back(connector);
181                         return this->SendPacket(connect, servername);
182                 }
183                 else
184                 {
185                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
186                 }
187         }
188         return false;
189 }
190
191 bool connection::MeshCookie(char* targethost, int port, long cookie, char* servername)
192 {
193         char connect[MAXBUF];
194         
195         ircd_connector connector;
196         
197         WriteOpers("Establishing meshed link to %s:%d",servername,port);
198
199         if (this->fd)
200         {
201                 if (connector.MakeOutboundConnection(targethost,port))
202                 {
203                         // targethost has been turned into an ip...
204                         // we dont want this as the server name.
205                         connector.SetServerName(servername);
206                         sprintf(connect,"- %d %s :%s",cookie,getservername().c_str(),getserverdesc().c_str());
207                         connector.SetState(STATE_NOAUTH_OUTBOUND);
208                         this->connectors.push_back(connector);
209                         return this->SendPacket(connect, servername);
210                 }
211                 else
212                 {
213                         WriteOpers("Could not create outbound connection to %s:%d",targethost,port);
214                 }
215         }
216         return false;
217 }
218
219 bool connection::AddIncoming(int fd,char* targethost, int sourceport)
220 {
221         char connect[MAXBUF];
222         
223         ircd_connector connector;
224         
225         // targethost has been turned into an ip...
226         // we dont want this as the server name.
227         connector.SetHostAndPort(targethost, sourceport);
228         connector.SetServerName(targethost);
229         connector.SetDescriptor(fd);
230         connector.SetState(STATE_NOAUTH_INBOUND);
231         int flags = fcntl(fd, F_GETFL, 0);
232         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
233         int sendbuf = 32768;
234         int recvbuf = 32768;
235         setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); 
236         setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf));
237         log(DEBUG,"connection::AddIncoming() Added connection: %s:%d",host,sourceport);
238         this->connectors.push_back(connector);
239         return true;
240 }
241
242 void connection::TerminateLink(char* targethost)
243 {
244         // this locates the targethost in the connection::connectors vector of the class,
245         // and terminates it by sending it an SQUIT token and closing its descriptor.
246         // TerminateLink with a null string causes a terminate of ALL links
247 }
248
249
250 // Returns a pointer to the connector for 'host'
251 ircd_connector* connection::FindHost(std::string host)
252 {
253         for (int i = 0; i < this->connectors.size(); i++)
254         {
255                 if (this->connectors[i].GetServerName() == host)
256                 {
257                         return &this->connectors[i];
258                 }
259         }
260         return NULL;
261 }
262
263 std::string ircd_connector::GetServerName()
264 {
265         return this->servername;
266 }
267
268 void ircd_connector::SetServerName(std::string serv)
269 {
270         this->servername = serv;
271 }
272
273
274 int ircd_connector::GetDescriptor()
275 {
276         return this->fd;
277 }
278
279 int ircd_connector::GetState()
280 {
281         return this->state;
282 }
283
284
285 void ircd_connector::SetState(int state)
286 {
287         this->state = state;
288 }
289
290 void ircd_connector::SetDescriptor(int fd)
291 {
292         this->fd = fd;
293 }
294
295 bool connection::SendPacket(char *message, const char* host)
296 {
297         ircd_connector* cn = this->FindHost(host);
298         
299         if (cn)
300         {
301                 log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str());
302
303                 strncat(message,"\n",MAXBUF);
304                 // returns false if the packet could not be sent (e.g. target host down)
305                 if (send(cn->GetDescriptor(),message,strlen(message),0)<0)
306                 {
307                         log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno));
308                         return false;
309                 }
310                 return true;
311         }
312 }
313
314 // receives a packet from any where there is data waiting, first come, first served
315 // fills the message and host values with the host where the data came from.
316
317 bool connection::RecvPacket(std::deque<std::string> &messages, char* host)
318 {
319         char data[32767];
320         memset(data, 0, 32767);
321         for (int i = 0; i < this->connectors.size(); i++)
322         {
323                 // returns false if the packet could not be sent (e.g. target host down)
324                 int rcvsize = 0;
325                 if (rcvsize = recv(this->connectors[i].GetDescriptor(),data,32767,0))
326                 {
327                         if (rcvsize > 0)
328                         {
329                                 char* l = strtok(data,"\n");
330                                 while (l)
331                                 {
332                                         char sanitized[32767];
333                                         memset(sanitized, 0, 32767);
334                                         int ptt = 0;
335                                         for (int pt = 0; pt < strlen(l); pt++)
336                                         {
337                                                 if (l[pt] != '\r')
338                                                 {
339                                                         sanitized[ptt++] = l[pt];
340                                                 }
341                                         }
342                                         sanitized[ptt] = '\0';
343                                         if (strlen(sanitized))
344                                         {
345                                                 messages.push_back(sanitized);
346                                                 strncpy(host,this->connectors[i].GetServerName().c_str(),160);
347                                                 log(DEBUG,"main: Connection::RecvPacket() got '%s' from %s",sanitized,host);
348                                                 
349                                         }
350                                         l = strtok(NULL,"\n");
351                                 }
352                                 return true;
353                         }
354                 }
355         }
356         // nothing new yet -- message and host will be undefined
357         return false;
358 }
359
360 long connection::GenKey()
361 {
362         srand(time(NULL));
363         return (random()*time(NULL));
364 }
365