Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

socket.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
00006  *                       E-mail:
00007  *                <brain@chatspike.net>
00008  *                <Craig@chatspike.net>
00009  *     
00010  * Written by Craig Edwards, Craig McLure, and others.
00011  * This program is free but copyrighted software; see
00012  *            the file COPYING for details.
00013  *
00014  * ---------------------------------------------------
00015  */
00016 
00017 using namespace std;
00018 
00019 #include "inspircd_config.h"
00020 #include <sys/time.h>
00021 #include <sys/resource.h>
00022 #include <sys/types.h>
00023 #include <sys/socket.h>
00024 #include <netinet/in.h>
00025 #include <string>
00026 #include <unistd.h>
00027 #include <fcntl.h>
00028 #include <poll.h>
00029 #include <sstream>
00030 #include <iostream>
00031 #include <fstream>
00032 #include "socket.h"
00033 #include "inspircd.h"
00034 #include "inspircd_io.h"
00035 #include "inspstring.h"
00036 #include "helperfuncs.h"
00037 #include "socketengine.h"
00038 
00039 
00040 extern InspIRCd* ServerInstance;
00041 extern time_t TIME;
00042 
00043 InspSocket* socket_ref[65535];
00044 
00045 InspSocket::InspSocket()
00046 {
00047         this->state = I_DISCONNECTED;
00048 }
00049 
00050 InspSocket::InspSocket(int newfd, char* ip)
00051 {
00052         this->fd = newfd;
00053         this->state = I_CONNECTED;
00054         this->IP = ip;
00055         ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00056         socket_ref[this->fd] = this;
00057 }
00058 
00059 InspSocket::InspSocket(std::string host, int port, bool listening, unsigned long maxtime)
00060 {
00061         if (listening) {
00062                 if ((this->fd = OpenTCPSocket()) == ERROR)
00063                 {
00064                         this->fd = -1;
00065                         this->state = I_ERROR;
00066                         this->OnError(I_ERR_SOCKET);
00067                         log(DEBUG,"OpenTCPSocket() error");
00068                         return;
00069                 }
00070                 else
00071                 {
00072                         if (BindSocket(this->fd,this->client,this->server,port,(char*)host.c_str()) == ERROR)
00073                         {
00074                                 this->Close();
00075                                 this->fd = -1;
00076                                 this->state = I_ERROR;
00077                                 this->OnError(I_ERR_BIND);
00078                                 log(DEBUG,"BindSocket() error %s",strerror(errno));
00079                                 return;
00080                         }
00081                         else
00082                         {
00083                                 this->state = I_LISTENING;
00084                                 ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00085                                 socket_ref[this->fd] = this;
00086                                 log(DEBUG,"New socket now in I_LISTENING state");
00087                                 return;
00088                         }
00089                 }                       
00090         } else {
00091                 char* ip;
00092                 this->host = host;
00093                 hostent* hoste = gethostbyname(host.c_str());
00094                 if (!hoste) {
00095                         ip = (char*)host.c_str();
00096                 } else {
00097                         struct in_addr* ia = (in_addr*)hoste->h_addr;
00098                         ip = inet_ntoa(*ia);
00099                 }
00100 
00101                 this->IP = ip;
00102 
00103                 timeout_end = time(NULL)+maxtime;
00104                 timeout = false;
00105                 if ((this->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
00106                 {
00107                         this->state = I_ERROR;
00108                         this->OnError(I_ERR_SOCKET);
00109                         return;
00110                 }
00111                 this->port = port;
00112                 inet_aton(ip,&addy);
00113                 addr.sin_family = AF_INET;
00114                 addr.sin_addr = addy;
00115                 addr.sin_port = htons(this->port);
00116 
00117                 int flags;
00118                 flags = fcntl(this->fd, F_GETFL, 0);
00119                 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
00120 
00121                 if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)) == -1)
00122                 {
00123                         if (errno != EINPROGRESS)
00124                         {
00125                                 this->Close();
00126                                 this->OnError(I_ERR_CONNECT);
00127                                 this->state = I_ERROR;
00128                                 return;
00129                         }
00130                 }
00131                 this->state = I_CONNECTING;
00132                 ServerInstance->SE->AddFd(this->fd,false,X_ESTAB_MODULE);
00133                 socket_ref[this->fd] = this;
00134                 return;
00135         }
00136 }
00137 
00138 void InspSocket::Close()
00139 {
00140         if (this->fd != -1)
00141         {
00142                 this->OnClose();
00143                 shutdown(this->fd,2);
00144                 close(this->fd);
00145                 socket_ref[this->fd] = NULL;
00146                 this->fd = -1;
00147         }
00148 }
00149 
00150 std::string InspSocket::GetIP()
00151 {
00152         return this->IP;
00153 }
00154 
00155 char* InspSocket::Read()
00156 {
00157         int n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
00158         if (n > 0)
00159         {
00160                 ibuf[n] = 0;
00161                 return ibuf;
00162         }
00163         else
00164         {
00165                 log(DEBUG,"EOF or error on socket");
00166                 return NULL;
00167         }
00168 }
00169 
00170 // There are two possible outcomes to this function.
00171 // It will either write all of the data, or an undefined amount.
00172 // If an undefined amount is written the connection has failed
00173 // and should be aborted.
00174 int InspSocket::Write(std::string data)
00175 {
00176         this->Buffer = this->Buffer + data;
00177         this->FlushWriteBuffer();
00178         return data.length();
00179 }
00180 
00181 void InspSocket::FlushWriteBuffer()
00182 {
00183         int result = 0;
00184         if (this->Buffer.length())
00185         {
00186                 result = send(this->fd,this->Buffer.c_str(),this->Buffer.length(),0);
00187                 if (result > 0)
00188                 {
00189                         /* If we wrote some, advance the buffer forwards */
00190                         char* n = (char*)this->Buffer.c_str();
00191                         n += result;
00192                         this->Buffer = n;
00193                 }
00194         }
00195 }
00196 
00197 bool InspSocket::Timeout(time_t current)
00198 {
00199         if ((this->state == I_CONNECTING) && (current > timeout_end))
00200         {
00201                 // for non-listening sockets, the timeout can occur
00202                 // which causes termination of the connection after
00203                 // the given number of seconds without a successful
00204                 // connection.
00205                 this->OnTimeout();
00206                 this->OnError(I_ERR_TIMEOUT);
00207                 timeout = true;
00208                 this->state = I_ERROR;
00209                 return true;
00210         }
00211         if (this->Buffer.length())
00212                 this->FlushWriteBuffer();
00213         return false;
00214 }
00215 
00216 bool InspSocket::Poll()
00217 {
00218         int incoming = -1;
00219         
00220         switch (this->state)
00221         {
00222                 case I_CONNECTING:
00223                         this->SetState(I_CONNECTED);
00224                         /* Our socket was in write-state, so delete it and re-add it
00225                          * in read-state.
00226                          */
00227                         ServerInstance->SE->DelFd(this->fd);
00228                         ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00229                         return this->OnConnected();
00230                 break;
00231                 case I_LISTENING:
00232                         length = sizeof (client);
00233                         incoming = accept (this->fd, (sockaddr*)&client,&length);
00234                         this->OnIncomingConnection(incoming,inet_ntoa(client.sin_addr));
00235                         return true;
00236                 break;
00237                 case I_CONNECTED:
00238                         return this->OnDataReady();
00239                 break;
00240                 default:
00241                 break;
00242         }
00243 
00244         return true;
00245 }
00246 
00247 void InspSocket::SetState(InspSocketState s)
00248 {
00249         log(DEBUG,"Socket state change");
00250         this->state = s;
00251 }
00252 
00253 InspSocketState InspSocket::GetState()
00254 {
00255         return this->state;
00256 }
00257 
00258 int InspSocket::GetFd()
00259 {
00260         return this->fd;
00261 }
00262 
00263 bool InspSocket::OnConnected() { return true; }
00264 void InspSocket::OnError(InspSocketError e) { return; }
00265 int InspSocket::OnDisconnect() { return 0; }
00266 int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
00267 bool InspSocket::OnDataReady() { return true; }
00268 void InspSocket::OnTimeout() { return; }
00269 void InspSocket::OnClose() { return; }
00270 
00271 InspSocket::~InspSocket()
00272 {
00273         this->Close();
00274 }
00275 
00276 /*
00277 int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr)
00278 int OpenTCPSocket (void)
00279 */

Generated on Mon Dec 19 18:02:13 2005 for InspIRCd by  doxygen 1.4.4-20050815