source: trunk/src/network/kernel/qnetworkinterface_os2.cpp@ 324

Last change on this file since 324 was 160, checked in by Dmitry A. Kuminov, 16 years ago

network: Ported QHostInfo and QNetworkInterface to OS/2.

File size: 7.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** Copyright (C) 2009 netlabs.org. OS/2 parts.
7**
8** This file is part of the QtNetwork module of the Qt Toolkit.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial Usage
12** Licensees holding valid Qt Commercial licenses may use this file in
13** accordance with the Qt Commercial License Agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and Nokia.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Nokia gives you certain
26** additional rights. These rights are described in the Nokia Qt LGPL
27** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28** package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you are unsure which license is appropriate for your use, please
39** contact the sales department at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "qset.h"
45#include "qnetworkinterface.h"
46#include "qnetworkinterface_p.h"
47#include "qalgorithms.h"
48
49#ifndef QT_NO_NETWORKINTERFACE
50
51#include <sys/types.h>
52#include <sys/socket.h>
53
54#include <sys/sockio.h>
55#include <net/if.h>
56
57#include <qplatformdefs.h>
58
59QT_BEGIN_NAMESPACE
60
61static 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}
72
73static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags)
74{
75 QNetworkInterface::InterfaceFlags flags = 0;
76 flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0);
77 flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0);
78 flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0);
79 flags |= (rawFlags & IFF_LOOPBACK) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0);
80#ifdef IFF_POINTOPOINT //cygwin doesn't define IFF_POINTOPOINT
81 flags |= (rawFlags & IFF_POINTOPOINT) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0);
82#endif
83
84#ifdef IFF_MULTICAST
85 flags |= (rawFlags & IFF_MULTICAST) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0);
86#endif
87 return flags;
88}
89
90static const int STORAGEBUFFER_GROWTH = 256;
91
92static 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 QByteArray name = QByteArray(interfaceList.ifc_req[i].ifr_name);
124 if (!name.isEmpty())
125 result << name;
126 }
127
128 return result;
129}
130
131static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfacePrivate *> &interfaces,
132 struct ifreq &req)
133{
134 QNetworkInterfacePrivate *iface = 0;
135 int ifindex = 0;
136
137 // Search by name
138 QList<QNetworkInterfacePrivate *>::Iterator if_it = interfaces.begin();
139 for ( ; if_it != interfaces.end(); ++if_it)
140 if ((*if_it)->name == QLatin1String(req.ifr_name)) {
141 // existing interface
142 iface = *if_it;
143 break;
144 }
145
146 if (!iface) {
147 // new interface, create data:
148 iface = new QNetworkInterfacePrivate;
149 iface->index = ifindex;
150 interfaces << iface;
151
152#ifdef SIOCGIFNAME
153 // Get the canonical name
154 QByteArray oldName = req.ifr_name;
155 if (::ioctl(socket, SIOCGIFNAME, &req) >= 0) {
156 iface->name = QString::fromLatin1(req.ifr_name);
157
158 // reset the name:
159 memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
160 } else
161#endif
162 {
163 // use this name anyways
164 iface->name = QString::fromLatin1(req.ifr_name);
165 }
166
167 // Get interface flags
168 if (::ioctl(socket, SIOCGIFFLAGS, &req) >= 0) {
169 iface->flags = convertFlags(req.ifr_flags);
170 }
171
172#ifdef SIOCGIFHWADDR
173 // Get the HW address
174 if (::ioctl(socket, SIOCGIFHWADDR, &req) >= 0) {
175 uchar *addr = (uchar *)&req.ifr_addr;
176 iface->hardwareAddress = iface->makeHwAddress(6, addr);
177 }
178#endif
179 }
180
181 return iface;
182}
183
184static QList<QNetworkInterfacePrivate *> interfaceListing()
185{
186 QList<QNetworkInterfacePrivate *> interfaces;
187
188 int socket;
189 if ((socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
190 return interfaces; // error
191
192 QSet<QByteArray> names = interfaceNames(socket);
193 QSet<QByteArray>::ConstIterator it = names.constBegin();
194 for ( ; it != names.constEnd(); ++it) {
195 ifreq req;
196 memset(&req, 0, sizeof(ifreq));
197 memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
198
199 QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
200
201 // Get the interface broadcast address
202 QNetworkAddressEntry entry;
203 if (iface->flags & QNetworkInterface::CanBroadcast) {
204 if (::ioctl(socket, SIOCGIFBRDADDR, &req) >= 0) {
205 sockaddr *sa = &req.ifr_addr;
206 if (sa->sa_family == AF_INET)
207 entry.setBroadcast(addressFromSockaddr(sa));
208 }
209 }
210
211 // Get the interface netmask
212 if (::ioctl(socket, SIOCGIFNETMASK, &req) >= 0) {
213 sockaddr *sa = &req.ifr_addr;
214 entry.setNetmask(addressFromSockaddr(sa));
215 }
216
217 // Get the address of the interface
218 if (::ioctl(socket, SIOCGIFADDR, &req) >= 0) {
219 sockaddr *sa = &req.ifr_addr;
220 entry.setIp(addressFromSockaddr(sa));
221 }
222
223 iface->addressEntries << entry;
224 }
225
226 ::close(socket);
227 return interfaces;
228}
229
230QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan()
231{
232 return interfaceListing();
233}
234
235QT_END_NAMESPACE
236
237#endif // QT_NO_NETWORKINTERFACE
Note: See TracBrowser for help on using the repository browser.