diff --git a/servant/libservant/EndpointInfo.cpp b/servant/libservant/EndpointInfo.cpp index b7426a5..ca93112 100644 --- a/servant/libservant/EndpointInfo.cpp +++ b/servant/libservant/EndpointInfo.cpp @@ -16,6 +16,8 @@ #include "servant/EndpointInfo.h" #include "servant/TarsLogger.h" +#include "servant/NetworkUtil.h" +#include "util/tc_socket.h" namespace tars { @@ -27,9 +29,10 @@ EndpointInfo::EndpointInfo() , _weight(-1) , _weighttype(0) , _authType(0) +, _isIPv6(false) { _setDivision.clear(); - memset(&_addr,0,sizeof(struct sockaddr_in)); + memset(&_addr,0,sizeof(_addr)); } EndpointInfo::EndpointInfo(const string& host, uint16_t port, EndpointInfo::EType type, int32_t grid, const string & setDivision, int qos, int weight, unsigned int weighttype, int authType) @@ -43,6 +46,7 @@ EndpointInfo::EndpointInfo(const string& host, uint16_t port, EndpointInfo::ETyp , _weighttype(weighttype) , _authType(authType) { + _isIPv6 = TC_Socket::addressIsIPv6(host); try { if(_weighttype == 0) @@ -59,7 +63,14 @@ EndpointInfo::EndpointInfo(const string& host, uint16_t port, EndpointInfo::ETyp _weight = (_weight > 100 ? 100 : _weight); } - NetworkUtil::getAddress(_host, _port, _addr); + if (_isIPv6) + { + NetworkUtil::getAddress(_host, _port, _addr.in6); + } + else + { + NetworkUtil::getAddress(_host, _port, _addr.in); + } _cmpDesc = createCompareDesc(); @@ -139,7 +150,12 @@ uint16_t EndpointInfo::port() const const struct sockaddr_in& EndpointInfo::addr() const { - return _addr; + return _addr.in; +} + +const struct sockaddr * EndpointInfo::addrPtr() const +{ + return _isIPv6 ? (struct sockaddr *)&_addr.in6 : (struct sockaddr *)&_addr.in; } EndpointInfo::EType EndpointInfo::type() const diff --git a/servant/libservant/EndpointManager.cpp b/servant/libservant/EndpointManager.cpp index dcdca00..f8db0a6 100644 --- a/servant/libservant/EndpointManager.cpp +++ b/servant/libservant/EndpointManager.cpp @@ -216,6 +216,21 @@ void QueryEpBase::setObjName(const string & sObjName) } } +bool isRealEndpoint(const string & s, const string & s1) +{ + if (s1.empty()) + return true; + + const string delim = " \t\n\r"; + string::size_type beg; + string::size_type end = 0; + + beg = s1.find_first_not_of(delim, end); + if (s1[beg] != 't' && s1[beg] != 'u' && s1[beg] != 's') + return false; + return true; +} + void QueryEpBase::setEndpoints(const string & sEndpoints, set & setEndpoints) { if(sEndpoints == "") @@ -227,7 +242,7 @@ void QueryEpBase::setEndpoints(const string & sEndpoints, set & se bool bFirstWeightType = true; unsigned int iWeightType = 0; - vector vEndpoints = TC_Common::sepstr(sEndpoints, ":", false); + vector vEndpoints = TC_Common::sepstr(sEndpoints, ":", false, isRealEndpoint); for (size_t i = 0; i < vEndpoints.size(); ++i) { diff --git a/servant/libservant/NetworkUtil.cpp b/servant/libservant/NetworkUtil.cpp index ed8aada..ab8a985 100644 --- a/servant/libservant/NetworkUtil.cpp +++ b/servant/libservant/NetworkUtil.cpp @@ -25,18 +25,12 @@ using namespace std; using namespace tars; -int NetworkUtil::createSocket(bool udp, bool isLocal/* = false*/) +int NetworkUtil::createSocket(bool udp, bool isLocal/* = false*/, bool isIpv6/* = false*/) { - int fd; - - if (udp) - { - fd = socket((isLocal ? PF_LOCAL : PF_INET), SOCK_DGRAM, IPPROTO_UDP); - } - else - { - fd = socket((isLocal ? PF_LOCAL : PF_INET), SOCK_STREAM, IPPROTO_TCP); - } + int domain = isLocal ? PF_LOCAL : (isIpv6 ? PF_INET6 : PF_INET); + int type = udp ? SOCK_DGRAM : SOCK_STREAM; + int protocol = udp ? IPPROTO_UDP : IPPROTO_TCP; + int fd = socket(domain, type, protocol); if (fd == INVALID_SOCKET) { @@ -127,6 +121,17 @@ void NetworkUtil::doBind(int fd, struct sockaddr_in& addr) getsockname(fd, reinterpret_cast(&addr), &len); } +void NetworkUtil::doBind(int fd, const struct sockaddr *addr, socklen_t len) +{ + if (bind(fd, addr, len) == SOCKET_ERROR) + { + closeSocketNoThrow(fd); + ostringstream os; + os << "doBind ex:(" << errorToString(errno) << ")" << __FILE__ << ":" << __LINE__; + throw TarsNetSocketException(os.str()); + } +} + bool NetworkUtil::doConnect(int fd, const struct sockaddr_in& addr) { bool bConnected = false; @@ -146,6 +151,19 @@ bool NetworkUtil::doConnect(int fd, const struct sockaddr_in& addr) return bConnected; } +bool NetworkUtil::doConnect(int fd, const struct sockaddr *addr, socklen_t len) +{ + int iRet = ::connect(fd, addr, len); + + if (iRet == -1 && errno != EINPROGRESS) + { + ::close(fd); + throw TarsNetConnectException(strerror(errno)); + } + + return iRet == 0 ? true : false; +} + void NetworkUtil::getAddress(const string& host, int port, struct sockaddr_in& addr) { memset(&addr, 0, sizeof(struct sockaddr_in)); @@ -188,6 +206,46 @@ void NetworkUtil::getAddress(const string& host, int port, struct sockaddr_in& a } } + +void NetworkUtil::getAddress(const string& host, int port, struct sockaddr_in6& addr) +{ +#define RETRY_TIMES (5) + struct addrinfo *res = NULL; + struct addrinfo hints; + + memset(&addr, 0, sizeof(addr)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET6; + + ostringstream os; + os << port; + + int ret = -1; + int retry = RETRY_TIMES; + do + { + ret = getaddrinfo(host.c_str(), os.str().c_str(), &hints, &res); + } + while (NULL == res && ret == EAI_AGAIN && --retry >= 0); + + if (ret) + { + ostringstream ex; + ex << "DNSException ex:(" << errorToString(errno) << ":" << gai_strerror(ret) << ":" << ret << ")" << + "|" << host << ":" << port << "| at " << __FUNCTION__ << ":" << __LINE__; + if (res) + { + freeaddrinfo(res); + } + throw TarsNetSocketException(ex.str()); + } + assert(res); + assert(res->ai_family == PF_INET6); + memcpy(&addr, res->ai_addr, sizeof(addr)); + freeaddrinfo(res); +#undef RETRY_TIMES +} + string NetworkUtil::errorToString(int error) { return strerror(error); diff --git a/servant/libservant/Transceiver.cpp b/servant/libservant/Transceiver.cpp index b56d5fc..0cda3cc 100644 --- a/servant/libservant/Transceiver.cpp +++ b/servant/libservant/Transceiver.cpp @@ -89,16 +89,17 @@ void Transceiver::connect() if (_ep.type() == EndpointInfo::UDP) { - fd = NetworkUtil::createSocket(true); + fd = NetworkUtil::createSocket(true, false, _ep.isIPv6()); NetworkUtil::setBlock(fd, false); _connStatus = eConnected; } else { - fd = NetworkUtil::createSocket(false); + fd = NetworkUtil::createSocket(false, false, _ep.isIPv6()); NetworkUtil::setBlock(fd, false); - bool bConnected = NetworkUtil::doConnect(fd, _ep.addr()); + socklen_t len = _ep.isIPv6() ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + bool bConnected = NetworkUtil::doConnect(fd, _ep.addrPtr(), len); if(bConnected) { setConnected(); diff --git a/servant/servant/EndpointInfo.h b/servant/servant/EndpointInfo.h index 2ef0f80..f0fc869 100644 --- a/servant/servant/EndpointInfo.h +++ b/servant/servant/EndpointInfo.h @@ -18,7 +18,7 @@ #define __TARS_ENDPOINT_INFO_H_ #include "servant/Global.h" -#include "servant/NetworkUtil.h" +#include "util/tc_socket.h" using namespace std; @@ -122,6 +122,13 @@ public: */ const struct sockaddr_in& addr() const; + /** + * Get ipv4 or ipv6 struct sockaddr + * + * @return const struct sockaddr * + */ + const struct sockaddr * addrPtr() const; + /** * 返回端口类型 * @@ -148,6 +155,12 @@ public: */ int authType() const { return _authType; } + /** + * @brief is ipv6 socket or not + * @return true if is ipv6 + */ + bool isIPv6() const { return _isIPv6; } + /** * 等于 * @param r @@ -233,7 +246,11 @@ private: /** * 地址 */ - struct sockaddr_in _addr; + union + { + struct sockaddr_in in; + struct sockaddr_in6 in6; + } _addr; /** * 比较的地址字符串描述 @@ -249,6 +266,11 @@ private: * 认证类型 */ int _authType; + + /** + * _host is IPv6 or not + */ + bool _isIPv6; }; ///////////////////////////////////////////////////////////////////////////// } diff --git a/servant/servant/NetworkUtil.h b/servant/servant/NetworkUtil.h index 7f29cd7..00b7b94 100644 --- a/servant/servant/NetworkUtil.h +++ b/servant/servant/NetworkUtil.h @@ -41,7 +41,7 @@ struct NetworkUtil static const int INVALID_SOCKET = -1; static const int SOCKET_ERROR = -1; - static int createSocket(bool, bool isLocal = false); + static int createSocket(bool, bool isLocal = false, bool isIpv6 = false); static void closeSocketNoThrow(int); @@ -53,10 +53,16 @@ struct NetworkUtil static void doBind(int, struct sockaddr_in&); + static void doBind(int, const struct sockaddr *, socklen_t); + static bool doConnect(int, const struct sockaddr_in&); + static bool doConnect(int, const struct sockaddr *, socklen_t); + static void getAddress(const std::string&, int, struct sockaddr_in&); + static void getAddress(const std::string&, int, struct sockaddr_in6&); + static std::string errorToString(int); }; diff --git a/servant/servant/StatReport.h b/servant/servant/StatReport.h index d3b3a27..854599b 100644 --- a/servant/servant/StatReport.h +++ b/servant/servant/StatReport.h @@ -76,7 +76,7 @@ public: typedef TC_LoopQueue stat_queue; const static int MAX_MASTER_NAME_LEN = 127; - const static int MAX_MASTER_IP_LEN = 20; + const static int MAX_MASTER_IP_LEN = 50; const static int MAX_REPORT_SIZE = 1400; //上报的最大大小限制 const static int MIN_REPORT_SIZE = 500; //上报的最小大小限制 const static int STAT_PROTOCOL_LEN = 100; //一次stat mic上报纯协议部分占用大小,用来控制udp大小防止超MTU diff --git a/util/include/util/tc_clientsocket.h b/util/include/util/tc_clientsocket.h index 1b5476a..e2cacd1 100644 --- a/util/include/util/tc_clientsocket.h +++ b/util/include/util/tc_clientsocket.h @@ -98,6 +98,7 @@ public: _weight = l._weight; _weighttype = l._weighttype; _authType = l._authType; + _isIPv6 = l._isIPv6; } /** @@ -119,6 +120,7 @@ public: _weight = l._weight; _weighttype = l._weighttype; _authType = l._authType; + _isIPv6 = l._isIPv6; } return *this; @@ -132,7 +134,9 @@ public: */ bool operator == (const TC_Endpoint& l) { - return (_host == l._host && _port == l._port && _timeout == l._timeout && _type == l._type && _grid == l._grid && _qos == l._qos && _weight == l._weight && _weighttype == l._weighttype && _authType == l._authType); + return (_host == l._host && _port == l._port && _timeout == l._timeout && _type == l._type && + _grid == l._grid && _qos == l._qos && _weight == l._weight && _weighttype == l._weighttype && + _authType == l._authType && _isIPv6 == l._isIPv6); } /** @@ -255,6 +259,12 @@ public: */ bool isUnixLocal() const { return _port == 0; } + /** + * @brief is ipv6 socket or not + * @return true if is ipv6 + */ + bool isIPv6() const { return _isIPv6; } + /** * @brief 获取认证类型 */ @@ -356,6 +366,11 @@ protected: * 鉴权类型 */ int _authType; + + /** + * _host is ipv6 or not + */ + bool _isIPv6; }; /*************************************TC_ClientSocket**************************************/ @@ -397,6 +412,7 @@ public: _ip = sIp; _port = iPort; _timeout = iTimeout; + _isIPv6 = TC_Socket::addressIsIPv6(sIp); } /** @@ -450,6 +466,11 @@ protected: * 超时时间, 毫秒 */ int _timeout; + + /** + * _ip is ipv6 or not + */ + int _isIPv6; }; /** diff --git a/util/include/util/tc_common.h b/util/include/util/tc_common.h index 29375c9..e41dde9 100644 --- a/util/include/util/tc_common.h +++ b/util/include/util/tc_common.h @@ -241,6 +241,7 @@ public: template static T strto(const string &sStr, const string &sDefault); + typedef bool (*depthJudge)(const string& str1, const string& str2); /** * @brief 解析字符串,用分隔符号分隔,保存在vector里 * @@ -255,10 +256,11 @@ public: * @param sStr 输入字符串 * @param sSep 分隔字符串(每个字符都算为分隔符) * @param withEmpty true代表空的也算一个元素, false时空的过滤 + * @param depthJudge 对分割后的字符再次进行判断 * @return 解析后的字符vector */ template - static vector sepstr(const string &sStr, const string &sSep, bool withEmpty = false); + static vector sepstr(const string &sStr, const string &sSep, bool withEmpty = false, depthJudge judge = nullptr); /** * @brief T型转换成字符串,只要T能够使用ostream对象用<<重载,即可以被该函数支持 @@ -639,45 +641,56 @@ T TC_Common::strto(const string &sStr, const string &sDefault) template -vector TC_Common::sepstr(const string &sStr, const string &sSep, bool withEmpty) +vector TC_Common::sepstr(const string &sStr, const string &sSep, bool withEmpty, TC_Common::depthJudge judge) { vector vt; string::size_type pos = 0; string::size_type pos1 = 0; + int pos_tmp = -1; while(true) { string s; + string s1; pos1 = sStr.find_first_of(sSep, pos); if(pos1 == string::npos) { if(pos + 1 <= sStr.length()) { - s = sStr.substr(pos); + s = sStr.substr(-1 != pos_tmp ? pos_tmp : pos); + s1 = ""; } } - else if(pos1 == pos) + else if(pos1 == pos && (pos1 + 1 == sStr.length())) { s = ""; + s1 = ""; } else { - s = sStr.substr(pos, pos1 - pos); + s = sStr.substr(-1 != pos_tmp ? pos_tmp : pos, pos1 - (-1 != pos_tmp ? pos_tmp : pos)); + s1 = sStr.substr(pos1 + 1); + if (-1 == pos_tmp) + pos_tmp = pos; pos = pos1; } - if(withEmpty) + if (nullptr == judge || judge(s, s1)) { - vt.push_back(strto(s)); - } - else - { - if(!s.empty()) + if(withEmpty) { - T tmp = strto(s); - vt.push_back(tmp); + vt.push_back(strto(s)); } + else + { + if(!s.empty()) + { + T tmp = strto(s); + vt.push_back(tmp); + } + } + pos_tmp = -1; } if(pos1 == string::npos) diff --git a/util/include/util/tc_epoll_server.h b/util/include/util/tc_epoll_server.h index c640e84..addd173 100644 --- a/util/include/util/tc_epoll_server.h +++ b/util/include/util/tc_epoll_server.h @@ -1474,7 +1474,7 @@ public: * 新连接建立 * @param fd */ - bool accept(int fd); + bool accept(int fd, int domain = AF_INET); /** * 绑定端口 diff --git a/util/include/util/tc_socket.h b/util/include/util/tc_socket.h index 34622a8..d394e04 100644 --- a/util/include/util/tc_socket.h +++ b/util/include/util/tc_socket.h @@ -433,7 +433,7 @@ public: * @throws TC_Socket_Exception * @return 本地所有ip */ - static vector getLocalHosts(); + static vector getLocalHosts(int domain = AF_INET); /** * @brief 设置socket方式. @@ -464,6 +464,30 @@ public: */ static void parseAddr(const string &sAddr, struct in_addr &stAddr); + /** + * @brief 解析地址, 从字符串(ipv6或域名), 解析到in6_addr结构. + * + * @param sAddr 字符串 + * @param stAddr 地址 + * @throws TC_Socket_Exception + * @return + */ + static void parseAddr(const string &sAddr, struct in6_addr &stAddr); + + /** + * @brief: Determine whether an address is ipv6 by including the character ':' + * if address is a domain name, return default(not use now) + * @param addr: ip address or domain name + * @param def_value: if address is a domain name, return default(not use now) + * @return: return true if addr is ipv6, false by ipv4, and default by domain name + */ + static bool addressIsIPv6(const string& addr, bool def_value = false) + { + #define IPv6_ADDRESS_CHAR ':' + return (addr.find(IPv6_ADDRESS_CHAR) != string::npos) ? true : false; + #undef IPv6_ADDRESS_CHAR + } + /** * @brief 绑定. * diff --git a/util/src/tc_clientsocket.cpp b/util/src/tc_clientsocket.cpp index 4a45654..a4ed205 100644 --- a/util/src/tc_clientsocket.cpp +++ b/util/src/tc_clientsocket.cpp @@ -19,6 +19,7 @@ #include "util/tc_clientsocket.h" #include "util/tc_epoller.h" #include "util/tc_common.h" +#include "util/tc_socket.h" namespace tars { @@ -33,6 +34,7 @@ TC_Endpoint::TC_Endpoint() _weight = -1; _weighttype = 0; _authType = 0; + _isIPv6 = false; } void TC_Endpoint::init(const string& host, int port, int timeout, int type, int grid, int qos, int weight, unsigned int weighttype, int authType) @@ -59,6 +61,8 @@ void TC_Endpoint::init(const string& host, int port, int timeout, int type, int } _authType = authType; + + _isIPv6 = TC_Socket::addressIsIPv6(_host); } void TC_Endpoint::parse(const string &str) @@ -239,6 +243,7 @@ void TC_Endpoint::parse(const string &str) { const_cast(_host) = "0.0.0.0"; } + _isIPv6 = TC_Socket::addressIsIPv6(_host); if (_authType < 0) _authType = 0; @@ -256,15 +261,7 @@ int TC_TCPClient::checkSocket() { try { - if(_port == 0) - { - _socket.createSocket(SOCK_STREAM, AF_LOCAL); - } - else - { - _socket.createSocket(SOCK_STREAM, AF_INET); - - } + _socket.createSocket(SOCK_STREAM, _port ? (_isIPv6 ? AF_INET6 : AF_INET) : AF_LOCAL); //设置非阻塞模式 _socket.setblock(false); @@ -631,14 +628,7 @@ int TC_UDPClient::checkSocket() { try { - if(_port == 0) - { - _socket.createSocket(SOCK_DGRAM, AF_LOCAL); - } - else - { - _socket.createSocket(SOCK_DGRAM, AF_INET); - } + _socket.createSocket(SOCK_DGRAM, _port ? (_isIPv6 ? AF_INET6 : AF_INET) : AF_LOCAL); } catch(TC_Socket_Exception &ex) { diff --git a/util/src/tc_epoll_server.cpp b/util/src/tc_epoll_server.cpp index 227a6c9..6317c39 100644 --- a/util/src/tc_epoll_server.cpp +++ b/util/src/tc_epoll_server.cpp @@ -630,7 +630,7 @@ TC_EpollServer::NetThread::Connection::Connection(TC_EpollServer::BindAdapter *p _iLastRefreshTime = TNOW; - _sock.init(fd, true, AF_INET); + _sock.init(fd, true, pBindAdapter->_ep.isIPv6() ? AF_INET6 : AF_INET); } TC_EpollServer::NetThread::Connection::Connection(BindAdapter *pBindAdapter, int fd) @@ -651,7 +651,7 @@ TC_EpollServer::NetThread::Connection::Connection(BindAdapter *pBindAdapter, int { _iLastRefreshTime = TNOW; - _sock.init(fd, false, AF_INET); + _sock.init(fd, false, pBindAdapter->_ep.isIPv6() ? AF_INET6 : AF_INET); } TC_EpollServer::NetThread::Connection::Connection(BindAdapter *pBindAdapter) @@ -1583,7 +1583,7 @@ TC_EpollServer::BindAdapterPtr TC_EpollServer::NetThread::getBindAdapter(const s void TC_EpollServer::NetThread::bind(const TC_Endpoint &ep, TC_Socket &s) { - int type = ep.isUnixLocal()?AF_LOCAL:AF_INET; + int type = ep.isUnixLocal() ? AF_LOCAL : ep.isIPv6() ? AF_INET6 : AF_INET; if(ep.isTcp()) { @@ -1698,11 +1698,13 @@ void TC_EpollServer::NetThread::terminate() _epoller.mod(_shutdown.getfd(), H64(ET_CLOSE), EPOLLOUT); } -bool TC_EpollServer::NetThread::accept(int fd) +bool TC_EpollServer::NetThread::accept(int fd, int domain) { - struct sockaddr_in stSockAddr; + struct sockaddr_in stSockAddr4; + struct sockaddr_in6 stSockAddr6; - socklen_t iSockAddrSize = sizeof(sockaddr_in); + socklen_t iSockAddrSize = (AF_INET6 == domain) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); + struct sockaddr *stSockAddr = (AF_INET6 == domain) ? (struct sockaddr *)&stSockAddr6 : (struct sockaddr *)&stSockAddr4; TC_Socket cs; @@ -1711,9 +1713,9 @@ bool TC_EpollServer::NetThread::accept(int fd) //接收连接 TC_Socket s; - s.init(fd, false, AF_INET); + s.init(fd, false, domain); - int iRetCode = s.accept(cs, (struct sockaddr *) &stSockAddr, iSockAddrSize); + int iRetCode = s.accept(cs, stSockAddr, iSockAddrSize); if (iRetCode > 0) { @@ -1721,14 +1723,12 @@ bool TC_EpollServer::NetThread::accept(int fd) uint16_t port; - char sAddr[INET_ADDRSTRLEN] = "\0"; + char sAddr[INET6_ADDRSTRLEN] = "\0"; - struct sockaddr_in *p = (struct sockaddr_in *)&stSockAddr; - - inet_ntop(AF_INET, &p->sin_addr, sAddr, sizeof(sAddr)); + inet_ntop(domain, (AF_INET6 == domain) ? (const void *)&stSockAddr6.sin6_addr : (const void *)&stSockAddr4.sin_addr, sAddr, sizeof(sAddr)); ip = sAddr; - port = ntohs(p->sin_port); + port = (AF_INET6 == domain) ? ntohs(stSockAddr6.sin6_port) : ntohs(stSockAddr4.sin_port); debug("accept [" + ip + ":" + TC_Common::tostr(port) + "] [" + TC_Common::tostr(cs.getfd()) + "] incomming"); @@ -2085,7 +2085,7 @@ void TC_EpollServer::NetThread::run() bool ret; do { - ret = accept(ev.data.u32); + ret = accept(ev.data.u32, it->second->_ep.isIPv6() ? AF_INET6 : AF_INET); }while(ret); } } diff --git a/util/src/tc_socket.cpp b/util/src/tc_socket.cpp index fc480af..8698162 100644 --- a/util/src/tc_socket.cpp +++ b/util/src/tc_socket.cpp @@ -75,21 +75,19 @@ void TC_Socket::createSocket(int iSocketType, int iDomain) void TC_Socket::getPeerName(string &sPeerAddress, uint16_t &iPeerPort) { - assert(_iDomain == AF_INET); + assert(_iDomain == AF_INET && _iDomain == AF_INET6); - struct sockaddr stPeer; - bzero(&stPeer, sizeof(struct sockaddr)); - socklen_t iPeerLen = sizeof(sockaddr); + char sAddr[INET6_ADDRSTRLEN] = "\0"; + struct sockaddr_in stPeer4; + struct sockaddr_in6 stPeer6; + struct sockaddr *stPeer = (AF_INET6 == _iDomain) ? (struct sockaddr *)&stPeer6 : (struct sockaddr *)&stPeer4; + socklen_t iPeerLen = (AF_INET6 == _iDomain) ? sizeof(stPeer6) : sizeof(stPeer4); - getPeerName(&stPeer, iPeerLen); - - char sAddr[INET_ADDRSTRLEN] = "\0"; - struct sockaddr_in *p = (struct sockaddr_in *)&stPeer; - - inet_ntop(_iDomain, &p->sin_addr, sAddr, sizeof(sAddr)); - - sPeerAddress= sAddr; - iPeerPort = ntohs(p->sin_port); + bzero(stPeer, iPeerLen); + getPeerName(stPeer, iPeerLen); + inet_ntop(_iDomain, (AF_INET6 == _iDomain) ? (const void*)&stPeer6.sin6_addr : (const void *)&stPeer4.sin_addr, sAddr, sizeof(sAddr)); + sPeerAddress = sAddr; + iPeerPort = (AF_INET6 == _iDomain) ? ntohs(stPeer6.sin6_port) : ntohs(stPeer4.sin_port); } void TC_Socket::getPeerName(string &sPathName) @@ -114,21 +112,19 @@ void TC_Socket::getPeerName(struct sockaddr *pstPeerAddr, socklen_t &iPeerLen) void TC_Socket::getSockName(string &sSockAddress, uint16_t &iSockPort) { - assert(_iDomain == AF_INET); + assert(_iDomain == AF_INET || _iDomain == AF_INET6); - struct sockaddr stSock; - bzero(&stSock, sizeof(struct sockaddr)); - socklen_t iSockLen = sizeof(sockaddr); - - getSockName(&stSock, iSockLen); - - char sAddr[INET_ADDRSTRLEN] = "\0"; - struct sockaddr_in *p = (struct sockaddr_in *)&stSock; - - inet_ntop(_iDomain, &p->sin_addr, sAddr, sizeof(sAddr)); + char sAddr[INET6_ADDRSTRLEN] = "\0"; + struct sockaddr_in6 in6; + struct sockaddr_in in4; + struct sockaddr *in = (AF_INET6 == _iDomain) ? (struct sockaddr *)&in6 : (struct sockaddr *)&in4; + socklen_t len = (AF_INET6 == _iDomain) ? sizeof(in6) : sizeof(in4); + bzero(in, len); + getSockName(in, len); + inet_ntop(_iDomain, (AF_INET6 == _iDomain) ? (const void *)&in6.sin6_addr : (const void *)&in4.sin_addr, sAddr, sizeof(sAddr)); sSockAddress = sAddr; - iSockPort = ntohs(p->sin_port); + iSockPort = (AF_INET6 == _iDomain) ? ntohs(in6.sin6_port) : ntohs(in4.sin_port); } void TC_Socket::getSockName(string &sPathName) @@ -192,29 +188,80 @@ void TC_Socket::parseAddr(const string &sAddr, struct in_addr &stSinAddr) } } +void TC_Socket::parseAddr(const string &sAddr, struct in6_addr &stSinAddr) +{ + int iRet = inet_pton(AF_INET6, sAddr.c_str(), &stSinAddr); + if(iRet < 0) + { + throw TC_Socket_Exception("[TC_Socket::parseAddr6] inet_pton error", errno); + } + else if(iRet == 0) + { + struct hostent stHostent; + struct hostent *pstHostent; + char buf[2048] = "\0"; + int iError; + + gethostbyname2_r(sAddr.c_str(), AF_INET6, &stHostent, buf, sizeof(buf), &pstHostent, &iError); + + if (pstHostent == NULL) + { + throw TC_Socket_Exception("[TC_Socket::parseAddr6] gethostbyname2_r error! :" + string(hstrerror(iError))); + } + else + { + if (pstHostent->h_addrtype != AF_INET6) + { + throw TC_Socket_Exception("[TC_Socket::parseAddr6] gethostbyname2_r return addrtype is not AF_INET6"); + } + stSinAddr = *(struct in6_addr *) pstHostent->h_addr; + } + } +} + void TC_Socket::bind(const string &sServerAddr, int port) { - assert(_iDomain == AF_INET); + assert(_iDomain == AF_INET || _iDomain == AF_INET6); - struct sockaddr_in bindAddr; + struct sockaddr_in6 bindAddr6; + struct sockaddr_in bindAddr4; + struct sockaddr *bindAddr = (AF_INET6 == _iDomain) ? (struct sockaddr *)&bindAddr6 : (struct sockaddr *)&bindAddr4; + socklen_t len = (AF_INET6 == _iDomain) ? sizeof(bindAddr6) : sizeof(bindAddr4); - bzero(&bindAddr, sizeof(bindAddr)); + bzero(bindAddr, len); - bindAddr.sin_family = _iDomain; - bindAddr.sin_port = htons(port); - - if (sServerAddr == "") + if (AF_INET6 == _iDomain) { - bindAddr.sin_addr.s_addr = htonl(INADDR_ANY); + bindAddr6.sin6_family = _iDomain; + bindAddr6.sin6_port = htons(port); + + if (sServerAddr == "") + { + bindAddr6.sin6_addr = in6addr_any; + } + else + { + parseAddr(sServerAddr, bindAddr6.sin6_addr); + } } else { - parseAddr(sServerAddr, bindAddr.sin_addr); + bindAddr4.sin_family = _iDomain; + bindAddr4.sin_port = htons(port); + + if (sServerAddr == "") + { + bindAddr4.sin_addr.s_addr = htonl(INADDR_ANY); + } + else + { + parseAddr(sServerAddr, bindAddr4.sin_addr); + } } try { - bind((struct sockaddr *)(&bindAddr), sizeof(bindAddr)); + bind(bindAddr, len); } catch(...) { @@ -268,28 +315,41 @@ void TC_Socket::close() int TC_Socket::connectNoThrow(const string &sServerAddr, uint16_t port) { - assert(_iDomain == AF_INET); + assert(_iDomain == AF_INET || _iDomain == AF_INET6); if (sServerAddr == "") { throw TC_Socket_Exception("[TC_Socket::connect] server address is empty error!"); } - struct sockaddr_in serverAddr; - bzero(&serverAddr, sizeof(serverAddr)); + struct sockaddr_in6 serverAddr6; + struct sockaddr_in serverAddr4; + struct sockaddr *serverAddr = (AF_INET6 == _iDomain) ? (struct sockaddr *)&serverAddr6 : (struct sockaddr *)&serverAddr4; + socklen_t len = (AF_INET6 == _iDomain) ? sizeof(serverAddr6) : sizeof(serverAddr4); - serverAddr.sin_family = _iDomain; - parseAddr(sServerAddr, serverAddr.sin_addr); - serverAddr.sin_port = htons(port); + bzero(serverAddr, len); - return connect((struct sockaddr *)(&serverAddr), sizeof(serverAddr)); + if (AF_INET6 == _iDomain) + { + serverAddr6.sin6_family = _iDomain; + parseAddr(sServerAddr, serverAddr6.sin6_addr); + serverAddr6.sin6_port = htons(port); + } + else + { + serverAddr4.sin_family = _iDomain; + parseAddr(sServerAddr, serverAddr4.sin_addr); + serverAddr4.sin_port = htons(port); + } + + return connect(serverAddr, len); } int TC_Socket::connectNoThrow(struct sockaddr* addr) { - assert(_iDomain == AF_INET); + assert(_iDomain == AF_INET || _iDomain == AF_INET6); - return connect(addr, sizeof(struct sockaddr)); + return connect(addr, (AF_INET6 == _iDomain) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); } void TC_Socket::connect(const string &sServerAddr, uint16_t port) @@ -349,23 +409,21 @@ int TC_Socket::send(const void *pvBuf, size_t iLen, int iFlag) int TC_Socket::recvfrom(void *pvBuf, size_t iLen, string &sFromAddr, uint16_t &iFromPort, int iFlags) { - struct sockaddr stFromAddr; - socklen_t iFromLen = sizeof(struct sockaddr); - struct sockaddr_in *p = (struct sockaddr_in *)&stFromAddr; + int iBytes; + struct sockaddr_in6 stFromAddr6; + struct sockaddr_in stFromAddr4; + struct sockaddr *stFromAddr = (AF_INET6 == _iDomain) ? (struct sockaddr *)&stFromAddr6 : (struct sockaddr *)&stFromAddr4; + socklen_t iFromLen = (AF_INET6 == _iDomain) ? sizeof(stFromAddr6) : sizeof(stFromAddr4); - bzero(&stFromAddr, sizeof(struct sockaddr)); - - int iBytes = recvfrom(pvBuf, iLen, &stFromAddr, iFromLen, iFlags); + bzero(stFromAddr, iFromLen); + iBytes = recvfrom(pvBuf, iLen, stFromAddr, iFromLen, iFlags); if (iBytes >= 0) { - char sAddr[INET_ADDRSTRLEN] = "\0"; - - inet_ntop(_iDomain, &p->sin_addr, sAddr, sizeof(sAddr)); - + char sAddr[INET6_ADDRSTRLEN] = "\0"; + inet_ntop(_iDomain, (AF_INET6 == _iDomain) ? (const void *)&stFromAddr6.sin6_addr : (const void *)&stFromAddr4.sin_addr, sAddr, sizeof(sAddr)); sFromAddr = sAddr; - iFromPort = ntohs(p->sin_port); + iFromPort = (AF_INET6 == _iDomain) ? ntohs(stFromAddr6.sin6_port) : ntohs(stFromAddr4.sin_port); } - return iBytes; } @@ -376,24 +434,43 @@ int TC_Socket::recvfrom(void *pvBuf, size_t iLen, struct sockaddr *pstFromAddr, int TC_Socket::sendto(const void *pvBuf, size_t iLen, const string &sToAddr, uint16_t port, int iFlags) { - struct sockaddr_in toAddr; + struct sockaddr_in6 toAddr6; + struct sockaddr_in toAddr4; + struct sockaddr *toAddr = (AF_INET6 == _iDomain) ? (struct sockaddr *)&toAddr6 : (struct sockaddr *)&toAddr4; + socklen_t len = (AF_INET6 == _iDomain) ? sizeof(toAddr6) : sizeof(toAddr4); - bzero(&toAddr, sizeof(struct sockaddr_in)); - - toAddr.sin_family = _iDomain; - - if (sToAddr == "") + bzero(toAddr, len); + if (AF_INET6 == _iDomain) { - toAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); + toAddr6.sin6_family = _iDomain; + + if (sToAddr == "") + { + //toAddr.sin6_addr = in6addr_linklocal_allrouters; + } + else + { + parseAddr(sToAddr, toAddr6.sin6_addr); + } + toAddr6.sin6_port = htons(port); } else { - parseAddr(sToAddr, toAddr.sin_addr); + toAddr4.sin_family = _iDomain; + + if (sToAddr == "") + { + toAddr4.sin_addr.s_addr = htonl(INADDR_BROADCAST); + } + else + { + parseAddr(sToAddr, toAddr4.sin_addr); + } + + toAddr4.sin_port = htons(port); } - toAddr.sin_port = htons(port); - - return sendto(pvBuf, iLen, (struct sockaddr *)(&toAddr), sizeof(toAddr), iFlags); + return sendto(pvBuf, iLen, toAddr, len, iFlags); } int TC_Socket::sendto(const void *pvBuf, size_t iLen, struct sockaddr *pstToAddr, socklen_t iToLen, int iFlags) @@ -565,12 +642,12 @@ void TC_Socket::createPipe(int fds[2], bool bBlock) } } -vector TC_Socket::getLocalHosts() +vector TC_Socket::getLocalHosts(int domain) { vector result; TC_Socket ts; - ts.createSocket(SOCK_STREAM, AF_INET); + ts.createSocket(SOCK_STREAM, domain); int cmd = SIOCGIFCONF; @@ -619,6 +696,16 @@ vector TC_Socket::getLocalHosts() result.push_back(sAddr); } } + else if (ifr[i].ifr_addr.sa_family == AF_INET6) + { + struct sockaddr_in6* addr = reinterpret_cast(&ifr[i].ifr_addr); + if(!memcmp(&addr->sin6_addr, &in6addr_any, sizeof(addr->sin6_addr))) + { + char sAddr[INET6_ADDRSTRLEN] = "\0"; + inet_ntop(AF_INET6, &(*addr).sin6_addr, sAddr, sizeof(sAddr)); + result.push_back(sAddr); + } + } } free(ifc.ifc_buf); @@ -626,5 +713,12 @@ vector TC_Socket::getLocalHosts() return result; } +bool addressIsIPv6(const string& addr, bool def_value) +{ +#define IPv6_ADDRESS_CHAR ':' + return (addr.find(IPv6_ADDRESS_CHAR) != string::npos) ? true : false; +#undef IPv6_ADDRESS_CHAR +} + }