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