forked from qt-creator/qt-creator
Devices: Unify Port Gathering method
All devices that support it use the same mechanism to gather ports so this patch removes the individual implementations in favor of a single one in IDevice.cpp. This patch also removes: * canAutodetectPorts() as it was not used. * Port::parseFrom...Output as they are not used anymore. Change-Id: I8ecedec2d71e60985402387982c64311c5a651e6 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -33,56 +33,6 @@ quint16 Port::number() const
|
|||||||
QTC_ASSERT(isValid(), return -1); return quint16(m_port);
|
QTC_ASSERT(isValid(), return -1); return quint16(m_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Port> Port::parseFromSedOutput(const QByteArray &output)
|
|
||||||
{
|
|
||||||
QList<Port> ports;
|
|
||||||
const QList<QByteArray> portStrings = output.split('\n');
|
|
||||||
for (const QByteArray &portString : portStrings) {
|
|
||||||
if (portString.size() != 4)
|
|
||||||
continue;
|
|
||||||
bool ok;
|
|
||||||
const Port port(portString.toInt(&ok, 16));
|
|
||||||
if (ok) {
|
|
||||||
if (!ports.contains(port))
|
|
||||||
ports << port;
|
|
||||||
} else {
|
|
||||||
qWarning("%s: Unexpected string '%s' is not a port.",
|
|
||||||
Q_FUNC_INFO, portString.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Port> Port::parseFromCatOutput(const QByteArray &output)
|
|
||||||
{
|
|
||||||
// Parse something like
|
|
||||||
// sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
|
||||||
// : 00000000:2717 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3995881 1 0000000000000000 100 0 0 10 0
|
|
||||||
// : 00000000:2716 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 3594482 1 0000000000000000 100 0 0 10 0
|
|
||||||
const QRegularExpression re(".*: [[:xdigit:]]*:([[:xdigit:]]{4}).*");
|
|
||||||
|
|
||||||
QList<Port> ports;
|
|
||||||
const QStringList lines = QString::fromLocal8Bit(output).split('\n');
|
|
||||||
for (const QString &line : lines) {
|
|
||||||
const QRegularExpressionMatch match = re.match(line);
|
|
||||||
if (!match.hasMatch())
|
|
||||||
continue;
|
|
||||||
const QString portString = match.captured(1);
|
|
||||||
if (portString.size() != 4)
|
|
||||||
continue;
|
|
||||||
bool ok;
|
|
||||||
const Port port(portString.toInt(&ok, 16));
|
|
||||||
if (ok) {
|
|
||||||
if (!ports.contains(port))
|
|
||||||
ports << port;
|
|
||||||
} else {
|
|
||||||
qWarning("%s: Unexpected string '%s' is not a port.",
|
|
||||||
Q_FUNC_INFO, qPrintable(portString));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Port> Port::parseFromNetstatOutput(const QByteArray &output)
|
QList<Port> Port::parseFromNetstatOutput(const QByteArray &output)
|
||||||
{
|
{
|
||||||
QList<Port> ports;
|
QList<Port> ports;
|
||||||
|
@@ -24,8 +24,6 @@ public:
|
|||||||
|
|
||||||
QString toString() const { return QString::number(m_port); }
|
QString toString() const { return QString::number(m_port); }
|
||||||
|
|
||||||
static QList<Port> parseFromSedOutput(const QByteArray &output);
|
|
||||||
static QList<Port> parseFromCatOutput(const QByteArray &output);
|
|
||||||
static QList<Port> parseFromNetstatOutput(const QByteArray &output);
|
static QList<Port> parseFromNetstatOutput(const QByteArray &output);
|
||||||
|
|
||||||
friend bool operator<(const Port &p1, const Port &p2) { return p1.number() < p2.number(); }
|
friend bool operator<(const Port &p1, const Port &p2) { return p1.number() < p2.number(); }
|
||||||
|
@@ -388,11 +388,6 @@ IDeviceWidget *AndroidDevice::createWidget()
|
|||||||
return new AndroidDeviceWidget(sharedFromThis());
|
return new AndroidDeviceWidget(sharedFromThis());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidDevice::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
|
DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const
|
||||||
{
|
{
|
||||||
return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation());
|
return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation());
|
||||||
|
@@ -61,7 +61,6 @@ private:
|
|||||||
void addActionsIfNotFound();
|
void addActionsIfNotFound();
|
||||||
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
||||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
ProjectExplorer::DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||||
QUrl toolControlChannel(const ControlChannelHint &) const override;
|
QUrl toolControlChannel(const ControlChannelHint &) const override;
|
||||||
|
|
||||||
|
@@ -419,7 +419,7 @@ DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &dat
|
|||||||
{
|
{
|
||||||
setFileAccess(&d->m_fileAccess);
|
setFileAccess(&d->m_fileAccess);
|
||||||
setDisplayType(Tr::tr("Docker"));
|
setDisplayType(Tr::tr("Docker"));
|
||||||
setOsType(OsTypeOtherUnix);
|
setOsType(OsTypeLinux);
|
||||||
setDefaultDisplayName(Tr::tr("Docker Image"));
|
setDefaultDisplayName(Tr::tr("Docker Image"));
|
||||||
setupId(IDevice::ManuallyAdded);
|
setupId(IDevice::ManuallyAdded);
|
||||||
setType(Constants::DOCKER_DEVICE_TYPE);
|
setType(Constants::DOCKER_DEVICE_TYPE);
|
||||||
@@ -832,33 +832,6 @@ ProcessInterface *DockerDevice::createProcessInterface() const
|
|||||||
return new DockerProcessImpl(this->sharedFromThis(), d);
|
return new DockerProcessImpl(this->sharedFromThis(), d);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PortsGatheringMethod DockerDevice::portsGatheringMethod() const
|
|
||||||
{
|
|
||||||
return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine {
|
|
||||||
// We might encounter the situation that protocol is given IPv6
|
|
||||||
// but the consumer of the free port information decides to open
|
|
||||||
// an IPv4(only) port. As a result the next IPv6 scan will
|
|
||||||
// report the port again as open (in IPv6 namespace), while the
|
|
||||||
// same port in IPv4 namespace might still be blocked, and
|
|
||||||
// re-use of this port fails.
|
|
||||||
// GDBserver behaves exactly like this.
|
|
||||||
|
|
||||||
Q_UNUSED(protocol)
|
|
||||||
|
|
||||||
// /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6
|
|
||||||
return {filePath("sed"),
|
|
||||||
"-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*",
|
|
||||||
CommandLine::Raw};
|
|
||||||
},
|
|
||||||
|
|
||||||
&Port::parseFromSedOutput};
|
|
||||||
};
|
|
||||||
|
|
||||||
DeviceProcessList *DockerDevice::createProcessListModel(QObject *parent) const
|
DeviceProcessList *DockerDevice::createProcessListModel(QObject *parent) const
|
||||||
{
|
{
|
||||||
return new ProcessList(sharedFromThis(), parent);
|
return new ProcessList(sharedFromThis(), parent);
|
||||||
|
@@ -73,8 +73,6 @@ public:
|
|||||||
|
|
||||||
Utils::ProcessInterface *createProcessInterface() const override;
|
Utils::ProcessInterface *createProcessInterface() const override;
|
||||||
|
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override;
|
|
||||||
bool canCreateProcessModel() const override { return true; }
|
bool canCreateProcessModel() const override { return true; }
|
||||||
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
||||||
bool hasDeviceTester() const override { return false; }
|
bool hasDeviceTester() const override { return false; }
|
||||||
|
@@ -185,12 +185,6 @@ Utils::Port IosDevice::nextPort() const
|
|||||||
return Utils::Port(m_lastPort);
|
return Utils::Port(m_lastPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IosDevice::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// IosDeviceManager
|
// IosDeviceManager
|
||||||
|
|
||||||
IosDeviceManager::TranslationMap IosDeviceManager::translationMap()
|
IosDeviceManager::TranslationMap IosDeviceManager::translationMap()
|
||||||
|
@@ -36,7 +36,6 @@ public:
|
|||||||
QString osVersion() const;
|
QString osVersion() const;
|
||||||
QString cpuArchitecture() const;
|
QString cpuArchitecture() const;
|
||||||
Utils::Port nextPort() const;
|
Utils::Port nextPort() const;
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
|
|
||||||
static QString name();
|
static QString name();
|
||||||
|
|
||||||
|
@@ -66,11 +66,6 @@ Utils::Port IosSimulator::nextPort() const
|
|||||||
return Utils::Port(m_lastPort);
|
return Utils::Port(m_lastPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IosSimulator::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IosDeviceType
|
// IosDeviceType
|
||||||
|
|
||||||
IosDeviceType::IosDeviceType(IosDeviceType::Type type, const QString &identifier, const QString &displayName) :
|
IosDeviceType::IosDeviceType(IosDeviceType::Type type, const QString &identifier, const QString &displayName) :
|
||||||
|
@@ -48,7 +48,6 @@ public:
|
|||||||
|
|
||||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||||
Utils::Port nextPort() const;
|
Utils::Port nextPort() const;
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class IosSimulatorFactory;
|
friend class IosSimulatorFactory;
|
||||||
|
@@ -87,11 +87,6 @@ IDeviceWidget *DesktopDevice::createWidget()
|
|||||||
// range can be confusing to the user. Hence, disabling the widget for now.
|
// range can be confusing to the user. Hence, disabling the widget for now.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDevice::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::canCreateProcessModel() const
|
bool DesktopDevice::canCreateProcessModel() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -107,31 +102,6 @@ DeviceProcessSignalOperation::Ptr DesktopDevice::signalOperation() const
|
|||||||
return DeviceProcessSignalOperation::Ptr(new DesktopProcessSignalOperation());
|
return DeviceProcessSignalOperation::Ptr(new DesktopProcessSignalOperation());
|
||||||
}
|
}
|
||||||
|
|
||||||
PortsGatheringMethod DesktopDevice::portsGatheringMethod() const
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine {
|
|
||||||
// We might encounter the situation that protocol is given IPv6
|
|
||||||
// but the consumer of the free port information decides to open
|
|
||||||
// an IPv4(only) port. As a result the next IPv6 scan will
|
|
||||||
// report the port again as open (in IPv6 namespace), while the
|
|
||||||
// same port in IPv4 namespace might still be blocked, and
|
|
||||||
// re-use of this port fails.
|
|
||||||
// GDBserver behaves exactly like this.
|
|
||||||
|
|
||||||
Q_UNUSED(protocol)
|
|
||||||
|
|
||||||
if (HostOsInfo::isWindowsHost() || HostOsInfo::isMacHost())
|
|
||||||
return {filePath("netstat"), {"-a", "-n"}};
|
|
||||||
if (HostOsInfo::isLinuxHost())
|
|
||||||
return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}};
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
|
|
||||||
&Port::parseFromNetstatOutput
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const
|
QUrl DesktopDevice::toolControlChannel(const ControlChannelHint &) const
|
||||||
{
|
{
|
||||||
QUrl url;
|
QUrl url;
|
||||||
|
@@ -25,10 +25,8 @@ public:
|
|||||||
IDevice::DeviceInfo deviceInformation() const override;
|
IDevice::DeviceInfo deviceInformation() const override;
|
||||||
|
|
||||||
IDeviceWidget *createWidget() override;
|
IDeviceWidget *createWidget() override;
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
bool canCreateProcessModel() const override;
|
bool canCreateProcessModel() const override;
|
||||||
DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
||||||
ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override;
|
|
||||||
DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
DeviceProcessSignalOperation::Ptr signalOperation() const override;
|
||||||
QUrl toolControlChannel(const ControlChannelHint &) const override;
|
QUrl toolControlChannel(const ControlChannelHint &) const override;
|
||||||
bool usableAsBuildDevice() const override;
|
bool usableAsBuildDevice() const override;
|
||||||
|
@@ -371,6 +371,27 @@ const QList<IDevice::DeviceAction> IDevice::deviceActions() const
|
|||||||
return d->deviceActions;
|
return d->deviceActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PortsGatheringMethod IDevice::portsGatheringMethod() const
|
||||||
|
{
|
||||||
|
return {[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine {
|
||||||
|
// We might encounter the situation that protocol is given IPv6
|
||||||
|
// but the consumer of the free port information decides to open
|
||||||
|
// an IPv4(only) port. As a result the next IPv6 scan will
|
||||||
|
// report the port again as open (in IPv6 namespace), while the
|
||||||
|
// same port in IPv4 namespace might still be blocked, and
|
||||||
|
// re-use of this port fails.
|
||||||
|
// GDBserver behaves exactly like this.
|
||||||
|
|
||||||
|
Q_UNUSED(protocol)
|
||||||
|
|
||||||
|
if (filePath("/proc/net").isReadableDir())
|
||||||
|
return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}};
|
||||||
|
|
||||||
|
return {filePath("netstat"), {"-a", "-n"}};
|
||||||
|
},
|
||||||
|
&Port::parseFromNetstatOutput};
|
||||||
|
};
|
||||||
|
|
||||||
DeviceProcessList *IDevice::createProcessListModel(QObject *parent) const
|
DeviceProcessList *IDevice::createProcessListModel(QObject *parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
|
@@ -139,10 +139,7 @@ public:
|
|||||||
void addDeviceAction(const DeviceAction &deviceAction);
|
void addDeviceAction(const DeviceAction &deviceAction);
|
||||||
const QList<DeviceAction> deviceActions() const;
|
const QList<DeviceAction> deviceActions() const;
|
||||||
|
|
||||||
// Devices that can auto detect ports need not return a ports gathering method. Such devices can
|
virtual PortsGatheringMethod portsGatheringMethod() const;
|
||||||
// obtain a free port on demand. eg: Desktop device.
|
|
||||||
virtual bool canAutoDetectPorts() const { return false; }
|
|
||||||
virtual PortsGatheringMethod portsGatheringMethod() const { return {}; }
|
|
||||||
virtual bool canCreateProcessModel() const { return false; }
|
virtual bool canCreateProcessModel() const { return false; }
|
||||||
virtual DeviceProcessList *createProcessListModel(QObject *parent = nullptr) const;
|
virtual DeviceProcessList *createProcessListModel(QObject *parent = nullptr) const;
|
||||||
virtual bool hasDeviceTester() const { return false; }
|
virtual bool hasDeviceTester() const { return false; }
|
||||||
|
@@ -78,16 +78,6 @@ public:
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
PortsGatheringMethod portsGatheringMethod() const final
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
[this](QAbstractSocket::NetworkLayerProtocol) {
|
|
||||||
return CommandLine(filePath("netstat"), {"-na"});
|
|
||||||
},
|
|
||||||
&Port::parseFromNetstatOutput
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceProcessSignalOperation::Ptr signalOperation() const final
|
DeviceProcessSignalOperation::Ptr signalOperation() const final
|
||||||
{
|
{
|
||||||
return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis()));
|
return DeviceProcessSignalOperation::Ptr(new QnxDeviceProcessSignalOperation(sharedFromThis()));
|
||||||
|
@@ -993,39 +993,6 @@ IDeviceWidget *LinuxDevice::createWidget()
|
|||||||
return new Internal::GenericLinuxDeviceConfigurationWidget(sharedFromThis());
|
return new Internal::GenericLinuxDeviceConfigurationWidget(sharedFromThis());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::canAutoDetectPorts() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PortsGatheringMethod LinuxDevice::portsGatheringMethod() const
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
[this](QAbstractSocket::NetworkLayerProtocol protocol) -> CommandLine {
|
|
||||||
// We might encounter the situation that protocol is given IPv6
|
|
||||||
// but the consumer of the free port information decides to open
|
|
||||||
// an IPv4(only) port. As a result the next IPv6 scan will
|
|
||||||
// report the port again as open (in IPv6 namespace), while the
|
|
||||||
// same port in IPv4 namespace might still be blocked, and
|
|
||||||
// re-use of this port fails.
|
|
||||||
// GDBserver behaves exactly like this.
|
|
||||||
|
|
||||||
Q_UNUSED(protocol)
|
|
||||||
|
|
||||||
// We used to have
|
|
||||||
// // /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6
|
|
||||||
// return {filePath("sed"),
|
|
||||||
// "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*",
|
|
||||||
//
|
|
||||||
// here, but that doesn't pass quoting on double-remote setups.
|
|
||||||
// Chicken out by using a simpler command.
|
|
||||||
return {filePath("/bin/sh"), {"-c", "cat /proc/net/tcp*"}};
|
|
||||||
},
|
|
||||||
|
|
||||||
&Port::parseFromCatOutput
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
DeviceProcessList *LinuxDevice::createProcessListModel(QObject *parent) const
|
DeviceProcessList *LinuxDevice::createProcessListModel(QObject *parent) const
|
||||||
{
|
{
|
||||||
return new ProcessList(sharedFromThis(), parent);
|
return new ProcessList(sharedFromThis(), parent);
|
||||||
|
@@ -22,8 +22,6 @@ public:
|
|||||||
|
|
||||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||||
|
|
||||||
bool canAutoDetectPorts() const override;
|
|
||||||
ProjectExplorer::PortsGatheringMethod portsGatheringMethod() const override;
|
|
||||||
bool canCreateProcessModel() const override { return true; }
|
bool canCreateProcessModel() const override { return true; }
|
||||||
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
ProjectExplorer::DeviceProcessList *createProcessListModel(QObject *parent) const override;
|
||||||
bool hasDeviceTester() const override { return true; }
|
bool hasDeviceTester() const override { return true; }
|
||||||
|
Reference in New Issue
Block a user