Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Port & IPv6 Support #354

Merged
merged 7 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ endif ()
target_link_libraries(moonlight-lib PUBLIC commons-ss4s-modules-list commons-sps-parser)

target_link_libraries(moonlight-lib PUBLIC commons-logging commons-gamecontrollerdb-updater commons-lazy
commons-refcounter commons-executor commons-linked-list commons-wol commons-ini-writer commons-copyfile)
commons-refcounter commons-executor commons-linked-list commons-wol commons-ini-writer commons-copyfile
commons-sockaddr)

configure_file(src/app/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
target_include_directories(moonlight-lib PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Expand Down
6 changes: 5 additions & 1 deletion core/libgamestream/libgamestream/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ typedef struct _SERVER_DATA {
const char *mac;
const char *hostname;
const char *gpuType;
/** HttpsPort */
unsigned short httpsPort;
/** ExternalPort */
unsigned short extPort;
bool paired;
bool supports4K;
bool supportsHdr;
Expand All @@ -55,7 +59,7 @@ void gs_destroy(GS_CLIENT hnd);

void gs_set_timeout(GS_CLIENT hnd, int timeout_secs);

int gs_get_status(GS_CLIENT hnd, PSERVER_DATA server, const char *address, bool unsupported);
int gs_get_status(GS_CLIENT hnd, PSERVER_DATA server, const char *address, uint16_t port, bool unsupported);

int gs_start_app(GS_CLIENT hnd, PSERVER_DATA server, PSTREAM_CONFIGURATION config, int appId, bool is_gfe, bool sops,
bool localaudio, int gamepad_mask);
Expand Down
402 changes: 236 additions & 166 deletions core/libgamestream/src/client.c

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/app/backend/pcmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -132,4 +133,4 @@ bool pcmanager_send_wol(pcmanager_t *manager, const uuidstr_t *uuid, pcmanager_c
* @param userdata
* @return
*/
int pcmanager_update_by_ip(worker_context_t *context, const char *ip, bool force);
int pcmanager_update_by_ip(worker_context_t *context, const char *ip, uint16_t port, bool force);
30 changes: 26 additions & 4 deletions src/app/backend/pcmanager/discovery/discovery_libmicrodns.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <microdns/microdns.h>
#include "util/bus.h"
#include "backend/pcmanager/worker/worker.h"
#include "sockaddr.h"

struct discovery_task_t {
pcmanager_t *manager;
Expand Down Expand Up @@ -89,12 +90,33 @@ static void discovery_callback(discovery_task_t *task, int status, const struct
return;
}
if (task->stop) { return; }
struct sockaddr *addr = sockaddr_new();
for (const struct rr_entry *cur = entries; cur != NULL; cur = cur->next) {
if (cur->type != RR_A) { continue; }
worker_context_t *ctx = worker_context_new(task->manager, NULL, NULL, NULL);
ctx->arg1 = strdup(cur->data.A.addr_str);
pcmanager_worker_queue(task->manager, worker_host_discovered, ctx);
switch (cur->type) {
case RR_A: {
if (addr->sa_family != AF_UNSPEC) { continue; }
sockaddr_set_ip(addr, AF_INET, &cur->data.A.addr);
break;
}
case RR_AAAA: {
if (addr->sa_family != AF_UNSPEC) { continue; }
// Ignore any link-local addresses
if (IN6_IS_ADDR_LINKLOCAL(&cur->data.AAAA.addr)) { 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) {
return;
}
worker_context_t *ctx = worker_context_new(task->manager, NULL, NULL, NULL);
ctx->arg1 = addr;
pcmanager_worker_queue(task->manager, worker_host_discovered, ctx);
}

static void discovery_finalize(void *arg, int result) {
Expand Down
86 changes: 44 additions & 42 deletions src/app/backend/pcmanager/known_hosts.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "known_hosts.h"
#include "priv.h"
#include "pclist.h"
#include "app.h"
Expand All @@ -8,27 +9,7 @@
#include "util/ini_ext.h"
#include "util/path.h"
#include "app_settings.h"

typedef struct known_host_t {
uuidstr_t uuid;
char *mac;
char *hostname;
char *address;
bool selected;
appid_list_t *favs;
appid_list_t *hidden;
struct known_host_t *next;
} known_host_t;

#define LINKEDLIST_IMPL
#define LINKEDLIST_MODIFIER static
#define LINKEDLIST_TYPE known_host_t
#define LINKEDLIST_PREFIX hostlist

#include "linked_list.h"

#undef LINKEDLIST_TYPE
#undef LINKEDLIST_PREFIX
#include "sockaddr.h"

#define LINKEDLIST_IMPL
#define LINKEDLIST_MODIFIER static
Expand All @@ -43,34 +24,33 @@ typedef struct known_host_t {
#undef LINKEDLIST_TYPE
#undef LINKEDLIST_PREFIX

static int known_hosts_parse(known_host_t **list, const char *section, const char *name, const char *value);
static int known_hosts_handle(known_host_t **list, const char *section, const char *name, const char *value);

static int hostlist_find_uuid(known_host_t *node, void *v);

static void hostlist_node_free(known_host_t *node);
static int known_hosts_find_uuid(known_host_t *node, void *v);

void pcmanager_load_known_hosts(pcmanager_t *manager) {
commons_log_info("PCManager", "Load unknown hosts");
char *conf_file = path_join(manager->app->settings.conf_dir, CONF_NAME_HOSTS);
known_host_t *hosts = NULL;
if (ini_parse(conf_file, (ini_handler) known_hosts_parse, &hosts) != 0) {
goto cleanup;
}
known_host_t *hosts = known_hosts_parse(conf_file);

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;
}

PSERVER_DATA server = serverdata_new();
server->uuid = uuidstr_tostr(&cur->uuid);
server->mac = mac;
server->hostname = hostname;
server->serverInfo.address = address;
server->serverInfo.address = strdup(address_buf);
server->extPort = sockaddr_get_port(address);

pclist_t *node = pclist_insert_known(manager, &cur->uuid, server);

Expand All @@ -85,8 +65,7 @@ void pcmanager_load_known_hosts(pcmanager_t *manager) {
selected_set = true;
}
}
cleanup:
hostlist_free(hosts, hostlist_node_free);
known_hosts_free(hosts, known_hosts_node_free);
free(conf_file);
}

Expand All @@ -101,12 +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);
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;
Expand All @@ -127,20 +118,20 @@ void pcmanager_save_known_hosts(pcmanager_t *manager) {
fclose(fp);
}

static int known_hosts_parse(known_host_t **list, const char *section, const char *name, const char *value) {
static int known_hosts_handle(known_host_t **list, const char *section, const char *name, const char *value) {
if (!section) { return 1; }
known_host_t *host = hostlist_find_by(*list, section, (hostlist_find_fn) hostlist_find_uuid);
known_host_t *host = known_hosts_find_by(*list, section, (known_hosts_find_fn) known_hosts_find_uuid);
if (!host) {
host = hostlist_new();
host = known_hosts_new();
uuidstr_fromstr(&host->uuid, section);
*list = hostlist_append(*list, host);
*list = known_hosts_append(*list, host);
}
if (INI_NAME_MATCH("mac")) {
host->mac = SDL_strdup(value);
} else if (INI_NAME_MATCH("hostname")) {
host->hostname = SDL_strdup(value);
} else if (INI_NAME_MATCH("address")) {
host->address = SDL_strdup(value);
host->address = sockaddr_parse(value);
} else if (INI_NAME_MATCH("selected")) {
host->selected = INI_IS_TRUE(value);
} else if (INI_NAME_MATCH("favorite")) {
Expand All @@ -155,16 +146,27 @@ static int known_hosts_parse(known_host_t **list, const char *section, const cha
return 1;
}

static int hostlist_find_uuid(known_host_t *node, void *v) {
static int known_hosts_find_uuid(known_host_t *node, void *v) {
return !uuidstr_t_equals_s(&node->uuid, v);
}

static void hostlist_node_free(known_host_t *node) {
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);
}
if (node->hidden) {
appid_list_free(node->hidden, (appid_list_nodefree_fn) free);
}
free(node);
}

known_host_t *known_hosts_parse(const char *conf_file) {
known_host_t *hosts = NULL;
if (ini_parse(conf_file, (ini_handler) known_hosts_handle, &hosts) != 0) {
return NULL;
}
return hosts;
}
48 changes: 48 additions & 0 deletions src/app/backend/pcmanager/known_hosts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Ningyuan Li <https://github.com/mariotaku>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#pragma once

#include "backend/types.h"
#include "uuidstr.h"
#include "sockaddr.h"

typedef struct known_host_t {
uuidstr_t uuid;
char *mac;
char *hostname;
struct sockaddr *address;
bool selected;
appid_list_t *favs;
appid_list_t *hidden;
struct known_host_t *next;
} known_host_t;

void known_hosts_node_free(known_host_t *node);

known_host_t *known_hosts_parse(const char *conf_file);

#define LINKEDLIST_IMPL
#define LINKEDLIST_MODIFIER static
#define LINKEDLIST_TYPE known_host_t
#define LINKEDLIST_PREFIX known_hosts

#include "linked_list.h"

#undef LINKEDLIST_TYPE
#undef LINKEDLIST_PREFIX
9 changes: 6 additions & 3 deletions src/app/backend/pcmanager/pairing.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/app/backend/pcmanager/pcmanager_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ PSERVER_DATA serverdata_clone(const SERVER_DATA *src) {
server->mac = strdup_nullable(src->mac);
server->hostname = strdup_nullable(src->hostname);
server->gpuType = strdup_nullable(src->gpuType);
server->extPort = src->extPort;
server->httpsPort = src->httpsPort;
server->paired = src->paired;
server->supports4K = src->supports4K;
server->supportsHdr = src->supportsHdr;
Expand Down
20 changes: 17 additions & 3 deletions src/app/backend/pcmanager/worker/manual_add.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
#include "worker.h"
#include "backend/pcmanager/priv.h"
#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, true);
return updated_by_addr(context, true);
}

int worker_host_discovered(worker_context_t *context) {
return pcmanager_update_by_ip(context, context->arg1, false);
}
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_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, force);
}
Loading