inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_base_socket 00005 #define inlib_base_socket 00006 00007 #include <string> 00008 #include <vector> 00009 #include <ostream> 00010 #include <sstream> 00011 00012 #include "../typedefs" 00013 #include "../platform" 00014 #include "../file" 00015 #include "../buffer" 00016 #include "../mnmx" 00017 00018 #ifdef WIN32 00019 #include <io.h> 00020 //#include <winsock2.h> 00021 #include <winsock.h> 00022 #ifndef SD_BOTH 00023 #define SD_BOTH 0x02 00024 #endif 00025 #else 00026 #include <sys/socket.h> 00027 #include <errno.h> 00028 #include <unistd.h> 00029 #include <cstring> 00030 #endif 00031 00032 namespace inlib { 00033 namespace net { 00034 00035 inline std::string serror() { 00036 std::ostringstream strm; 00037 #ifdef WIN32 00038 strm << (int)WSAGetLastError(); 00039 return std::string(" error : ")+strm.str()+"."; 00040 #else 00041 strm << (int)errno; 00042 return std::string(" error : ")+strm.str() 00043 + " : " +std::string(strerror(errno))+"."; 00044 #endif 00045 } 00046 00047 inline bool host_name(std::ostream& a_out,std::string& a_host){ 00048 char s[512]; 00049 if(::gethostname(s,sizeof(s))<0) { 00050 a_out << "inlib::net::host_name :" 00051 << " gethostname() :" << serror() 00052 << std::endl; 00053 a_host.clear(); 00054 return false; 00055 } 00056 a_host = s; 00057 return true; 00058 } 00059 00060 inline bool set_reuse_addr(std::ostream& a_out,int a_socket) { 00061 int val = 1; 00062 if(::setsockopt(a_socket,SOL_SOCKET, 00063 SO_REUSEADDR,(char*)&val,sizeof(val))<0) { 00064 a_out << "inlib::net::set_reuse_addr :" 00065 << " setsockopt() :" << serror() 00066 << std::endl; 00067 return false; 00068 } 00069 return true; 00070 } 00071 00072 inline bool set_input_timer(std::ostream& a_out,int a_socket,unsigned int a_micro_secs) { 00073 struct timeval val; 00074 val.tv_sec = 0; 00075 val.tv_usec = a_micro_secs; 00076 if(::setsockopt(a_socket,SOL_SOCKET, 00077 SO_RCVTIMEO,(char*)&val,sizeof(val))<0) { 00078 a_out << "inlib::base_socket::set_input_timer :" 00079 << " setsockopt():" << serror() 00080 << std::endl; 00081 return false; 00082 } 00083 return true; 00084 } 00085 00086 inline bool is_there_input(const std::vector<int>& a_socks,bool& a_is) { 00087 a_is = false; 00088 if(a_socks.empty()) return false; 00089 00090 struct timeval timeout; 00091 timeout.tv_sec = 0; 00092 timeout.tv_usec = 10; //microsec 00093 00094 fd_set mask; 00095 FD_ZERO(&mask); 00096 int nfds = 0; 00097 {std::vector<int>::const_iterator it; 00098 for(it=a_socks.begin();it!=a_socks.end();++it) { 00099 FD_SET(*it,&mask); 00100 nfds = mx(nfds,*it); 00101 }} 00102 nfds++; 00103 00104 if(::select(nfds,&mask,0,0,&timeout)==(-1)) { 00105 a_is = false; 00106 return false; 00107 } 00108 00109 {std::vector<int>::const_iterator it; 00110 for(it=a_socks.begin();it!=a_socks.end();++it) { 00111 if(FD_ISSET(*it,&mask)) { 00112 a_is = true; 00113 break; 00114 } 00115 }} 00116 00117 return true; 00118 } 00119 00120 inline bool wait_input(const std::vector<int>& a_socks) { 00121 if(a_socks.empty()) return false; 00122 00123 fd_set mask; 00124 FD_ZERO(&mask); 00125 int nfds = 0; 00126 {std::vector<int>::const_iterator it; 00127 for(it=a_socks.begin();it!=a_socks.end();++it) { 00128 FD_SET(*it,&mask); 00129 nfds = mx(nfds,*it); 00130 }} 00131 nfds++; 00132 00133 if(::select(nfds,&mask,0,0,0)==(-1)) return false; 00134 00135 return true; 00136 } 00137 00138 class base_socket { 00139 public: 00140 virtual void disconnect() = 0; 00141 virtual bool fetch_cbk(inlib::uint64) {return true;} 00142 public: 00143 base_socket(std::ostream& a_out,bool a_verbose) 00144 :m_out(a_out) 00145 ,m_verbose(a_verbose) 00146 ,m_socket(-1) 00147 ,m_is_LE(true) 00148 { 00149 m_is_LE = inlib::is_little_endian(); 00150 } 00151 virtual ~base_socket(){close();} 00152 protected: 00153 base_socket(const base_socket& aFrom) 00154 :m_out(aFrom.m_out) 00155 ,m_verbose(aFrom.m_verbose) 00156 ,m_socket(aFrom.m_socket) 00157 ,m_is_LE(aFrom.m_is_LE) 00158 {} 00159 base_socket& operator=(const base_socket& aFrom){ 00160 m_verbose = aFrom.m_verbose; 00161 m_socket = aFrom.m_socket; 00162 m_is_LE = aFrom.m_is_LE; 00163 return *this; 00164 } 00165 public: 00166 bool verbose() const {return m_verbose;} 00167 bool is_connected() const {return (m_socket==(-1)?false:true);} 00168 int socket() const {return m_socket;} 00169 std::ostream& out() const {return m_out;} 00170 protected: 00171 void close(){ 00172 if(m_socket!=(-1)) { 00173 #ifdef WIN32 00174 if(::shutdown(m_socket,SD_BOTH)<0) { 00175 if(WSAGetLastError()==WSAENOTCONN) { 00176 #else 00177 if(::shutdown(m_socket,SHUT_RDWR)<0) { 00178 if(errno==ENOTCONN) { 00179 #endif 00180 // ok, the "other side" may have already done a shutdown. 00181 } else { 00182 m_out << "inlib::base_socket::close :" 00183 << " for socket : " << m_socket 00184 << ", shutdown : " << serror() 00185 << std::endl; 00186 } 00187 } else { 00188 if(m_verbose) { 00189 m_out << "inlib::base_socket::close :" 00190 << " close ok." 00191 << " Socket was " << m_socket << "." 00192 << std::endl; 00193 } 00194 } 00195 ::close(m_socket); 00196 m_socket = -1; 00197 } 00198 } 00199 public: 00200 bool send_buffer(const char* a_buffer,inlib::uint64 a_length,inlib::uint64 a_BLOCK = 65536) { 00201 if(!a_length) return true; 00202 if(m_socket==(-1)) return false; 00203 char* buf = (char*)a_buffer; 00204 inlib::uint64 sent = 0; 00205 while(true) { 00206 inlib::uint64 to_send = mn(a_BLOCK,a_length-sent); 00207 if(!to_send) break; 00208 #ifdef WIN32 00209 int 00210 #else 00211 ssize_t 00212 #endif 00213 num_char = ::send(m_socket,(char*)buf,(size_t)to_send,0); 00214 if(num_char<0) { 00215 m_out << "inlib::base_socket::send_buffer :" 00216 << " send : " << serror() 00217 << std::endl; 00218 disconnect(); 00219 return false; 00220 } 00221 if(num_char==0) { 00222 m_out << "inlib::base_socket::send_buffer :" 00223 << " send : returned 0." 00224 << std::endl; 00225 } 00226 00227 //NOTE : num_char not necessary equal to to_send. 00228 buf += num_char; 00229 sent += num_char; 00230 } 00231 return true; 00232 } 00233 00234 bool fetch_buffer(char* a_buffer,inlib::uint64 a_length,inlib::uint64 a_BLOCK = 65536){ 00235 if(!a_length) return true; 00236 if(m_socket==(-1)) return false; 00237 char* buf = a_buffer; 00238 inlib::uint64 got = 0; 00239 while(true) { 00240 inlib::uint64 to_get = mn(a_BLOCK,a_length-got); 00241 if(!to_get) break; 00242 #ifdef WIN32 00243 int 00244 #else 00245 ssize_t 00246 #endif 00247 num_char = ::recv(m_socket,buf,(size_t)to_get,0); 00248 if(num_char<0) { 00249 //ECONNRESET 00250 m_out << "inlib::base_socket::fetch_buffer :" 00251 << " recv : " << serror() 00252 << std::endl; 00253 disconnect(); 00254 return false; 00255 } 00256 if(num_char==0) { 00257 m_out << "inlib::base_socket::fetch_buffer :" 00258 << " recv : returned 0." 00259 << std::endl; 00260 return false; 00261 } 00262 00263 //NOTE : num_char not necessary equal to to_get. 00264 buf += num_char; 00265 got += num_char; 00266 } 00267 return true; 00268 } 00269 00270 bool fetch_upto_char( 00271 char a_char 00272 ,char*& a_buffer 00273 ,inlib::uint64& a_length 00274 ,unsigned int a_BLOCK = 65536){ 00275 a_buffer = 0; 00276 a_length = 0; 00277 if(m_socket==(-1)) return false; 00278 char* buf = new char[a_BLOCK]; 00279 if(!buf) return false; 00280 while(true) { 00281 #ifdef WIN32 00282 int 00283 #else 00284 ssize_t 00285 #endif 00286 num_char = ::recv(m_socket,buf,(size_t)a_BLOCK,0); 00287 if(num_char<0) { 00288 m_out << "inlib::base_socket::fetch_upto_char :" 00289 << " recv : " << serror() 00290 << std::endl; 00291 disconnect(); 00292 delete [] buf; 00293 delete [] a_buffer; 00294 a_buffer = 0; 00295 a_length = 0; 00296 return false; 00297 } 00298 if(num_char==0) { 00299 m_out << "inlib::base_socket::fetch_upto_char :" 00300 << " recv : returned 0." 00301 << std::endl; 00302 delete [] buf; 00303 delete [] a_buffer; 00304 a_buffer = 0; 00305 a_length = 0; 00306 return false; 00307 } 00308 00309 if(m_verbose) { 00310 m_out << "inlib::base_socket::fetch_upto_char :" 00311 << " recv : " << (int)num_char 00312 << std::endl; 00313 } 00314 00315 if(!a_buffer) { 00316 a_buffer = new char[num_char]; 00317 if(!a_buffer) { 00318 delete [] buf; 00319 a_length = 0; 00320 return false; 00321 } 00322 ::memcpy(a_buffer,buf,num_char); 00323 a_length = num_char; 00324 } else { 00325 char* b = new char[(size_t)(a_length+num_char)]; 00326 if(!b) { 00327 delete [] buf; 00328 delete [] a_buffer; 00329 a_buffer = 0; 00330 a_length = 0; 00331 return false; 00332 } 00333 ::memcpy(b,a_buffer,(size_t)a_length); 00334 ::memcpy(b+a_length,buf,num_char); 00335 delete [] a_buffer; 00336 a_buffer = b; 00337 a_length += num_char; 00338 } 00339 00340 {char* pos = buf; 00341 for(unsigned int index=0;index<(unsigned int)num_char;index++,pos++) { 00342 //printf("debug : %d : %d\n",index,*pos); 00343 if(*pos==a_char) { //found 00344 // 01234 00345 // ^ 00346 a_length -= (num_char-(index+1)); 00347 delete [] buf; 00348 return true; 00349 } 00350 }} 00351 00352 //a_char not in buf, continue. 00353 } 00354 } 00355 00356 bool fetch_upto_end(char*& a_buffer,inlib::uint64& a_length,unsigned int a_BLOCK = 65536){ 00357 a_buffer = 0; 00358 a_length = 0; 00359 if(m_socket==(-1)) return false; 00360 00361 char* buf = new char[a_BLOCK]; 00362 if(!buf) return false; 00363 while(true) { 00364 //m_out << "inlib::base_socket::fetch_upto_end :" 00365 // << " recv... " 00366 // << std::endl; 00367 #ifdef WIN32 00368 int 00369 #else 00370 ssize_t 00371 #endif 00372 num_char = ::recv(m_socket,buf,(size_t)a_BLOCK,0); 00373 if(num_char<0) { 00374 //if(errno==EAGAIN) continue; 00375 m_out << "inlib::base_socket::fetch_upto_end :" 00376 << " recv : " << serror() 00377 << std::endl; 00378 disconnect(); 00379 delete [] buf; 00380 delete [] a_buffer; 00381 a_buffer = 0; 00382 a_length = 0; 00383 return false; 00384 } 00385 if(num_char==0) { 00386 if(m_verbose) { 00387 m_out << "inlib::base_socket::fetch_upto_end :" 00388 << " end." 00389 << std::endl; 00390 } 00391 delete [] buf; 00392 return true; 00393 } 00394 00395 if(m_verbose) { 00396 m_out << "inlib::base_socket::fetch_upto_end :" 00397 << " recv : " << (int)num_char 00398 << std::endl; 00399 } 00400 00401 if(!a_buffer) { 00402 a_buffer = new char[num_char]; 00403 if(!a_buffer) { 00404 delete [] buf; 00405 a_length = 0; 00406 return false; 00407 } 00408 ::memcpy(a_buffer,buf,num_char); 00409 a_length = num_char; 00410 } else { 00411 char* b = new char[(size_t)(a_length+num_char)]; 00412 if(!b) { 00413 delete [] buf; 00414 delete [] a_buffer; 00415 a_buffer = 0; 00416 a_length = 0; 00417 return false; 00418 } 00419 ::memcpy(b,a_buffer,(size_t)a_length); 00420 ::memcpy(b+a_length,buf,num_char); 00421 delete [] a_buffer; 00422 a_buffer = b; 00423 a_length += num_char; 00424 } 00425 } 00426 } 00427 00428 bool fetch_upto_end(FILE* a_FILE,inlib::uint64& a_length,unsigned int a_BLOCK = 65536){ 00429 a_length = 0; 00430 if(m_socket==(-1)) return false; 00431 00432 char* buf = new char[a_BLOCK]; 00433 if(!buf) return false; 00434 while(true) { 00435 //m_out << "inlib::base_socket::fetch_upto_end(FILE) :" 00436 // << " recv... " 00437 // << std::endl; 00438 #ifdef WIN32 00439 int 00440 #else 00441 ssize_t 00442 #endif 00443 num_char = ::recv(m_socket,buf,(size_t)a_BLOCK,0); 00444 if(num_char<0) { 00445 //if(errno==EAGAIN) continue; 00446 m_out << "inlib::base_socket::fetch_upto_end(FILE) :" 00447 << " recv : " << serror() 00448 << std::endl; 00449 disconnect(); 00450 delete [] buf; 00451 a_length = 0; 00452 return false; 00453 } 00454 if(num_char==0) { 00455 if(m_verbose) { 00456 m_out << "inlib::base_socket::fetch_upto_end(FILE) :" 00457 << " end." 00458 << std::endl; 00459 } 00460 delete [] buf; 00461 return true; 00462 } 00463 00464 if(m_verbose) { 00465 m_out << "inlib::base_socket::fetch_upto_end(FILE) :" 00466 << " recv : " << (int)num_char 00467 << std::endl; 00468 } 00469 00470 if(::fwrite((char*)buf,num_char,(size_t)1,a_FILE)!=1) { 00471 delete [] buf; 00472 a_length = 0; 00473 return false; 00474 } 00475 a_length += num_char; 00476 if(!fetch_cbk(a_length)) { 00477 m_out << "inlib::base_socket::fetch_upto_end(FILE) :" 00478 << " fetch_cbk returns false, stop recv data." 00479 << std::endl; 00480 return false; 00481 } 00482 } 00483 } 00484 00488 template <class T> 00489 bool send(const T& a_value) { 00490 char buffer[sizeof(T)]; 00491 inlib::write_buffer<T>(a_value,buffer); 00492 return send_buffer(buffer,sizeof(T)); 00493 } 00494 00495 template <class T> 00496 bool fetch(T& a_value) { 00497 char buffer[sizeof(T)]; 00498 if(!fetch_buffer(buffer,sizeof(T))) return false; 00499 inlib::read_buffer<T>(buffer,a_value); 00500 return true; 00501 } 00502 00503 bool send_uchar(unsigned char a_value) { 00504 char buffer[1]; 00505 ::memcpy(buffer,&a_value,1); 00506 return send_buffer(buffer,1); 00507 } 00508 00509 bool fetch_uchar(unsigned char& a_value) { 00510 char buffer[1]; 00511 if(!fetch_buffer(buffer,1)) return false; 00512 ::memcpy(&a_value,buffer,1); 00513 return true; 00514 } 00515 00516 bool send_bool(bool a_value) { 00517 unsigned char c = a_value?1:0; 00518 return send_uchar(c); 00519 } 00520 00521 bool fetch_bool(bool& a_value) { 00522 unsigned char c; 00523 if(!fetch_uchar(c)) {a_value = false;return false;} 00524 a_value = (c==1?true:false); 00525 return true; 00526 } 00527 00528 bool send_string(const std::string& a_string) { 00529 if(!send<inlib::uint64>(a_string.size())) return false; 00530 return send_buffer(a_string.c_str(),a_string.size()); 00531 } 00532 00533 bool fetch_string(std::string& a_string) { 00534 inlib::uint64 length; 00535 if(!fetch<inlib::uint64>(length)) { 00536 a_string.clear(); 00537 return false; 00538 } 00539 a_string.resize((std::string::size_type)length); 00540 if(!fetch_buffer((char*)a_string.c_str(),length)) { 00541 a_string.clear(); 00542 return false; 00543 } 00544 return true; 00545 } 00546 00547 bool send_text(const std::vector<std::string>& a_text) { 00548 unsigned int number = a_text.size(); 00549 if(!send<inlib::uint64>(number)) return false; 00550 for(unsigned int index=0;index<number;index++) { 00551 if(!send_string(a_text[index])) return false; 00552 } 00553 return true; 00554 } 00555 00556 bool fetch_text(std::vector<std::string>& a_text){ 00557 inlib::uint64 number; 00558 if(!fetch<inlib::uint64>(number)) { 00559 a_text.clear(); 00560 return false; 00561 } 00562 for(unsigned int index=0;index<number;index++) { 00563 std::string s; 00564 if(!fetch_string(s)) { 00565 a_text.clear(); 00566 return false; 00567 } 00568 a_text.push_back(s); 00569 } 00570 return true; 00571 } 00572 00573 bool send_file(const std::string& a_file) { 00574 char* buffer; 00575 long length; 00576 if(!inlib::file::read_bytes(a_file,buffer,length)) { 00577 m_out << "inlib::base_socket::send_file : " 00578 << " can't read file \"" << a_file << "\"." 00579 << std::endl; 00580 return false; 00581 } 00582 if(!send<inlib::uint64>((inlib::uint64)length)) return false; 00583 bool stat = send_buffer(buffer,length); 00584 delete [] buffer; 00585 return stat; 00586 } 00587 00588 bool fetch_file(const std::string& a_file) { 00589 inlib::uint64 length; 00590 if(!fetch<inlib::uint64>(length)) return false; 00591 char* buffer = 0; 00592 if(length) { 00593 buffer = new char[(size_t)length]; 00594 if(!buffer) return false; 00595 } 00596 if(!fetch_buffer(buffer,length)) { 00597 delete [] buffer; 00598 return false; 00599 } 00600 bool stat = inlib::file::write_bytes(a_file,buffer,(size_t)length); 00601 if(!stat) { 00602 m_out << "inlib::base_socket::send_file : " 00603 << " can't write file \"" << a_file << "\"." 00604 << std::endl; 00605 } 00606 delete [] buffer; 00607 return stat; 00608 } 00609 00610 bool is_there_input(bool& a_is) { 00611 a_is = false; 00612 if(m_socket==(-1)) return false; 00613 00614 fd_set mask; 00615 FD_ZERO(&mask); 00616 FD_SET(m_socket,&mask); 00617 00618 struct timeval timeout; 00619 timeout.tv_sec = 0; 00620 timeout.tv_usec = 10; //microsec 00621 00622 int nfds = 0; 00623 nfds = mx(nfds,m_socket); 00624 nfds++; 00625 if(::select(nfds,&mask,0,0,&timeout)==(-1)) { 00626 a_is = false; 00627 return false; 00628 } 00629 00630 a_is = FD_ISSET(m_socket,&mask)?true:false; 00631 return true; 00632 } 00633 00634 protected: 00635 std::ostream& m_out; 00636 bool m_verbose; 00637 int m_socket; 00638 bool m_is_LE; 00639 }; 00640 00641 00642 }} 00643 00644 #endif