diff options
| author | Sepalani <sepalani@hotmail.fr> | 2020-04-19 23:30:50 +0400 |
|---|---|---|
| committer | Sepalani <sepalani@hotmail.fr> | 2020-04-27 21:47:00 +0400 |
| commit | 5e33cd48da132e0b2b4e459ef83388233d4e3a2f (patch) | |
| tree | 62942d5550e52f3deb1e6ad37b096ac5c9d7f2da /Source/Core/DolphinQt/Debugger/NetworkWidget.cpp | |
| parent | 88ae4c7914af3a5487bdbff2920973833b77d6ce (diff) | |
Debugger: Add a Network widget
Display socket table, SSL context and options
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/NetworkWidget.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Debugger/NetworkWidget.cpp | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/Source/Core/DolphinQt/Debugger/NetworkWidget.cpp b/Source/Core/DolphinQt/Debugger/NetworkWidget.cpp new file mode 100644 index 0000000000..8adee91ca2 --- /dev/null +++ b/Source/Core/DolphinQt/Debugger/NetworkWidget.cpp @@ -0,0 +1,301 @@ +// Copyright 2020 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt/Debugger/NetworkWidget.h" + +#include <QCheckBox> +#include <QGridLayout> +#include <QGroupBox> +#include <QHeaderView> +#include <QTableWidget> +#include <QVBoxLayout> + +#ifdef _WIN32 +#include <winsock2.h> +#else +#include <sys/socket.h> +#include <sys/types.h> +#endif + +#include "Core/ConfigManager.h" +#include "Core/IOS/Network/SSL.h" +#include "Core/IOS/Network/Socket.h" +#include "DolphinQt/Host.h" +#include "DolphinQt/Settings.h" + +namespace +{ +QTableWidgetItem* GetSocketDomain(s32 host_fd) +{ + if (host_fd < 0) + return new QTableWidgetItem(); + + sockaddr sa; + socklen_t sa_len = sizeof(sa); + const int ret = getsockname(host_fd, &sa, &sa_len); + if (ret != 0) + return new QTableWidgetItem(QTableWidget::tr("Unknown")); + + switch (sa.sa_family) + { + case 2: + return new QTableWidgetItem(QLatin1Literal("AF_INET")); + case 23: + return new QTableWidgetItem(QLatin1Literal("AF_INET6")); + default: + return new QTableWidgetItem(QString::number(sa.sa_family)); + } +} + +QTableWidgetItem* GetSocketType(s32 host_fd) +{ + if (host_fd < 0) + return new QTableWidgetItem(); + + int so_type; + socklen_t opt_len = sizeof(so_type); + const int ret = + getsockopt(host_fd, SOL_SOCKET, SO_TYPE, reinterpret_cast<char*>(&so_type), &opt_len); + if (ret != 0) + return new QTableWidgetItem(QTableWidget::tr("Unknown")); + + switch (so_type) + { + case 1: + return new QTableWidgetItem(QLatin1Literal("SOCK_STREAM")); + case 2: + return new QTableWidgetItem(QLatin1Literal("SOCK_DGRAM")); + default: + return new QTableWidgetItem(QString::number(so_type)); + } +} + +QTableWidgetItem* GetSocketState(s32 host_fd) +{ + if (host_fd < 0) + return new QTableWidgetItem(); + + sockaddr_in peer_addr; + socklen_t peer_addr_len = sizeof(sockaddr_in); + if (getpeername(host_fd, reinterpret_cast<sockaddr*>(&peer_addr), &peer_addr_len) == 0) + return new QTableWidgetItem(QTableWidget::tr("Connected")); + + int so_accept = 0; + socklen_t opt_len = sizeof(so_accept); + const int ret = + getsockopt(host_fd, SOL_SOCKET, SO_ACCEPTCONN, reinterpret_cast<char*>(&so_accept), &opt_len); + if (ret == 0 && so_accept > 0) + return new QTableWidgetItem(QTableWidget::tr("Listening")); + return new QTableWidgetItem(QTableWidget::tr("Unbound")); +} + +QTableWidgetItem* GetSocketName(s32 host_fd) +{ + if (host_fd < 0) + return new QTableWidgetItem(); + + sockaddr_in sock_addr; + socklen_t sock_addr_len = sizeof(sockaddr_in); + if (getsockname(host_fd, reinterpret_cast<sockaddr*>(&sock_addr), &sock_addr_len) != 0) + return new QTableWidgetItem(QTableWidget::tr("Unknown")); + + const QString sock_name = QStringLiteral("%1:%2") + .arg(QString::fromLatin1(inet_ntoa(sock_addr.sin_addr))) + .arg(ntohs(sock_addr.sin_port)); + + sockaddr_in peer_addr; + socklen_t peer_addr_len = sizeof(sockaddr_in); + if (getpeername(host_fd, reinterpret_cast<sockaddr*>(&peer_addr), &peer_addr_len) != 0) + return new QTableWidgetItem(sock_name); + + const QString peer_name = QStringLiteral("%1:%2") + .arg(QString::fromLatin1(inet_ntoa(peer_addr.sin_addr))) + .arg(ntohs(peer_addr.sin_port)); + return new QTableWidgetItem(QStringLiteral("%1->%2").arg(sock_name).arg(peer_name)); +} +} // namespace + +NetworkWidget::NetworkWidget(QWidget* parent) : QDockWidget(parent) +{ + setWindowTitle(tr("Network")); + setObjectName(QStringLiteral("network")); + + setHidden(!Settings::Instance().IsNetworkVisible() || !Settings::Instance().IsDebugModeEnabled()); + + setAllowedAreas(Qt::AllDockWidgetAreas); + + CreateWidgets(); + + auto& settings = Settings::GetQSettings(); + + restoreGeometry(settings.value(QStringLiteral("networkwidget/geometry")).toByteArray()); + // macOS: setHidden() needs to be evaluated before setFloating() for proper window presentation + // according to Settings + setFloating(settings.value(QStringLiteral("networkwidget/floating")).toBool()); + + ConnectWidgets(); + + connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &NetworkWidget::Update); + + connect(&Settings::Instance(), &Settings::NetworkVisibilityChanged, + [this](bool visible) { setHidden(!visible); }); + + connect(&Settings::Instance(), &Settings::DebugModeToggled, [this](bool enabled) { + setHidden(!enabled || !Settings::Instance().IsNetworkVisible()); + }); +} + +NetworkWidget::~NetworkWidget() +{ + auto& settings = Settings::GetQSettings(); + + settings.setValue(QStringLiteral("networkwidget/geometry"), saveGeometry()); + settings.setValue(QStringLiteral("networkwidget/floating"), isFloating()); +} + +void NetworkWidget::closeEvent(QCloseEvent*) +{ + Settings::Instance().SetNetworkVisible(false); +} + +void NetworkWidget::showEvent(QShowEvent* event) +{ + Update(); +} + +void NetworkWidget::CreateWidgets() +{ + auto* widget = new QWidget; + auto* layout = new QVBoxLayout; + widget->setLayout(layout); + layout->addWidget(CreateSocketTableGroup()); + layout->addWidget(CreateSSLContextGroup()); + layout->addWidget(CreateSSLOptionsGroup()); + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)); + setWidget(widget); + + Update(); +} + +void NetworkWidget::ConnectWidgets() +{ + connect(m_dump_ssl_read_checkbox, &QCheckBox::stateChanged, + [](int state) { SConfig::GetInstance().m_SSLDumpRead = state == Qt::Checked; }); + connect(m_dump_ssl_write_checkbox, &QCheckBox::stateChanged, + [](int state) { SConfig::GetInstance().m_SSLDumpWrite = state == Qt::Checked; }); + connect(m_dump_root_ca_checkbox, &QCheckBox::stateChanged, + [](int state) { SConfig::GetInstance().m_SSLDumpRootCA = state == Qt::Checked; }); + connect(m_dump_peer_cert_checkbox, &QCheckBox::stateChanged, + [](int state) { SConfig::GetInstance().m_SSLDumpPeerCert = state == Qt::Checked; }); + connect(m_verify_certificates_checkbox, &QCheckBox::stateChanged, + [](int state) { SConfig::GetInstance().m_SSLVerifyCert = state == Qt::Checked; }); +} + +void NetworkWidget::Update() +{ + m_socket_table->setRowCount(0); + for (u32 wii_fd = 0; wii_fd < IOS::HLE::WII_SOCKET_FD_MAX; wii_fd++) + { + m_socket_table->insertRow(wii_fd); + const s32 host_fd = IOS::HLE::WiiSockMan::GetInstance().GetHostSocket(wii_fd); + m_socket_table->setItem(wii_fd, 0, new QTableWidgetItem(QString::number(wii_fd))); + m_socket_table->setItem(wii_fd, 1, GetSocketDomain(host_fd)); + m_socket_table->setItem(wii_fd, 2, GetSocketType(host_fd)); + m_socket_table->setItem(wii_fd, 3, GetSocketState(host_fd)); + m_socket_table->setItem(wii_fd, 4, GetSocketName(host_fd)); + } + m_socket_table->resizeColumnsToContents(); + + m_ssl_table->setRowCount(0); + for (u32 ssl_id = 0; ssl_id < IOS::HLE::NET_SSL_MAXINSTANCES; ssl_id++) + { + m_ssl_table->insertRow(ssl_id); + s32 host_fd = -1; + if (IOS::HLE::Device::IsSSLIDValid(ssl_id) && + IOS::HLE::Device::NetSSL::_SSL[ssl_id].ctx.p_bio != nullptr) + { + host_fd = + static_cast<mbedtls_net_context*>(IOS::HLE::Device::NetSSL::_SSL[ssl_id].ctx.p_bio)->fd; + } + m_ssl_table->setItem(ssl_id, 0, new QTableWidgetItem(QString::number(ssl_id))); + m_ssl_table->setItem(ssl_id, 1, GetSocketDomain(host_fd)); + m_ssl_table->setItem(ssl_id, 2, GetSocketType(host_fd)); + m_ssl_table->setItem(ssl_id, 3, GetSocketState(host_fd)); + m_ssl_table->setItem(ssl_id, 4, GetSocketName(host_fd)); + } + m_ssl_table->resizeColumnsToContents(); + + const auto& config = SConfig::GetInstance(); + m_dump_ssl_read_checkbox->setChecked(config.m_SSLDumpRead); + m_dump_ssl_write_checkbox->setChecked(config.m_SSLDumpWrite); + m_dump_root_ca_checkbox->setChecked(config.m_SSLDumpRootCA); + m_dump_peer_cert_checkbox->setChecked(config.m_SSLDumpPeerCert); + m_verify_certificates_checkbox->setChecked(config.m_SSLVerifyCert); +} + +QGroupBox* NetworkWidget::CreateSocketTableGroup() +{ + QGroupBox* socket_table_group = new QGroupBox(tr("Socket table")); + QGridLayout* socket_table_layout = new QGridLayout; + socket_table_group->setLayout(socket_table_layout); + + m_socket_table = new QTableWidget(); + QStringList header{tr("FD"), tr("Domain"), tr("Type"), tr("State"), tr("Name")}; + m_socket_table->setColumnCount(header.size()); + + m_socket_table->setHorizontalHeaderLabels(header); + m_socket_table->setTabKeyNavigation(false); + m_socket_table->verticalHeader()->setVisible(false); + m_socket_table->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_socket_table->setSelectionMode(QAbstractItemView::NoSelection); + m_socket_table->setWordWrap(false); + + socket_table_layout->addWidget(m_socket_table, 0, 0); + socket_table_layout->setSpacing(1); + return socket_table_group; +} + +QGroupBox* NetworkWidget::CreateSSLContextGroup() +{ + QGroupBox* ssl_context_group = new QGroupBox(tr("SSL context")); + QGridLayout* ssl_context_layout = new QGridLayout; + ssl_context_group->setLayout(ssl_context_layout); + + m_ssl_table = new QTableWidget(); + QStringList header{tr("ID"), tr("Domain"), tr("Type"), tr("State"), tr("Name")}; + m_ssl_table->setColumnCount(header.size()); + + m_ssl_table->setHorizontalHeaderLabels(header); + m_ssl_table->setTabKeyNavigation(false); + m_ssl_table->verticalHeader()->setVisible(false); + m_ssl_table->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_ssl_table->setSelectionMode(QAbstractItemView::NoSelection); + m_ssl_table->setWordWrap(false); + + ssl_context_layout->addWidget(m_ssl_table, 0, 0); + ssl_context_layout->setSpacing(1); + return ssl_context_group; +} + +QGroupBox* NetworkWidget::CreateSSLOptionsGroup() +{ + QGroupBox* ssl_options_group = new QGroupBox(tr("SSL options")); + QGridLayout* ssl_options_layout = new QGridLayout; + ssl_options_group->setLayout(ssl_options_layout); + + m_dump_ssl_read_checkbox = new QCheckBox(tr("Dump SSL read")); + m_dump_ssl_write_checkbox = new QCheckBox(tr("Dump SSL write")); + m_dump_root_ca_checkbox = new QCheckBox(tr("Dump root CA")); + m_dump_peer_cert_checkbox = new QCheckBox(tr("Dump peer certificates")); + m_verify_certificates_checkbox = new QCheckBox(tr("Verify certificates")); + + ssl_options_layout->addWidget(m_dump_ssl_read_checkbox, 0, 0); + ssl_options_layout->addWidget(m_dump_ssl_write_checkbox, 1, 0); + ssl_options_layout->addWidget(m_verify_certificates_checkbox, 2, 0); + ssl_options_layout->addWidget(m_dump_root_ca_checkbox, 0, 1); + ssl_options_layout->addWidget(m_dump_peer_cert_checkbox, 1, 1); + + ssl_options_layout->setSpacing(1); + return ssl_options_group; +} |
