Marine Library  1.0
C++ library for Linux Networking Development
sock_addr.hh
1 #ifndef DOZERG_SOCKET_ADDR_H_20080229
2 #define DOZERG_SOCKET_ADDR_H_20080229
3 
4 /*
5  对网络地址的简单包装,隐藏了IPv4和IPv6协议相关性 CSockAddr IPv4或IPv6地址 //*/ #include <sys/types.h> #include <sys/socket.h> //socket #include <arpa/inet.h> #include <sys/ioctl.h> //ioctl #include <net/if.h> //ifreq #include <netdb.h> //getaddrinfo #include <unistd.h> #include <cstring> //memset,memcpy #include <string> #include <cassert> #include "to_string.hh" NS_SERVER_BEGIN class CSockAddr { typedef struct sockaddr_storage __SS; typedef struct sockaddr __SA; typedef struct sockaddr_in __SA4; typedef struct sockaddr_in6 __SA6; public: //将ipv4转换成可读字符串 //hostOrder: true-主机序; false-网络序 static std::string IPv4String(uint32_t ipv4, bool hostOrder = true){ struct in_addr in; in.s_addr = (hostOrder ? htonl(ipv4) : ipv4); return ipv4Str(in); } //将ipv6转换成可读字符串 //return: // true 成功 // false 失败 static bool IPv6String(const struct in6_addr & ipv6, std::string * result){ if(NULL == result) return false; std::string ret = ipv6Str(ipv6); if(ret.empty()) return false; result->swap(ret); return true; } //将"ddd.ddd.ddd.ddd"形式字符串转换成为ipv4 //hostOrder: true-主机序; false-网络序 static uint32_t IPv4FromStr(const std::string & ipv4, bool hostOrder = true){ struct in_addr in; if(ipv4.empty() || 0 >= inet_pton(AF_INET, strPtr(ipv4), &in)) return 0; return (hostOrder ? ntohl(in.s_addr) : in.s_addr); } //将字符串转换成为ipv6 //return: // true 成功 // false 失败 static bool IPv6FromStr(const std::string & ipv6, struct in6_addr * addr){ return (NULL != addr && !ipv6.empty() && inet_pton(AF_INET6, strPtr(ipv6), addr) > 0); } //将接口名转换成为ipv4 //hostOrder: true-主机序; false-网络序 static uint32_t IPv4FromIf(const std::string & eth, bool hostOrder = true){ __SS addr; const socklen_t len = tryIfr(strPtr(eth), &addr); if(sizeof(__SA4) != len) return 0; uint32_t ret = reinterpret_cast<const __SA4 *>(&addr)->sin_addr.s_addr; return (hostOrder ? ntohl(ret) : ret); } //默认构造 CSockAddr(){} //设置地址 //host: 主机名,域名,ip地址,本机接口名(eth1) //serv: 服务名或者端口号 //ipv4: IPv4 //ipv6: IPv6 //port: 端口号 //hostOrder: true-主机序; false-网络序 //addr: 通用地址结构体 //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
6  CSockAddr IPv4或IPv6地址
7 //*/
8 
9 #include <sys/types.h>
10 #include <sys/socket.h> //socket
11 #include <arpa/inet.h>
12 #include <sys/ioctl.h> //ioctl
13 #include <net/if.h> //ifreq
14 #include <netdb.h> //getaddrinfo
15 #include <unistd.h>
16 #include <cstring> //memset,memcpy
17 #include <string>
18 #include <cassert>
19 
20 #include "to_string.hh"
21 
22 NS_SERVER_BEGIN
23 
24 class CSockAddr
25 {
26  typedef struct sockaddr_storage __SS;
27  typedef struct sockaddr __SA;
28  typedef struct sockaddr_in __SA4;
29  typedef struct sockaddr_in6 __SA6;
30 public:
31  //将ipv4转换成可读字符串
32  //hostOrder: true-主机序; false-网络序
33  static std::string IPv4String(uint32_t ipv4, bool hostOrder = true){
34  struct in_addr in;
35  in.s_addr = (hostOrder ? htonl(ipv4) : ipv4);
36  return ipv4Str(in);
37  }
38  //将ipv6转换成可读字符串
39  //return:
40  // true 成功
41  // false 失败 static bool IPv6String(const struct in6_addr & ipv6, std::string * result){ if(NULL == result) return false; std::string ret = ipv6Str(ipv6); if(ret.empty()) return false; result->swap(ret); return true; } //将"ddd.ddd.ddd.ddd"形式字符串转换成为ipv4 //hostOrder: true-主机序; false-网络序 static uint32_t IPv4FromStr(const std::string & ipv4, bool hostOrder = true){ struct in_addr in; if(ipv4.empty() || 0 >= inet_pton(AF_INET, strPtr(ipv4), &in)) return 0; return (hostOrder ? ntohl(in.s_addr) : in.s_addr); } //将字符串转换成为ipv6 //return: // true 成功 // false 失败 static bool IPv6FromStr(const std::string & ipv6, struct in6_addr * addr){ return (NULL != addr && !ipv6.empty() && inet_pton(AF_INET6, strPtr(ipv6), addr) > 0); } //将接口名转换成为ipv4 //hostOrder: true-主机序; false-网络序 static uint32_t IPv4FromIf(const std::string & eth, bool hostOrder = true){ __SS addr; const socklen_t len = tryIfr(strPtr(eth), &addr); if(sizeof(__SA4) != len) return 0; uint32_t ret = reinterpret_cast<const __SA4 *>(&addr)->sin_addr.s_addr; return (hostOrder ? ntohl(ret) : ret); } //默认构造 CSockAddr(){} //设置地址 //host: 主机名,域名,ip地址,本机接口名(eth1) //serv: 服务名或者端口号 //ipv4: IPv4 //ipv6: IPv6 //port: 端口号 //hostOrder: true-主机序; false-网络序 //addr: 通用地址结构体 //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
42  static bool IPv6String(const struct in6_addr & ipv6, std::string * result){
43  if(NULL == result)
44  return false;
45  std::string ret = ipv6Str(ipv6);
46  if(ret.empty())
47  return false;
48  result->swap(ret);
49  return true;
50  }
51  //将"ddd.ddd.ddd.ddd"形式字符串转换成为ipv4
52  //hostOrder: true-主机序; false-网络序
53  static uint32_t IPv4FromStr(const std::string & ipv4, bool hostOrder = true){
54  struct in_addr in;
55  if(ipv4.empty() || 0 >= inet_pton(AF_INET, strPtr(ipv4), &in))
56  return 0;
57  return (hostOrder ? ntohl(in.s_addr) : in.s_addr);
58  }
59  //将字符串转换成为ipv6
60  //return:
61  // true 成功
62  // false 失败 static bool IPv6FromStr(const std::string & ipv6, struct in6_addr * addr){ return (NULL != addr && !ipv6.empty() && inet_pton(AF_INET6, strPtr(ipv6), addr) > 0); } //将接口名转换成为ipv4 //hostOrder: true-主机序; false-网络序 static uint32_t IPv4FromIf(const std::string & eth, bool hostOrder = true){ __SS addr; const socklen_t len = tryIfr(strPtr(eth), &addr); if(sizeof(__SA4) != len) return 0; uint32_t ret = reinterpret_cast<const __SA4 *>(&addr)->sin_addr.s_addr; return (hostOrder ? ntohl(ret) : ret); } //默认构造 CSockAddr(){} //设置地址 //host: 主机名,域名,ip地址,本机接口名(eth1) //serv: 服务名或者端口号 //ipv4: IPv4 //ipv6: IPv6 //port: 端口号 //hostOrder: true-主机序; false-网络序 //addr: 通用地址结构体 //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
63  static bool IPv6FromStr(const std::string & ipv6, struct in6_addr * addr){
64  return (NULL != addr && !ipv6.empty() && inet_pton(AF_INET6, strPtr(ipv6), addr) > 0);
65  }
66  //将接口名转换成为ipv4
67  //hostOrder: true-主机序; false-网络序
68  static uint32_t IPv4FromIf(const std::string & eth, bool hostOrder = true){
69  __SS addr;
70  const socklen_t len = tryIfr(strPtr(eth), &addr);
71  if(sizeof(__SA4) != len)
72  return 0;
73  uint32_t ret = reinterpret_cast<const __SA4 *>(&addr)->sin_addr.s_addr;
74  return (hostOrder ? ntohl(ret) : ret);
75  }
76  //默认构造
77  CSockAddr(){}
78  //设置地址
79  //host: 主机名,域名,ip地址,本机接口名(eth1)
80  //serv: 服务名或者端口号 //ipv4: IPv4 //ipv6: IPv6 //port: 端口号 //hostOrder: true-主机序; false-网络序 //addr: 通用地址结构体 //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
81  //ipv4: IPv4
82  //ipv6: IPv6
83  //port: 端口号 //hostOrder: true-主机序; false-网络序 //addr: 通用地址结构体 //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
84  //hostOrder: true-主机序; false-网络序
85  //addr: 通用地址结构体
86  //len: 地址结构体字节长度 CSockAddr(const std::string & host, const std::string & serv){ __SS addr; socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr); if(setSs(addr, len)) return; assert(!valid()); if(!host.empty() && !setIpAux(host)) return; //invalid host if(!serv.empty() && !setPort(serv)) clear(); //invalid serv } explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){ if(!host.empty()){ if(!setIpAux(host)) return; //invalid host }else if(!setPort("0")) //generate default ip return; assert(valid()); if(port) setPortAux(port, hostOrder); } CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);} CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);} explicit CSockAddr(const __SA4 & addr){setAddr(addr);} explicit CSockAddr(const __SA6 & addr){setAddr(addr);} bool setIp(const std::string & host){ const uint16_t port = getPort(false); //old port if(!setIpAux(host)) return false; assert(valid()); if(port) setPortAux(port, false); return true; } bool setIp(uint32_t ipv4, bool hostOrder = true){ if(setIpv4Aux(ipv4, hostOrder)) return true; assert(!valid() || isIpv6()); const uint16_t port = getPort(false); //old port if(!setIpAux("0.0.0.0")) return false; assert(isIpv4()); if(ipv4) setIpv4Aux(ipv4, hostOrder); if(port) setPortAux(port, false); return true; } bool setIp(const in6_addr & ipv6){ //TODO: in case of invalid or ipv4 if(!isIpv6()) return false; sa<__SA6>()->sin6_addr = ipv6; return true; } bool setPort(const std::string & serv){ char buf[sizeof(__SS)]; __SS * const addr = reinterpret_cast<__SS *>(buf); socklen_t len = tryGai(NULL, strPtr(serv), addr); if(!valid()) return setSs(*addr, len); assert(valid()); uint16_t port = 0; if(sizeof(__SA4) == len){ const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf); port = a4->sin_port; }else if(sizeof(__SA6) == len){ const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf); port = a6->sin6_port; }else return false; return setPortAux(port, false); } bool setPort(uint16_t port, bool hostOrder = true){ if(setPortAux(port, hostOrder)) return true; assert(!valid()); __SS addr; const socklen_t len = tryGai(NULL, "0", &addr); if(!setSs(addr, len)) return false; assert(valid()); if(port) setPortAux(port, hostOrder); return true; } bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);} bool setAddr(const __SA & addr, socklen_t len){ return setAddr(reinterpret_cast<const __SS &>(addr), len); } bool setAddr(const __SA4 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4)); } bool setAddr(const __SA6 & addr){ return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6)); } //获取IPv4 //hostOrder: true-主机序; false-网络序 uint32_t getIpv4(bool hostOrder = true) const{ const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0); return (hostOrder ? htonl(ret) : ret); } //获取IPv6,返回是否成功 bool getIpv6(struct in6_addr & ipv6) const{ if(!isIpv6()) return false; ipv6 = sa<__SA6>()->sin6_addr; return true; } //获取port //hostOrder: true-主机序; false-网络序 uint16_t getPort(bool hostOrder = true) const{ const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port : (isIpv6() ? sa<__SA6>()->sin6_port : 0)); return (hostOrder ? htons(ret) : ret); } //清除地址 void clear(){sa_.clear();} //返回地址是否有效 bool valid() const{return (isIpv4() || isIpv6());} //返回可读字符串 std::string toString() const{ std::string ret = addr4Str(); if(ret.empty()) ret = addr6Str(); if(ret.empty()) return "unknown"; return ret; } //获取协议族(AF_INET/AF_INET6等) int family() const{ if(isIpv4()) return AF_INET; else if(isIpv6()) return AF_INET6; return AF_UNSPEC; } //转换成通用地址结构 const __SA * sockaddr() const{ return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0])); } //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
87  CSockAddr(const std::string & host, const std::string & serv){
88  __SS addr;
89  socklen_t len = tryGai(strPtr(host), strPtr(serv), &addr);
90  if(setSs(addr, len))
91  return;
92  assert(!valid());
93  if(!host.empty() && !setIpAux(host))
94  return; //invalid host
95  if(!serv.empty() && !setPort(serv))
96  clear(); //invalid serv
97  }
98  explicit CSockAddr(const std::string & host, uint16_t port = 0, bool hostOrder = true){
99  if(!host.empty()){
100  if(!setIpAux(host))
101  return; //invalid host
102  }else if(!setPort("0")) //generate default ip
103  return;
104  assert(valid());
105  if(port)
106  setPortAux(port, hostOrder);
107  }
108  CSockAddr(const __SS & addr, socklen_t len){setAddr(addr, len);}
109  CSockAddr(const __SA & addr, socklen_t len){setAddr(addr, len);}
110  explicit CSockAddr(const __SA4 & addr){setAddr(addr);}
111  explicit CSockAddr(const __SA6 & addr){setAddr(addr);}
112  bool setIp(const std::string & host){
113  const uint16_t port = getPort(false); //old port
114  if(!setIpAux(host))
115  return false;
116  assert(valid());
117  if(port)
118  setPortAux(port, false);
119  return true;
120  }
121  bool setIp(uint32_t ipv4, bool hostOrder = true){
122  if(setIpv4Aux(ipv4, hostOrder))
123  return true;
124  assert(!valid() || isIpv6());
125  const uint16_t port = getPort(false); //old port
126  if(!setIpAux("0.0.0.0"))
127  return false;
128  assert(isIpv4());
129  if(ipv4)
130  setIpv4Aux(ipv4, hostOrder);
131  if(port)
132  setPortAux(port, false);
133  return true;
134  }
135  bool setIp(const in6_addr & ipv6){
136  //TODO: in case of invalid or ipv4
137  if(!isIpv6())
138  return false;
139  sa<__SA6>()->sin6_addr = ipv6;
140  return true;
141  }
142  bool setPort(const std::string & serv){
143  char buf[sizeof(__SS)];
144  __SS * const addr = reinterpret_cast<__SS *>(buf);
145  socklen_t len = tryGai(NULL, strPtr(serv), addr);
146  if(!valid())
147  return setSs(*addr, len);
148  assert(valid());
149  uint16_t port = 0;
150  if(sizeof(__SA4) == len){
151  const __SA4 * const a4 = reinterpret_cast<const __SA4 *>(buf);
152  port = a4->sin_port;
153  }else if(sizeof(__SA6) == len){
154  const __SA6 * const a6 = reinterpret_cast<const __SA6 *>(buf);
155  port = a6->sin6_port;
156  }else
157  return false;
158  return setPortAux(port, false);
159  }
160  bool setPort(uint16_t port, bool hostOrder = true){
161  if(setPortAux(port, hostOrder))
162  return true;
163  assert(!valid());
164  __SS addr;
165  const socklen_t len = tryGai(NULL, "0", &addr);
166  if(!setSs(addr, len))
167  return false;
168  assert(valid());
169  if(port)
170  setPortAux(port, hostOrder);
171  return true;
172  }
173  bool setAddr(const __SS & addr, socklen_t len){return setSs(addr, len);}
174  bool setAddr(const __SA & addr, socklen_t len){
175  return setAddr(reinterpret_cast<const __SS &>(addr), len);
176  }
177  bool setAddr(const __SA4 & addr){
178  return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA4));
179  }
180  bool setAddr(const __SA6 & addr){
181  return setAddr(reinterpret_cast<const __SS &>(addr), sizeof(__SA6));
182  }
183  //获取IPv4
184  //hostOrder: true-主机序; false-网络序
185  uint32_t getIpv4(bool hostOrder = true) const{
186  const uint32_t ret = (isIpv4() ? sa<__SA4>()->sin_addr.s_addr : 0);
187  return (hostOrder ? htonl(ret) : ret);
188  }
189  //获取IPv6,返回是否成功
190  bool getIpv6(struct in6_addr & ipv6) const{
191  if(!isIpv6())
192  return false;
193  ipv6 = sa<__SA6>()->sin6_addr;
194  return true;
195  }
196  //获取port
197  //hostOrder: true-主机序; false-网络序
198  uint16_t getPort(bool hostOrder = true) const{
199  const uint16_t ret = (isIpv4() ? sa<__SA4>()->sin_port
200  : (isIpv6() ? sa<__SA6>()->sin6_port
201  : 0));
202  return (hostOrder ? htons(ret) : ret);
203  }
204  //清除地址
205  void clear(){sa_.clear();}
206  //返回地址是否有效
207  bool valid() const{return (isIpv4() || isIpv6());}
208  //返回可读字符串
209  std::string toString() const{
210  std::string ret = addr4Str();
211  if(ret.empty())
212  ret = addr6Str();
213  if(ret.empty())
214  return "unknown";
215  return ret;
216  }
217  //获取协议族(AF_INET/AF_INET6等)
218  int family() const{
219  if(isIpv4())
220  return AF_INET;
221  else if(isIpv6())
222  return AF_INET6;
223  return AF_UNSPEC;
224  }
225  //转换成通用地址结构
226  const __SA * sockaddr() const{
227  return (sa_.empty() ? NULL : reinterpret_cast<const __SA *>(&sa_[0]));
228  }
229  //获取地址结构的字节长度 socklen_t socklen() const{return sa_.size();} private: bool isIpv4() const{ return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family); } bool isIpv6() const{ return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family); } //re-interpret address template<class T> const T * sa() const{ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<const T *>(&sa_[0]); } template<class T> T * sa(){ if(sa_.size() != sizeof(T)) return NULL; return reinterpret_cast<T *>(&sa_[0]); } //translate ipv4 to readable string static std::string ipv4Str(const struct in_addr & addr){ std::string buf(16, 0); if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //translate ipv6 to readable string static std::string ipv6Str(const struct in6_addr & addr){ std::string buf(128, 0); if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size())) return std::string(); buf.resize(std::char_traits<char>::length(buf.c_str())); return buf; } //try to translate current address to readable string std::string addr4Str() const{ if(!isIpv4()) return std::string(); //empty for error const __SA4 * const s = sa<__SA4>(); CToString oss; oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port); return oss.str(); } std::string addr6Str() const{ if(!isIpv6()) return std::string(); //empty for error const __SA6 * const s = sa<__SA6>(); CToString oss; oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port); return oss.str(); } //translate str to C string static const char * strPtr(const std::string & str){ return (str.empty() ? NULL : str.c_str()); } //parse node and service as host/ip and service/port //return: // 0 failed // +n length of addr static socklen_t tryGai(const char * node, const char * service, __SS * addr){ assert(addr); if(NULL == node && NULL == service) return 0; struct addrinfo hints; ::memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; struct addrinfo * ai = NULL; if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai) return 0; socklen_t len = ai->ai_addrlen; ::memcpy(addr, ai->ai_addr, len); //get first addr freeaddrinfo(ai); return len; } //parse node as interface name //return: // 0 failed // +n length of addr static socklen_t tryIfr(const char * node, __SS * addr){ assert(addr); if(NULL == node) return 0; struct ifreq ifr; ::memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, node, IFNAMSIZ); const int fd = socket(AF_INET, SOCK_STREAM, 0); if(fd < 0) return 0; int ret = ioctl(fd, SIOCGIFADDR, &ifr); ::close(fd); if(ret < 0) return 0; ::memset(addr, 0, sizeof(__SS)); ret = ifr.ifr_addr.sa_family; socklen_t len = (AF_INET == ret ? sizeof(__SA4) : (AF_INET6 == ret ? sizeof(__SA6) : 0)); if(len > sizeof ifr.ifr_addr) len = sizeof ifr.ifr_addr; ::memcpy(addr, &ifr.ifr_addr, len); return len; } //parse ip, set addr, clear port bool setIpAux(const std::string & host){ __SS addr; socklen_t len = tryGai(strPtr(host), NULL, &addr); if(!len) len = tryIfr(strPtr(host), &addr); return setSs(addr, len); } //set ipv4 directly bool setIpv4Aux(uint32_t ipv4, bool hostOrder){ if(!isIpv4()) return false; if(hostOrder && ipv4) ipv4 = htonl(ipv4); sa<__SA4>()->sin_addr.s_addr = ipv4; return true; } //set port directly bool setPortAux(uint16_t port, bool hostOrder){ if(hostOrder && port) port = htons(port); if(isIpv4()) sa<__SA4>()->sin_port = port; else if(isIpv6()) sa<__SA6>()->sin6_port = port; else return false; return true; } //set sockaddr_storage directly bool setSs(const __SS & addr, socklen_t len){ if(sizeof(__SA4) != len && sizeof(__SA6) != len) return false; sa_.resize(len); ::memcpy(&sa_[0], &addr, sa_.size()); assert(valid()); return true; } //fields std::string sa_; }; NS_SERVER_END #endif
230  socklen_t socklen() const{return sa_.size();}
231 private:
232  bool isIpv4() const{
233  return (NULL != sa<__SA4>() && AF_INET == sa<__SA4>()->sin_family);
234  }
235  bool isIpv6() const{
236  return (NULL != sa<__SA6>() && AF_INET6 == sa<__SA6>()->sin6_family);
237  }
238  //re-interpret address
239  template<class T>
240  const T * sa() const{
241  if(sa_.size() != sizeof(T))
242  return NULL;
243  return reinterpret_cast<const T *>(&sa_[0]);
244  }
245  template<class T>
246  T * sa(){
247  if(sa_.size() != sizeof(T))
248  return NULL;
249  return reinterpret_cast<T *>(&sa_[0]);
250  }
251  //translate ipv4 to readable string
252  static std::string ipv4Str(const struct in_addr & addr){
253  std::string buf(16, 0);
254  if(NULL == inet_ntop(AF_INET, &addr, &buf[0], buf.size()))
255  return std::string();
256  buf.resize(std::char_traits<char>::length(buf.c_str()));
257  return buf;
258  }
259  //translate ipv6 to readable string
260  static std::string ipv6Str(const struct in6_addr & addr){
261  std::string buf(128, 0);
262  if(NULL == inet_ntop(AF_INET6, &addr, &buf[0], buf.size()))
263  return std::string();
264  buf.resize(std::char_traits<char>::length(buf.c_str()));
265  return buf;
266  }
267  //try to translate current address to readable string
268  std::string addr4Str() const{
269  if(!isIpv4())
270  return std::string(); //empty for error
271  const __SA4 * const s = sa<__SA4>();
272  CToString oss;
273  oss<<ipv4Str(s->sin_addr)<<":"<<ntohs(s->sin_port);
274  return oss.str();
275  }
276  std::string addr6Str() const{
277  if(!isIpv6())
278  return std::string(); //empty for error
279  const __SA6 * const s = sa<__SA6>();
280  CToString oss;
281  oss<<'['<<ipv6Str(s->sin6_addr)<<"]:"<<ntohs(s->sin6_port);
282  return oss.str();
283  }
284  //translate str to C string
285  static const char * strPtr(const std::string & str){
286  return (str.empty() ? NULL : str.c_str());
287  }
288  //parse node and service as host/ip and service/port
289  //return:
290  // 0 failed
291  // +n length of addr
292  static socklen_t tryGai(const char * node, const char * service, __SS * addr){
293  assert(addr);
294  if(NULL == node && NULL == service)
295  return 0;
296  struct addrinfo hints;
297  ::memset(&hints, 0, sizeof hints);
298  hints.ai_family = AF_UNSPEC;
299  hints.ai_socktype = SOCK_STREAM;
300  struct addrinfo * ai = NULL;
301  if(0 != getaddrinfo(node, service, &hints, &ai) || NULL == ai)
302  return 0;
303  socklen_t len = ai->ai_addrlen;
304  ::memcpy(addr, ai->ai_addr, len); //get first addr
305  freeaddrinfo(ai);
306  return len;
307  }
308  //parse node as interface name
309  //return:
310  // 0 failed
311  // +n length of addr
312  static socklen_t tryIfr(const char * node, __SS * addr){
313  assert(addr);
314  if(NULL == node)
315  return 0;
316  struct ifreq ifr;
317  ::memset(&ifr, 0, sizeof ifr);
318  strncpy(ifr.ifr_name, node, IFNAMSIZ);
319  const int fd = socket(AF_INET, SOCK_STREAM, 0);
320  if(fd < 0)
321  return 0;
322  int ret = ioctl(fd, SIOCGIFADDR, &ifr);
323  ::close(fd);
324  if(ret < 0)
325  return 0;
326  ::memset(addr, 0, sizeof(__SS));
327  ret = ifr.ifr_addr.sa_family;
328  socklen_t len = (AF_INET == ret ? sizeof(__SA4)
329  : (AF_INET6 == ret ? sizeof(__SA6) : 0));
330  if(len > sizeof ifr.ifr_addr)
331  len = sizeof ifr.ifr_addr;
332  ::memcpy(addr, &ifr.ifr_addr, len);
333  return len;
334  }
335  //parse ip, set addr, clear port
336  bool setIpAux(const std::string & host){
337  __SS addr;
338  socklen_t len = tryGai(strPtr(host), NULL, &addr);
339  if(!len)
340  len = tryIfr(strPtr(host), &addr);
341  return setSs(addr, len);
342  }
343  //set ipv4 directly
344  bool setIpv4Aux(uint32_t ipv4, bool hostOrder){
345  if(!isIpv4())
346  return false;
347  if(hostOrder && ipv4)
348  ipv4 = htonl(ipv4);
349  sa<__SA4>()->sin_addr.s_addr = ipv4;
350  return true;
351  }
352  //set port directly
353  bool setPortAux(uint16_t port, bool hostOrder){
354  if(hostOrder && port)
355  port = htons(port);
356  if(isIpv4())
357  sa<__SA4>()->sin_port = port;
358  else if(isIpv6())
359  sa<__SA6>()->sin6_port = port;
360  else
361  return false;
362  return true;
363  }
364  //set sockaddr_storage directly
365  bool setSs(const __SS & addr, socklen_t len){
366  if(sizeof(__SA4) != len && sizeof(__SA6) != len)
367  return false;
368  sa_.resize(len);
369  ::memcpy(&sa_[0], &addr, sa_.size());
370  assert(valid());
371  return true;
372  }
373  //fields
374  std::string sa_;
375 };
376 
377 NS_SERVER_END
378 
379 #endif
380 
Definition: to_string.hh:43
Definition: sock_addr.hh:24