Changeset 801


Ignore:
Timestamp:
Oct 20, 2010, 1:09:45 AM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

network: QNetworkInterface: Fixed: hardwareAddress() returned null instead of a real MAC; netmask() returned null; allInterfaces() could sometimes return non-existent interfaces. Closes #63.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/network/kernel/qnetworkinterface_os2.cpp

    r783 r801  
    5454#include <sys/sockio.h>
    5555#include <net/if.h>
     56
    5657
    5758#include <qplatformdefs.h>
    5859
    5960QT_BEGIN_NAMESPACE
    60 
    61 static QHostAddress addressFromSockaddr(sockaddr *sa)
    62 {
    63     QHostAddress address;
    64     if (!sa)
    65         return address;
    66 
    67     if (sa->sa_family == AF_INET)
    68         address.setAddress(htonl(((sockaddr_in *)sa)->sin_addr.s_addr));
    69     return address;
    70 
    71 }
    7261
    7362static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
     
    7867    flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
    7968    flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
    80 #ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT
    8169    flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
    82 #endif
    83 
    84 #ifdef IFF_MULTICAST
    8570    flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
    86 #endif
    8771    return flags;
    88 }
    89 
    90 static const int STORAGEBUFFER_GROWTH = 256;
    91 
    92 static QSet<QByteArray> interfaceNames(int socket)
    93 {
    94     QSet<QByteArray> result;
    95     QByteArray storageBuffer;
    96     struct ifconf interfaceList;
    97 
    98     forever {
    99         // grow the storage buffer
    100         storageBuffer.resize(storageBuffer.size() + STORAGEBUFFER_GROWTH);
    101         interfaceList.ifc_buf = storageBuffer.data();
    102         interfaceList.ifc_len = storageBuffer.size();
    103 
    104         // get the interface list
    105         if (::ioctl(socket, SIOCGIFCONF, &interfaceList) >= 0) {
    106             if (int(interfaceList.ifc_len + sizeof(ifreq) + 64) < storageBuffer.size()) {
    107                 // if the buffer was big enough, break
    108                 storageBuffer.resize(interfaceList.ifc_len);
    109                 break;
    110             }
    111         } else {
    112             // internal error
    113             return result;
    114         }
    115         if (storageBuffer.size() > 100000) {
    116             // out of space
    117             return result;
    118         }
    119     }
    120 
    121     int interfaceCount = interfaceList.ifc_len / sizeof(ifreq);
    122     for (int i = 0; i < interfaceCount; ++i) {
    123         // for some reason, this ioctl returns garbage entries (names starting
    124         // with characters like 0x00, 0x06, 0x14 and even 0x22). Filter those
    125         // out by requiring the first character to be a latin letter.
    126         if (!isalpha(interfaceList.ifc_req[i].ifr_name[0]))
    127             continue;
    128         result << QByteArray(interfaceList.ifc_req[i].ifr_name);
    129     }
    130 
    131     return result;
    132 }
    133 
    134 static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces,
    135                                                struct ifreq &req)
    136 {
    137     QNetworkInterfacePrivate *iface = 0;
    138     int ifindex = 0;
    139 
    140     // Search by name
    141     QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
    142     for ( ; if_it != interfaces.end(); ++if_it)
    143         if ((*if_it)->name == QLatin1String(req.ifr_name)) {
    144             // existing interface
    145             iface = *if_it;
    146             break;
    147         }
    148 
    149     if (!iface) {
    150         // new interface, create data:
    151         iface = new QNetworkInterfacePrivate;
    152         iface->index = ifindex;
    153         interfaces << iface;
    154 
    155 #ifdef SIOCGIFNAME
    156         // Get the canonical name
    157         QByteArray oldName = req.ifr_name;
    158         if (::ioctl(socket, SIOCGIFNAME, &req) >= 0) {
    159             iface->name = QString::fromLatin1(req.ifr_name);
    160 
    161             // reset the name:
    162             memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
    163         } else
    164 #endif
    165         {
    166             // use this name anyways
    167             iface->name = QString::fromLatin1(req.ifr_name);
    168         }
    169 
    170         // Get interface flags
    171         if (::ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
    172             iface->flags = convertFlags(req.ifr_flags);
    173         }
    174 
    175 #ifdef SIOCGIFHWADDR
    176         // Get the HW address
    177         if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
    178             uchar *addr = (uchar *)&req.ifr_addr;
    179             iface->hardwareAddress = iface->makeHwAddress(6, addr);
    180         }
    181 #endif
    182     }
    183 
    184     return iface;
    18572}
    18673
    18774static QList<QNetworkInterfacePrivate *> interfaceListing()
    18875{
     76
     77
     78
     79
     80
    18981    QList<QNetworkInterfacePrivate *> interfaces;
    19082
     
    19385        return interfaces;      // error
    19486
    195     QSet<QByteArray> names = interfaceNames(socket);
    196     QSet<QByteArray>::ConstIterator it = names.constBegin();
    197     for ( ; it != names.constEnd(); ++it) {
     87    // rumors say that the address buffer should be at least 65536 bytes long
     88    char addrBuf[65536];
     89    short naddrs;
     90    statatreq *addrs;
     91
     92    ifmib ifmibget;
     93    // zero the interface table because garbage will be returned in interface
     94    // names otherwise
     95    memset(&ifmibget,0, sizeof(ifmib));
     96
     97    int rc;
     98
     99    // get available interfaces
     100    rc = ::os2_ioctl(socket, SIOSTATIF, (char*)&ifmibget, sizeof(ifmib));
     101    if (rc == -1) {
     102        ::close(socket);
     103        return interfaces;
     104    }
     105
     106    // get IP addresses
     107    rc = ::os2_ioctl(socket, SIOSTATAT, addrBuf, sizeof(addrBuf));
     108    if (rc == -1) {
     109        ::close(socket);
     110        return interfaces;
     111    }
     112    naddrs = *(short *)addrBuf;
     113    addrs = (statatreq *)(addrBuf + sizeof(unsigned short));
     114
     115    // loop over interfaces
     116    int idx = 0;
     117    for (int i = 0; i < IFMIB_ENTRIES && idx < ifmibget.ifNumber; ++i) {
     118        // skip empty interface entries
     119        if (ifmibget.iftable[i].iftType == 0)
     120            continue;
     121
     122        QNetworkInterfacePrivate *iface = new QNetworkInterfacePrivate;
     123        iface->index = ifmibget.iftable[i].iftIndex;
     124
     125        // Derive the interface name. Not perfect, but there seems to be no
     126        // other documented way (taken from Odin sources)
     127        if (iface->index >= 0 && iface->index < 9) {// lanX
     128            iface->name = QString(QLatin1String("lan%1")).arg(iface->index);
     129        } else if (strstr(ifmibget.iftable[i].iftDescr, "back")) { // loopback
     130            iface->name = QLatin1String("lo");
     131        }
     132        else if (strstr(ifmibget.iftable[i].iftDescr, "ace ppp")) {// pppX
     133            iface->name = QLatin1String(strstr(ifmibget.iftable[i].iftDescr, "ppp"));
     134        } else if (strstr(ifmibget.iftable[i].iftDescr,"ace sl")) { // slX
     135            iface->name = QLatin1String(strstr(ifmibget.iftable[i].iftDescr, "sl"));
     136        } else if (strstr(ifmibget.iftable[i].iftDescr,"ace dod")) { // dodX
     137            iface->name = QLatin1String(strstr(ifmibget.iftable[i].iftDescr, "dod"));
     138        } else { // something else...
     139            iface->name = QString(QLatin1String("unk%1")).arg(iface->index);
     140        }
     141
     142        iface->friendlyName = QString::fromLocal8Bit(ifmibget.iftable[i].iftDescr);
     143        iface->hardwareAddress =
     144            iface->makeHwAddress(sizeof(ifmibget.iftable[i].iftPhysAddr),
     145                                 (uchar *)&ifmibget.iftable[i].iftPhysAddr[0]);
     146
     147        // get interface flags
    198148        ifreq req;
    199149        memset(&req, 0, sizeof(ifreq));
    200         memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
     150        strncpy(req.ifr_name, iface->name.toLatin1(), sizeof(req.ifr_name));
     151        if (::ioctl(socket, SIOCGIFFLAGS, &req) != -1) {
     152            iface->flags = convertFlags(req.ifr_flags);
     153        }
    201154
    202         QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
    203 
    204         // Get the interface broadcast address
    205         QNetworkAddressEntry entry;
    206         if (iface->flags & QNetworkInterface::CanBroadcast) {
    207             if (::ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
    208                 sockaddr *sa = &req.ifr_addr;
    209                 if (sa->sa_family == AF_INET)
    210                     entry.setBroadcast(addressFromSockaddr(sa));
     155       
     156        for (int j = 0; j < naddrs; ++j) {
     157       
     158        QNetworkAddressEntry entry;
     159       
     160           
     161                ;
     162               
     163                ;
    211164            }
    212165        }
    213166
    214         // Get the interface netmask
    215         if (::ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
    216             sockaddr *sa = &req.ifr_addr;
    217             entry.setNetmask(addressFromSockaddr(sa));
    218         }
    219 
    220         // Get the address of the interface
    221         if (::ioctl(socket, SIOCGIFADDR, &req) >= 0) {
    222             sockaddr *sa = &req.ifr_addr;
    223             entry.setIp(addressFromSockaddr(sa));
    224         }
    225 
    226         iface->addressEntries << entry;
     167        // store the interface
     168        interfaces << iface;
    227169    }
    228170
Note: See TracChangeset for help on using the changeset viewer.