Wed, 23 Nov 2022 10:48:46 +0100
Debugger
- increased the configuration possibilities for the network interface the debug server listens on
- added the capability to configure the debug server of the IDE to listen at a fixed network port (default 35000)
diff -r e12589f1d408 -r a663a8be64da docs/changelog.md --- a/docs/changelog.md Tue Nov 22 16:33:30 2022 +0100 +++ b/docs/changelog.md Wed Nov 23 10:48:46 2022 +0100 @@ -10,6 +10,11 @@ utility - CycloneDX Interface - addad capability to generate readable (prettified) output +- Debugger + - increased the configuration possibilities for the network interface the debug + server listens on + - added the capability to configure the debug server of the IDE to listen at a + fixed network port (default 35000) - MicroPython - introduced a configuration option to enable manual selection of devices (e.g. for unknown devices or inside the Linux container of ChromeOS)
diff -r e12589f1d408 -r a663a8be64da src/eric7/Debugger/DebugServer.py --- a/src/eric7/Debugger/DebugServer.py Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/Debugger/DebugServer.py Wed Nov 23 10:48:46 2022 +0100 @@ -28,6 +28,14 @@ "None": "DebuggerInterfaceNone", } +NetworkInterfaceMapping = { + "all": QHostAddress.SpecialAddress.Any, + "allv4": QHostAddress.SpecialAddress.AnyIPv4, + "allv6": QHostAddress.SpecialAddress.AnyIPv6, + "localv4": QHostAddress.SpecialAddress.LocalHost, + "localv6": QHostAddress.SpecialAddress.LocalHostIPv6, +} + class DebugServer(QTcpServer): """ @@ -190,28 +198,34 @@ self.__reportedWatchpointIssues = [] self.networkInterface = Preferences.getDebugger("NetworkInterface") - if self.networkInterface == "all": - hostAddress = QHostAddress("0.0.0.0") - # QHostAddress.SpecialAddress.AnyIPv4) # secok - elif self.networkInterface == "allv6": - hostAddress = QHostAddress("::") - # QHostAddress.SpecialAddress.AnyIPv6) - else: - hostAddress = QHostAddress(self.networkInterface) + hostAddress = ( + QHostAddress(NetworkInterfaceMapping[self.networkInterface]) + if self.networkInterface in NetworkInterfaceMapping + else QHostAddress(self.networkInterface) + ) ( self.networkInterfaceName, self.networkInterfaceIndex, ) = self.__getNetworkInterfaceAndIndex(self.networkInterface) if not preventPassiveDebugging and Preferences.getDebugger("PassiveDbgEnabled"): - sock = Preferences.getDebugger("PassiveDbgPort") # default: 42424 - self.listen(hostAddress, sock) + port = Preferences.getDebugger("PassiveDbgPort") # default: 42424 + self.listen(hostAddress, port) self.passive = True self.passiveClientExited = False else: if hostAddress.toString().lower().startswith("fe80"): hostAddress.setScopeId(self.networkInterfaceName) - self.listen(hostAddress) + if Preferences.getDebugger("NetworkPortFixed"): + port = Preferences.getDebugger("NetworkPort") + res = self.listen(hostAddress, port) + if not res and Preferences.getDebugger("NetworkPortIncrement"): + maxPort = port + 100 # try a maximum of 100 ports + while not res and port < maxPort: + port += 1 + res = self.listen(hostAddress, port) + else: + self.listen(hostAddress) self.passive = False self.debuggerInterface = None @@ -261,13 +275,13 @@ @return IP address or hostname @rtype str """ - if self.networkInterface == "all": - if localhost: + if self.networkInterface in ("allv4", "localv4"): + if localhost or self.networkInterface == "localv4": return "127.0.0.1" else: return "{0}@@v4".format(QHostInfo.localHostName()) - elif self.networkInterface == "allv6": - if localhost: + elif self.networkInterface in ("all", "allv6", "localv6"): + if localhost or self.networkInterface == "localv6": return "::1" else: return "{0}@@v6".format(QHostInfo.localHostName())
diff -r e12589f1d408 -r a663a8be64da src/eric7/EricNetwork/EricJsonServer.py --- a/src/eric7/EricNetwork/EricJsonServer.py Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/EricNetwork/EricJsonServer.py Wed Nov 23 10:48:46 2022 +0100 @@ -54,20 +54,27 @@ # setup the network interface networkInterface = Preferences.getDebugger("NetworkInterface") - if networkInterface == "all" or "." in networkInterface: + if networkInterface in ("allv4", "localv4") or "." in networkInterface: # IPv4 self.__hostAddress = "127.0.0.1" - else: + elif networkInterface in ("all", "allv6", "localv6"): # IPv6 self.__hostAddress = "::1" + else: + self.__hostAddress = networkInterface self.listen(QHostAddress(self.__hostAddress)) self.newConnection.connect(self.handleNewConnection) - ## Note: Need the port if client is started external in debugger. + ## Note: Need the address and port if client is started external in debugger. + hostAddressStr = ( + "[{0}]".format(self.__hostAddress) + if ":" in self.__hostAddress + else self.__hostAddress + ) print( # __IGNORE_WARNING_M801__ - "JSON server ({1}) listening on: {0:d}".format( - self.serverPort(), self.__name + "JSON server ({2}) listening on: {0}:{1:d}".format( + hostAddressStr, self.serverPort(), self.__name ) )
diff -r e12589f1d408 -r a663a8be64da src/eric7/EricNetwork/EricJsonStreamReader.py --- a/src/eric7/EricNetwork/EricJsonStreamReader.py Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/EricNetwork/EricJsonStreamReader.py Wed Nov 23 10:48:46 2022 +0100 @@ -47,22 +47,29 @@ # setup the network interface if ip is None: networkInterface = Preferences.getDebugger("NetworkInterface") - if networkInterface == "all" or "." in networkInterface: + if networkInterface in ("allv4", "localv4") or "." in networkInterface: # IPv4 self.__hostAddress = "127.0.0.1" - else: + elif networkInterface in ("all", "allv6", "localv6"): # IPv6 self.__hostAddress = "::1" + else: + self.__hostAddress = networkInterface else: self.__hostAddress = ip self.listen(QHostAddress(self.__hostAddress)) self.newConnection.connect(self.handleNewConnection) - ## Note: Need the port if writer is started external in debugger. + ## Note: Need the address and port if client is started external in debugger. + hostAddressStr = ( + "[{0}]".format(self.__hostAddress) + if ":" in self.__hostAddress + else self.__hostAddress + ) print( # __IGNORE_WARNING_M801__ - "JSON reader ({1}) listening on: {0:d}".format( - self.serverPort(), self.__name + "JSON server ({2}) listening on: {0}:{1:d}".format( + hostAddressStr, self.serverPort(), self.__name ) )
diff -r e12589f1d408 -r a663a8be64da src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py --- a/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.py Wed Nov 23 10:48:46 2022 +0100 @@ -7,8 +7,6 @@ Module implementing the Debugger General configuration page. """ -import re - from PyQt6.QtCore import QAbstractItemModel, QModelIndex, Qt, pyqtSlot from PyQt6.QtGui import QBrush, QColor from PyQt6.QtNetwork import QAbstractSocket, QHostAddress, QNetworkInterface @@ -58,43 +56,66 @@ self.dbgTranslationLocalEdit ) - # set initial values - interfaces = [] + self.interfaceSelectorComboBox.addItem( + self.tr("All Network Interfaces (IPv4 & IPv6)"), + "all", + ) + self.interfaceSelectorComboBox.addItem( + self.tr("All Network Interfaces (IPv4"), + "allv4", + ) + self.interfaceSelectorComboBox.addItem( + self.tr("All Network Interfaces (IPv6)"), + "allv6", + ) + self.interfaceSelectorComboBox.addItem( + self.tr("Localhost (IPv4)"), + "localv4", + ) + self.interfaceSelectorComboBox.addItem( + self.tr("Localhost (IPv6)"), + "localv6", + ) + self.interfaceSelectorComboBox.addItem( + self.tr("Selected Interface"), + "selected", + ) + networkInterfaces = QNetworkInterface.allInterfaces() for networkInterface in networkInterfaces: addressEntries = networkInterface.addressEntries() if len(addressEntries) > 0: for addressEntry in addressEntries: - interfaces.append( - "{0} ({1})".format( - networkInterface.humanReadableName(), - addressEntry.ip().toString(), - ) + ip = addressEntry.ip().toString() + self.interfacesCombo.addItem( + "{0} ({1})".format(networkInterface.humanReadableName(), ip), ip ) - self.interfacesCombo.addItems(interfaces) + + # set initial values interface = Preferences.getDebugger("NetworkInterface") - # TODO: change config 'all' to 'allv4' - # TODO: change radiobutton selection to combo box and include - # - Localhost (IPv4) (localv4) - # - LocalHost (IPv6) (localv6) - # - Any (IPv4) (allv4) - # - Any (IPv6) (allv6) - # - Any (IPv4 and IPv6) (all) - # - Selected Interface + selectorIndex = self.interfaceSelectorComboBox.findData(interface) + if selectorIndex != -1: + self.interfaceSelectorComboBox.setCurrentIndex(selectorIndex) + else: + # Interface given by IP address + self.interfaceSelectorComboBox.setCurrentIndex( + self.interfaceSelectorComboBox.count() - 1 + ) + self.interfacesCombo.setCurrentIndex( + self.interfacesCombo.findData(interface) + ) + self.on_interfaceSelectorComboBox_currentIndexChanged( + self.interfacesCombo.currentIndex() + ) + self.serverPortStaticGroup.setChecked( + Preferences.getDebugger("NetworkPortFixed") + ) + self.serverPortIncrementCheckBox.setChecked( + Preferences.getDebugger("NetworkPortIncrement") + ) + self.serverPortSpinBox.setValue(Preferences.getDebugger("NetworkPort")) # TODO: allow to listen on a specific port with auto-increment if port is in # use already - if interface == "all": - self.allInterfacesButton.setChecked(True) - elif interface == "allv6": - self.all6InterfacesButton.setChecked(True) - else: - self.selectedInterfaceButton.setChecked(True) - index = -1 - for i in range(len(interfaces)): - if re.fullmatch(".*{0}.*".format(interface), interfaces[i]): - index = i - break - self.interfacesCombo.setCurrentIndex(index) self.allowedHostsList.addItems(Preferences.getDebugger("AllowedHosts")) @@ -193,17 +214,17 @@ "PassiveDbgType", self.passiveDbgBackendCombo.currentText() ) - if self.allInterfacesButton.isChecked(): - Preferences.setDebugger("NetworkInterface", "all") - elif self.all6InterfacesButton.isChecked(): - Preferences.setDebugger("NetworkInterface", "allv6") - else: - interface = self.interfacesCombo.currentText() - interface = interface.split("(")[1].split(")")[0] - if not interface: - Preferences.setDebugger("NetworkInterface", "all") - else: - Preferences.setDebugger("NetworkInterface", interface) + interface = self.interfaceSelectorComboBox.currentData() + if interface == "selected": + interface = self.interfacesCombo.currentData() + Preferences.setDebugger("NetworkInterface", interface) + Preferences.setDebugger( + "NetworkPortFixed", self.serverPortStaticGroup.isChecked() + ) + Preferences.setDebugger( + "NetworkPortIncrement", self.serverPortIncrementCheckBox.isChecked() + ) + Preferences.setDebugger("NetworkPort", self.serverPortSpinBox.value()) allowedHosts = [] for row in range(self.allowedHostsList.count()): @@ -255,6 +276,18 @@ "AutoViewSourceCode", self.autoViewSourcecodeCheckBox.isChecked() ) + @pyqtSlot(int) + def on_interfaceSelectorComboBox_currentIndexChanged(self, index): + """ + Private slot to handle the selection of a network interface type. + + @param index index of the selected entry + @type int + """ + self.interfacesCombo.setEnabled( + index == self.interfaceSelectorComboBox.count() - 1 + ) + def on_allowedHostsList_currentItemChanged(self, current, previous): """ Private method set the state of the edit and delete button.
diff -r e12589f1d408 -r a663a8be64da src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui --- a/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/Preferences/ConfigurationPages/DebuggerGeneralPage.ui Wed Nov 23 10:48:46 2022 +0100 @@ -7,10 +7,10 @@ <x>0</x> <y>0</y> <width>550</width> - <height>1694</height> + <height>1804</height> </rect> </property> - <layout class="QVBoxLayout" name="verticalLayout_7"> + <layout class="QVBoxLayout" name="verticalLayout_9"> <item> <widget class="QLabel" name="headerLabel"> <property name="text"> @@ -36,8 +36,8 @@ <property name="title"> <string>Network Interface</string> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0" colspan="4"> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> <widget class="QLabel" name="TextLabel1_2_3"> <property name="text"> <string><font color="#FF0000"><b>Note:</b> These settings are activated at the next startup of the application.</font></string> @@ -47,50 +47,14 @@ </property> </widget> </item> - <item row="1" column="0" colspan="2"> - <widget class="QRadioButton" name="allInterfacesButton"> + <item> + <widget class="QComboBox" name="interfaceSelectorComboBox"> <property name="toolTip"> - <string>Select to listen on all available network interfaces (IPv4 mode)</string> - </property> - <property name="text"> - <string>All network interfaces (IPv4)</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QRadioButton" name="all6InterfacesButton"> - <property name="toolTip"> - <string>Select to listen on all available network interfaces (IPv6 mode)</string> - </property> - <property name="text"> - <string>All network interfaces (IPv6)</string> + <string>Select the interface(s) to listen on</string> </property> </widget> </item> - <item row="1" column="3"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>103</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="0"> - <widget class="QRadioButton" name="selectedInterfaceButton"> - <property name="toolTip"> - <string>Select to listen on the configured interface</string> - </property> - <property name="text"> - <string>Only selected interface</string> - </property> - </widget> - </item> - <item row="2" column="1" colspan="3"> + <item> <widget class="QComboBox" name="interfacesCombo"> <property name="enabled"> <bool>false</bool> @@ -100,6 +64,73 @@ </property> </widget> </item> + <item> + <widget class="QGroupBox" name="serverPortStaticGroup"> + <property name="toolTip"> + <string>Select to listen on a fixed network port</string> + </property> + <property name="title"> + <string>Static Server Port</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Server Port:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="serverPortSpinBox"> + <property name="toolTip"> + <string>Enter the port number to listen on</string> + </property> + <property name="minimum"> + <number>1025</number> + </property> + <property name="maximum"> + <number>65535</number> + </property> + <property name="singleStep"> + <number>1</number> + </property> + <property name="value"> + <number>35000</number> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>333</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0" colspan="3"> + <widget class="QCheckBox" name="serverPortIncrementCheckBox"> + <property name="toolTip"> + <string>Select to increment the server port to listen on if the configured one is unavailable</string> + </property> + <property name="text"> + <string>Increment server port if unavailable</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> </layout> </widget> </item> @@ -836,10 +867,11 @@ </layout> </widget> <tabstops> - <tabstop>allInterfacesButton</tabstop> - <tabstop>all6InterfacesButton</tabstop> - <tabstop>selectedInterfaceButton</tabstop> + <tabstop>interfaceSelectorComboBox</tabstop> <tabstop>interfacesCombo</tabstop> + <tabstop>serverPortStaticGroup</tabstop> + <tabstop>serverPortSpinBox</tabstop> + <tabstop>serverPortIncrementCheckBox</tabstop> <tabstop>allowedHostsList</tabstop> <tabstop>addAllowedHostButton</tabstop> <tabstop>editAllowedHostButton</tabstop> @@ -880,12 +912,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>121</x> - <y>467</y> + <x>154</x> + <y>730</y> </hint> <hint type="destinationlabel"> - <x>107</x> - <y>498</y> + <x>140</x> + <y>763</y> </hint> </hints> </connection> @@ -896,28 +928,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>219</x> - <y>467</y> + <x>252</x> + <y>730</y> </hint> <hint type="destinationlabel"> - <x>205</x> - <y>498</y> - </hint> - </hints> - </connection> - <connection> - <sender>selectedInterfaceButton</sender> - <signal>toggled(bool)</signal> - <receiver>interfacesCombo</receiver> - <slot>setEnabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>587</x> - <y>107</y> - </hint> - <hint type="destinationlabel"> - <x>307</x> - <y>137</y> + <x>218</x> + <y>763</y> </hint> </hints> </connection> @@ -928,12 +944,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>78</x> - <y>467</y> + <x>111</x> + <y>730</y> </hint> <hint type="destinationlabel"> - <x>410</x> - <y>498</y> + <x>148</x> + <y>795</y> </hint> </hints> </connection> @@ -944,12 +960,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>257</x> - <y>467</y> + <x>290</x> + <y>730</y> </hint> <hint type="destinationlabel"> - <x>484</x> - <y>497</y> + <x>233</x> + <y>795</y> </hint> </hints> </connection>
diff -r e12589f1d408 -r a663a8be64da src/eric7/Utilities/BackgroundService.py --- a/src/eric7/Utilities/BackgroundService.py Tue Nov 22 16:33:30 2022 +0100 +++ b/src/eric7/Utilities/BackgroundService.py Wed Nov 23 10:48:46 2022 +0100 @@ -56,18 +56,27 @@ self.services = {} networkInterface = Preferences.getDebugger("NetworkInterface") - if networkInterface == "all" or "." in networkInterface: - self.hostAddress = "127.0.0.1" + if networkInterface in ("allv4", "localv4") or "." in networkInterface: + # IPv4 + self.__hostAddress = "127.0.0.1" + elif networkInterface in ("all", "allv6", "localv6"): + # IPv6 + self.__hostAddress = "::1" else: - self.hostAddress = "::1" - self.listen(QHostAddress(self.hostAddress)) + self.__hostAddress = networkInterface + self.listen(QHostAddress(self.__hostAddress)) self.newConnection.connect(self.on_newConnection) + ## Note: Need the address and port if started external in debugger: port = self.serverPort() - ## Note: Need the port if started external in debugger: - print("Background Service listening on: {0:d}".format(port)) - # __IGNORE_WARNING__ + hostAddressStr = ( + "[{0}]".format(self.__hostAddress) + if ":" in self.__hostAddress + else self.__hostAddress + ) + print("Background Service listening on: {0}:{1:d}".format(hostAddressStr, port)) + # __IGNORE_WARNING_M801__ interpreter = self.__getPythonInterpreter() if interpreter: @@ -112,7 +121,7 @@ proc.setProcessChannelMode(QProcess.ProcessChannelMode.ForwardedChannels) args = [ backgroundClient, - self.hostAddress, + self.__hostAddress, str(port), str(Preferences.getUI("BackgroundServiceProcesses")), Globals.getPythonLibraryDirectory(),