The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download | Blog | Stats
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 #include "socket.h"
00015 #include "configreader.h"
00016 #include "inspstring.h"
00017 #include "socketengine.h"
00018 #include "inspircd.h"
00019 
00020 using irc::sockets::OpenTCPSocket;
00021 using irc::sockets::NonBlocking;
00022 
00023 bool InspSocket::Readable()
00024 {
00025         return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
00026 }
00027 
00028 InspSocket::InspSocket(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 InspSocket::InspSocket(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 InspSocket::InspSocket(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->Log(DEBUG,"BUG: Hostname passed to InspSocket, 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 InspSocket::WantWrite()
00143 {
00144         this->Instance->SE->WantWrite(this);
00145         this->WaitingForWriteEvent = true;
00146 }
00147 
00148 void InspSocket::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                 // per 1.2 change, commenting this out .. sick of people trying to interpret this
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 InspSocket::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 IP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
00182                 if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
00183                 {
00184                         if (!ip.empty() || ((IP != "*") && (IP != "127.0.0.1") && (!IP.empty()) && (IP != "::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, IP.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(IP.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 (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         return true;
00240 }
00241 
00242 bool InspSocket::DoConnect()
00243 {
00244         /* The [2] is required because we may write a sockaddr_in6 here, and sockaddr_in6 is larger than sockaddr, where sockaddr_in4 is not. */
00245         sockaddr* addr = new sockaddr[2];
00246         socklen_t size = sizeof(sockaddr_in);
00247 #ifdef IPV6
00248         bool v6 = false;
00249         if ((!*this->host) || strchr(this->host, ':'))
00250                 v6 = true;
00251 
00252         if (v6)
00253         {
00254                 this->fd = socket(AF_INET6, SOCK_STREAM, 0);
00255                 if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
00256                 {
00257                         if (!this->BindAddr(this->cbindip))
00258                         {
00259                                 delete[] addr;
00260                                 return false;
00261                         }
00262                 }
00263         }
00264         else
00265 #endif
00266         {
00267                 this->fd = socket(AF_INET, SOCK_STREAM, 0);
00268                 if (this->fd > -1)
00269                 {
00270                         if (!this->BindAddr(this->cbindip))
00271                         {
00272                                 delete[] addr;
00273                                 return false;
00274                         }
00275                 }
00276         }
00277 
00278         if (this->fd == -1)
00279         {
00280                 this->state = I_ERROR;
00281                 this->OnError(I_ERR_SOCKET);
00282                 delete[] addr;
00283                 return false;
00284         }
00285 
00286 #ifdef IPV6
00287         if (v6)
00288         {
00289                 in6_addr addy;
00290                 if (inet_pton(AF_INET6, this->host, &addy) > 0)
00291                 {
00292                         ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
00293                         memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
00294                         ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
00295                         size = sizeof(sockaddr_in6);
00296                 }
00297         }
00298         else
00299 #endif
00300         {
00301                 in_addr addy;
00302                 if (inet_aton(this->host, &addy) > 0)
00303                 {
00304                         ((sockaddr_in*)addr)->sin_family = AF_INET;
00305                         ((sockaddr_in*)addr)->sin_addr = addy;
00306                         ((sockaddr_in*)addr)->sin_port = htons(this->port);
00307                 }
00308         }
00309 #ifndef WIN32
00310         int flags = fcntl(this->fd, F_GETFL, 0);
00311         fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
00312 #else
00313         unsigned long flags = 0;
00314         ioctlsocket(this->fd, FIONBIO, &flags);
00315 #endif
00316         if (connect(this->fd, (sockaddr*)addr, size) == -1)
00317         {
00318                 if (errno != EINPROGRESS)
00319                 {
00320                         this->OnError(I_ERR_CONNECT);
00321                         this->Close();
00322                         this->state = I_ERROR;
00323                         delete[] addr;
00324                         return false;
00325                 }
00326 
00327                 this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
00328                 this->Instance->Timers->AddTimer(this->Timeout);
00329         }
00330 #ifdef WIN32
00331         /* Set nonblocking mode after the connect() call */
00332         flags = 0;
00333         ioctlsocket(this->fd, FIONBIO, &flags);
00334 #endif
00335         this->state = I_CONNECTING;
00336         delete[] addr;
00337         if (this->fd > -1)
00338         {
00339                 if (!this->Instance->SE->AddFd(this))
00340                 {
00341                         this->OnError(I_ERR_NOMOREFDS);
00342                         this->Close();
00343                         this->state = I_ERROR;
00344                         return false;
00345                 }
00346                 this->SetQueues(this->fd);
00347         }
00348         return true;
00349 }
00350 
00351 
00352 void InspSocket::Close()
00353 {
00354         /* Save this, so we dont lose it,
00355          * otherise on failure, error messages
00356          * might be inaccurate.
00357          */
00358         int save = errno;
00359         if (this->fd > -1)
00360         {
00361                 if (this->IsIOHooked && Instance->Config->GetIOHook(this))
00362                 {
00363                         try
00364                         {
00365                                 if (this->state != I_LISTENING)
00366                                         Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
00367                         }
00368                         catch (CoreException& modexcept)
00369                         {
00370                                 Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00371                         }
00372                 }
00373                 shutdown(this->fd,2);
00374                 if (close(this->fd) != -1)
00375                         this->OnClose();
00376 
00377                 if (Instance->SocketCull.find(this) == Instance->SocketCull.end())
00378                         Instance->SocketCull[this] = this;
00379         }
00380         errno = save;
00381 }
00382 
00383 std::string InspSocket::GetIP()
00384 {
00385         return this->IP;
00386 }
00387 
00388 char* InspSocket::Read()
00389 {
00390 #ifdef WINDOWS
00391         if ((fd < 0) || (m_internalFd > MAX_DESCRIPTORS))
00392 #else
00393         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
00394 #endif
00395                 return NULL;
00396 
00397         int n = 0;
00398 
00399         if (this->IsIOHooked)
00400         {
00401                 int result2 = 0;
00402                 int MOD_RESULT = 0;
00403                 try
00404                 {
00405                         MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf) - 1,result2);
00406                 }
00407                 catch (CoreException& modexcept)
00408                 {
00409                         Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00410                 }
00411                 if (MOD_RESULT < 0)
00412                 {
00413                         n = -1;
00414                         errno = EAGAIN;
00415                 }
00416                 else
00417                 {
00418                         n = result2;
00419                 }
00420         }
00421         else
00422         {
00423                 n = recv(this->fd,this->ibuf,sizeof(this->ibuf) - 1,0);
00424         }
00425 
00426         /*
00427          * This used to do some silly bounds checking instead of just passing bufsize - 1 to recv.
00428          * Not only does that make absolutely no sense, but it could potentially result in a read buffer's worth
00429          * of data being thrown into the bit bucket for no good reason, which is just *stupid*.. do things correctly now.
00430          * --w00t (july 2, 2008)
00431          */
00432         if (n > 0)
00433         {
00434                 ibuf[n] = 0;
00435                 return ibuf;
00436         }
00437         else
00438         {
00439                 int err = errno;
00440                 if (err == EAGAIN)
00441                         return "";
00442                 else
00443                         return NULL;
00444         }
00445 }
00446 
00447 void InspSocket::MarkAsClosed()
00448 {
00449 }
00450 
00451  /*
00452   * This function formerly tried to flush write buffer each call.
00453   * While admirable in attempting to get the data out to wherever
00454   * it is going, on a full socket, it's just going to syscall write() and
00455   * EAGAIN constantly, instead of waiting in the SE to know if it can write
00456   * which will chew a bit of CPU.
00457   *
00458   * So, now this function returns void (take note) and just adds to the sendq.
00459   *
00460   * It'll get written at a determinate point when the socketengine tells us it can write.
00461   *        -- w00t (april 1, 2008)
00462   */
00463 void InspSocket::Write(const std::string &data)
00464 {
00465         /* Try and append the data to the back of the queue, and send it on its way
00466          */
00467         outbuffer.push_back(data);
00468         this->Instance->SE->WantWrite(this);
00469 }
00470 
00471 bool InspSocket::FlushWriteBuffer()
00472 {
00473         errno = 0;
00474         if ((this->fd > -1) && (this->state == I_CONNECTED))
00475         {
00476                 if (this->IsIOHooked)
00477                 {
00478                         while (outbuffer.size() && (errno != EAGAIN))
00479                         {
00480                                 try
00481                                 {
00482                                         /* XXX: The lack of buffering here is NOT a bug, modules implementing this interface have to
00483                                          * implement their own buffering mechanisms
00484                                          */
00485                                         Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
00486                                         outbuffer.pop_front();
00487                                 }
00488                                 catch (CoreException& modexcept)
00489                                 {
00490                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00491                                         return true;
00492                                 }
00493                         }
00494                 }
00495                 else
00496                 {
00497                         /* If we have multiple lines, try to send them all,
00498                          * not just the first one -- Brain
00499                          */
00500                         while (outbuffer.size() && (errno != EAGAIN))
00501                         {
00502                                 /* Send a line */
00503 #ifndef WIN32
00504                                 int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
00505 #else
00506                                 int result = send(this->fd,outbuffer[0].c_str(),outbuffer[0].length(), 0);
00507 #endif
00508                                 if (result > 0)
00509                                 {
00510                                         if ((unsigned int)result >= outbuffer[0].length())
00511                                         {
00512                                                 /* The whole block was written (usually a line)
00513                                                  * Pop the block off the front of the queue,
00514                                                  * dont set errno, because we are clear of errors
00515                                                  * and want to try and write the next block too.
00516                                                  */
00517                                                 outbuffer.pop_front();
00518                                         }
00519                                         else
00520                                         {
00521                                                 std::string temp = outbuffer[0].substr(result);
00522                                                 outbuffer[0] = temp;
00523                                                 /* We didnt get the whole line out. arses.
00524                                                  * Try again next time, i guess. Set errno,
00525                                                  * because we shouldnt be writing any more now,
00526                                                  * until the socketengine says its safe to do so.
00527                                                  */
00528                                                 errno = EAGAIN;
00529                                         }
00530                                 }
00531                                 else if (result == 0)
00532                                 {
00533                                         this->Instance->SE->DelFd(this);
00534                                         this->Close();
00535                                         return true;
00536                                 }
00537                                 else if ((result == -1) && (errno != EAGAIN))
00538                                 {
00539                                         this->OnError(I_ERR_WRITE);
00540                                         this->state = I_ERROR;
00541                                         this->Instance->SE->DelFd(this);
00542                                         this->Close();
00543                                         return true;
00544                                 }
00545                         }
00546                 }
00547         }
00548 
00549         if ((errno == EAGAIN) && (fd > -1))
00550         {
00551                 this->Instance->SE->WantWrite(this);
00552         }
00553 
00554         return (fd < 0);
00555 }
00556 
00557 void SocketTimeout::Tick(time_t now)
00558 {
00559         if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
00560                 return;
00561 
00562         if (this->sock->state == I_CONNECTING)
00563         {
00564                 // for non-listening sockets, the timeout can occur
00565                 // which causes termination of the connection after
00566                 // the given number of seconds without a successful
00567                 // connection.
00568                 this->sock->OnTimeout();
00569                 this->sock->OnError(I_ERR_TIMEOUT);
00570                 this->sock->timeout = true;
00571 
00572                 /* NOTE: We must set this AFTER DelFd, as we added
00573                  * this socket whilst writeable. This means that we
00574                  * must DELETE the socket whilst writeable too!
00575                  */
00576                 this->sock->state = I_ERROR;
00577 
00578                 if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
00579                         ServerInstance->SocketCull[this->sock] = this->sock;
00580         }
00581 
00582         this->sock->Timeout = NULL;
00583 }
00584 
00585 bool InspSocket::Poll()
00586 {
00587 #ifdef WINDOWS
00588         if(Instance->SE->GetRef(this->fd) != this)
00589                 return false;
00590         int incoming = -1;
00591 #else
00592         if (this->Instance->SE->GetRef(this->fd) != this)
00593                 return false;
00594 
00595         int incoming = -1;
00596 
00597         if ((fd < 0) || (fd > MAX_DESCRIPTORS))
00598                 return false;
00599 #endif
00600         switch (this->state)
00601         {
00602                 case I_CONNECTING:
00603                         /* Our socket was in write-state, so delete it and re-add it
00604                          * in read-state.
00605                          */
00606 #ifndef WINDOWS
00607                         if (this->fd > -1)
00608                         {
00609                                 this->Instance->SE->DelFd(this);
00610                                 this->SetState(I_CONNECTED);
00611                                 if (!this->Instance->SE->AddFd(this))
00612                                         return false;
00613                         }
00614 #else
00615                         this->SetState(I_CONNECTED);
00616 #endif
00617                         Instance->Log(DEBUG,"Inspsocket I_CONNECTING state");
00618                         if (Instance->Config->GetIOHook(this))
00619                         {
00620                                 Instance->Log(DEBUG,"Hook for raw connect");
00621                                 try
00622                                 {
00623                                         Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
00624                                 }
00625                                 catch (CoreException& modexcept)
00626                                 {
00627                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00628                                 }
00629                         }
00630                         return this->OnConnected();
00631                 break;
00632                 case I_LISTENING:
00633                 {
00634                         /* The [2] is required because we may write a sockaddr_in6 here, and sockaddr_in6 is larger than sockaddr, where sockaddr_in4 is not. */
00635                         sockaddr* client = new sockaddr[2];
00636                         length = sizeof (sockaddr_in);
00637                         std::string recvip;
00638 #ifdef IPV6
00639                         if ((!*this->host) || strchr(this->host, ':'))
00640                                 length = sizeof(sockaddr_in6);
00641 #endif
00642                         incoming = _accept (this->fd, client, &length);
00643 #ifdef IPV6
00644                         if ((!*this->host) || strchr(this->host, ':'))
00645                         {
00646                                 char buf[1024];
00647                                 recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
00648                         }
00649                         else
00650 #endif
00651                         recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
00652                         this->OnIncomingConnection(incoming, (char*)recvip.c_str());
00653 
00654                         NonBlocking(incoming);
00655 
00656                         if (this->IsIOHooked)
00657                         {
00658                                 try
00659                                 {
00660                                         Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
00661                                 }
00662                                 catch (CoreException& modexcept)
00663                                 {
00664                                         Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00665                                 }
00666                         }
00667 
00668                         this->SetQueues(incoming);
00669 
00670                         delete[] client;
00671                         return true;
00672                 }
00673                 break;
00674                 case I_CONNECTED:
00675                         /* Process the read event */
00676                         return this->OnDataReady();
00677                 break;
00678                 default:
00679                 break;
00680         }
00681         return true;
00682 }
00683 
00684 void InspSocket::SetState(InspSocketState s)
00685 {
00686         this->state = s;
00687 }
00688 
00689 InspSocketState InspSocket::GetState()
00690 {
00691         return this->state;
00692 }
00693 
00694 int InspSocket::GetFd()
00695 {
00696         return this->fd;
00697 }
00698 
00699 bool InspSocket::OnConnected() { return true; }
00700 void InspSocket::OnError(InspSocketError e) { return; }
00701 int InspSocket::OnDisconnect() { return 0; }
00702 int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
00703 bool InspSocket::OnDataReady() { return true; }
00704 bool InspSocket::OnWriteReady() { return true; }
00705 void InspSocket::OnTimeout() { return; }
00706 void InspSocket::OnClose() { return; }
00707 
00708 InspSocket::~InspSocket()
00709 {
00710         this->Close();
00711         if (Timeout)
00712         {
00713                 Instance->Timers->DelTimer(Timeout);
00714                 Timeout = NULL;
00715         }
00716 }
00717 
00718 void InspSocket::HandleEvent(EventType et, int errornum)
00719 {
00720         switch (et)
00721         {
00722                 case EVENT_ERROR:
00723                         switch (errornum)
00724                         {
00725                                 case ETIMEDOUT:
00726                                         this->OnError(I_ERR_TIMEOUT);
00727                                 break;
00728                                 case ECONNREFUSED:
00729                                 case 0:
00730                                         this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
00731                                 break;
00732                                 case EADDRINUSE:
00733                                         this->OnError(I_ERR_BIND);
00734                                 break;
00735                                 case EPIPE:
00736                                 case EIO:
00737                                         this->OnError(I_ERR_WRITE);
00738                                 break;
00739                         }
00740                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00741                                 this->Instance->SocketCull[this] = this;
00742                         return;
00743                 break;
00744                 case EVENT_READ:
00745                         if (!this->Poll())
00746                         {
00747                                 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00748                                         this->Instance->SocketCull[this] = this;
00749                                 return;
00750                         }
00751                 break;
00752                 case EVENT_WRITE:
00753                         if (this->WaitingForWriteEvent)
00754                         {
00755                                 this->WaitingForWriteEvent = false;
00756                                 if (!this->OnWriteReady())
00757                                 {
00758                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00759                                                 this->Instance->SocketCull[this] = this;
00760                                         return;
00761                                 }
00762                         }
00763                         if (this->state == I_CONNECTING)
00764                         {
00765                                 /* This might look wrong as if we should be actually calling
00766                                  * with EVENT_WRITE, but trust me it is correct. There are some
00767                                  * writeability-state things in the read code, because of how
00768                                  * InspSocket used to work regarding write buffering in previous
00769                                  * versions of InspIRCd. - Brain
00770                                  */
00771                                 this->HandleEvent(EVENT_READ);
00772                                 return;
00773                         }
00774                         else
00775                         {
00776                                 if (this->FlushWriteBuffer())
00777                                 {
00778                                         if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00779                                                 this->Instance->SocketCull[this] = this;
00780                                         return;
00781                                 }
00782                         }
00783                 break;
00784         }
00785 }
00786