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 Class Reference

InspSocket is an extendable socket class which modules can use for TCP socket support. More...

#include <inspsocket.h>

Inheritance diagram for InspSocket:

Inheritance graph
[legend]
Collaboration diagram for InspSocket:

Collaboration graph
[legend]
List of all members.

Public Member Functions

bool FlushWriteBuffer ()
 Flushes the write buffer.
void SetQueues (int nfd)
 Set the queue sizes This private method sets the operating system queue sizes for this socket to 65535 so that it can queue more information without application-level queueing which was required in older software.
bool BindAddr (const std::string &ip)
 Bind to an address.
 InspSocket (InspIRCd *SI)
 The default constructor does nothing and should not be used.
 InspSocket (InspIRCd *SI, int newfd, const char *ip)
 This constructor is used to associate an existing connecting with an InspSocket class.
 InspSocket (InspIRCd *SI, const std::string &ipaddr, int port, bool listening, unsigned long maxtime, const std::string &connectbindip="")
 This constructor is used to create a new socket, either listening for connections, or an outbound connection to another host.
virtual bool OnConnected ()
 This method is called when an outbound connection on your socket is completed.
virtual void OnError (InspSocketError e)
 This method is called when an error occurs.
virtual int OnDisconnect ()
 When an established connection is terminated, the OnDisconnect method is triggered.
virtual bool OnDataReady ()
 When there is data waiting to be read on a socket, the OnDataReady() method is called.
virtual bool OnWriteReady ()
 When it is ok to write to the socket, and a write event was requested, this method is triggered.
virtual void OnTimeout ()
 When an outbound connection fails, and the attempt times out, you will receive this event.
virtual void OnClose ()
 Whenever close() is called, OnClose() will be called first.
virtual char * Read ()
 Reads all pending bytes from the socket into a char* array which can be up to 16 kilobytes in length.
std::string GetIP ()
 Returns the IP address associated with this connection, or an empty string if no IP address exists.
virtual void Write (const std::string &data)
 Writes a std::string to the socket.
virtual int OnIncomingConnection (int newfd, char *ip)
 If your socket is a listening socket, when a new connection comes in on the socket this method will be called.
void SetState (InspSocketState s)
 Changes the socket's state.
void WantWrite ()
 Call this to receive the next write event that comes along for this fd to the OnWriteReady method.
InspSocketState GetState ()
 Returns the current socket state.
bool Poll ()
 Only the core should call this function.
int GetFd ()
 This method returns the socket's file descriptor as assigned by the operating system, or -1 if no descriptor has been assigned.
virtual void Close ()
 This method causes the socket to close, and may also be triggered by other methods such as OnTimeout and OnError.
virtual ~InspSocket ()
 The destructor may implicitly call OnClose(), and will close() and shutdown() the file descriptor used for this socket.
virtual bool DoConnect ()
 This method attempts to connect to a hostname.
void MarkAsClosed ()
 This method marks the socket closed.
void HandleEvent (EventType et, int errornum=0)
 Handle event from EventHandler parent class.
bool Readable ()
 Returns true if this socket is readable.

Public Attributes

std::string cbindip
 Bind IP.
bool IsIOHooked
 Is hooked by a module for low level IO.
InspIRCdInstance
 Instance we were created by.
SocketTimeoutTimeout
 Timeout class or NULL.
unsigned long timeout_val
 Timeout length.
std::deque< std::stringoutbuffer
 Socket output buffer (binary safe).
char host [MAXBUF]
 The hostname connected to.
int port
 The port connected to, or the port this socket is listening on.
InspSocketState state
 The state for this socket, either listening, connecting, connected or error.
bool timeout
 This value is true if the socket has timed out.
char ibuf [65535]
 Socket input buffer, used by read().
char IP [MAXBUF]
 The IP address being connected to stored in string form for easy retrieval by accessors.
socklen_t length
 Used by accept() to indicate the sizes of the sockaddr_in structures.
bool ClosePending
 When the socket has been marked as closing, this flag will be set to true, then the next time the socket is examined, the socket is deleted and closed.
bool WaitingForWriteEvent
 Set to true when we're waiting for a write event.

Detailed Description

InspSocket is an extendable socket class which modules can use for TCP socket support.

It is fully integrated into InspIRCds socket loop and attaches its sockets to the core's instance of the SocketEngine class, meaning that any sockets you create have the same power and abilities as a socket created by the core itself. To use InspSocket, you must inherit a class from it, and use the InspSocket constructors to establish connections and bindings.

Definition at line 112 of file inspsocket.h.


Constructor & Destructor Documentation

InspSocket::InspSocket InspIRCd SI  ) 
 

The default constructor does nothing and should not be used.

Definition at line 28 of file inspsocket.cpp.

References EventHandler::fd, I_DISCONNECTED, Instance, IsIOHooked, state, Timeout, and WaitingForWriteEvent.

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 }

InspSocket::InspSocket InspIRCd SI,
int  newfd,
const char *  ip
 

This constructor is used to associate an existing connecting with an InspSocket class.

The given file descriptor must be valid, and when initialized, the InspSocket will be set with the given IP address and placed in CONNECTED state.

Definition at line 38 of file inspsocket.cpp.

References SocketEngine::AddFd(), EventHandler::fd, I_CONNECTED, Instance, IsIOHooked, MAXBUF, InspIRCd::SE, state, strlcpy(), Timeout, and WaitingForWriteEvent.

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 }

InspSocket::InspSocket InspIRCd SI,
const std::string ipaddr,
int  port,
bool  listening,
unsigned long  maxtime,
const std::string connectbindip = ""
 

This constructor is used to create a new socket, either listening for connections, or an outbound connection to another host.

Note that if you specify a hostname in the 'ipaddr' parameter, this class will not connect. You must resolve your hostnames before passing them to InspSocket. To do so, you should use the nonblocking class 'Resolver'.

Parameters:
ipaddr The IP to connect to, or bind to
port The port number to connect to, or bind to
listening true to listen on the given host:port pair, or false to connect to them
maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated
connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound.
Returns:
On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error.

Definition at line 51 of file inspsocket.cpp.

References InspIRCd::BindSocket(), cbindip, Close(), ClosePending, DEBUG, ERROR, EventHandler::fd, host, I_ERR_BIND, I_ERR_CONNECT, I_ERR_NOMOREFDS, I_ERR_SOCKET, I_ERROR, I_LISTENING, Instance, IsIOHooked, InspIRCd::Log(), MAXBUF, OnError(), irc::sockets::OpenTCPSocket(), port, state, strlcpy(), Timeout, timeout_val, and WaitingForWriteEvent.

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 }

InspSocket::~InspSocket  )  [virtual]
 

The destructor may implicitly call OnClose(), and will close() and shutdown() the file descriptor used for this socket.

Definition at line 708 of file inspsocket.cpp.

References Close(), TimerManager::DelTimer(), Instance, Timeout, and InspIRCd::Timers.

00709 {
00710         this->Close();
00711         if (Timeout)
00712         {
00713                 Instance->Timers->DelTimer(Timeout);
00714                 Timeout = NULL;
00715         }
00716 }


Member Function Documentation

bool InspSocket::BindAddr const std::string ip  ) 
 

Bind to an address.

Parameters:
ip IP to bind to
Returns:
True is the binding succeeded

Definition at line 168 of file inspsocket.cpp.

References Conf, ConfigReader::Enumerate(), EventHandler::fd, I_ERR_BIND, I_ERROR, IP, OnError(), ConfigReader::ReadValue(), and state.

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 }

void InspSocket::Close  )  [virtual]
 

This method causes the socket to close, and may also be triggered by other methods such as OnTimeout and OnError.

Definition at line 352 of file inspsocket.cpp.

