inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/net/base_socket
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines