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_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