diff --git a/softmmu/vl.c b/softmmu/vl.c index 10dca8428e..27e84bf925 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -115,6 +115,7 @@ #include "ui/xemu-settings.h" #include "ui/xemu-notifications.h" +#include "ui/xemu-net.h" #define MAX_VIRTIO_CONSOLES 1 @@ -4381,6 +4382,14 @@ void qemu_init(int argc, char **argv, char **envp) exit(1); } +#ifdef XBOX + int xemu_net_enabled; + xemu_settings_get_bool(XEMU_SETTINGS_NETWORK_ENABLED, &xemu_net_enabled); + if (xemu_net_enabled) { + xemu_net_enable(); + } +#endif + qemu_opts_foreach(qemu_find_opts("object"), user_creatable_add_opts_foreach, object_create_delayed, &error_fatal); diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 3d06e206e1..5c9153f6b7 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -37,6 +37,7 @@ sdl.mo-objs := \ xemu-hud.o \ xemu-input.o \ xemu-monitor.o \ + xemu-net.o \ xemu-settings.o \ xemu-shaders.o \ diff --git a/ui/xemu-hud.cc b/ui/xemu-hud.cc index 9a38b085b8..fd428514d5 100644 --- a/ui/xemu-hud.cc +++ b/ui/xemu-hud.cc @@ -30,6 +30,7 @@ #include "xemu-monitor.h" #include "xemu-version.h" #include "xemu-data.h" +#include "xemu-net.h" #include "imgui/imgui.h" #include "imgui/examples/imgui_impl_sdl.h" @@ -95,6 +96,9 @@ static void ShowSettingsWindow(bool* p_open); bool show_about_window = false; static void ShowAboutWindow(bool* p_open); +bool show_network_window = false; +static void ShowNetworkWindow(bool* p_open); + bool show_demo_window = false; float ui_scale = 1.0; @@ -244,7 +248,8 @@ static void ShowMainMenu() { if (ImGui::BeginMenu("Machine")) { - ImGui::MenuItem("Input", NULL, &show_input_window); + ImGui::MenuItem("Input", NULL, &show_input_window); + ImGui::MenuItem("Network", NULL, &show_network_window); ImGui::MenuItem("Settings", NULL, &show_settings_window); ImGui::Separator(); if (ImGui::MenuItem(running ? "Pause" : "Run")) { @@ -526,6 +531,7 @@ void xemu_hud_render(SDL_Window *window) if (show_settings_window) ShowSettingsWindow(&show_settings_window); if (show_monitor_window) ShowMonitorConsole(&show_monitor_window); if (show_about_window) ShowAboutWindow(&show_about_window); + if (show_network_window) ShowNetworkWindow(&show_network_window); if (show_demo_window) ImGui::ShowDemoWindow(&show_demo_window); if (notification.active) { @@ -1280,3 +1286,102 @@ static void ShowFirstBootWindow(bool* p_open) static FirstBootWindow console; console.Draw("First Boot", p_open); } + +struct NetworkWindow +{ + char remote_addr[64]; + char local_addr[64]; + + NetworkWindow() + { + const char *tmp; + xemu_settings_get_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, &tmp); + strncpy(remote_addr, tmp, sizeof(remote_addr)-1); + xemu_settings_get_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, &tmp); + strncpy(local_addr, tmp, sizeof(local_addr)-1); + } + + ~NetworkWindow() + { + } + + void Draw(const char* title, bool* p_open) + { + ImVec2 size(400*ui_scale, 250*ui_scale); + + ImGui::SetNextWindowSize(size, ImGuiCond_Appearing); + if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) { + ImGui::End(); + return; + } + + bool is_enabled = xemu_net_is_enabled(); + + ImGui::TextWrapped( + "xemu socket networking works by sending and recieving packets over " + "UDP which encapsulate the network traffic that the machine would " + "send or recieve when connected to a Local Area Network (LAN)." + ); + + ImGui::Dummy(ImVec2(0, 5*ui_scale)); + ImGui::Separator(); + ImGui::Dummy(ImVec2(0, 5*ui_scale)); + + ImGui::Columns(2, "", false); + ImGui::SetColumnWidth(0, ImGui::GetWindowWidth()*0.33); + + ImGuiInputTextFlags flg = 0; + if (is_enabled) { + flg |= ImGuiInputTextFlags_ReadOnly; + } + + ImGui::Text("Remote Host"); + ImGui::SameLine(); HelpMarker("The remote : to forward packets to (e.g. 1.2.3.4:9368)"); + ImGui::NextColumn(); + float w = ImGui::GetColumnWidth()-10*ui_scale; + ImGui::SetNextItemWidth(w); + if (is_enabled) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f); + ImGui::InputText("###remote_host", remote_addr, sizeof(remote_addr), flg); + if (is_enabled) ImGui::PopStyleVar(); + ImGui::NextColumn(); + + ImGui::Text("Local Host"); + ImGui::SameLine(); HelpMarker("The local : to recieve packets on (e.g. 0.0.0.0:9368)"); + ImGui::NextColumn(); + ImGui::SetNextItemWidth(w); + if (is_enabled) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.6f); + ImGui::InputText("###local_host", local_addr, sizeof(local_addr), flg); + if (is_enabled) ImGui::PopStyleVar(); + ImGui::NextColumn(); + + ImGui::Columns(1); + + ImGui::SetCursorPosY(ImGui::GetWindowHeight()-(10+20)*ui_scale); + ImGui::Text("Status: %sEnabled", is_enabled ? "" : "Not "); + ImGui::SameLine(); + + ImGui::SetCursorPosY(ImGui::GetWindowHeight()-(10+25)*ui_scale); + ImGui::SetCursorPosX(ImGui::GetWindowWidth()-(120+10)*ui_scale); + + ImGui::SetItemDefaultFocus(); + if (ImGui::Button(is_enabled ? "Disable" : "Enable", ImVec2(120*ui_scale, 0))) { + if (!is_enabled) { + xemu_settings_set_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, remote_addr); + xemu_settings_set_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, local_addr); + xemu_net_enable(); + } else { + xemu_net_disable(); + } + xemu_settings_set_bool(XEMU_SETTINGS_NETWORK_ENABLED, xemu_net_is_enabled()); + xemu_settings_save(); + } + + ImGui::End(); + } +}; + +static void ShowNetworkWindow(bool* p_open) +{ + static NetworkWindow console; + console.Draw("Network", p_open); +} diff --git a/ui/xemu-net.c b/ui/xemu-net.c new file mode 100644 index 0000000000..3432603eef --- /dev/null +++ b/ui/xemu-net.c @@ -0,0 +1,118 @@ +/* + * xemu Network Management + * + * Wrapper functions to configure network settings at runtime. + * + * Copyright (C) 2020 Matt Borgerson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xemu-net.h" +#include "xemu-settings.h" + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "monitor/qdev.h" +#include "qapi/qmp/qdict.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "net/net.h" +#include "net/hub.h" + +static const char *id = "xemu-netdev"; +static const char *id_hubport = "xemu-netdev-hubport"; + +void xemu_net_enable(void) +{ + Error *local_err = NULL; + + NetClientState *nc = qemu_find_netdev(id); + if (nc != NULL) { + return; + } + + const char *local_addr, *remote_addr; + xemu_settings_get_string(XEMU_SETTINGS_NETWORK_REMOTE_ADDR, &remote_addr); + xemu_settings_get_string(XEMU_SETTINGS_NETWORK_LOCAL_ADDR, &local_addr); + + // Create the UDP netdev + QDict *qdict = qdict_new(); + qdict_put_str(qdict, "id", id); + qdict_put_str(qdict, "type", "socket"); + qdict_put_str(qdict, "udp", remote_addr); + qdict_put_str(qdict, "localaddr", local_addr); + QemuOpts *opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &error_abort); + qobject_unref(qdict); + netdev_add(opts, &local_err); + if (local_err) { + qemu_opts_del(opts); + error_report_err(local_err); + // error_propagate(errp, local_err); + return; + } + + // Create the hubport + qdict = qdict_new(); + qdict_put_str(qdict, "id", id_hubport); + qdict_put_str(qdict, "type", "hubport"); + qdict_put_int(qdict, "hubid", 0); + qdict_put_str(qdict, "netdev", id); + opts = qemu_opts_from_qdict(qemu_find_opts("netdev"), qdict, &error_abort); + qobject_unref(qdict); + netdev_add(opts, &local_err); + if (local_err) { + qemu_opts_del(opts); + error_report_err(local_err); + // error_propagate(errp, local_err); + } +} + +static void remove_netdev(const char *name) +{ + NetClientState *nc; + QemuOpts *opts; + + nc = qemu_find_netdev(name); + if (!nc) { + // error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + // "Device '%s' not found", name); + return; + } + + opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name); + if (!opts) { + // error_setg(errp, "Device '%s' is not a netdev", name); + return; + } + + qemu_opts_del(opts); + qemu_del_net_client(nc); +} + +void xemu_net_disable(void) +{ + remove_netdev(id); + remove_netdev(id_hubport); +} + +int xemu_net_is_enabled(void) +{ + NetClientState *nc; + nc = qemu_find_netdev(id); + return (nc != NULL); +} diff --git a/ui/xemu-net.h b/ui/xemu-net.h new file mode 100644 index 0000000000..2c3f0dc668 --- /dev/null +++ b/ui/xemu-net.h @@ -0,0 +1,37 @@ +/* + * xemu Network Management + * + * Wrapper functions to configure network settings at runtime. + * + * Copyright (C) 2020 Matt Borgerson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XEMU_NETWORK_H +#define XEMU_NETWORK_H + +#ifdef __cplusplus +extern "C" { +#endif + +void xemu_net_enable(void); +void xemu_net_disable(void); +int xemu_net_is_enabled(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ui/xemu-settings.c b/ui/xemu-settings.c index 70234e5f96..0b20cce0fa 100644 --- a/ui/xemu-settings.c +++ b/ui/xemu-settings.c @@ -53,6 +53,11 @@ struct xemu_settings { char *controller_2_guid; char *controller_3_guid; char *controller_4_guid; + + // [network] + int net_enabled; // Boolean + char *net_local_addr; + char *net_remote_addr; }; struct enum_str_map { @@ -95,6 +100,10 @@ struct config_offset_table { [XEMU_SETTINGS_INPUT_CONTROLLER_2_GUID] = { CONFIG_TYPE_STRING, "input", "controller_2_guid", offsetof(struct xemu_settings, controller_2_guid), { .default_str = "" } }, [XEMU_SETTINGS_INPUT_CONTROLLER_3_GUID] = { CONFIG_TYPE_STRING, "input", "controller_3_guid", offsetof(struct xemu_settings, controller_3_guid), { .default_str = "" } }, [XEMU_SETTINGS_INPUT_CONTROLLER_4_GUID] = { CONFIG_TYPE_STRING, "input", "controller_4_guid", offsetof(struct xemu_settings, controller_4_guid), { .default_str = "" } }, + + [XEMU_SETTINGS_NETWORK_ENABLED] = { CONFIG_TYPE_BOOL, "network", "enabled", offsetof(struct xemu_settings, net_enabled), { .default_bool = 0 } }, + [XEMU_SETTINGS_NETWORK_LOCAL_ADDR] = { CONFIG_TYPE_STRING, "network", "local_addr", offsetof(struct xemu_settings, net_local_addr), { .default_str = "0.0.0.0:9368" } }, + [XEMU_SETTINGS_NETWORK_REMOTE_ADDR] = { CONFIG_TYPE_STRING, "network", "remote_addr", offsetof(struct xemu_settings, net_remote_addr), { .default_str = "1.2.3.4:9368" } }, }; static const char *settings_path; diff --git a/ui/xemu-settings.h b/ui/xemu-settings.h index eba56427dc..e92ca66ea7 100644 --- a/ui/xemu-settings.h +++ b/ui/xemu-settings.h @@ -42,6 +42,9 @@ enum xemu_settings_keys { XEMU_SETTINGS_INPUT_CONTROLLER_2_GUID, XEMU_SETTINGS_INPUT_CONTROLLER_3_GUID, XEMU_SETTINGS_INPUT_CONTROLLER_4_GUID, + XEMU_SETTINGS_NETWORK_ENABLED, + XEMU_SETTINGS_NETWORK_LOCAL_ADDR, + XEMU_SETTINGS_NETWORK_REMOTE_ADDR, XEMU_SETTINGS__COUNT, XEMU_SETTINGS_INVALID = -1 };