Main Page   Packages   Class Hierarchy   Alphabetical List   Data Structures   File List   Namespace Members   Data Fields   Globals  

Socket.cpp

Go to the documentation of this file.
00001 /*
00002  * $Id: Socket.cpp,v 1.7 2002/08/09 08:26:45 mindstorm2600 Exp $
00003  */
00004 /*
00005  * This class provides all the functionality for working with TCP sockets<br>
00006  * <b>NOTE: This socket interface is not backward compatible with previous 
00007  * versions of the clawlib library, sorry but all the old interfaces were to
00008  * redundant and for sanity we took the desicion to upgrade the class this 
00009  * way</b>
00010  */
00011  /*
00012  * $Log: Socket.cpp,v $
00013  * Revision 1.7  2002/08/09 08:26:45  mindstorm2600
00014  * Fixing some weird things
00015  *
00016  * Revision 1.6  2002/07/14 05:30:56  mindstorm2600
00017  * I'm sleepy :-( I guess that it would be better to send this before ZZZZzzzzzzz
00018  *
00019  * Revision 1.5  2002/07/11 21:41:27  mindstorm2600
00020  * Added a few constructor
00021  *
00022  * Revision 1.4  2002/07/11 20:44:41  mindstorm2600
00023  * I've fixed a leak in Socket::operator<<(String .....
00024  *
00025  * Revision 1.3  2002/07/11 20:26:50  mindstorm2600
00026  *
00027  * I could solve the problem with the operator >> it seems i forgot to
00028  * use the SOCK_CHUNK_CHIZE constant and the check reported something
00029  * wrong, after that everything went fine
00030  *
00031  * Revision 1.2  2002/07/08 04:58:12  mindstorm2600
00032  * Adding every class to the clawsoft namespace
00033  *
00034  * Revision 1.1  2002/07/06 05:17:17  mindstorm2600
00035  * The socket part has been finally added, it still needs a
00036  * read and or readLine method
00037  *
00038  */
00039 
00040 #include<stdio.h>
00041 #include<iostream.h>
00042 #include<netdb.h>
00043 #include <sys/poll.h>
00044 #include<sys/socket.h>
00045 #include<unistd.h>
00046 #include<signal.h>
00047 #include<string.h>
00048 #include"Socket.h"
00049 #include<errno.h>
00050 
00051 #ifndef SOCK_CHUNK_SIZE
00052 #define SOCK_CHUNK_SIZE 4096
00053 #endif
00054 
00055 #ifndef READ_TIMEOUT
00056 #define READ_TIMEOUT 120000
00057 #endif
00058 
00059 namespace clawsoft{
00060 
00062 static
00063 void claw_sigpipe_handler(int signum){
00064         signal(SIGPIPE, claw_sigpipe_handler);
00065 }
00066 
00069 static int __sigpipe_done;
00070 
00072 void addSigpipeHandler(){
00073         if(!__sigpipe_done){
00074                 signal(SIGPIPE, claw_sigpipe_handler);
00075                 __sigpipe_done = 1;
00076         }
00077 }
00078 
00079 int Socket::CreateSocket(String thehost, int theport){
00080  struct hostent *hp;
00081  struct sockaddr_in name;
00082  struct linger opt;
00083 #ifdef SOLARIS
00084  char *ptr;
00085 #endif
00086  addSigpipeHandler();
00087  host = thehost;
00088  port = theport;
00089  sock = socket(PF_INET, SOCK_STREAM, 0);
00090  if(sock < 0){
00091          switch(errno){
00092                 case EMFILE:
00093                         throw ProcOutOfFileDescriptorsException();
00094                 break;
00095                 case ENFILE:
00096                         throw SysOutOfFileDescriptorsException();
00097                 break;
00098                 default:
00099                         throw IOException();
00100          }
00101  }
00102  hp = gethostbyname(thehost.toCharPtr());
00103  if(hp == NULL){
00104   cerr << thehost << " not found!!!" << endl;
00105   return 0;
00106  }
00107  name.sin_family = AF_INET;
00108  name.sin_port = htons (port);
00109  name.sin_addr = *(struct in_addr *) hp->h_addr;
00110  opt.l_onoff = 1;
00111  opt.l_linger = 0; 
00112 #ifdef SOLARIS
00113  ptr = (char *)&opt;
00114  setsockopt(sock, SOL_SOCKET, SO_LINGER, ptr, sizeof(opt));
00115 #else
00116  setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger*)&opt, sizeof(opt));
00117 #endif
00118  if(connect(sock, (struct sockaddr *)&name, sizeof(name)) != 0){
00119   sock = -1;
00120   switch(errno){
00121           case ETIMEDOUT:
00122                   throw ConnectionTimeoutException();
00123                   break;
00124           case ECONNREFUSED:
00125                   throw ConnectionRefusedException();
00126                   break;
00127           case ENETUNREACH:
00128                   throw NetworkUnreachableException();
00129                   break;
00130           default:
00131                   throw NetworkException();
00132   }
00133   return 0;
00134  }
00135  return 1;
00136 }
00137 
00138 Socket::Socket(const Socket &s){
00139         sock = s.sock;
00140         port = s.port;
00141 }
00142 
00143 Socket::Socket(int s, int pport){
00144    setClassName("Socket");
00145    host = 0;
00146    sock = s;
00147    port = pport;
00148 }
00149 
00150 Socket::Socket(String thehost, int theport){
00151  setClassName("Socket");
00152  CreateSocket(thehost, theport);
00153 }
00154 
00155 Socket::Socket(const char *thehost, const int theport){
00156  setClassName("Socket");
00157  CreateSocket(thehost, theport);
00158 }
00159 
00160 void Socket::close(void){
00161  if(sock >= 0){
00162   ::close(sock);
00163   sock = -1;
00164  }
00165 }
00166 
00167 Socket& Socket::operator<<(const char chr){
00168         Socket::write(&chr, sizeof(char));
00169         return *this;
00170 }
00171 
00172 Socket& Socket::operator<<(const int value){
00173         Socket::write((void *)&value, sizeof(int));
00174         return *this;
00175 }
00176 
00177 Socket& Socket::operator<<(const unsigned int value){
00178         Socket::write((void *)&value, sizeof(int));
00179         return *this;
00180 }
00181 
00182 Socket& Socket::operator<<(const float value){
00183         Socket::write((void *)&value, sizeof(float));
00184         return *this;
00185 }
00186 
00187 Socket& Socket::operator<<(const double value){
00188         Socket::write((void *)&value, sizeof(double));
00189         return *this;
00190 }
00191 
00192 Socket& Socket::operator<<(const long double value){
00193         Socket::write((void *)&value, sizeof(long double));
00194         return *this;
00195 }
00196 
00197 Socket& Socket::operator<<(const long value){
00198         Socket::write((void *)&value, sizeof(long));
00199         return *this;
00200 }
00201 
00202 Socket& Socket::operator<<(const unsigned long value){
00203         Socket::write(&value, (long)sizeof(long));
00204         return *this;
00205 }
00206 
00207 Socket& Socket::operator<<(const unsigned long long value){
00208         Socket::write(&value, (long)sizeof(long long));
00209         return *this;
00210 }
00211 
00212 Socket& Socket::operator<<(String str){
00213         char *buf;
00214         buf = new char[str.size() + 2];
00215         strcpy(buf, str.toCharPtr());
00216         buf[str.size()] = 0;
00217         try{
00218                 this->write((const void *)buf, str.size() + 1);
00219         }
00220         catch(...){
00221         //      delete buf;
00222                 claw_delete_array(buf);
00223                 throw;
00224         }
00225         claw_delete_array(buf);
00226         return *this;
00227 }
00228 
00229 void Socket::write(const void *buffer, unsigned long size){
00230         unsigned int i;
00231         char *tmpbuf;
00232         char *ptr;
00233         unsigned int siz;
00234         if(size < SOCK_CHUNK_SIZE){
00235                 if(::write(sock, buffer, size) == -1){
00236                         switch(errno){
00237                                 case EINVAL:
00238                                         throw SocketUnableToWriteException();
00239                                         break;
00240                                 case EPIPE:
00241                                         throw BrokenPipeException();
00242                                         break;
00243                                 default:
00244                                         throw NetworkException();
00245                         }
00246                 }
00247         }
00248         else{
00249                 tmpbuf = new char[SOCK_CHUNK_SIZE + 1];
00250                 ptr = (char *)buffer;
00251                 siz = size - (size % SOCK_CHUNK_SIZE);
00252                 for(i = 0; i < siz; i += SOCK_CHUNK_SIZE){
00253                         memcpy(tmpbuf, (ptr + i), SOCK_CHUNK_SIZE);
00254                         if(::write(sock, tmpbuf, SOCK_CHUNK_SIZE) == -1){
00255                                 switch(errno){
00256                                         case EINVAL:
00257                                                 throw SocketUnableToWriteException();
00258                                                 break;
00259                                         case EPIPE:
00260                                                 throw BrokenPipeException();
00261                                                 break;
00262                                         default:
00263                                                 throw NetworkException();
00264                                 }
00265                         }
00266                 }
00267                 if(size % SOCK_CHUNK_SIZE != 0){
00268                         memcpy(tmpbuf, (ptr + siz), size - siz);
00269                         if(::write(sock, tmpbuf, size - siz) == -1){
00270                                 switch(errno){
00271                                         case EINVAL:
00272                                                 throw SocketUnableToWriteException();
00273                                                 break;
00274                                         case EPIPE:
00275                                                 throw BrokenPipeException();
00276                                                 break;
00277                                         default:
00278                                                 throw NetworkException();
00279                                 }
00280                         }
00281                 }
00282                 delete tmpbuf;
00283         }
00284 }
00285 
00286 
00287 Socket& Socket::operator>>(char &chr){
00288         Socket::read((void *)&chr, sizeof(char));
00289         return *this;
00290 }
00291 
00292 Socket& Socket::operator>>(int &chr){
00293         Socket::read((void *)&chr, sizeof(int));
00294         return *this;
00295 }
00296 
00297 Socket& Socket::operator>>(unsigned int &chr){
00298         Socket::read((void *)&chr, sizeof(int));
00299         return *this;
00300 }
00301 
00302 Socket& Socket::operator>>(float &chr){
00303         Socket::read((void *)&chr, sizeof(float));
00304         return *this;
00305 }
00306 
00307 Socket& Socket::operator>>(double &chr){
00308         Socket::read((void *)&chr, sizeof(double));
00309         return *this;
00310 }
00311 
00312 Socket& Socket::operator>>(long double &chr){
00313         Socket::read((void *)&chr, sizeof(long double));
00314         return *this;
00315 }
00316 
00317 Socket& Socket::operator>>(long &chr){
00318         Socket::read((void *)&chr, sizeof(long));
00319         return *this;
00320 }
00321 
00322 Socket& Socket::operator>>(unsigned long &chr){
00323         Socket::read((void *)&chr, sizeof(long));
00324         return *this;
00325 }
00326 
00327 Socket& Socket::operator>>(unsigned long long &chr){
00328         Socket::read((void *)&chr, sizeof(long long));
00329         return *this;
00330 }
00331 
00332 Socket& Socket::operator>>(String &str){
00333         //This one is quite awful because waht one has to do is read 
00334         //every byte till the end without knowing how many data bytes 
00335         //are comming through the channel
00336         char chr[2];
00337         struct pollfd fd;
00338         fd.fd = sock;
00339         fd.events = POLLIN | POLLPRI;
00340         chr[1] = 0;
00341         while(true){
00342                 if(poll(&fd, 1, READ_TIMEOUT) == 0)
00343                         throw ConnectionTimeoutException();
00344                 try{
00345                         read(chr, sizeof(char));
00346                 }
00347                 catch(...){
00348                         throw;
00349                 }
00350                 if(chr[0] == 0 || chr[0] == '\r' || chr[0] == '\n')
00351                         break;
00352                 else
00353                         str += chr;
00354         }
00355         return *this;
00356 }
00357 
00358 void Socket::read(void *buffer, unsigned long size){
00359         unsigned int i;
00360         char *tmpbuf;
00361         char *ptr;
00362         unsigned int siz;
00363         struct pollfd fd;
00364         //Lets put some delay code here, no problem, we can do it work
00365         fd.fd = sock;
00366         fd.events = POLLIN | POLLPRI;
00367         if(poll(&fd, 1, READ_TIMEOUT) == 0)
00368                 throw ConnectionTimeoutException();
00369         if(size < SOCK_CHUNK_SIZE){
00370                 if(::read(sock, buffer, size) == -1){
00371                         switch(errno){
00372                                 case EINVAL:
00373                                         throw SocketUnableToReadException();
00374                                         break;
00375                                 case EPIPE:
00376                                         throw BrokenPipeException();
00377                                         break;
00378                                 default:
00379                                         throw NetworkException();
00380                         }
00381                 }
00382         }
00383         else{
00384                 tmpbuf = new char[SOCK_CHUNK_SIZE + 1];
00385                 ptr = (char *)buffer;
00386                 siz = size - (size % SOCK_CHUNK_SIZE);
00387                 for(i = 0; i < siz; i += SOCK_CHUNK_SIZE){
00388                         if(::read(sock, tmpbuf, SOCK_CHUNK_SIZE) == -1){
00389                                 switch(errno){
00390                                         case EINVAL:
00391                                                 throw SocketUnableToReadException();
00392                                                 break;
00393                                         case EPIPE:
00394                                                 throw BrokenPipeException();
00395                                                 break;
00396                                         default:
00397                                                 throw NetworkException();
00398                                 }
00399                         }
00400                         memcpy((ptr + i), tmpbuf, SOCK_CHUNK_SIZE);
00401                 }
00402                 if(size % SOCK_CHUNK_SIZE != 0){
00403                         if(::read(sock, tmpbuf, size - siz) == -1){
00404                                 switch(errno){
00405                                         case EINVAL:
00406                                                 throw SocketUnableToReadException();
00407                                                 break;
00408                                         case EPIPE:
00409                                                 throw BrokenPipeException();
00410                                                 break;
00411                                         default:
00412                                                 throw NetworkException();
00413                                 }
00414                         }
00415                         memcpy((ptr + siz), tmpbuf, size - siz);
00416                 }
00417                 delete tmpbuf;
00418         }
00419 }
00420 
00421 
00422 
00423 
00424 };
00425 

Powered by:

SourceForge Logo