]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/inspsocket.cpp
We were already sending FMODE +nt after each channel creation to keep services happy...
[user/henk/code/inspircd.git] / src / inspsocket.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "socket.h"
15 #include "configreader.h"
16 #include "inspstring.h"
17 #include "socketengine.h"
18 #include "inspircd.h"
19
20 using irc::sockets::OpenTCPSocket;
21
22 bool InspSocket::Readable()
23 {
24         return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
25 }
26
27 InspSocket::InspSocket(InspIRCd* SI)
28 {
29         this->Timeout = NULL;
30         this->state = I_DISCONNECTED;
31         this->fd = -1;
32         this->WaitingForWriteEvent = false;
33         this->Instance = SI;
34         this->IsIOHooked = false;
35 }
36
37 InspSocket::InspSocket(InspIRCd* SI, int newfd, const char* ip)
38 {
39         this->Timeout = NULL;
40         this->fd = newfd;
41         this->state = I_CONNECTED;
42         strlcpy(this->IP,ip,MAXBUF);
43         this->WaitingForWriteEvent = false;
44         this->Instance = SI;
45         this->IsIOHooked = false;
46         if (this->fd > -1)
47                 this->Instance->SE->AddFd(this);
48 }
49
50 InspSocket::InspSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)
51 {
52         this->cbindip = connectbindip;
53         this->fd = -1;
54         this->Instance = SI;
55         strlcpy(host,ipaddr.c_str(),MAXBUF);
56         this->WaitingForWriteEvent = false;
57         this->IsIOHooked = false;
58         this->Timeout = NULL;
59         if (listening)
60         {
61                 if ((this->fd = OpenTCPSocket(host)) == ERROR)
62                 {
63                         this->fd = -1;
64                         this->state = I_ERROR;
65                         this->OnError(I_ERR_SOCKET);
66                         return;
67                 }
68                 else
69                 {
70                         if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))
71                         {
72                                 this->Close();
73                                 this->fd = -1;
74                                 this->state = I_ERROR;
75                                 this->OnError(I_ERR_BIND);
76                                 this->ClosePending = true;
77                                 return;
78                         }
79                         else
80                         {
81                                 this->state = I_LISTENING;
82                                 if (this->fd > -1)
83                                 {
84                                         if (!this->Instance->SE->AddFd(this))
85                                         {
86                                                 this->Close();
87                                                 this->state = I_ERROR;
88                                                 this->OnError(I_ERR_NOMOREFDS);
89                                         }
90                                 }
91                                 return;
92                         }
93                 }
94         }
95         else
96         {
97                 strlcpy(this->host,ipaddr.c_str(),MAXBUF);
98                 this->port = aport;
99
100                 bool ipvalid = true;
101 #ifdef IPV6
102                 if (strchr(host,':'))
103                 {
104                         in6_addr n;
105                         if (inet_pton(AF_INET6, host, &n) < 1)
106                                 ipvalid = false;
107                 }
108                 else
109                 {
110                         in_addr n;
111                         if (inet_aton(host,&n) < 1)
112                                 ipvalid = false;
113                 }
114 #else
115                 in_addr n;
116                 if (inet_aton(host,&n) < 1)
117                         ipvalid = false;
118 #endif
119                 if (!ipvalid)
120                 {
121                         this->Instance->Log(DEBUG,"BUG: Hostname passed to InspSocket, rather than an IP address!");
122                         this->OnError(I_ERR_CONNECT);
123                         this->Close();
124                         this->fd = -1;
125                         this->state = I_ERROR;
126                         return;
127                 }
128                 else
129                 {
130                         strlcpy(this->IP,host,MAXBUF);
131                         timeout_val = maxtime;
132                         if (!this->DoConnect())
133                         {
134                                 this->OnError(I_ERR_CONNECT);
135                                 this->Close();
136                                 this->fd = -1;
137                                 this->state = I_ERROR;
138                                 return;
139                         }
140                 }
141         }
142 }
143
144 void InspSocket::WantWrite()
145 {
146         this->Instance->SE->WantWrite(this);
147         this->WaitingForWriteEvent = true;
148 }
149
150 void InspSocket::SetQueues(int nfd)
151 {
152         // attempt to increase socket sendq and recvq as high as its possible
153         int sendbuf = 32768;
154         int recvbuf = 32768;
155         setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf));
156         setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf));
157 }
158
159 /* Most irc servers require you to specify the ip you want to bind to.
160  * If you dont specify an IP, they rather dumbly bind to the first IP
161  * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP
162  * addresses we've bound server ports to, and we try and bind our outbound
163  * connections to the first usable non-loopback and non-any IP we find.
164  * This is easier to configure when you have a lot of links and a lot
165  * of servers to configure.
166  */
167 bool InspSocket::BindAddr(const std::string &ip)
168 {
169         ConfigReader Conf(this->Instance);
170         socklen_t size = sizeof(sockaddr_in);
171 #ifdef IPV6
172         bool v6 = false;
173         /* Are we looking for a binding to fit an ipv6 host? */
174         if ((ip.empty()) || (ip.find(':') != std::string::npos))
175                 v6 = true;
176 #endif
177         int j = 0;
178         while (j < Conf.Enumerate("bind") || (!ip.empty()))
179         {
180                 std::string IP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
181                 if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
182                 {
183                         if (!ip.empty() || ((IP != "*") && (IP != "127.0.0.1") && (IP != "") && (IP != "::1")))
184                         {
185                                 sockaddr* s = new sockaddr[2];
186 #ifdef IPV6
187                                 if (v6)
188                                 {
189                                         in6_addr n;
190                                         if (inet_pton(AF_INET6, IP.c_str(), &n) > 0)
191                                         {
192                                                 memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(n));
193                                                 ((sockaddr_in6*)s)->sin6_port = 0;
194                                                 ((sockaddr_in6*)s)->sin6_family = AF_INET6;
195                                                 size = sizeof(sockaddr_in6);
196                                         }
197                                         else
198                                         {
199                                                 delete[] s;
200                                                 j++;
201                                                 continue;
202                                         }
203                                 }
204                                 else
205                                 {
206                                         in_addr n;
207                                         if (inet_aton(IP.c_str(), &n) > 0)
208                                         {
209                                                 ((sockaddr_in*)s)->sin_addr = n;
210                                                 ((sockaddr_in*)s)->sin_port = 0;
211                                                 ((sockaddr_in*)s)->sin_family = AF_INET;
212                                         }
213                                         else
214                                         {
215                                                 delete[] s;
216                                                 j++;
217                                                 continue;
218                                         }
219                                 }
220 #else
221                                 in_addr n;
222                                 if (insp_aton(IP.c_str(), &n) > 0)
223                                 {
224                                         ((sockaddr_in*)s)->sin_addr = n;
225                                         ((sockaddr_in*)s)->sin_port = 0;
226                                         ((sockaddr_in*)s)->sin_family = AF_INET;
227                                 }
228                                 else
229                                 {
230                                         delete[] s;
231                                         j++;
232                                         continue;
233                                 }
234 #endif
235
236                                 if (bind(this->fd, s, size) < 0)
237                                 {
238                                         this->state = I_ERROR;
239                                         this->OnError(I_ERR_BIND);
240                                         this->fd = -1;
241                                         delete[] s;
242                                         return false;
243                                 }
244
245                                 delete[] s;
246                                 return true;
247                         }
248                 }
249                 j++;
250         }
251         return true;
252 }
253
254 bool InspSocket::DoConnect()
255 {
256         sockaddr* addr = new sockaddr[2];
257         socklen_t size = sizeof(sockaddr_in);
258 #ifdef IPV6
259         bool v6 = false;
260         if ((!*this->host) || strchr(this->host, ':'))
261                 v6 = true;
262
263         if (v6)
264         {
265                 this->fd = socket(AF_INET6, SOCK_STREAM, 0);
266                 if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
267                 {
268                         if (!this->BindAddr(this->cbindip))
269                         {
270                                 delete[] addr;
271                                 return false;
272                         }
273                 }
274         }
275         else
276         {
277                 this->fd = socket(AF_INET, SOCK_STREAM, 0);
278                 if (this->fd > -1)
279                 {
280                         if (!this->BindAddr(this->cbindip))
281                         {
282                                 delete[] addr;
283                                 return false;
284                         }
285                 }
286         }
287 #else
288         this->fd = socket(AF_INET, SOCK_STREAM, 0);
289         if (this->fd > -1)
290         {
291                 if (!this->BindAddr(this->cbindip))
292                 {
293                         delete[] addr;
294                         return false;
295                 }
296         }
297 #endif
298
299         if (this->fd == -1)
300         {
301                 this->state = I_ERROR;
302                 this->OnError(I_ERR_SOCKET);
303                 delete[] addr;
304                 return false;
305         }
306
307 #ifdef IPV6
308         if (v6)
309         {
310                 in6_addr addy;
311                 if (inet_pton(AF_INET6, this->host, &addy) > 0)
312                 {
313                         ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
314                         memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
315                         ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
316                         size = sizeof(sockaddr_in6);
317                 }
318         }
319         else
320         {
321                 in_addr addy;
322                 if (inet_aton(this->host, &addy) > 0)
323                 {
324                         ((sockaddr_in*)addr)->sin_family = AF_INET;
325                         ((sockaddr_in*)addr)->sin_addr = addy;
326                         ((sockaddr_in*)addr)->sin_port = htons(this->port);
327                 }
328         }
329 #else
330         in_addr addy;
331         if (inet_aton(this->host, &addy) > 0)
332         {
333                 ((sockaddr_in*)addr)->sin_family = AF_INET;
334                 ((sockaddr_in*)addr)->sin_addr = addy;
335                 ((sockaddr_in*)addr)->sin_port = htons(this->port);
336         }
337 #endif
338 #ifndef WIN32
339         int flags = fcntl(this->fd, F_GETFL, 0);
340         fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
341 #else
342         unsigned long flags = 0;
343         ioctlsocket(this->fd, FIONBIO, &flags);
344 #endif
345         if (connect(this->fd, (sockaddr*)addr, size) == -1)
346         {
347                 if (errno != EINPROGRESS)
348                 {
349                         this->OnError(I_ERR_CONNECT);
350                         this->Close();
351                         this->state = I_ERROR;
352                         return false;
353                 }
354
355                 this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
356                 this->Instance->Timers->AddTimer(this->Timeout);
357         }
358         this->state = I_CONNECTING;
359         if (this->fd > -1)
360         {
361                 if (!this->Instance->SE->AddFd(this))
362                 {
363                         this->OnError(I_ERR_NOMOREFDS);
364                         this->Close();
365                         this->state = I_ERROR;
366                         return false;
367                 }
368                 this->SetQueues(this->fd);
369         }
370         return true;
371 }
372
373
374 void InspSocket::Close()
375 {
376         /* Save this, so we dont lose it,
377          * otherise on failure, error messages
378          * might be inaccurate.
379          */
380         int save = errno;
381         if (this->fd > -1)
382         {
383                 if (this->IsIOHooked && Instance->Config->GetIOHook(this))
384                 {
385                         try
386                         {
387                                 Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
388                         }
389                         catch (CoreException& modexcept)
390                         {
391                                 Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
392                         }
393                 }
394                 this->OnClose();
395                 shutdown(this->fd,2);
396                 close(this->fd);
397         }
398         errno = save;
399 }
400
401 std::string InspSocket::GetIP()
402 {
403         return this->IP;
404 }
405
406 char* InspSocket::Read()
407 {
408 #ifdef WINDOWS
409         if ((fd < 0) || (m_internalFd > MAX_DESCRIPTORS))
410 #else
411         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
412 #endif
413                 return NULL;
414
415         int n = 0;
416
417         if (this->IsIOHooked)
418         {
419                 int result2 = 0;
420                 int MOD_RESULT = 0;
421                 try
422                 {
423                         MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf),result2);
424                 }
425                 catch (CoreException& modexcept)
426                 {
427                         Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
428                 }
429                 if (MOD_RESULT < 0)
430                 {
431                         n = -1;
432                         errno = EAGAIN;
433                 }
434                 else
435                 {
436                         n = result2;
437                 }
438         }
439         else
440         {
441                 n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
442         }
443
444         if ((n > 0) && (n <= (int)sizeof(this->ibuf)))
445         {
446                 ibuf[n] = 0;
447                 return ibuf;
448         }
449         else
450         {
451                 int err = errno;
452                 if (err == EAGAIN)
453                         return "";
454                 else
455                         return NULL;
456         }
457 }
458
459 void InspSocket::MarkAsClosed()
460 {
461 }
462
463 // There are two possible outcomes to this function.
464 // It will either write all of the data, or an undefined amount.
465 // If an undefined amount is written the connection has failed
466 // and should be aborted.
467 int InspSocket::Write(const std::string &data)
468 {
469         /* Try and append the data to the back of the queue, and send it on its way
470          */
471         outbuffer.push_back(data);
472         this->Instance->SE->WantWrite(this);
473         return (!this->FlushWriteBuffer());
474 }
475
476 bool InspSocket::FlushWriteBuffer()
477 {
478         errno = 0;
479         if ((this->fd > -1) && (this->state == I_CONNECTED))
480         {
481                 if (this->IsIOHooked)
482                 {
483                         while (outbuffer.size() && (errno != EAGAIN))
484                         {
485                                 try
486                                 {
487                                         int result = Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
488                                         if (result > 0)
489                                         {
490                                                 if ((unsigned int)result >= outbuffer[0].length())
491                                                 {
492                                                         outbuffer.pop_front();
493                                                 }
494                                                 else
495                                                 {
496                                                         std::string temp = outbuffer[0].substr(result);
497                                                         outbuffer[0] = temp;
498                                                         errno = EAGAIN;
499                                                 }
500                                         }
501                                         else if (((result == -1) && (errno != EAGAIN)) || (result == 0))
502                                         {
503                                                 this->OnError(I_ERR_WRITE);
504                                                 this->state = I_ERROR;
505                                                 this->Instance->SE->DelFd(this);
506                                                 this->Close();
507                                                 return true;
508                                         }
509                                 }
510                                 catch (CoreException& modexcept)
511                                 {
512                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
513                                         return true;
514                                 }
515                         }
516                 }
517                 else
518                 {
519                         /* If we have multiple lines, try to send them all,
520                          * not just the first one -- Brain
521                          */
522                         while (outbuffer.size() && (errno != EAGAIN))
523                         {
524                                 /* Send a line */
525 #ifndef WIN32
526                                 int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
527 #else
528                                 int result = send(this->fd,outbuffer[0].c_str(),outbuffer[0].length(), 0);
529 #endif
530                                 if (result > 0)
531                                 {
532                                         if ((unsigned int)result >= outbuffer[0].length())
533                                         {
534                                                 /* The whole block was written (usually a line)
535                                                  * Pop the block off the front of the queue,
536                                                  * dont set errno, because we are clear of errors
537                                                  * and want to try and write the next block too.
538                                                  */
539                                                 outbuffer.pop_front();
540                                         }
541                                         else
542                                         {
543                                                 std::string temp = outbuffer[0].substr(result);
544                                                 outbuffer[0] = temp;
545                                                 /* We didnt get the whole line out. arses.
546                                                  * Try again next time, i guess. Set errno,
547                                                  * because we shouldnt be writing any more now,
548                                                  * until the socketengine says its safe to do so.
549                                                  */
550                                                 errno = EAGAIN;
551                                         }
552                                 }
553                                 else if ((result == -1) && (errno != EAGAIN))
554                                 {
555                                         this->OnError(I_ERR_WRITE);
556                                         this->state = I_ERROR;
557                                         this->Instance->SE->DelFd(this);
558                                         this->Close();
559                                         return true;
560                                 }
561                         }
562                 }
563         }
564
565         if ((errno == EAGAIN) && (fd > -1))
566         {
567                 this->Instance->SE->WantWrite(this);
568         }
569
570         return (fd < 0);
571 }
572
573 void SocketTimeout::Tick(time_t now)
574 {
575         if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
576                 return;
577
578         if (this->sock->state == I_CONNECTING)
579         {
580                 // for non-listening sockets, the timeout can occur
581                 // which causes termination of the connection after
582                 // the given number of seconds without a successful
583                 // connection.
584                 this->sock->OnTimeout();
585                 this->sock->OnError(I_ERR_TIMEOUT);
586                 this->sock->timeout = true;
587
588                 /* NOTE: We must set this AFTER DelFd, as we added
589                  * this socket whilst writeable. This means that we
590                  * must DELETE the socket whilst writeable too!
591                  */
592                 this->sock->state = I_ERROR;
593
594                 if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
595                         ServerInstance->SocketCull[this->sock] = this->sock;
596         }
597
598         this->sock->Timeout = NULL;
599 }
600
601 bool InspSocket::Poll()
602 {
603 #ifdef WINDOWS
604         if(Instance->SE->GetRef(this->fd) != this)
605                 return false;
606         int incoming = -1;
607 #else
608         if (this->Instance->SE->GetRef(this->fd) != this)
609                 return false;
610
611         int incoming = -1;
612
613         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
614                 return false;
615 #endif
616         switch (this->state)
617         {
618                 case I_CONNECTING:
619                         /* Our socket was in write-state, so delete it and re-add it
620                          * in read-state.
621                          */
622 #ifndef WINDOWS
623                         if (this->fd > -1)
624                         {
625                                 this->Instance->SE->DelFd(this);
626                                 this->SetState(I_CONNECTED);
627                                 if (!this->Instance->SE->AddFd(this))
628                                         return false;
629                         }
630 #else
631                         this->SetState(I_CONNECTED);
632 #endif
633                         if (Instance->Config->GetIOHook(this))
634                         {
635                                 try
636                                 {
637                                         Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
638                                 }
639                                 catch (CoreException& modexcept)
640                                 {
641                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
642                                 }
643                         }
644                         return this->OnConnected();
645                 break;
646                 case I_LISTENING:
647                 {
648                         sockaddr* client = new sockaddr[2];
649                         length = sizeof (sockaddr_in);
650                         std::string recvip;
651 #ifdef IPV6
652                         if ((!*this->host) || strchr(this->host, ':'))
653                                 length = sizeof(sockaddr_in6);
654 #endif
655                         incoming = _accept (this->fd, client, &length);
656 #ifdef IPV6
657                         if ((!*this->host) || strchr(this->host, ':'))
658                         {
659                                 char buf[1024];
660                                 recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
661                         }
662                         else
663                         {
664                                 recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
665                         }
666 #else
667                         recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
668 #endif
669                         this->OnIncomingConnection(incoming, (char*)recvip.c_str());
670
671                         if (this->IsIOHooked)
672                         {
673                                 try
674                                 {
675                                         Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
676                                 }
677                                 catch (CoreException& modexcept)
678                                 {
679                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
680                                 }
681                         }
682
683                         this->SetQueues(incoming);
684
685                         delete[] client;
686                         return true;
687                 }
688                 break;
689                 case I_CONNECTED:
690                         /* Process the read event */
691                         return this->OnDataReady();
692                 break;
693                 default:
694                 break;
695         }
696         return true;
697 }
698
699 void InspSocket::SetState(InspSocketState s)
700 {
701         this->state = s;
702 }
703
704 InspSocketState InspSocket::GetState()
705 {
706         return this->state;
707 }
708
709 int InspSocket::GetFd()
710 {
711         return this->fd;
712 }
713
714 bool InspSocket::OnConnected() { return true; }
715 void InspSocket::OnError(InspSocketError e) { return; }
716 int InspSocket::OnDisconnect() { return 0; }
717 int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
718 bool InspSocket::OnDataReady() { return true; }
719 bool InspSocket::OnWriteReady() { return true; }
720 void InspSocket::OnTimeout() { return; }
721 void InspSocket::OnClose() { return; }
722
723 InspSocket::~InspSocket()
724 {
725         this->Close();
726         if (Timeout)
727         {
728                 Instance->Timers->DelTimer(Timeout);
729                 Timeout = NULL;
730         }
731 }
732
733 void InspSocket::HandleEvent(EventType et, int errornum)
734 {
735         switch (et)
736         {
737                 case EVENT_ERROR:
738                         switch (errornum)
739                         {
740                                 case ETIMEDOUT:
741                                         this->OnError(I_ERR_TIMEOUT);
742                                 break;
743                                 case ECONNREFUSED:
744                                 case 0:
745                                         this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
746                                 break;
747                                 case EADDRINUSE:
748                                         this->OnError(I_ERR_BIND);
749                                 break;
750                                 case EPIPE:
751                                 case EIO:
752                                         this->OnError(I_ERR_WRITE);
753                                 break;
754                         }
755                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
756                                 this->Instance->SocketCull[this] = this;
757                         return;
758                 break;
759                 case EVENT_READ:
760                         if (!this->Poll())
761                         {
762                                 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
763                                         this->Instance->SocketCull[this] = this;
764                                 return;
765                         }
766                 break;
767                 case EVENT_WRITE:
768                         if (this->WaitingForWriteEvent)
769                         {
770                                 this->WaitingForWriteEvent = false;
771                                 if (!this->OnWriteReady())
772                                 {
773                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
774                                                 this->Instance->SocketCull[this] = this;
775                                         return;
776                                 }
777                         }
778                         if (this->state == I_CONNECTING)
779                         {
780                                 /* This might look wrong as if we should be actually calling
781                                  * with EVENT_WRITE, but trust me it is correct. There are some
782                                  * writeability-state things in the read code, because of how
783                                  * InspSocket used to work regarding write buffering in previous
784                                  * versions of InspIRCd. - Brain
785                                  */
786                                 this->HandleEvent(EVENT_READ);
787                                 return;
788                         }
789                         else
790                         {
791                                 if (this->FlushWriteBuffer())
792                                 {
793                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
794                                                 this->Instance->SocketCull[this] = this;
795                                         return;
796                                 }
797                         }
798                 break;
799         }
800 }
801