From 0205c84b812796a93b4308a0cb20ef12ca1be610 Mon Sep 17 00:00:00 2001 From: Ningyuan Li Date: Sat, 6 Jan 2024 19:33:20 +0900 Subject: [PATCH] ipv6 support wip --- core/libgamestream/src/client.c | 15 ++++--- src/app/backend/pcmanager.h | 3 +- .../discovery/discovery_libmicrodns.c | 10 ++++- src/app/backend/pcmanager/known_hosts.c | 39 ++++++++++++------- src/app/backend/pcmanager/known_hosts.h | 4 +- src/app/backend/pcmanager/pairing.c | 9 +++-- src/app/backend/pcmanager/worker/manual_add.c | 14 +++++-- src/app/ui/launcher/add.dialog.c | 21 ++++++---- 8 files changed, 75 insertions(+), 40 deletions(-) diff --git a/core/libgamestream/src/client.c b/core/libgamestream/src/client.c index bd7f6b213..259a12a3a 100644 --- a/core/libgamestream/src/client.c +++ b/core/libgamestream/src/client.c @@ -919,17 +919,22 @@ static bool construct_url(GS_CLIENT hnd, char *url, size_t ulen, bool secure, co port = secure ? 47984 : 47989; } char *const proto = secure ? "https" : "http"; + size_t w_len = snprintf(url, ulen, "%s://", proto); + bool is_ipv6 = strchr(address, ':') != NULL; + if (is_ipv6) { + w_len += snprintf(url + w_len, ulen - w_len, "[%s]", address); + } else { + w_len += snprintf(url + w_len, ulen - w_len, "%s", address); + } + w_len += snprintf(url + w_len, ulen - w_len, ":%u/%s?uniqueid=%s&uuid=%.*s", port, action, hnd->unique_id, 36, + uuid.data); if (fmt) { char params[4096]; va_list ap; va_start(ap, fmt); vsnprintf(params, 4096, fmt, ap); va_end(ap); - snprintf(url, ulen, "%s://%s:%u/%s?uniqueid=%s&uuid=%.*s&%s", proto, address, port, action, - hnd->unique_id, 36, uuid.data, params); - } else { - snprintf(url, ulen, "%s://%s:%u/%s?uniqueid=%s&uuid=%.*s", proto, address, port, - action, hnd->unique_id, 36, uuid.data); + snprintf(url + w_len, ulen - w_len, "&%s", params); } return true; } diff --git a/src/app/backend/pcmanager.h b/src/app/backend/pcmanager.h index f7671b697..7dc2a3347 100644 --- a/src/app/backend/pcmanager.h +++ b/src/app/backend/pcmanager.h @@ -6,6 +6,7 @@ #include "libgamestream/client.h" #include "uuidstr.h" +#include "sockaddr.h" typedef struct app_t app_t; typedef struct pcmanager_t pcmanager_t; @@ -76,7 +77,7 @@ void pcmanager_unregister_listener(pcmanager_t *manager, const pcmanager_listene * @param userdata * @return */ -bool pcmanager_manual_add(pcmanager_t *manager, const char *address, pcmanager_callback_t callback, void *userdata); +bool pcmanager_manual_add(pcmanager_t *manager, sockaddr_t *address, pcmanager_callback_t callback, void *userdata); /** * @brief Generates a PIN code, and start pairing process. diff --git a/src/app/backend/pcmanager/discovery/discovery_libmicrodns.c b/src/app/backend/pcmanager/discovery/discovery_libmicrodns.c index 06c3f013e..ac3e4e604 100644 --- a/src/app/backend/pcmanager/discovery/discovery_libmicrodns.c +++ b/src/app/backend/pcmanager/discovery/discovery_libmicrodns.c @@ -95,12 +95,18 @@ static void discovery_callback(discovery_task_t *task, int status, const struct switch (cur->type) { case RR_A: { if (addr->sa_family != AF_UNSPEC) { continue; } - sockaddr_set_address(addr, AF_INET, &cur->data.A.addr); + sockaddr_set_ip(addr, AF_INET, &cur->data.A.addr); break; } - case RR_SRV: + case RR_AAAA: { + if (addr->sa_family != AF_UNSPEC) { continue; } + sockaddr_set_ip(addr, AF_INET6, &cur->data.AAAA.addr); + break; + } + case RR_SRV: { sockaddr_set_port(addr, cur->data.SRV.port); break; + } } } if (addr->sa_family == AF_UNSPEC) { diff --git a/src/app/backend/pcmanager/known_hosts.c b/src/app/backend/pcmanager/known_hosts.c index df6a9f46d..3b770e41a 100644 --- a/src/app/backend/pcmanager/known_hosts.c +++ b/src/app/backend/pcmanager/known_hosts.c @@ -9,6 +9,7 @@ #include "util/ini_ext.h" #include "util/path.h" #include "app_settings.h" +#include "sockaddr.h" #define LINKEDLIST_IMPL #define LINKEDLIST_MODIFIER static @@ -34,10 +35,13 @@ void pcmanager_load_known_hosts(pcmanager_t *manager) { bool selected_set = false; for (known_host_t *cur = hosts; cur; cur = cur->next) { - const char *mac = cur->mac, *hostname = cur->hostname, *address = cur->address; + const char *mac = cur->mac, *hostname = cur->hostname; + const struct sockaddr *address = cur->address; + char address_buf[64] = {0}; + sockaddr_get_ip_str(address, address_buf, sizeof(address_buf)); if (!mac || !hostname || !address) { commons_log_warn("PCManager", "Unknown host entry: mac=%s, hostname=%s, address=%s", mac, hostname, - address); + address_buf); continue; } @@ -45,8 +49,8 @@ void pcmanager_load_known_hosts(pcmanager_t *manager) { server->uuid = uuidstr_tostr(&cur->uuid); server->mac = mac; server->hostname = hostname; - server->serverInfo.address = address; - server->extPort = cur->port; + server->serverInfo.address = strdup(address_buf); + server->extPort = sockaddr_get_port(address); pclist_t *node = pclist_insert_known(manager, &cur->uuid, server); @@ -76,16 +80,24 @@ void pcmanager_save_known_hosts(pcmanager_t *manager) { if (!cur->server || !cur->known) { continue; } + char address_buf[64] = {0}; const SERVER_DATA *server = cur->server; ini_write_section(fp, server->uuid); ini_write_string(fp, "mac", server->mac); ini_write_string(fp, "hostname", server->hostname); - if (server->extPort && server->extPort != 47989) { - ini_write_stringf(fp, "address", "%s:%d", server->serverInfo.address, server->extPort); - } else { - ini_write_string(fp, "address", server->serverInfo.address); + + struct sockaddr *address = sockaddr_new(); + if (sockaddr_set_ip_str(address, strchr(server->serverInfo.address, ':') ? AF_INET6 : AF_INET, + server->serverInfo.address) != 0) { + free(address); + continue; } + sockaddr_set_port(address, server->extPort); + sockaddr_to_string(address, address_buf, sizeof(address_buf)); + ini_write_string(fp, "address", address_buf); + free(address); + if (!selected_set && cur->selected) { ini_write_bool(fp, "selected", true); selected_set = true; @@ -119,13 +131,7 @@ static int known_hosts_handle(known_host_t **list, const char *section, const ch } else if (INI_NAME_MATCH("hostname")) { host->hostname = SDL_strdup(value); } else if (INI_NAME_MATCH("address")) { - char *address = SDL_strdup(value); - char *port_colon = SDL_strrchr(address, ':'); - host->address = address; - if (port_colon) { - port_colon[0] = '\0'; - host->port = SDL_atoi(port_colon + 1); - } + host->address = sockaddr_parse(value); } else if (INI_NAME_MATCH("selected")) { host->selected = INI_IS_TRUE(value); } else if (INI_NAME_MATCH("favorite")) { @@ -145,6 +151,9 @@ static int known_hosts_find_uuid(known_host_t *node, void *v) { } void known_hosts_node_free(known_host_t *node) { + if (node->address) { + free(node->address); + } if (node->favs) { appid_list_free(node->favs, (appid_list_nodefree_fn) free); } diff --git a/src/app/backend/pcmanager/known_hosts.h b/src/app/backend/pcmanager/known_hosts.h index 3f745a247..7291977bf 100644 --- a/src/app/backend/pcmanager/known_hosts.h +++ b/src/app/backend/pcmanager/known_hosts.h @@ -20,13 +20,13 @@ #include "backend/types.h" #include "uuidstr.h" +#include "sockaddr.h" typedef struct known_host_t { uuidstr_t uuid; char *mac; char *hostname; - char *address; - uint16_t port; + struct sockaddr *address; bool selected; appid_list_t *favs; appid_list_t *hidden; diff --git a/src/app/backend/pcmanager/pairing.c b/src/app/backend/pcmanager/pairing.c index 9e5b68a18..1806a2445 100644 --- a/src/app/backend/pcmanager/pairing.c +++ b/src/app/backend/pcmanager/pairing.c @@ -16,7 +16,7 @@ bool pcmanager_pair(pcmanager_t *manager, const uuidstr_t *uuid, char *pin, pcma return false; } SERVER_DATA *server = node->server; - if (server->paired) return false; + if (server->paired) { return false; } if (server->currentGame) { commons_log_info("PCManager", "The server %s is in game", server->hostname); } @@ -28,9 +28,12 @@ bool pcmanager_pair(pcmanager_t *manager, const uuidstr_t *uuid, char *pin, pcma return true; } -bool pcmanager_manual_add(pcmanager_t *manager, const char *address, pcmanager_callback_t callback, void *userdata) { +bool pcmanager_manual_add(pcmanager_t *manager, sockaddr_t *address, pcmanager_callback_t callback, void *userdata) { + if (address == NULL) { + return false; + } worker_context_t *ctx = worker_context_new(manager, NULL, callback, userdata); - ctx->arg1 = strdup(address); + ctx->arg1 = address; pcmanager_worker_queue(manager, worker_add_by_ip, ctx); return true; } diff --git a/src/app/backend/pcmanager/worker/manual_add.c b/src/app/backend/pcmanager/worker/manual_add.c index 150a17c47..274491041 100644 --- a/src/app/backend/pcmanager/worker/manual_add.c +++ b/src/app/backend/pcmanager/worker/manual_add.c @@ -3,16 +3,22 @@ #include "errors.h" #include "sockaddr.h" +static int updated_by_addr(worker_context_t *context, bool force); + int worker_add_by_ip(worker_context_t *context) { - return pcmanager_update_by_ip(context, context->arg1, 0, true); + return updated_by_addr(context, true); } int worker_host_discovered(worker_context_t *context) { + return updated_by_addr(context, false); +} + +int updated_by_addr(worker_context_t *context, bool force) { struct sockaddr *addr = context->arg1; char ip[64]; - if (sockaddr_address_to_string(addr, ip, sizeof(ip)) != 0) { + if (sockaddr_get_ip_str(addr, ip, sizeof(ip)) != 0) { return GS_FAILED; } uint16_t port = sockaddr_get_port(addr); - return pcmanager_update_by_ip(context, ip, port, false); -} \ No newline at end of file + return pcmanager_update_by_ip(context, ip, port, force); +} diff --git a/src/app/ui/launcher/add.dialog.c b/src/app/ui/launcher/add.dialog.c index cc438b584..f4fc70649 100644 --- a/src/app/ui/launcher/add.dialog.c +++ b/src/app/ui/launcher/add.dialog.c @@ -46,6 +46,7 @@ static lv_obj_t *create_dialog(lv_fragment_t *self, lv_obj_t *parent) { lv_obj_set_style_pad_all(content, lv_dpx(8), 0); lv_obj_set_style_pad_gap(content, lv_dpx(8), 0); lv_obj_set_layout(content, LV_LAYOUT_GRID); + lv_obj_clear_flag(content, LV_OBJ_FLAG_SCROLLABLE); static lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_CONTENT, 1, LV_GRID_TEMPLATE_LAST}; static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST}; col_dsc[2] = LV_DPX(10); @@ -58,9 +59,9 @@ static lv_obj_t *create_dialog(lv_fragment_t *self, lv_obj_t *parent) { lv_obj_t *ip_input = lv_textarea_create(content); lv_obj_set_grid_cell(ip_input, LV_GRID_ALIGN_STRETCH, 0, 3, LV_GRID_ALIGN_STRETCH, 1, 1); - lv_textarea_set_placeholder_text(ip_input, locstr("IPv4 address only")); + lv_textarea_set_placeholder_text(ip_input, locstr("IPv4 or IPv6 address")); lv_textarea_set_one_line(ip_input, true); - lv_textarea_set_accepted_chars(ip_input, ".-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + lv_textarea_set_accepted_chars(ip_input, ".-_:[]0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); lv_obj_add_event_cb(ip_input, input_changed_cb, LV_EVENT_VALUE_CHANGED, controller); lv_obj_add_event_cb(ip_input, input_key_cb, LV_EVENT_KEY, controller); lv_obj_add_event_cb(ip_input, input_cancel_cb, LV_EVENT_CANCEL, controller); @@ -74,7 +75,7 @@ static lv_obj_t *create_dialog(lv_fragment_t *self, lv_obj_t *parent) { lv_obj_t *add_error = lv_label_create(content); lv_obj_add_flag(add_error, LV_OBJ_FLAG_HIDDEN); - lv_obj_set_height(add_error, LV_SIZE_CONTENT); + lv_obj_set_size(add_error, LV_PCT(100), LV_SIZE_CONTENT); lv_obj_set_grid_cell(add_error, LV_GRID_ALIGN_START, 0, 3, LV_GRID_ALIGN_STRETCH, 2, 1); lv_label_set_long_mode(add_error, LV_LABEL_LONG_WRAP); lv_label_set_text_static(add_error, locstr("Failed to add computer.")); @@ -93,11 +94,15 @@ static lv_obj_t *create_dialog(lv_fragment_t *self, lv_obj_t *parent) { static void dialog_cb(lv_event_t *event) { add_dialog_controller_t *controller = lv_event_get_user_data(event); lv_obj_t *dialog = lv_event_get_current_target(event); - if (dialog != controller->base.obj) return; + if (dialog != controller->base.obj) { + return; + } uint16_t btn = lv_msgbox_get_active_btn(dialog); if (btn == 1) { - const char *address = lv_textarea_get_text(controller->input); - if (!address || !address[0])return; + sockaddr_t *address = sockaddr_parse(lv_textarea_get_text(controller->input)); + if (!address) { + return; + } lv_obj_add_state(controller->btns, LV_STATE_DISABLED); lv_obj_add_state(controller->input, LV_STATE_DISABLED); lv_obj_clear_flag(controller->progress, LV_OBJ_FLAG_HIDDEN); @@ -110,8 +115,8 @@ static void dialog_cb(lv_event_t *event) { static void input_changed_cb(lv_event_t *event) { add_dialog_controller_t *controller = lv_event_get_user_data(event); - const char *address = lv_textarea_get_text(controller->input); - if (address && address[0]) { + sockaddr_t *address = sockaddr_parse(lv_textarea_get_text(controller->input)); + if (address) { lv_btnmatrix_clear_btn_ctrl(controller->btns, 1, LV_BTNMATRIX_CTRL_DISABLED); } else { lv_btnmatrix_set_btn_ctrl(controller->btns, 1, LV_BTNMATRIX_CTRL_DISABLED);