References InspIRCd::Config, DEFAULT, ServerConfig::GetIOHook(), CoreException::GetReason(), CoreException::GetSource(), I_LISTENING, Instance, InspIRCd::Log(), OnClose(), Module::OnRawSocketClose(), and InspIRCd::SocketCull.

Referenced by DoConnect(), ModuleSpanningTree::DoPingChecks(), FlushWriteBuffer(), cmd_rsquit::Handle(), ModuleSpanningTree::HandleSquit(), TreeSocket::Inbound_Server(), InspSocket(), SpanningTreeUtilities::ReadConfiguration(), ~InspSocket(), and SpanningTreeUtilities::~SpanningTreeUtilities().

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 }

bool InspSocket::DoConnect  )  [virtual]
 

This method attempts to connect to a hostname.

This only occurs on a non-listening socket. This method is asyncronous.

Definition at line 242 of file inspsocket.cpp.

References TimerManager::AddTimer(), Close(), EventHandler::fd, I_CONNECTING, I_ERR_CONNECT, I_ERR_NOMOREFDS, I_ERR_SOCKET, I_ERROR, Instance, OnError(), SetQueues(), state, InspIRCd::Time(), Timeout, timeout_val, and InspIRCd::Timers.

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 }

bool InspSocket::FlushWriteBuffer  ) 
 

Flushes the write buffer.

Definition at line 471 of file inspsocket.cpp.

References Close(), InspIRCd::Config, DEBUG, SocketEngine::DelFd(), EventHandler::fd, ServerConfig::GetIOHook(), CoreException::GetReason(), CoreException::GetSource(), I_CONNECTED, I_ERR_WRITE, I_ERROR, Instance, length, InspIRCd::Log(), OnError(), Module::OnRawSocketWrite(), outbuffer, InspIRCd::SE, state, and SocketEngine::WantWrite().

Referenced by HttpServerSocket::Page(), TreeSocket::SendError(), HttpServerSocket::SendHeaders(), and HttpServerSocket::ServeData().

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 }

int InspSocket::GetFd  ) 
 

This method returns the socket's file descriptor as assigned by the operating system, or -1 if no descriptor has been assigned.

Reimplemented from EventHandler.

Definition at line 694 of file inspsocket.cpp.

References EventHandler::fd.

Referenced by ModuleSpanningTree::ConnectServer(), HandshakeTimer::HandshakeTimer(), ServernameResolver::OnLookupComplete(), ModuleSSLOpenSSL::OnRequest(), and ModuleSSLGnuTLS::OnRequest().

00695 {
00696         return this->fd;
00697 }

std::string InspSocket::GetIP  ) 
 

Returns the IP address associated with this connection, or an empty string if no IP address exists.

Definition at line 383 of file inspsocket.cpp.

References IP.

Referenced by TreeSocket::OnConnected(), and TreeSocket::SendError().

00384 {
00385         return this->IP;
00386 }

InspSocketState InspSocket::GetState  ) 
 

Returns the current socket state.

Definition at line 689 of file inspsocket.cpp.

References state.

Referenced by SpanningTreeUtilities::ReadConfiguration().

00690 {
00691         return this->state;
00692 }

void InspSocket::HandleEvent EventType  et,
int  errornum = 0
[virtual]
 

Handle event from EventHandler parent class.

Implements EventHandler.

Definition at line 718 of file inspsocket.cpp.

References EVENT_ERROR, EVENT_READ, EVENT_WRITE, I_CONNECTING, I_ERR_BIND, I_ERR_CONNECT, I_ERR_TIMEOUT, I_ERR_WRITE, Instance, OnError(), InspIRCd::SocketCull, and WaitingForWriteEvent.

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 }

void InspSocket::MarkAsClosed  ) 
 

This method marks the socket closed.

The next time the core examines a socket marked as closed, the socket will be closed and the memory reclaimed.

NOTE: This method is DEPRECIATED and will be ignored if called!

Definition at line 447 of file inspsocket.cpp.

00448 {
00449 }

void InspSocket::OnClose  )  [virtual]
 

Whenever close() is called, OnClose() will be called first.

Please note that this means OnClose will be called alongside OnError(), OnTimeout(), and Close(), and also when cancelling a listening socket by calling the destructor indirectly.

Reimplemented in HttpServerSocket, and TreeSocket.

Definition at line 706 of file inspsocket.cpp.

Referenced by Close().

00706 { return; }

bool InspSocket::OnConnected  )  [virtual]
 

This method is called when an outbound connection on your socket is completed.

Returns:
false to abort the connection, true to continue

Reimplemented in TreeSocket.

Definition at line 699 of file inspsocket.cpp.

Referenced by Poll().

00699 { return true; }

bool InspSocket::OnDataReady  )  [virtual]
 

When there is data waiting to be read on a socket, the OnDataReady() method is called.

Within this method, you *MUST* call the Read() method to read any pending data. At its lowest level, this event is signalled by the core via the socket engine. If you return false from this function, the core removes your socket from its list and erases it from the socket engine, then calls InspSocket::Close() and deletes it.

Returns:
false to close the socket

Reimplemented in HttpServerSocket, Notifier, and TreeSocket.

Definition at line 703 of file inspsocket.cpp.

Referenced by Poll().

00703 { return true; }

int InspSocket::OnDisconnect  )  [virtual]
 

When an established connection is terminated, the OnDisconnect method is triggered.

Reimplemented in TreeSocket.

Definition at line 701 of file inspsocket.cpp.

00701 { return 0; }

void InspSocket::OnError InspSocketError  e  )  [virtual]
 

This method is called when an error occurs.

A closed socket in itself is not an error, however errors also generate close events.

Parameters:
e The error type which occured

Reimplemented in TreeSocket.

Definition at line 700 of file inspsocket.cpp.

Referenced by BindAddr(), DoConnect(), FlushWriteBuffer(), HandleEvent(), InspSocket(), SocketTimeout::Tick(), and ModuleSQLite3::~ModuleSQLite3().

00700 { return; }

int InspSocket::OnIncomingConnection int  newfd,
char *  ip
[virtual]
 

If your socket is a listening socket, when a new connection comes in on the socket this method will be called.

Given the new file descriptor in the parameters, and the IP, it is recommended you copy them to a new instance of your socket class, e.g.:

MySocket* newsocket = new MySocket(newfd,ip);

Once you have done this, you can then associate the new socket with the core using Server::AddSocket().

Reimplemented in HttpServerSocket, Notifier, ResultNotifier, and TreeSocket.

Definition at line 702 of file inspsocket.cpp.

Referenced by Poll().

00702 { return 0; }

void InspSocket::OnTimeout  )  [virtual]
 

When an outbound connection fails, and the attempt times out, you will receive this event.

The method will trigger once maxtime seconds are reached (as given in the constructor) just before the socket's descriptor is closed. A failed DNS lookup may cause this event if the DNS server is not responding, as well as a failed connect() call, because DNS lookups are nonblocking as implemented by this class.

Reimplemented in TreeSocket.

Definition at line 705 of file inspsocket.cpp.

Referenced by SocketTimeout::Tick().

00705 { return; }

bool InspSocket::OnWriteReady  )  [virtual]
 

When it is ok to write to the socket, and a write event was requested, this method is triggered.

Within this method you should call write() or send() etc, to send data to the other end of the socket. Further write events will not be triggered unless you call WantWrite().

Returns:
false to close the socket

Reimplemented in HttpServerSocket.

Definition at line 704 of file inspsocket.cpp.

00704 { return true; }

bool InspSocket::Poll  ) 
 

Only the core should call this function.

When called, it is assumed the socket is ready to read data, and the method call routes the event to the various methods of InspSocket for you to handle. This can also cause the socket's state to change.

Definition at line 585 of file inspsocket.cpp.

