inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/net/inet_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_inet_socket
00005 #define inlib_inet_socket
00006 
00007 //inheritance :
00008 #include "base_socket"
00009 
00010 #include "../sys/sleep"
00011 #include "../sout"
00012 
00013 #ifdef WIN32
00014 typedef unsigned long in_addr_t;
00015 #else
00016 #include <arpa/inet.h>
00017 #include <netinet/in.h>
00018 #include <netdb.h>
00019 #include <fcntl.h>
00020 #endif
00021 
00022 //#if TARGET_OS_IPHONE        //Device and Simulator
00023 //#if TARGET_IPHONE_SIMULATOR //Simulator
00024 //#if TARGET_OS_EMBEDDED      //Device
00025 
00026 #if TARGET_OS_EMBEDDED || ANDROID_NDK
00027 #include "addresses"
00028 #endif
00029 
00030 namespace inlib {
00031 namespace net {
00032 
00033 inline std::string herror() {
00034    std::ostringstream strm;
00035 #ifdef WIN32
00036    strm << (int)WSAGetLastError();
00037    return std::string(" error : ")+strm.str()+".";
00038 #else
00039    strm << (int)h_errno;
00040    return std::string(" error : ")+strm.str()
00041           + " : " +std::string(hstrerror(h_errno))+".";
00042 #endif
00043 }
00044 
00045 inline bool inet_addr(std::ostream& a_out,const std::string& a_host,in_addr_t& a_addr) {
00046   a_addr = ::inet_addr(a_host.c_str());
00047   if(a_addr!=INADDR_NONE) {
00048     //a_out << "inlib::net::inet_addr :"
00049     //      << " for " << sout(a_host)
00050     //      << " numeric."
00051     //      << std::endl;
00052     return true;
00053   }
00054   //perhaps not numeric form.
00055   hostent* host_p = ::gethostbyname(a_host.c_str());
00056   if(!host_p) {
00057     a_out << "inlib::net::inet_addr :"
00058           << " for " << sout(a_host)
00059           << " gethostbyname() : " << herror()
00060           << std::endl;
00061     a_addr = 0;      
00062     return false;
00063   }
00064   if(host_p->h_length!=sizeof(in_addr_t)) {
00065     a_out << "inlib::inet_socket:::connect :"
00066           << " for " << sout(a_host)
00067           << " gethostbyname() : bad length."
00068           << std::endl;
00069     a_addr = 0;      
00070     return false;
00071   }
00072   ::memcpy((char*)&a_addr,(char*)(host_p->h_addr),host_p->h_length);
00073   return true;
00074 }
00075 
00076 inline bool inet_host(std::ostream& a_out,std::string& a_host){
00077 #if TARGET_OS_EMBEDDED
00078   if(!inlib::net::if_address(a_out,"en0",a_host)) return false;
00079 #elif ANDROID_NDK
00080   inlib::net::dump_ip_addresses(a_out);    
00081   if(!inlib::net::if_address(a_out,"eth0",a_host)) return false;
00082 #else
00083   if(!host_name(a_out,a_host)) return false;
00084 #endif
00085   return true;
00086 }
00087 
00088 class inet_socket : public base_socket {
00089 public: //base_socket        
00090   virtual void disconnect(){close();}
00091 public:
00092   inet_socket(std::ostream& a_out,bool a_verbose = false)
00093   :base_socket(a_out,a_verbose)
00094   ,m_after_bind_func(0)
00095   ,m_after_bind_tag(0)
00096   ,m_accept_func(0)
00097   ,m_accept_tag(0)
00098   { 
00099 #ifdef WIN32
00100     WSADATA data;
00101     if (::WSAStartup(MAKEWORD(2,2),&data)!=NO_ERROR) {
00102       m_out << "inlib::inet_socket::inet_socket :"
00103             << " starting sockets failed." 
00104             << std::endl;
00105     } else {
00106       if(a_verbose) {
00107         m_out << "inlib::inet_socket::inet_socket :"
00108               << " WSAStartup ok." 
00109               << std::endl;
00110       }
00111     }
00112 #endif
00113   }
00114 
00115   virtual ~inet_socket() {
00116     close(); //WIN32 : must be done before the below.
00117 #ifdef WIN32
00118     ::WSACleanup();
00119 #endif
00120   }
00121 
00122 protected:
00123   inet_socket(const inet_socket& a_from) 
00124   :base_socket(a_from)
00125   ,m_after_bind_func(a_from.m_after_bind_func)
00126   ,m_after_bind_tag(a_from.m_after_bind_tag)
00127   ,m_accept_func(a_from.m_accept_func)
00128   ,m_accept_tag(a_from.m_accept_tag)
00129   {}
00130   inet_socket& operator=(const inet_socket&){ return *this;}
00131 public:
00132   struct bind_info {
00133     int m_true_port;
00134     unsigned int m_sin_addr; //in_addr_t = uint32
00135     unsigned short m_sin_port; //in_port_t = uint16    
00136   };
00137   typedef bool(*after_bind_func)(const bind_info&,void*);
00138 
00139   void set_after_bind_func(after_bind_func aFunc,void* aTag){
00140     m_after_bind_func = aFunc;
00141     m_after_bind_tag = aTag;
00142   }
00143 
00144   typedef bool(*accept_func)(void*);
00145 
00146   void set_accept_func(accept_func aFunc,void* aTag){
00147     m_accept_func = aFunc;
00148     m_accept_tag = aTag;
00149   }
00150 
00151   bool bind(const std::string& a_host,int a_port,
00152             unsigned int a_max_trial,unsigned int a_secs,bool a_reuse_addr){   
00153     if(m_socket!=(-1)) return true; //Done.
00154 
00155     if(m_verbose) {
00156       m_out << "inlib::inet_socket:::bind :"
00157             << " host : \"" << a_host << "\"."
00158             << std::endl;
00159     }
00160 
00161     in_addr_t addr = 0; //int32
00162     if(!inet_addr(m_out,a_host,addr)) return false;
00163 
00164     //if(m_verbose) {
00165     //  m_out << "inlib::inet_socket:::bind :"
00166     //        << " addr : " << ::inet_ntoa(*(struct in_addr*)&addr) << "."
00167     //        << std::endl;
00168     //}
00169 
00170     int fd_socket_waiting;
00171 
00172     unsigned int num_trial = 0;
00173     while(true) {
00174 
00175       // make socket
00176       fd_socket_waiting = ::socket(AF_INET,SOCK_STREAM,0);
00177       if(fd_socket_waiting<0) { 
00178         m_out << "inlib::inet_socket:::bind :"
00179               << " on host : " << a_host
00180               << " socket() : " << serror()
00181               << std::endl;
00182         return false;
00183       }
00184   
00185       // Force reuse of the server socket (i.e. do not wait for the time
00186       // out to pass).
00187       if(a_reuse_addr) {
00188         if(!set_reuse_addr(m_out,fd_socket_waiting)) return false;
00189       }
00190   
00191       // binding
00192       sockaddr_in address;
00193       ::memset((char*)&address,0,sizeof(address)); 
00194       address.sin_family = AF_INET;
00195       address.sin_port = htons(a_port);
00196       address.sin_addr.s_addr = addr;
00197   
00198       if(::bind(fd_socket_waiting,
00199                 (struct sockaddr*)(&address),sizeof(address))==0) {
00200         if(m_verbose) {
00201           m_out << "inlib::inet_socket:::bind :"
00202                 << " on host : " << a_host
00203                 << " socket is bound on port " << a_port << "." 
00204                 << std::endl;
00205         }
00206         break;
00207       }
00208   
00209 #ifdef WIN32
00210 #else
00211       std::string serror(strerror(errno));
00212 #endif
00213 
00214       ::close(fd_socket_waiting);
00215   
00216       if(num_trial>=a_max_trial) { 
00217         m_out << "inlib::inet_socket:::bind :"
00218               << " on host : " << a_host
00219               << " with port " << a_port
00220               << ". Max trials done. Cannot use port " << a_port << "." 
00221               << std::endl;
00222         return false;
00223       }
00224       num_trial++;
00225   
00226       //FIXME : should filter the errno. Some may be fatal.
00227       //if(m_verbose) {
00228         m_out << "inlib::inet_socket:::bind :"
00229               << " on host : " << a_host
00230               << " with port " << a_port
00231 #ifdef WIN32
00232               << " bind()"
00233 #else
00234               << " bind() : " << serror
00235 #endif
00236               << " : retry..." 
00237               << std::endl;
00238       //}
00239 
00240       sleep_secs(a_secs);                
00241     }
00242 
00243     sockaddr_in address;
00244     ::memset((char*)&address,0,sizeof(address)); 
00245 #ifdef WIN32
00246     int
00247 #else
00248     socklen_t 
00249 #endif
00250     address_length = sizeof(address);
00251     if(::getsockname(fd_socket_waiting,
00252                      (struct sockaddr*)&address,&address_length)!=0) { 
00253       m_out << "inlib::inet_socket:::bind :"
00254             << " on host : " << a_host
00255             << " getsockname() : " << serror()
00256             << std::endl;
00257       return false;
00258     }
00259 
00260     int true_port = a_port; 
00261     if(a_port==0) { //get the used port.
00262       true_port = ntohs(address.sin_port);
00263       if(m_verbose) {
00264         m_out << "inlib::inet_socket:::bind :"
00265               << " on host : " << a_host
00266               << " getsockname() : port " << true_port << "."
00267               << std::endl;
00268       }
00269     }
00270   
00271     if(m_after_bind_func)  {
00272       //getsockname again !
00273       bind_info info;
00274       info.m_true_port = true_port;
00275       info.m_sin_addr = address.sin_addr.s_addr;
00276       info.m_sin_port = address.sin_port;
00277       if(!m_after_bind_func(info,m_after_bind_tag)) return false;
00278     }
00279     
00280     // listen (wait connection)
00281     if(::listen(fd_socket_waiting,1)<0) { 
00282       m_out << "inlib::inet_socket:::bind :"
00283             << " on host : " << a_host
00284             << " listen() : " << serror()
00285             << std::endl;
00286       ::close(fd_socket_waiting);
00287       return false;
00288     }
00289 
00290     m_socket = fd_socket_waiting;
00291 
00292     if(m_verbose) {
00293       m_out << "inlib::inet_socket:::bind :"
00294             << " on host : " << a_host
00295             << " bind ok for port " << true_port << "."
00296             << " Socket is " << m_socket << "."
00297             << std::endl;
00298     }
00299   
00300     return true;
00301   }
00302 
00303   bool accept(int a_socket,bool a_blocking){
00304     if(m_socket!=(-1)) return true; //Done.
00305 
00306     std::string this_host;
00307     if(!host_name(m_out,this_host)) {
00308       // in this method this_host is used for m_out only
00309       // then we  ontinue anyway.
00310       this_host = "not_found";
00311       //return false;
00312     }
00313 
00314     if(a_blocking) {
00315       sockaddr_in address;
00316       ::memset((char*)&address,0,sizeof(address)); 
00317 #ifdef WIN32
00318       int
00319 #else
00320       socklen_t
00321 #endif
00322       address_length = sizeof(address);
00323       m_socket = ::accept(a_socket, 
00324                          (struct sockaddr*)(&address), 
00325                          &address_length);
00326       if(m_socket<0) { 
00327         m_out << "inlib::inet_socket:::accept :"
00328               << " on host : " << this_host
00329               << " accept() : " << serror()
00330               << std::endl;
00331         m_socket = -1;
00332         return false;
00333       }
00334       if(m_verbose) {
00335         m_out << "inlib::inet_socket:::accept :"
00336               << " on host : " << this_host
00337               << " accept ok."
00338               << " Socket is " << m_socket << "."
00339               << std::endl;
00340       }
00341     } else {
00342 #ifdef WIN32
00343      {unsigned long val = 1;
00344       if(::ioctlsocket(a_socket,FIONBIO,&val)!=0) {
00345         m_out << "inlib::inet_socket:::accept :"
00346               << " on host : " << this_host
00347               << " ioctlsocket FIONBIO failed."
00348               << std::endl;
00349         return false;
00350       }}
00351 #else
00352       int old_flags = ::fcntl(a_socket,F_GETFL);
00353       if(old_flags<0) {
00354         m_out << "inlib::inet_socket:::accept :"
00355               << " on host : " << this_host
00356               << " fcntl F_GETFL failed."
00357               << std::endl;
00358         return false;
00359       }
00360       if(::fcntl(a_socket,F_SETFL,old_flags+O_NONBLOCK)<0) {
00361         m_out << "inlib::inet_socket:::accept :"
00362               << " on host : " << this_host
00363               << " fcntl F_SETFL failed."
00364               << std::endl;
00365         return false;
00366       }
00367 #endif
00368   
00369       bool status = false;
00370   
00371       while(true) {
00372         sockaddr_in address;
00373         ::memset((char*)&address,0,sizeof(address)); 
00374 #ifdef WIN32
00375         int
00376 #else
00377         socklen_t
00378 #endif
00379         address_length = sizeof(address);
00380         int retval = ::accept(a_socket, 
00381                               (struct sockaddr*)(&address), 
00382                               &address_length);
00383         if(retval<0) {
00384 #ifdef WIN32
00385           if(WSAGetLastError()==WSAEWOULDBLOCK) {
00386 #else
00387           if(errno==EWOULDBLOCK) {
00388 #endif
00389             if(m_accept_func)  {
00390               if(!m_accept_func(m_accept_tag)) {
00391                 status = true;
00392                 break;
00393               }
00394             }
00395             continue;
00396           } else {
00397             m_out << "inlib::inet_socket:::accept :"
00398                   << " on host : " << this_host
00399                   << " accept() : " << serror()
00400                   << std::endl;
00401             status = false;
00402             break;  
00403           }
00404         }
00405   
00406         m_socket = retval;
00407         status = true;
00408         break;
00409       }
00410   
00411 #ifdef WIN32
00412      {unsigned long val = 0;
00413       if(::ioctlsocket(a_socket, FIONBIO, &val)!=0) {
00414         m_out << "inlib::inet_socket:::accept :"
00415               << " on host : " << this_host
00416               << " ioctlsocket FIONBIO failed."
00417               << std::endl;
00418         if(m_socket!=(-1)) {
00419           ::close(m_socket);
00420           m_socket = -1;
00421         }
00422         return false;
00423       }}
00424 #else
00425       if(::fcntl(a_socket,F_SETFL,old_flags)<0) {
00426         m_out << "inlib::inet_socket:::accept :"
00427               << " on host : " << this_host
00428               << " fcntl F_SETFL (2) failed."
00429               << std::endl;
00430         if(m_socket!=(-1)) {
00431           ::close(m_socket);
00432           m_socket = -1;
00433         }
00434         return false;
00435       }
00436 #endif
00437 
00438       if(m_socket!=(-1)) {
00439 #ifdef WIN32
00440        {unsigned long val = 0;
00441         if(::ioctlsocket(m_socket,FIONBIO,&val)!=0) {
00442           m_out << "inlib::inet_socket:::accept :"
00443                 << " on host : " << this_host
00444                 << " ioctlsocket FIONBIO failed."
00445                 << std::endl;
00446           ::close(m_socket);
00447           m_socket = -1;
00448           return false;
00449         }}
00450 #else
00451         if(::fcntl(m_socket,F_SETFL,old_flags)<0) {
00452           m_out << "inlib::inet_socket:::accept :"
00453                 << " on host : " << this_host
00454                 << " fcntl F_SETFL (2) failed."
00455                 << std::endl;
00456           ::close(m_socket);
00457           m_socket = -1;
00458           return false;
00459         }
00460 #endif
00461       }
00462 
00463       if(!status) return false;
00464 
00465       if(m_verbose) {
00466         if(m_socket==(-1)) {
00467           m_out << "inlib::inet_socket:::accept :"
00468                 << " on host : " << this_host
00469                 << " accept exit without a socket."
00470                 << std::endl;
00471         } else {
00472           m_out << "inlib::inet_socket:::accept :"
00473                 << " on host : " << this_host
00474                 << " accept ok."
00475                 << " Socket is " << m_socket << "."
00476                 << std::endl;
00477         }
00478       }
00479     }
00480   
00481     return true;
00482   }
00483 
00484   bool bind_accept(const std::string& a_host,int a_port,unsigned int a_max_trial,unsigned int a_secs,bool a_reuse_addr,bool a_blocking){
00485     if(!bind(a_host,a_port,a_max_trial,a_secs,a_reuse_addr)) return false;
00486     int sock = m_socket;
00487     m_socket = -1;
00488     bool status = accept(sock,a_blocking);
00489     ::close(sock);
00490     return status;
00491   }
00492   
00493   bool connect(const std::string& a_host,int a_port,unsigned int a_max_trial,unsigned int a_secs){
00494     if(m_socket!=(-1)) return true; //Done.
00495   
00496     std::string this_host;
00497     if(!host_name(m_out,this_host)) {
00498       // in this method this_host is used for m_out only
00499       // then we  ontinue anyway.
00500       this_host = "not_found";
00501       //return false;
00502     }
00503 
00504     //if(m_verbose) {
00505     //  m_out << "inlib::inet_socket:::connect :"
00506     //        << " this host : \"" << this_host << "\"."
00507     //        << std::endl;
00508     //}
00509 
00510     in_addr_t addr = 0; //int32
00511     if(!inet_addr(m_out,a_host,addr)) return false;
00512   
00513     unsigned int num_trial = 0;
00514     while(true) {
00515 
00516       // make socket :
00517       m_socket = ::socket(AF_INET, SOCK_STREAM,0);
00518       if(m_socket<0) { 
00519         m_out << "inlib::inet_socket:::connect :"
00520               << " on host : " << this_host
00521               << " socket() : " << serror()
00522               << std::endl;
00523         m_socket = -1;
00524         return false;
00525       }
00526 
00527       sockaddr_in address;
00528       ::memset((char*)&address,0,sizeof(address)); 
00529       address.sin_family = AF_INET;
00530       address.sin_port = htons(a_port);
00531       address.sin_addr.s_addr = addr;
00532 
00533       if(::connect(m_socket,
00534                    (struct sockaddr*)(&address),sizeof(address))==0) {
00535         if(m_verbose) {
00536           m_out << "inlib::inet_socket:::connect :"
00537                 << " on host : " << this_host
00538                 << " connect to " << a_host << " on port " << a_port << " ok."
00539                 << " Socket is " << m_socket << "."
00540                 << std::endl;
00541         }
00542         return true;
00543       }
00544 
00545 #ifdef WIN32
00546       if(WSAGetLastError()==WSAECONNREFUSED) {
00547 #else
00548       if(errno==ECONNREFUSED) {
00549 #endif
00550         if(m_verbose) {
00551           m_out << "inlib::inet_socket:::connect :"
00552                 << " on host : " << this_host
00553                 << " connect to " << a_host 
00554                 << " with port " << a_port
00555                 << " connect() : " << serror()
00556                 << " Retry..."
00557                 << std::endl;
00558         }
00559   
00560         ::close(m_socket);
00561         m_socket = -1;
00562   
00563         if(num_trial>=a_max_trial) { 
00564           m_out << "inlib::inet_socket:::connect :"
00565                 << " on host : " << this_host
00566                 << " connect to " << a_host 
00567                 << " with port " << a_port
00568                 << ". Max trials done. Can't connect."
00569                 << std::endl;
00570           return false;
00571         }
00572         num_trial++;
00573   
00574         sleep_secs(a_secs);                
00575       } else {
00576         m_out << "inlib::inet_socket:::connect :"
00577               << " on host : " << this_host
00578               << " connect to " << a_host 
00579               << " with port " << a_port
00580               << " connect() : " << serror()
00581               << std::endl;
00582         ::close(m_socket);
00583         m_socket = -1;
00584         return false;
00585       }
00586     }
00587 
00588     return false;
00589   }
00590 
00591 protected:        
00592   after_bind_func m_after_bind_func;
00593   void* m_after_bind_tag;
00594   accept_func m_accept_func;
00595   void* m_accept_tag;
00596 
00597 };
00598 
00599 }}
00600 
00601 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines