void NetworkInterfaceInfo::ParseIPv6Addr()

in source/code/scxsystemlib/networkinterface/networkinterface.cpp [1808:2045]


    void NetworkInterfaceInfo::ParseIPv6Addr(SCXCoreLib::SCXHandle<NetworkInterfaceDependencies> deps)
    {
#if defined(linux)
        class AutoIFAddr
        {
            struct ifaddrs * m_ifAddr;
            SCXCoreLib::SCXHandle<NetworkInterfaceDependencies> m_deps;
        public:
            AutoIFAddr(struct ifaddrs * ifAddr, SCXCoreLib::SCXHandle<NetworkInterfaceDependencies> depsInit):
                    m_ifAddr(ifAddr), m_deps(depsInit)
            {
            }
            ~AutoIFAddr()
            {
                if(m_ifAddr != NULL)
                {
                    m_deps->freeifaddrs(m_ifAddr);
                }
            }
            struct ifaddrs * GetIFAddr()
            {
                return m_ifAddr;
            }
        };

        struct ifaddrs *ifAddrPtr;
        if (deps->getifaddrs(&ifAddrPtr) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" getifaddrs() failed, errno : " + wstrerror(errno) + L'.');
            return;
        }
        AutoIFAddr ifAddr(ifAddrPtr, m_deps);

        struct ifaddrs * ifa = NULL;
        void * pTmpAddr = NULL;

        for (ifa = ifAddr.GetIFAddr(); ifa != NULL; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6 && strcmp(ifa->ifa_name, StrToUTF8(m_name).c_str()) == 0)
            { 
                pTmpAddr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
                char addrStr[INET6_ADDRSTRLEN];
                inet_ntop(AF_INET6, pTmpAddr, addrStr, INET6_ADDRSTRLEN);
                m_ipv6Address.push_back(StrFromUTF8(addrStr));
            }
        }
#endif
#if defined(sun) || defined(hpux) || defined(aix)
        class AutoSocket
        {
            wstring m_devName;
            int m_sock;
            SCXCoreLib::SCXHandle<NetworkInterfaceDependencies> m_deps;
            SCXCoreLib::SCXLogHandle m_log;
        public:
            AutoSocket(int sock, SCXCoreLib::SCXHandle<NetworkInterfaceDependencies> depsInit,
                    SCXCoreLib::SCXLogHandle log, const wstring &devName):
                    m_sock(sock), m_deps(depsInit), m_log(log), m_devName(devName)
            {
            }
            ~AutoSocket()
            {
                if(m_sock != -1)
                {
                    if(m_deps->close(m_sock) != 0)
                    {
                        SCX_LOGERROR(m_log, L"For net device " + m_devName + L" closing socket failed, errno : " +
                            wstrerror(errno) + L'.');
                    }
                }
            }
            int GetSock()
            {
                return m_sock;
            }
        };
        
        AutoSocket sd(deps->socket(AF_INET6, SOCK_DGRAM, 0), m_deps, m_log, m_name);
        if(sd.GetSock() == -1)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name +
                L" opening socket(AF_INET6, SOCK_DGRAM, 0) failed, errno : " + wstrerror(errno) + L'.');
            return;
        }

#if defined(sun)
        int ifCnt = 0;
        struct lifnum lifn;
        lifn.lifn_family = AF_UNSPEC;
        lifn.lifn_flags = 0;
        if (deps->ioctl(sd.GetSock(), SIOCGLIFNUM, &lifn) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGLIFNUM) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }
        ifCnt = lifn.lifn_count;

        if (ifCnt == 0)
        {
            // Nothing to do, and also later we count on the vector size to be more than 0.
            return;
        }

        vector<lifreq> lifcBuff;
        struct lifconf lifc;
        lifcBuff.resize(ifCnt);
        lifc.lifc_len = ifCnt * sizeof (lifreq);
        lifc.lifc_buf = (caddr_t)&lifcBuff[0];// It's safe because size of the vector is always more than 0.
        lifc.lifc_family = AF_UNSPEC;
        lifc.lifc_flags = 0;
        if (deps->ioctl(sd.GetSock(), SIOCGLIFCONF, &lifc) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGLIFCONF) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }

        size_t lifrCnt = lifc.lifc_len / sizeof (lifreq);
        for (size_t i = 0; i < lifrCnt; i++)
        {
            string currName = lifcBuff[i].lifr_name;
            string name = SCXCoreLib::StrToUTF8(m_name);
            string name1 = name + ':';
            if (currName == name || currName.substr(0, name1.size()) == name1)
            {
                struct sockaddr * sockAddr = (struct sockaddr *)&lifcBuff[i].lifr_addr;
                if (sockAddr->sa_family == AF_INET6)
                {
                    char addrStr[INET6_ADDRSTRLEN];
                    inet_ntop(sockAddr->sa_family, &((struct sockaddr_in6 *)sockAddr)->sin6_addr, addrStr, INET6_ADDRSTRLEN);
                    m_ipv6Address.push_back(StrFromUTF8(addrStr)); 
                }
            }
        }
#elif defined(hpux)
        int ifCnt = 0;
        if (deps->ioctl(sd.GetSock(), SIOCGLIFNUM, &ifCnt) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGLIFNUM) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }

        if (ifCnt == 0)
        {
            // Nothing to do, and also later we count on the vector size to be more than 0.
            return;
        }
        vector<if_laddrreq> lifcBuff;
        struct if_laddrconf lifc;
        lifcBuff.resize(ifCnt);
        lifc.iflc_len = ifCnt * sizeof (if_laddrreq);
        lifc.iflc_buf = (caddr_t)&lifcBuff[0];// It's safe because size of the vector is always more than 0.
        if (deps->ioctl(sd.GetSock(), SIOCGLIFCONF, &lifc) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGLIFCONF) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }

        size_t lifrCnt = lifc.iflc_len / sizeof (if_laddrreq);
        for (size_t i = 0; i < lifrCnt; i++)
        {
            string currName = lifcBuff[i].iflr_name;
            string name = SCXCoreLib::StrToUTF8(m_name);
            string name1 = name + ':';
            if (currName == name || currName.substr(0, name1.size()) == name1)
            {
                struct sockaddr * sockAddr = (struct sockaddr *)&lifcBuff[i].iflr_addr;
                if (sockAddr->sa_family == AF_INET6)
                {
                    char addrStr[INET6_ADDRSTRLEN];
                    // We cast sockAddr to char* to stop the warning on RISC machines: sockaddr_in6 more strictly
                    // alligned than sockAddr. Addresses must be right anyway since they're returned by the previous
                    // ioctl(SIOCGLIFCONF) call.
                    inet_ntop(sockAddr->sa_family, &((struct sockaddr_in6 *)((char*)sockAddr))->sin6_addr, addrStr,
                        INET6_ADDRSTRLEN);
                    m_ipv6Address.push_back(StrFromUTF8(addrStr)); 
                }
            }
        }
#elif defined(aix)
// Code inspired by the IBM examples on how to use network system calls.
#if !defined(MAX)
#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
#endif
#define SIZE(p) MAX((p).sa_len, sizeof(p))
        int buffSize = 0;
        if (deps->ioctl(sd.GetSock(), SIOCGSIZIFCONF, &buffSize) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGSIZIFCONF) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }

        vector<char> ifconfBuf;
        ifconfBuf.resize(buffSize);
        struct ifconf ifc;
        ifc.ifc_buf = &ifconfBuf[0];
        ifc.ifc_len = ifconfBuf.size();
        if (deps->ioctl(sd.GetSock(), SIOCGIFCONF, &ifc) != 0)
        {
            SCX_LOGTRACE(m_log, L"For net device " + m_name + L" ioctl(SIOCGIFCONF) failed, errno : " +
                wstrerror(errno) + L'.');
            return;
        }

        char *cp, *cplim;
        struct ifreq *ifr = ifc.ifc_req;
        cp = (char *)ifc.ifc_req;
        cplim = cp + ifc.ifc_len;
        // Iterate through the sequence of variable size data structures containing the interface name. cplim points to
        // the end of the sequence. Each data structure consists of the fixed size name array and variable size
        // additional data whose size is obtained by using the SIZE macro.
        for(; cp < cplim; cp += (sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr)))
        {
            ifr = (struct ifreq *)cp;
            if (0 == strcmp(ifr->ifr_name, StrToUTF8(m_name).c_str()))
            {
                // Interface name matches.
                struct sockaddr *sa;
                sa = (struct sockaddr *)&(ifr->ifr_addr);
                if (sa->sa_family == AF_INET6)
                {
                    // It is IPv6 address.
                    char addrStr[INET6_ADDRSTRLEN];
                    // Translate address to string.
                    inet_ntop(AF_INET6, (struct in6_addr *)&(((struct sockaddr_in6 *)sa)->sin6_addr), addrStr,
                        INET6_ADDRSTRLEN);
                    // Store the address.
                    m_ipv6Address.push_back(StrFromUTF8(addrStr));
                }
            }
        }
#endif
#endif// defined(sun) || defined(hpux) || defined(aix)
}