References _accept, InspIRCd::Config, DEBUG, SocketEngine::DelFd(), EventHandler::fd, ServerConfig::GetIOHook(), CoreException::GetReason(), SocketEngine::GetRef(), CoreException::GetSource(), I_CONNECTED, I_CONNECTING, I_LISTENING, Instance, length, InspIRCd::Log(), MAX_DESCRIPTORS, irc::sockets::NonBlocking(), OnConnected(), OnDataReady(), OnIncomingConnection(), Module::OnRawSocketAccept(), Module::OnRawSocketConnect(), port, InspIRCd::SE, SetQueues(), and SetState().

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 }

char * InspSocket::Read  )  [virtual]
 

Reads all pending bytes from the socket into a char* array which can be up to 16 kilobytes in length.

Definition at line 388 of file inspsocket.cpp.

References InspIRCd::Config, DEFAULT, EventHandler::fd, ServerConfig::GetIOHook(), CoreException::GetReason(), CoreException::GetSource(), ibuf, Instance, InspIRCd::Log(), MAX_DESCRIPTORS, and Module::OnRawSocketRead().

Referenced by TreeSocket::OnDataReady(), and HttpServerSocket::OnDataReady().

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 }

bool InspSocket::Readable  )  [virtual]
 

Returns true if this socket is readable.

Reimplemented from EventHandler.

Definition at line 23 of file inspsocket.cpp.

References I_CONNECTING.

00024 {
00025         return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
00026 }

void InspSocket::SetQueues int  nfd  ) 
 

Set the queue sizes This private method sets the operating system queue sizes for this socket to 65535 so that it can queue more information without application-level queueing which was required in older software.

Definition at line 148 of file inspsocket.cpp.

Referenced by DoConnect(), and Poll().

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 }

void InspSocket::SetState InspSocketState  s  ) 
 

Changes the socket's state.

The core uses this to change socket states, and you should not call it directly.

Definition at line 684 of file inspsocket.cpp.

References state.

Referenced by Poll().

00685 {
00686         this->state = s;
00687 }

void InspSocket::WantWrite  ) 
 

Call this to receive the next write event that comes along for this fd to the OnWriteReady method.

Definition at line 142 of file inspsocket.cpp.

References Instance, InspIRCd::SE, WaitingForWriteEvent, and SocketEngine::WantWrite().

00143 {
00144         this->Instance->SE->WantWrite(this);
00145         this->WaitingForWriteEvent = true;
00146 }

void InspSocket::Write const std::string data  )  [virtual]
 

Writes a std::string to the socket.

No carriage returns or linefeeds are appended to the string.

Parameters:
data The data to send

Definition at line 463 of file inspsocket.cpp.

References Instance, outbuffer, InspIRCd::SE, and SocketEngine::WantWrite().

Referenced by HttpServerSocket::Page(), HttpServerSocket::SendHeaders(), HttpServerSocket::ServeData(), and TreeSocket::WriteLine().

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 }


Member Data Documentation

std::string InspSocket::cbindip
 

Bind IP.

Definition at line 119 of file inspsocket.h.

Referenced by InspSocket().

bool InspSocket::ClosePending
 

When the socket has been marked as closing, this flag will be set to true, then the next time the socket is examined, the socket is deleted and closed.

Definition at line 208 of file inspsocket.h.

Referenced by InspSocket(), and ModuleSQLite3::~ModuleSQLite3().

char InspSocket::host[MAXBUF]
 

The hostname connected to.

Definition at line 149 of file inspsocket.h.

Referenced by InspSocket().

char InspSocket::ibuf[65535]
 

Socket input buffer, used by read().

The class which extends InspSocket is expected to implement an extendable buffer which can grow much larger than 64k, this buffer is just designed to be temporary storage. space.

Definition at line 177 of file inspsocket.h.

Referenced by Read().

InspIRCd* InspSocket::Instance
 

Instance we were created by.

Definition at line 129 of file inspsocket.h.

Referenced by TreeSocket::AddLine(), TreeSocket::Admin(), TreeSocket::Capab(), TreeSocket::ChangeHost(), TreeSocket::ChangeName(), Close(), TreeSocket::ComparePass(), TreeSocket::DoBurst(), DoConnect(), TreeSocket::Error(), FlushWriteBuffer(), TreeSocket::ForceJoin(), TreeSocket::ForceMode(), TreeSocket::ForceNick(), TreeSocket::ForceTopic(), HandleEvent(), TreeSocket::HandleSetTime(), TreeSocket::Inbound_Server(), InspSocket(), TreeSocket::IntroduceClient(), TreeSocket::LocalPong(), TreeSocket::MakePass(), TreeSocket::MetaData(), TreeSocket::Modules(), TreeSocket::Motd(), TreeSocket::MyCapabilities(), TreeSocket::OnClose(), TreeSocket::OnConnected(), TreeSocket::OnIncomingConnection(), TreeSocket::OperQuit(), TreeSocket::OperType(), TreeSocket::Outbound_Reply_Server(), Poll(), TreeSocket::ProcessLine(), TreeSocket::Push(), Read(), TreeSocket::RemoteKill(), TreeSocket::RemoteRehash(), TreeSocket::RemoteServer(), TreeSocket::RemoveStatus(), TreeSocket::SendCapabilities(), TreeSocket::SendChannelModes(), TreeSocket::SendFJoins(), HttpServerSocket::SendHeaders(), TreeSocket::SendUsers(), TreeSocket::SendXLines(), TreeSocket::ServiceJoin(), TreeSocket::ServicePart(), HttpServerSocket::SetWrite(), TreeSocket::Squit(), TreeSocket::Stats(), TreeSocket::Time(), TreeSocket::TreeSocket(), WantWrite(), TreeSocket::Whois(), Write(), TreeSocket::WriteLine(), and ~InspSocket().

char InspSocket::IP[MAXBUF]
 

The IP address being connected to stored in string form for easy retrieval by accessors.

Definition at line 184 of file inspsocket.h.

Referenced by BindAddr(), and GetIP().

bool InspSocket::IsIOHooked
 

Is hooked by a module for low level IO.

Definition at line 124 of file inspsocket.h.

Referenced by ServerConfig::AddIOHook(), and InspSocket().

socklen_t InspSocket::length
 

Used by accept() to indicate the sizes of the sockaddr_in structures.

Definition at line 190 of file inspsocket.h.

Referenced by FlushWriteBuffer(), TreeSocket::IntroduceClient(), and Poll().

std::deque<std::string> InspSocket::outbuffer
 

Socket output buffer (binary safe).

Definition at line 144 of file inspsocket.h.

Referenced by FlushWriteBuffer(), and Write().

int InspSocket::port
 

The port connected to, or the port this socket is listening on.

Definition at line 155 of file inspsocket.h.

Referenced by InspSocket(), and Poll().

InspSocketState InspSocket::state
 

The state for this socket, either listening, connecting, connected or error.

Definition at line 162 of file inspsocket.h.

Referenced by BindAddr(), DoConnect(), FlushWriteBuffer(), GetState(), InspSocket(), SetState(), SocketTimeout::Tick(), and ModuleSQLite3::~ModuleSQLite3().

bool InspSocket::timeout
 

This value is true if the socket has timed out.

Definition at line 168 of file inspsocket.h.

Referenced by SocketTimeout::Tick().

SocketTimeout* InspSocket::Timeout
 

Timeout class or NULL.

Definition at line 134 of file inspsocket.h.

Referenced by DoConnect(), InspSocket(), SocketTimeout::Tick(), and ~InspSocket().

unsigned long InspSocket::timeout_val
 

Timeout length.

Definition at line 139 of file inspsocket.h.

Referenced by DoConnect(), and InspSocket().

bool InspSocket::WaitingForWriteEvent
 

Set to true when we're waiting for a write event.

If this is true and a write event comes in, we call the write instead of the read method.

Definition at line 214 of file inspsocket.h.

Referenced by HandleEvent(), InspSocket(), HttpServerSocket::SetWrite(), and WantWrite().


The documentation for this class was generated from the following files: