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

Generated on Fri Dec 9 20:20:03 2005 for InspIRCd by  doxygen 1.4.4-20050815