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: