Commit 45caf84c authored by hjk's avatar hjk

ProjectExplorer: Fix parsing ports from netstat output on Windows

Handle IPv6, and do not try to interpret the result as hex.

Change-Id: I700c233d03cc706bc8712ab9fabee75d7f126df3
Reviewed-by: Christian Stenger's avatarChristian Stenger <christian.stenger@qt.io>
parent 94747ea2
......@@ -269,4 +269,71 @@ QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString
return true;
}
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line)
{
const QByteArray trimmed = line.trimmed();
int base = 0;
QByteArray portString;
if (trimmed.startsWith("TCP") || trimmed.startsWith("UDP")) {
// Windows. Expected output is something like
//
// Active Connections
//
// Proto Local Address Foreign Address State
// TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
// TCP 0.0.0.0:113 0.0.0.0:0 LISTENING
// [...]
// TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING
// TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED
// [...]
// TCP [::]:445 [::]:0 LISTENING
// TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED
// UDP [fe80::880a:2932:8dff:a858%6]:1900 *:*
const int firstBracketPos = trimmed.indexOf('[');
int colonPos = -1;
if (firstBracketPos == -1) {
colonPos = trimmed.indexOf(':'); // IPv4
} else {
// jump over host part
const int secondBracketPos = trimmed.indexOf(']', firstBracketPos + 1);
colonPos = trimmed.indexOf(':', secondBracketPos);
}
const int firstDigitPos = colonPos + 1;
const int spacePos = trimmed.indexOf(' ', firstDigitPos);
if (spacePos < 0)
return -1;
const int len = spacePos - firstDigitPos;
base = 10;
portString = trimmed.mid(firstDigitPos, len);
} else {
// Expected output on Linux something like
//
// sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ...
// 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ...
//
const int firstColonPos = trimmed.indexOf(':');
if (firstColonPos < 0)
return -1;
const int secondColonPos = trimmed.indexOf(':', firstColonPos + 1);
if (secondColonPos < 0)
return -1;
const int spacePos = trimmed.indexOf(' ', secondColonPos + 1);
if (spacePos < 0)
return -1;
const int len = spacePos - secondColonPos - 1;
base = 16;
portString = trimmed.mid(secondColonPos + 1, len);
}
bool ok = true;
const int port = portString.toInt(&ok, base);
if (!ok) {
qWarning("%s: Unexpected string '%s' is not a port. Tried to read from '%s'",
Q_FUNC_INFO, line.data(), portString.data());
return -1;
}
return port;
}
} // namespace Utils
......@@ -79,4 +79,6 @@ private:
QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line);
} // namespace Utils
......@@ -39,6 +39,7 @@
#include <utils/environment.h>
#include <utils/hostosinfo.h>
#include <utils/portlist.h>
#include <utils/stringutils.h>
#include <QCoreApplication>
......@@ -168,65 +169,10 @@ class DesktopPortsGatheringMethod : public PortsGatheringMethod
{
QList<Utils::Port> ports;
const QList<QByteArray> lines = output.split('\n');
if (HostOsInfo::isWindowsHost()) {
// Expected output is something like
//
// Active Connections
//
// Proto Local Address Foreign Address State
// TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
// TCP 0.0.0.0:113 0.0.0.0:0 LISTENING
// [...]
// TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING
// TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED
for (const QByteArray &line : lines) {
const QByteArray trimmed = line.trimmed();
if (!trimmed.startsWith("TCP"))
continue;
int colonPos = trimmed.indexOf(':');
if (colonPos < 0)
continue;
int spacePos = trimmed.indexOf(':', colonPos + 1);
if (spacePos < 0)
continue;
bool ok;
int len = spacePos - colonPos - 1;
const Utils::Port port(line.mid(colonPos + 1, len).toInt(&ok, 16));
if (ok) {
if (!ports.contains(port))
ports << port;
} else {
qWarning("%s: Unexpected string '%s' is not a port.",
Q_FUNC_INFO, line.data());
}
}
} else if (HostOsInfo::isLinuxHost()) {
// Expected outpit is something like
//
// sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ...
// 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ...
//
for (const QByteArray &line : lines) {
int firstColonPos = line.indexOf(':');
if (firstColonPos < 0)
continue;
int secondColonPos = line.indexOf(':', firstColonPos + 1);
if (secondColonPos < 0)
continue;
int spacePos = line.indexOf(':', secondColonPos + 1);
if (spacePos < 0)
continue;
bool ok;
int len = spacePos - secondColonPos - 1;
const Utils::Port port(line.mid(secondColonPos + 1, len).toInt(&ok, 16));
if (ok) {
if (!ports.contains(port))
ports << port;
} else {
qWarning("%s: Unexpected string '%s' is not a port.",
Q_FUNC_INFO, line.data());
}
}
for (const QByteArray &line : lines) {
const Port port(Utils::parseUsedPortFromNetstatOutput(line));
if (port.isValid() && !ports.contains(port))
ports.append(port);
}
return ports;
}
......
......@@ -82,6 +82,8 @@ private slots:
void testMacroExpander();
void testStripAccelerator();
void testStripAccelerator_data();
void testParseUsedPortFromNetstatOutput();
void testParseUsedPortFromNetstatOutput_data();
private:
TestMacroExpander mx;
......@@ -202,6 +204,37 @@ void tst_StringUtils::testStripAccelerator_data()
QTest::newRow("Test&") << "Test";
}
void tst_StringUtils::testParseUsedPortFromNetstatOutput()
{
QFETCH(QString, line);
QFETCH(int, port);
QCOMPARE(Utils::parseUsedPortFromNetstatOutput(line.toUtf8()), port);
}
void tst_StringUtils::testParseUsedPortFromNetstatOutput_data()
{
QTest::addColumn<QString>("line");
QTest::addColumn<int>("port");
QTest::newRow("Empty") << "" << -1;
// Windows netstat.
QTest::newRow("Win1") << "Active Connection" << -1;
QTest::newRow("Win2") << " Proto Local Address Foreign Address State" << -1;
QTest::newRow("Win3") << " TCP 0.0.0.0:80 0.0.0.0:0 LISTENING" << 80;
QTest::newRow("Win4") << " TCP 0.0.0.0:113 0.0.0.0:0 LISTENING" << 113;
QTest::newRow("Win5") << " TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING" << 14714;
QTest::newRow("Win6") << " TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED" << 50233;
QTest::newRow("Win7") << " TCP [::]:445 [::]:0 LISTENING" << 445;
QTest::newRow("Win8") << " TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED" << 51905;
QTest::newRow("Win9") << " UDP [fe80::840a:2942:8def:abcd%6]:1900 *:* " << 1900;
// Linux
QTest::newRow("Linux1") << "sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ..." << -1;
QTest::newRow("Linux2") << "0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ..." << 10245;
}
QTEST_MAIN(tst_StringUtils)
#include "tst_stringutils.moc"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment