src/network/kernel/qnetworkinterface_symbian.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network/kernel/qnetworkinterface_symbian.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QNETWORKINTERFACE_DEBUG
+
+#include "qnetworkinterface.h"
+#include "qnetworkinterface_p.h"
+#include "../corelib/kernel/qcore_symbian_p.h"
+
+#ifndef QT_NO_NETWORKINTERFACE
+
+#include <in_sock.h>
+#include <in_iface.h>
+#include <es_sock.h>
+
+QT_BEGIN_NAMESPACE
+
+
+static QNetworkInterface::InterfaceFlags convertFlags(const TSoInetInterfaceInfo& aInfo)
+{
+    QNetworkInterface::InterfaceFlags flags = 0;
+    flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
+    // We do not have separate flag for running in Symbian OS
+    flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
+    flags |= (aInfo.iFeatures & KIfCanBroadcast) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
+    flags |= (aInfo.iFeatures & KIfIsLoopback) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
+    flags |= (aInfo.iFeatures & KIfIsPointToPoint) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
+    flags |= (aInfo.iFeatures & KIfCanMulticast) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
+    return flags;
+}
+
+static QList<QNetworkInterfacePrivate *> interfaceListing()
+{
+    TInt err(KErrNone);
+    QList<QNetworkInterfacePrivate *> interfaces;
+
+    // Connect to Native socket server
+    RSocketServ socketServ;
+    err = socketServ.Connect();
+    if (err)
+        return interfaces;
+
+    // Open dummy socket for interface queries
+    RSocket socket;
+    err = socket.Open(socketServ, _L("udp"));
+    if (err) {
+        socketServ.Close();
+        return interfaces;
+    }
+
+    // Ask socket to start enumerating interfaces
+    err =  socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+    if (err) {
+        socket.Close();
+        socketServ.Close();
+        return interfaces;
+    }
+
+    int ifindex = 0;
+    TPckgBuf<TSoInetInterfaceInfo> infoPckg;
+    TSoInetInterfaceInfo &info = infoPckg();
+    while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone) {
+        // Do not include IPv6 addresses because netmask and broadcast address cannot be determined correctly
+        if (info.iName != KNullDesC && info.iAddress.IsV4Mapped()) {
+            TName address;
+            QNetworkAddressEntry entry;
+            QNetworkInterfacePrivate *iface = 0;
+
+            iface = new QNetworkInterfacePrivate;
+            iface->index = ifindex++;
+            interfaces << iface;
+            iface->name = qt_TDesC2QString(info.iName);
+            iface->flags = convertFlags(info);
+
+            if (/*info.iFeatures&KIfHasHardwareAddr &&*/ info.iHwAddr.Family() != KAFUnspec) {
+                for (TInt i = sizeof(SSockAddr); i < sizeof(SSockAddr) + info.iHwAddr.GetUserLen(); i++) {
+                    address.AppendNumFixedWidth(info.iHwAddr[i], EHex, 2);
+                    if ((i + 1) < sizeof(SSockAddr) + info.iHwAddr.GetUserLen())
+                        address.Append(_L(":"));
+                }
+                address.UpperCase();
+                iface->hardwareAddress = qt_TDesC2QString(address);
+            }
+
+            // Get the address of the interface
+            info.iAddress.Output(address);
+            entry.setIp(QHostAddress(qt_TDesC2QString(address)));
+
+            // Get the interface netmask
+            // For some reason netmask is always 0.0.0.0
+            // info.iNetMask.Output(address);
+            // entry.setNetmask( QHostAddress( qt_TDesC2QString( address ) ) );
+
+            // Workaround: Let Symbian determine netmask based on IP address class
+            // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support
+            TInetAddr netmask;
+            netmask.NetMask(info.iAddress);
+            netmask.Output(address);
+            entry.setNetmask(QHostAddress(qt_TDesC2QString(address)));
+
+            // Get the interface broadcast address
+            if (iface->flags & QNetworkInterface::CanBroadcast) {
+                // For some reason broadcast address is always 0.0.0.0
+                // info.iBrdAddr.Output(address);
+                // entry.setBroadcast( QHostAddress( qt_TDesC2QString( address ) ) );
+
+                // Workaround: Let Symbian determine broadcast address based on IP address
+                // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support
+                TInetAddr broadcast;
+                broadcast.NetBroadcast(info.iAddress);
+                broadcast.Output(address);
+                entry.setBroadcast(QHostAddress(qt_TDesC2QString(address)));
+            }
+
+            // Add new entry to interface address entries
+            iface->addressEntries << entry;
+
+#if defined(QNETWORKINTERFACE_DEBUG)
+            printf("\n       Found network interface %s, interface flags:\n\
+                IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\
+                IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\
+                ip = %s, netmask = %s, broadcast = %s,\n\
+                hwaddress = %s",
+                   iface->name.toLatin1().constData(),
+                   iface->flags & QNetworkInterface::IsUp, iface->flags & QNetworkInterface::IsRunning, iface->flags & QNetworkInterface::CanBroadcast,
+                   iface->flags & QNetworkInterface::IsLoopBack, iface->flags & QNetworkInterface::IsPointToPoint, iface->flags & QNetworkInterface::CanMulticast,
+                   entry.ip().toString().toLatin1().constData(), entry.netmask().toString().toLatin1().constData(), entry.broadcast().toString().toLatin1().constData(),
+                   iface->hardwareAddress.toLatin1().constData());
+#endif
+        }
+    }
+
+    // we will try to use routing info to detect more precisely
+    // netmask and then ::postProcess() should calculate
+    // broadcast addresses
+
+    // use dummy socket to start enumerating routes
+    err =  socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl);
+    if (err) {
+        socket.Close();
+        socketServ.Close();
+        // return what we have
+        // up to this moment
+        return interfaces;
+    }
+
+    TSoInetRouteInfo routeInfo;
+    TPckg<TSoInetRouteInfo> routeInfoPkg(routeInfo);
+    while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone) {
+        TName address;
+
+        // get interface address
+        routeInfo.iIfAddr.Output(address);
+        QHostAddress ifAddr(qt_TDesC2QString(address));
+        if (ifAddr.isNull())
+            continue;
+
+        routeInfo.iDstAddr.Output(address);
+        QHostAddress destination(qt_TDesC2QString(address));
+        if (destination.isNull() || destination != ifAddr)
+            continue;
+
+        // search interfaces
+        for (int ifindex = 0; ifindex < interfaces.size(); ++ifindex) {
+            QNetworkInterfacePrivate *iface = interfaces.at(ifindex);
+            for (int eindex = 0; eindex < iface->addressEntries.size(); ++eindex) {
+                QNetworkAddressEntry entry = iface->addressEntries.at(eindex);
+                if (entry.ip() != ifAddr) {
+                    continue;
+                } else if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) {
+                    // skip if not IPv4 address (e.g. IPv6)
+                    // as results not reliable on Symbian
+                    continue;
+                } else {
+                    routeInfo.iNetMask.Output(address);
+                    QHostAddress netmask(qt_TDesC2QString(address));
+                    entry.setNetmask(netmask);
+                    // NULL boradcast address for
+                    // ::postProcess to have effect
+                    entry.setBroadcast(QHostAddress());
+                    iface->addressEntries.replace(eindex, entry);
+                }
+            }
+        }
+    }
+
+    socket.Close();
+    socketServ.Close();
+
+    return interfaces;
+}
+
+QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
+{
+    return interfaceListing();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKINTERFACE