The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

inspsocket.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 /* $Core */
00015 
00016 #include "socket.h"
00017 #include "inspstring.h"
00018 #include "socketengine.h"
00019 #include "inspircd.h"
00020 
00021 using irc::sockets::OpenTCPSocket;
00022 
00023 bool BufferedSocket::Readable()
00024 {
00025         return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
00026 }
00027 
00028 BufferedSocket::BufferedSocket(InspIRCd* SI)
00029 {
00030         this->Timeout = NULL;
00031         this->state = I_DISCONNECTED;
00032         this->fd = -1;
00033         this->WaitingForWriteEvent = false;
00034         this->Instance = SI;
00035         this->IsIOHooked = false;
00036 }
00037 
00038 BufferedSocket::BufferedSocket(InspIRCd* SI, int newfd, const char* ip)
00039 {
00040         this->Timeout = NULL;
00041         this->fd = newfd;
00042         this->state = I_CONNECTED;
00043         strlcpy(this->IP,ip,MAXBUF);
00044         this->WaitingForWriteEvent = false;
00045         this->Instance = SI;
00046         this->IsIOHooked = false;
00047         if (this->fd > -1)
00048                 this->Instance->SE->AddFd(this);
00049 }
00050 
00051 BufferedSocket::BufferedSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)
00052 {
00053         this->cbindip = connectbindip;
00054         this->fd = -1;
00055         this->Instance = SI;
00056         strlcpy(host,ipaddr.c_str(),MAXBUF);
00057         this->WaitingForWriteEvent = false;
00058         this->IsIOHooked = false;
00059         this->Timeout = NULL;
00060         if (listening)
00061         {
00062                 if ((this->fd = OpenTCPSocket(host)) == ERROR)
00063                 {
00064                         this->fd = -1;
00065                         this->state = I_ERROR;
00066                         this->OnError(I_ERR_SOCKET);
00067                         return;
00068                 }
00069                 else
00070                 {
00071                         if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))
00072                         {
00073                                 this->Close();
00074                                 this->fd = -1;
00075                                 this->state = I_ERROR;
00076                                 this->OnError(I_ERR_BIND);
00077                                 this->ClosePending = true;
00078                                 return;
00079                         }
00080                         else
00081                         {
00082                                 this->state = I_LISTENING;
00083                                 this->port = aport;
00084                                 if (this->fd > -1)
00085                                 {
00086                                         if (!this->Instance->SE->AddFd(this))
00087                                         {
00088                                                 this->Close();
00089                                                 this->state = I_ERROR;
00090                                                 this->OnError(I_ERR_NOMOREFDS);
00091                                         }
00092                                 }
00093                                 return;
00094                         }
00095                 }
00096         }
00097         else
00098         {
00099                 strlcpy(this->host,ipaddr.c_str(),MAXBUF);
00100                 this->port = aport;
00101 
00102                 bool ipvalid = true;
00103 #ifdef IPV6
00104                 if (strchr(host,':'))
00105                 {
00106                         in6_addr n;
00107                         if (inet_pton(AF_INET6, host, &n) < 1)
00108                                 ipvalid = false;
00109                 }
00110                 else
00111 #endif
00112                 {
00113                         in_addr n;
00114                         if (inet_aton(host,&n) < 1)
00115                                 ipvalid = false;
00116                 }
00117                 if (!ipvalid)
00118                 {
00119                         this->Instance->Logs->Log("SOCKET", DEBUG,"BUG: Hostname passed to BufferedSocket, rather than an IP address!");
00120                         this->OnError(I_ERR_CONNECT);
00121                         this->Close();
00122                         this->fd = -1;
00123                         this->state = I_ERROR;
00124                         return;
00125                 }
00126                 else
00127                 {
00128                         strlcpy(this->IP,host,MAXBUF);
00129                         timeout_val = maxtime;
00130                         if (!this->DoConnect())
00131                         {
00132                                 this->OnError(I_ERR_CONNECT);
00133                                 this->Close();
00134                                 this->fd = -1;
00135                                 this->state = I_ERROR;
00136                                 return;
00137                         }
00138                 }
00139         }
00140 }
00141 
00142 void BufferedSocket::WantWrite()
00143 {
00144         this->Instance->SE->WantWrite(this);
00145         this->WaitingForWriteEvent = true;
00146 }
00147 
00148 void BufferedSocket::SetQueues(int nfd)
00149 {
00150         // attempt to increase socket sendq and recvq as high as its possible
00151         int sendbuf = 32768;
00152         int recvbuf = 32768;
00153         if(setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf)) || setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf)))
00154         {
00155                 //this->Instance->Log(DEFAULT, "Could not increase SO_SNDBUF/SO_RCVBUF for socket %u", GetFd());
00156                 ; // do nothing. I'm a little sick of people trying to interpret this message as a result of why their incorrect setups don't work.
00157         }
00158 }
00159 
00160 /* Most irc servers require you to specify the ip you want to bind to.
00161  * If you dont specify an IP, they rather dumbly bind to the first IP
00162  * of the box (e.g. INADDR_ANY). In InspIRCd, we scan thought the IP
00163  * addresses we've bound server ports to, and we try and bind our outbound
00164  * connections to the first usable non-loopback and non-any IP we find.
00165  * This is easier to configure when you have a lot of links and a lot
00166  * of servers to configure.
00167  */
00168 bool BufferedSocket::BindAddr(const std::string &ip)
00169 {
00170         ConfigReader Conf(this->Instance);
00171         socklen_t size = sizeof(sockaddr_in);
00172 #ifdef IPV6
00173         bool v6 = false;
00174         /* Are we looking for a binding to fit an ipv6 host? */
00175         if ((ip.empty()) || (ip.find(':') != std::string::npos))
00176                 v6 = true;
00177 #endif
00178         int j = 0;
00179         while (j < Conf.Enumerate("bind") || (!ip.empty()))
00180         {
00181                 std::string sIP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
00182                 if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
00183                 {
00184                         if (!ip.empty() || ((sIP != "*") && (sIP != "127.0.0.1") && (!sIP.empty()) && (sIP != "::1")))
00185                         {
00186                                 /* The [2] is required because we may write a sockaddr_in6 here, and sockaddr_in6 is larger than sockaddr, where sockaddr_in4 is not. */
00187                                 sockaddr* s = new sockaddr[2];
00188 #ifdef IPV6
00189                                 if (v6)
00190                                 {
00191                                         in6_addr n;
00192                                         if (inet_pton(AF_INET6, sIP.c_str(), &n) > 0)
00193                                         {
00194                                                 memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(sockaddr_in6));
00195                                                 ((sockaddr_in6*)s)->sin6_port = 0;
00196                                                 ((sockaddr_in6*)s)->sin6_family = AF_INET6;
00197                                                 size = sizeof(sockaddr_in6);
00198                                         }
00199                                         else
00200                                         {
00201                                                 delete[] s;
00202                                                 j++;
00203                                                 continue;
00204                                         }
00205                                 }
00206                                 else
00207 #endif
00208                                 {
00209                                         in_addr n;
00210                                         if (inet_aton(sIP.c_str(), &n) > 0)
00211                                         {
00212                                                 ((sockaddr_in*)s)->sin_addr = n;
00213                                                 ((sockaddr_in*)s)->sin_port = 0;
00214                                                 ((sockaddr_in*)s)->sin_family = AF_INET;
00215                                         }
00216                                         else
00217                                         {
00218                                                 delete[] s;
00219                                                 j++;
00220                                                 continue;
00221                                         }
00222                                 }
00223 
00224                                 if (Instance->SE->Bind(this->fd, s, size) < 0)
00225                                 {
00226                                         this->state = I_ERROR;
00227                                         this->OnError(I_ERR_BIND);
00228                                         this->fd = -1;
00229                                         delete[] s;
00230                                         return false;
00231                                 }
00232 
00233                                 delete[] s;
00234                                 return true;
00235                         }
00236                 }
00237                 j++;
00238         }
00239         Instance->Logs->Log("SOCKET", DEBUG,"nothing in the config to bind()!");
00240         return true;
00241 }
00242 
00243 bool BufferedSocket::DoConnect()
00244 {
00245         /* The [2] is required because we may write a sockaddr_in6 here, and sockaddr_in6 is larger than sockaddr, where sockaddr_in4 is not. */
00246         sockaddr* addr = new sockaddr[2];
00247         socklen_t size = sizeof(sockaddr_in);
00248 #ifdef IPV6
00249         bool v6 = false;
00250         if ((!*this->host) || strchr(this->host, ':'))
00251                 v6 = true;
00252 
00253         if (v6)
00254         {
00255                 this->fd = socket(AF_INET6, SOCK_STREAM, 0);
00256                 if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
00257                 {
00258                         if (!this->BindAddr(this->cbindip))
00259                         {
00260                                 delete[] addr;
00261                                 return false;
00262                         }
00263                 }
00264         }
00265         else
00266 #endif
00267         {
00268                 this->fd = socket(AF_INET, SOCK_STREAM, 0);
00269                 if (this->fd > -1)
00270                 {
00271                         if (!this->BindAddr(this->cbindip))
00272                         {
00273                                 delete[] addr;
00274                                 return false;
00275                         }
00276                 }
00277         }
00278 
00279         if (this->fd == -1)
00280         {
00281                 this->state = I_ERROR;
00282                 this->OnError(I_ERR_SOCKET);
00283                 delete[] addr;
00284                 return false;
00285         }
00286 
00287 #ifdef IPV6
00288         if (v6)
00289         {
00290                 in6_addr addy;
00291                 if (inet_pton(AF_INET6, this->host, &addy) > 0)
00292                 {
00293                         ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
00294                         memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
00295                         ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
00296                         size = sizeof(sockaddr_in6);
00297                 }
00298         }
00299         else
00300 #endif
00301         {
00302                 in_addr addy;
00303                 if (inet_aton(this->host, &addy) > 0)
00304                 {
00305                         ((sockaddr_in*)addr)->sin_family = AF_INET;
00306                         ((sockaddr_in*)addr)->sin_addr = addy;
00307                         ((sockaddr_in*)addr)->sin_port = htons(this->port);
00308                 }
00309         }
00310 
00311         Instance->SE->NonBlocking(this->fd);
00312 
00313 #ifdef WIN32
00314         /* UGH for the LOVE OF ZOMBIE JESUS SOMEONE FIX THIS!!!!!!!!!!! */
00315         Instance->SE->Blocking(this->fd);
00316 #endif
00317 
00318         if (Instance->SE->Connect(this, (sockaddr*)addr, size) == -1)
00319         {
00320                 if (errno != EINPROGRESS)
00321                 {
00322                         this->OnError(I_ERR_CONNECT);
00323                         this->Close();
00324                         this->state = I_ERROR;
00325                         return false;
00326                 }
00327 
00328                 this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
00329                 this->Instance->Timers->AddTimer(this->Timeout);
00330         }
00331 #ifdef WIN32
00332         /* CRAQ SMOKING STUFF TO BE FIXED */
00333         Instance->SE->NonBlocking(this->fd);
00334 #endif
00335         this->state = I_CONNECTING;
00336         if (this->fd > -1)
00337         {
00338                 if (!this->Instance->SE->AddFd(this))
00339                 {
00340                         this->OnError(I_ERR_NOMOREFDS);
00341                         this->Close();
00342                         this->state = I_ERROR;
00343                         return false;
00344                 }
00345                 this->SetQueues(this->fd);
00346         }
00347 
00348         Instance->Logs->Log("SOCKET", DEBUG,"BufferedSocket::DoConnect success");
00349         return true;
00350 }
00351 
00352 
00353 void BufferedSocket::Close()
00354 {
00355         /* Save this, so we dont lose it,
00356          * otherise on failure, error messages
00357          * might be inaccurate.
00358          */
00359         int save = errno;
00360         if (this->fd > -1)
00361         {
00362                 if (this->IsIOHooked && Instance->Config->GetIOHook(this))
00363                 {
00364                         try
00365                         {
00366                                 if (this->state != I_LISTENING)
00367                                         Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
00368                         }
00369                         catch (CoreException& modexcept)
00370                         {
00371                                 Instance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00372                         }
00373                 }
00374                 Instance->SE->Shutdown(this, 2);
00375                 if (Instance->SE->Close(this) != -1)
00376                         this->OnClose();
00377 
00378                 if (Instance->SocketCull.find(this) == Instance->SocketCull.end())
00379                         Instance->SocketCull[this] = this;
00380         }
00381         errno = save;
00382 }
00383 
00384 std::string BufferedSocket::GetIP()
00385 {
00386         return this->IP;
00387 }
00388 
00389 const char* BufferedSocket::Read()
00390 {
00391         if (!Instance->SE->BoundsCheckFd(this))
00392                 return NULL;
00393 
00394         int n = 0;
00395         char* ReadBuffer = Instance->GetReadBuffer();
00396 
00397         if (this->IsIOHooked)
00398         {
00399                 int result2 = 0;
00400                 int MOD_RESULT = 0;
00401                 try
00402                 {
00403                         MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd, ReadBuffer, Instance->Config->NetBufferSize, result2);
00404                 }
00405                 catch (CoreException& modexcept)
00406                 {
00407                         Instance->Logs->Log("SOCKET", DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00408                 }
00409                 if (MOD_RESULT < 0)
00410                 {
00411                         n = -1;
00412                         errno = EAGAIN;
00413                 }
00414                 else
00415                 {
00416                         n = result2;
00417                 }
00418         }
00419         else
00420         {
00421                 n = recv(this->fd, ReadBuffer, Instance->Config->NetBufferSize, 0);
00422         }
00423 
00424         /*
00425          * This used to do some silly bounds checking instead of just passing bufsize - 1 to recv.
00426          * Not only does that make absolutely no sense, but it could potentially result in a read buffer's worth
00427          * of data being thrown into the bit bucket for no good reason, which is just *stupid*.. do things correctly now.
00428          * --w00t (july 2, 2008)
00429          */
00430         if (n > 0)
00431         {
00432                 ReadBuffer[n] = 0;
00433                 return ReadBuffer;
00434         }
00435         else
00436         {
00437                 int err = errno;
00438                 if (err == EAGAIN)
00439                         return "";
00440                 else
00441                         return NULL;
00442         }
00443 }
00444 
00445 /*
00446  * This function formerly tried to flush write buffer each call.
00447  * While admirable in attempting to get the data out to wherever
00448  * it is going, on a full socket, it's just going to syscall write() and
00449  * EAGAIN constantly, instead of waiting in the SE to know if it can write
00450  * which will chew a bit of CPU.
00451  *
00452  * So, now this function returns void (take note) and just adds to the sendq.
00453  *
00454  * It'll get written at a determinate point when the socketengine tells us it can write.
00455  *              -- w00t (april 1, 2008)
00456  */
00457 void BufferedSocket::Write(const std::string &data)
00458 {
00459         /* Append the data to the back of the queue ready for writing */
00460         outbuffer.push_back(data);
00461 
00462         /* Mark ourselves as wanting write */
00463         this->Instance->SE->WantWrite(this);
00464 }
00465 
00466 bool BufferedSocket::FlushWriteBuffer()
00467 {
00468         errno = 0;
00469         if ((this->fd > -1) && (this->state == I_CONNECTED))
00470         {
00471                 if (this->IsIOHooked)
00472                 {
00473                         while (outbuffer.size() && (errno != EAGAIN))
00474                         {
00475                                 try
00476                                 {
00477                                         /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
00478                                          * implement their own buffering mechanisms
00479                                          */
00480                                         Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
00481                                         outbuffer.pop_front();
00482                                 }
00483                                 catch (CoreException& modexcept)
00484                                 {
00485                                         Instance->Logs->Log("SOCKET", DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00486                                         return true;
00487                                 }
00488                         }
00489                 }
00490                 else
00491                 {
00492                         /* If we have multiple lines, try to send them all,
00493                          * not just the first one -- Brain
00494                          */
00495                         while (outbuffer.size() && (errno != EAGAIN))
00496                         {
00497                                 /* Send a line */
00498                                 int result = Instance->SE->Send(this, outbuffer[0].c_str(), outbuffer[0].length(), 0);
00499 
00500                                 if (result > 0)
00501                                 {
00502                                         if ((unsigned int)result >= outbuffer[0].length())
00503                                         {
00504                                                 /* The whole block was written (usually a line)
00505                                                  * Pop the block off the front of the queue,
00506                                                  * dont set errno, because we are clear of errors
00507                                                  * and want to try and write the next block too.
00508                                                  */
00509                                                 outbuffer.pop_front();
00510                                         }
00511                                         else
00512                                         {
00513                                                 std::string temp = outbuffer[0].substr(result);
00514                                                 outbuffer[0] = temp;
00515                                                 /* We didnt get the whole line out. arses.
00516                                                  * Try again next time, i guess. Set errno,
00517                                                  * because we shouldnt be writing any more now,
00518                                                  * until the socketengine says its safe to do so.
00519                                                  */
00520                                                 errno = EAGAIN;
00521                                         }
00522                                 }
00523                                 else if (result == 0)
00524                                 {
00525                                         this->Instance->SE->DelFd(this);
00526                                         this->Close();
00527                                         return true;
00528                                 }
00529                                 else if ((result == -1) && (errno != EAGAIN))
00530                                 {
00531                                         this->OnError(I_ERR_WRITE);
00532                                         this->state = I_ERROR;
00533                                         this->Instance->SE->DelFd(this);
00534                                         this->Close();
00535                                         return true;
00536                                 }
00537                         }
00538                 }
00539         }
00540 
00541         if ((errno == EAGAIN) && (fd > -1))
00542         {
00543                 this->Instance->SE->WantWrite(this);
00544         }
00545 
00546         return (fd < 0);
00547 }
00548 
00549 void SocketTimeout::Tick(time_t)
00550 {
00551         ServerInstance->Logs->Log("SOCKET", DEBUG,"SocketTimeout::Tick");
00552 
00553         if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
00554                 return;
00555 
00556         if (this->sock->state == I_CONNECTING)
00557         {
00558                 // for non-listening sockets, the timeout can occur
00559                 // which causes termination of the connection after
00560                 // the given number of seconds without a successful
00561                 // connection.
00562                 this->sock->OnTimeout();
00563                 this->sock->OnError(I_ERR_TIMEOUT);
00564                 this->sock->timeout = true;
00565 
00566                 /* NOTE: We must set this AFTER DelFd, as we added
00567                  * this socket whilst writeable. This means that we
00568                  * must DELETE the socket whilst writeable too!
00569                  */
00570                 this->sock->state = I_ERROR;
00571 
00572                 if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
00573                         ServerInstance->SocketCull[this->sock] = this->sock;
00574         }
00575 
00576         this->sock->Timeout = NULL;
00577 }
00578 
00579 bool BufferedSocket::Poll()
00580 {
00581         int incoming = -1;
00582 
00583 #ifndef WINDOWS
00584         if (!Instance->SE->BoundsCheckFd(this))
00585                 return false;
00586 #endif
00587 
00588         if (Instance->SE->GetRef(this->fd) != this)
00589                 return false;
00590 
00591         switch (this->state)
00592         {
00593                 case I_CONNECTING:
00594                         /* Our socket was in write-state, so delete it and re-add it
00595                          * in read-state.
00596                          */
00597 #ifndef WINDOWS
00598                         if (this->fd > -1)
00599                         {
00600                                 this->Instance->SE->DelFd(this);
00601                                 if (!this->Instance->SE->AddFd(this))
00602                                         return false;
00603                         }
00604 #endif
00605                         this->SetState(I_CONNECTED);
00606 
00607                         if (Instance->Config->GetIOHook(this))
00608                         {
00609                                 Instance->Logs->Log("SOCKET",DEBUG,"Hook for raw connect");
00610                                 try
00611                                 {
00612                                         Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
00613                                 }
00614                                 catch (CoreException& modexcept)
00615                                 {
00616                                         Instance->Logs->Log("SOCKET",DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00617                                 }
00618                         }
00619                         return this->OnConnected();
00620                 break;
00621                 case I_LISTENING:
00622                 {
00623                         /* The [2] is required because we may write a sockaddr_in6 here, and sockaddr_in6 is larger than sockaddr, where sockaddr_in4 is not. */
00624                         sockaddr* client = new sockaddr[2];
00625                         length = sizeof (sockaddr_in);
00626                         std::string recvip;
00627 #ifdef IPV6
00628                         if ((!*this->host) || strchr(this->host, ':'))
00629                                 length = sizeof(sockaddr_in6);
00630 #endif
00631                         incoming = Instance->SE->Accept(this, client, &length);
00632 #ifdef IPV6
00633                         if ((!*this->host) || strchr(this->host, ':'))
00634                         {
00635                                 char buf[1024];
00636                                 recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
00637                         }
00638                         else
00639 #endif
00640                         {
00641                                 // FIX: we were doing this for IPv6 connections as well, which was fucking recvip..
00642                                 // Add brackets to make this a bit clearer. -- w00t (Jan 15, 2008)
00643                                 recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
00644                         }
00645 
00646                         Instance->SE->NonBlocking(incoming);
00647 
00648                         this->OnIncomingConnection(incoming, (char*)recvip.c_str());
00649 
00650                         if (this->IsIOHooked)
00651                         {
00652                                 try
00653                                 {
00654                                         Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
00655                                 }
00656                                 catch (CoreException& modexcept)
00657                                 {
00658                                         Instance->Logs->Log("SOCKET",DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00659                                 }
00660                         }
00661 
00662                         this->SetQueues(incoming);
00663 
00664                         delete[] client;
00665                         return true;
00666                 }
00667                 break;
00668                 case I_CONNECTED:
00669                         /* Process the read event */
00670                         return this->OnDataReady();
00671                 break;
00672                 default:
00673                 break;
00674         }
00675         return true;
00676 }
00677 
00678 void BufferedSocket::SetState(BufferedSocketState s)
00679 {
00680         this->state = s;
00681 }
00682 
00683 BufferedSocketState BufferedSocket::GetState()
00684 {
00685         return this->state;
00686 }
00687 
00688 int BufferedSocket::GetFd()
00689 {
00690         return this->fd;
00691 }
00692 
00693 bool BufferedSocket::OnConnected() { return true; }
00694 void BufferedSocket::OnError(BufferedSocketError) { return; }
00695 int BufferedSocket::OnDisconnect() { return 0; }
00696 int BufferedSocket::OnIncomingConnection(int, char*) { return 0; }
00697 bool BufferedSocket::OnDataReady() { return true; }
00698 bool BufferedSocket::OnWriteReady() { return true; }
00699 void BufferedSocket::OnTimeout() { return; }
00700 void BufferedSocket::OnClose() { return; }
00701 
00702 BufferedSocket::~BufferedSocket()
00703 {
00704         this->Close();
00705         if (Timeout)
00706         {
00707                 Instance->Timers->DelTimer(Timeout);
00708                 Timeout = NULL;
00709         }
00710 }
00711 
00712 void BufferedSocket::HandleEvent(EventType et, int errornum)
00713 {
00714         switch (et)
00715         {
00716                 case EVENT_ERROR:
00717                         switch (errornum)
00718                         {
00719                                 case ETIMEDOUT:
00720                                         this->OnError(I_ERR_TIMEOUT);
00721                                 break;
00722                                 case ECONNREFUSED:
00723                                 case 0:
00724                                         this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
00725                                 break;
00726                                 case EADDRINUSE:
00727                                         this->OnError(I_ERR_BIND);
00728                                 break;
00729                                 case EPIPE:
00730                                 case EIO:
00731                                         this->OnError(I_ERR_WRITE);
00732                                 break;
00733                         }
00734                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00735                                 this->Instance->SocketCull[this] = this;
00736                         return;
00737                 break;
00738                 case EVENT_READ:
00739                         if (!this->Poll())
00740                         {
00741                                 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00742                                         this->Instance->SocketCull[this] = this;
00743                                 return;
00744                         }
00745                 break;
00746                 case EVENT_WRITE:
00747                         if (this->WaitingForWriteEvent)
00748                         {
00749                                 this->WaitingForWriteEvent = false;
00750                                 if (!this->OnWriteReady())
00751                                 {
00752                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00753                                                 this->Instance->SocketCull[this] = this;
00754                                         return;
00755                                 }
00756                         }
00757                         if (this->state == I_CONNECTING)
00758                         {
00759                                 /* This might look wrong as if we should be actually calling
00760                                  * with EVENT_WRITE, but trust me it is correct. There are some
00761                                  * writeability-state things in the read code, because of how
00762                                  * BufferedSocket used to work regarding write buffering in previous
00763                                  * versions of InspIRCd. - Brain
00764                                  */
00765                                 this->HandleEvent(EVENT_READ);
00766                                 return;
00767                         }
00768                         else
00769                         {
00770                                 if (this->FlushWriteBuffer())
00771                                 {
00772                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00773                                                 this->Instance->SocketCull[this] = this;
00774                                         return;
00775                                 }
00776                         }
00777                 break;
00778         }
00779 }
00780