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 "inspircd_util.h"
00036 #include "inspstring.h"
00037 #include "helperfuncs.h"
00038 #include "socketengine.h"
00039 
00040 extern SocketEngine* SE;
00041 
00042 extern int boundPortCount;
00043 extern int openSockfd[MAXSOCKS];
00044 extern time_t TIME;
00045 
00046 InspSocket* socket_ref[65535];
00047 
00048 InspSocket::InspSocket()
00049 {
00050         this->state = I_DISCONNECTED;
00051 }
00052 
00053 InspSocket::InspSocket(int newfd, char* ip)
00054 {
00055         this->fd = newfd;
00056         this->state = I_CONNECTED;
00057         this->IP = ip;
00058         SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00059         socket_ref[this->fd] = this;
00060 }
00061 
00062 InspSocket::InspSocket(std::string host, int port, bool listening, unsigned long maxtime)
00063 {
00064         if (listening) {
00065                 if ((this->fd = OpenTCPSocket()) == ERROR)
00066                 {
00067                         this->fd = -1;
00068                         this->state = I_ERROR;
00069                         this->OnError(I_ERR_SOCKET);
00070                         log(DEBUG,"OpenTCPSocket() error");
00071                         return;
00072                 }
00073                 else
00074                 {
00075                         if (BindSocket(this->fd,this->client,this->server,port,(char*)host.c_str()) == ERROR)
00076                         {
00077                                 this->Close();
00078                                 this->fd = -1;
00079                                 this->state = I_ERROR;
00080                                 this->OnError(I_ERR_BIND);
00081                                 log(DEBUG,"BindSocket() error %s",strerror(errno));
00082                                 return;
00083                         }
00084                         else
00085                         {
00086                                 this->state = I_LISTENING;
00087                                 SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00088                                 socket_ref[this->fd] = this;
00089                                 log(DEBUG,"New socket now in I_LISTENING state");
00090                                 return;
00091                         }
00092                 }                       
00093         } else {
00094                 char* ip;
00095                 this->host = host;
00096                 hostent* hoste = gethostbyname(host.c_str());
00097                 if (!hoste) {
00098                         ip = (char*)host.c_str();
00099                 } else {
00100                         struct in_addr* ia = (in_addr*)hoste->h_addr;
00101                         ip = inet_ntoa(*ia);
00102                 }
00103 
00104                 this->IP = ip;
00105 
00106                 timeout_end = time(NULL)+maxtime;
00107                 timeout = false;
00108                 if ((this->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
00109                 {
00110                         this->state = I_ERROR;
00111                         this->OnError(I_ERR_SOCKET);
00112                         return;
00113                 }
00114                 this->port = port;
00115                 inet_aton(ip,&addy);
00116                 addr.sin_family = AF_INET;
00117                 addr.sin_addr = addy;
00118                 addr.sin_port = htons(this->port);
00119 
00120                 int flags;
00121                 flags = fcntl(this->fd, F_GETFL, 0);
00122                 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
00123 
00124                 if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)) == -1)
00125                 {
00126                         if (errno != EINPROGRESS)
00127                         {
00128                                 this->Close();
00129                                 this->OnError(I_ERR_CONNECT);
00130                                 this->state = I_ERROR;
00131                                 return;
00132                         }
00133                 }
00134                 this->state = I_CONNECTING;
00135                 SE->AddFd(this->fd,false,X_ESTAB_MODULE);
00136                 socket_ref[this->fd] = this;
00137                 return;
00138         }
00139 }
00140 
00141 void InspSocket::Close()
00142 {
00143         if (this->fd != -1)
00144         {
00145                 this->OnClose();
00146                 shutdown(this->fd,2);
00147                 close(this->fd);
00148                 socket_ref[this->fd] = NULL;
00149                 this->fd = -1;
00150         }
00151 }
00152 
00153 std::string InspSocket::GetIP()
00154 {
00155         return this->IP;
00156 }
00157 
00158 char* InspSocket::Read()
00159 {
00160         int n = recv(this->fd,this->ibuf,sizeof(this->ibuf),0);
00161         if (n > 0)
00162         {
00163                 ibuf[n] = 0;
00164                 return ibuf;
00165         }
00166         else
00167         {
00168                 log(DEBUG,"EOF or error on socket");
00169                 return NULL;
00170         }
00171 }
00172 
00173 // There are two possible outcomes to this function.
00174 // It will either write all of the data, or an undefined amount.
00175 // If an undefined amount is written the connection has failed
00176 // and should be aborted.
00177 int InspSocket::Write(std::string data)
00178 {
00179         char* d = (char*)data.c_str();
00180         unsigned int written = 0;
00181         int n = 0;
00182         int s = data.length();
00183         while ((written < data.length()) && (n >= 0))
00184         {
00185                 n = send(this->fd,d,s,0);
00186                 if (n > 0)
00187                 {
00188                         // If we didnt write everything, advance
00189                         // the pointers so that when we retry
00190                         // the next time around the loop, we try
00191                         // to write what we failed to write before.
00192                         written += n;
00193                         s -= n;
00194                         d += n;
00195                 }
00196         }
00197         return written;
00198 }
00199 
00200 bool InspSocket::Timeout(time_t current)
00201 {
00202         if ((this->state == I_CONNECTING) && (current > timeout_end))
00203         {
00204                 // for non-listening sockets, the timeout can occur
00205                 // which causes termination of the connection after
00206                 // the given number of seconds without a successful
00207                 // connection.
00208                 this->OnTimeout();
00209                 this->OnError(I_ERR_TIMEOUT);
00210                 timeout = true;
00211                 this->state = I_ERROR;
00212                 return true;
00213         }
00214         return false;
00215 }
00216 
00217 bool InspSocket::Poll()
00218 {
00219         int incoming = -1;
00220         
00221         switch (this->state)
00222         {
00223                 case I_CONNECTING:
00224                         this->SetState(I_CONNECTED);
00225                         /* Our socket was in write-state, so delete it and re-add it
00226                          * in read-state.
00227                          */
00228                         SE->DelFd(this->fd);
00229                         SE->AddFd(this->fd,true,X_ESTAB_MODULE);
00230                         return this->OnConnected();
00231                 break;
00232                 case I_LISTENING:
00233                         length = sizeof (client);
00234                         incoming = accept (this->fd, (sockaddr*)&client,&length);
00235                         this->OnIncomingConnection(incoming,inet_ntoa(client.sin_addr));
00236                         return true;
00237                 break;
00238                 case I_CONNECTED:
00239                         return this->OnDataReady();
00240                 break;
00241                 default:
00242                 break;
00243         }
00244 
00245         return true;
00246 }
00247 
00248 void InspSocket::SetState(InspSocketState s)
00249 {
00250         log(DEBUG,"Socket state change");
00251         this->state = s;
00252 }
00253 
00254 InspSocketState InspSocket::GetState()
00255 {
00256         return this->state;
00257 }
00258 
00259 int InspSocket::GetFd()
00260 {
00261         return this->fd;
00262 }
00263 
00264 bool InspSocket::OnConnected() { return true; }
00265 void InspSocket::OnError(InspSocketError e) { return; }
00266 int InspSocket::OnDisconnect() { return 0; }
00267 int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
00268 bool InspSocket::OnDataReady() { return true; }
00269 void InspSocket::OnTimeout() { return; }
00270 void InspSocket::OnClose() { return; }
00271 
00272 InspSocket::~InspSocket()
00273 {
00274         this->Close();
00275 }
00276 
00277 /*
00278 int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr)
00279 int OpenTCPSocket (void)
00280 */

Generated on Wed Dec 14 15:55:46 2005 for InspIRCd by  doxygen 1.4.4-20050815