Serenity Operating System
at master 166 lines 7.6 kB view raw
1/* 2 * Copyright (c) 2022, Maciej <sppmacd@pm.me> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "NetworkSettingsWidget.h" 8 9#include <AK/DeprecatedString.h> 10#include <AK/IPv4Address.h> 11#include <AK/JsonParser.h> 12#include <Applications/NetworkSettings/NetworkSettingsGML.h> 13#include <LibCore/Command.h> 14#include <LibGUI/CheckBox.h> 15#include <LibGUI/ComboBox.h> 16#include <LibGUI/ItemListModel.h> 17#include <LibGUI/MessageBox.h> 18#include <LibGUI/Process.h> 19#include <LibGUI/SpinBox.h> 20#include <LibGUI/TextBox.h> 21 22namespace NetworkSettings { 23 24static int netmask_to_cidr(IPv4Address const& address) 25{ 26 auto address_in_host_representation = AK::convert_between_host_and_network_endian(address.to_u32()); 27 return 32 - count_trailing_zeroes_safe(address_in_host_representation); 28} 29 30NetworkSettingsWidget::NetworkSettingsWidget() 31{ 32 load_from_gml(network_settings_gml).release_value_but_fixme_should_propagate_errors(); 33 34 m_adapters_combobox = *find_descendant_of_type_named<GUI::ComboBox>("adapters_combobox"); 35 m_enabled_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("enabled_checkbox"); 36 m_enabled_checkbox->on_checked = [&](bool value) { 37 m_current_adapter_data->enabled = value; 38 on_switch_enabled_or_dhcp(); 39 set_modified(true); 40 }; 41 m_dhcp_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("dhcp_checkbox"); 42 m_dhcp_checkbox->on_checked = [&](bool value) { 43 m_current_adapter_data->dhcp = value; 44 on_switch_enabled_or_dhcp(); 45 set_modified(true); 46 }; 47 m_ip_address_textbox = *find_descendant_of_type_named<GUI::TextBox>("ip_address_textbox"); 48 m_ip_address_textbox->on_change = [&]() { 49 m_current_adapter_data->ip_address = m_ip_address_textbox->text(); 50 set_modified(true); 51 }; 52 m_cidr_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("cidr_spinbox"); 53 m_cidr_spinbox->on_change = [&](int value) { 54 m_current_adapter_data->cidr = value; 55 set_modified(true); 56 }; 57 m_default_gateway_textbox = *find_descendant_of_type_named<GUI::TextBox>("default_gateway_textbox"); 58 m_default_gateway_textbox->on_change = [&]() { 59 m_current_adapter_data->default_gateway = m_default_gateway_textbox->text(); 60 set_modified(true); 61 }; 62 63 auto config_file = Core::ConfigFile::open_for_system("Network").release_value_but_fixme_should_propagate_errors(); 64 65 auto proc_net_adapters_file = Core::File::open("/sys/kernel/net/adapters"sv, Core::File::OpenMode::Read).release_value_but_fixme_should_propagate_errors(); 66 auto data = proc_net_adapters_file->read_until_eof().release_value_but_fixme_should_propagate_errors(); 67 JsonParser parser(data); 68 JsonValue proc_net_adapters_json = parser.parse().release_value_but_fixme_should_propagate_errors(); 69 70 // FIXME: This should be done before creating a window. 71 if (proc_net_adapters_json.as_array().is_empty()) { 72 GUI::MessageBox::show_error(window(), "No network adapters found!"sv); 73 ::exit(1); 74 } 75 76 size_t selected_adapter_index = 0; 77 size_t index = 0; 78 proc_net_adapters_json.as_array().for_each([&](auto& value) { 79 auto& if_object = value.as_object(); 80 auto adapter_name = if_object.get_deprecated_string("name"sv).value(); 81 if (adapter_name == "loop") 82 return; 83 84 bool adapter_exists_in_config = config_file->has_group(adapter_name); 85 86 bool enabled = config_file->read_bool_entry(adapter_name, "Enabled", true); 87 if (enabled) 88 selected_adapter_index = index; 89 90 NetworkAdapterData adapter_data; 91 adapter_data.enabled = enabled; 92 adapter_data.dhcp = config_file->read_bool_entry(adapter_name, "DHCP", !adapter_exists_in_config); 93 adapter_data.ip_address = config_file->read_entry(adapter_name, "IPv4Address"); 94 auto netmask = IPv4Address::from_string(config_file->read_entry(adapter_name, "IPv4Netmask")); 95 adapter_data.cidr = netmask.has_value() ? netmask_to_cidr(*netmask) : 32; 96 adapter_data.default_gateway = config_file->read_entry(adapter_name, "IPv4Gateway"); 97 m_network_adapters.set(adapter_name, move(adapter_data)); 98 m_adapter_names.append(adapter_name); 99 index++; 100 }); 101 102 m_adapters_combobox->set_model(GUI::ItemListModel<DeprecatedString>::create(m_adapter_names)); 103 m_adapters_combobox->on_change = [this](DeprecatedString const& text, GUI::ModelIndex const&) { 104 on_switch_adapter(text); 105 }; 106 auto const& selected_adapter = selected_adapter_index; 107 dbgln("{} in {}", selected_adapter, m_adapter_names); 108 m_adapters_combobox->set_selected_index(selected_adapter); 109 on_switch_adapter(m_adapter_names[selected_adapter_index]); 110} 111 112void NetworkSettingsWidget::on_switch_adapter(DeprecatedString const& adapter) 113{ 114 auto& adapter_data = m_network_adapters.get(adapter).value(); 115 m_current_adapter_data = &adapter_data; 116 on_switch_enabled_or_dhcp(); 117 118 m_enabled_checkbox->set_checked(adapter_data.enabled, GUI::AllowCallback::No); 119 m_dhcp_checkbox->set_checked(adapter_data.dhcp, GUI::AllowCallback::No); 120 m_ip_address_textbox->set_text(adapter_data.ip_address, GUI::AllowCallback::No); 121 m_cidr_spinbox->set_value(adapter_data.cidr, GUI::AllowCallback::No); 122 m_default_gateway_textbox->set_text(adapter_data.default_gateway, GUI::AllowCallback::No); 123 124 VERIFY(m_current_adapter_data); 125} 126 127void NetworkSettingsWidget::on_switch_enabled_or_dhcp() 128{ 129 m_dhcp_checkbox->set_enabled(m_current_adapter_data->enabled); 130 m_ip_address_textbox->set_enabled(m_current_adapter_data->enabled && !m_current_adapter_data->dhcp); 131 m_cidr_spinbox->set_enabled(m_current_adapter_data->enabled && !m_current_adapter_data->dhcp); 132 m_default_gateway_textbox->set_enabled(m_current_adapter_data->enabled && !m_current_adapter_data->dhcp); 133} 134 135void NetworkSettingsWidget::apply_settings() 136{ 137 auto config_file = Core::ConfigFile::open_for_system("Network", Core::ConfigFile::AllowWriting::Yes).release_value_but_fixme_should_propagate_errors(); 138 for (auto const& adapter_data : m_network_adapters) { 139 auto netmask = IPv4Address::netmask_from_cidr(adapter_data.value.cidr).to_deprecated_string(); 140 config_file->write_bool_entry(adapter_data.key, "Enabled", adapter_data.value.enabled); 141 config_file->write_bool_entry(adapter_data.key, "DHCP", adapter_data.value.dhcp); 142 if (adapter_data.value.enabled && !adapter_data.value.dhcp) { 143 if (!IPv4Address::from_string(adapter_data.value.ip_address).has_value()) { 144 GUI::MessageBox::show_error(window(), DeprecatedString::formatted("Invalid IPv4 address for adapter {}", adapter_data.key)); 145 return; 146 } 147 if (!IPv4Address::from_string(adapter_data.value.default_gateway).has_value()) { 148 GUI::MessageBox::show_error(window(), DeprecatedString::formatted("Invalid IPv4 gateway for adapter {}", adapter_data.key)); 149 return; 150 } 151 } 152 config_file->write_entry(adapter_data.key, "IPv4Address", adapter_data.value.ip_address); 153 config_file->write_entry(adapter_data.key, "IPv4Netmask", netmask); 154 config_file->write_entry(adapter_data.key, "IPv4Gateway", adapter_data.value.default_gateway); 155 } 156 157 GUI::Process::spawn_or_show_error(window(), "/bin/NetworkServer"sv); 158} 159 160void NetworkSettingsWidget::switch_adapter(DeprecatedString const& adapter) 161{ 162 m_adapters_combobox->set_text(adapter, GUI::AllowCallback::No); 163 on_switch_adapter(adapter); 164} 165 166}