mirror of
https://github.com/rock88/moonlight-nx
synced 2024-11-10 06:14:15 +00:00
Use std::string and Data here - fix few memory leak errors
This commit is contained in:
parent
285416ba04
commit
d3233d1ee0
7 changed files with 281 additions and 292 deletions
|
@ -25,6 +25,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <Limelight.h>
|
||||
#include "Settings.hpp"
|
||||
#include "CryptoManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
|
||||
|
@ -34,19 +35,18 @@
|
|||
#define CHANNEL_MASK_STEREO 0x3
|
||||
#define CHANNEL_MASK_51_SURROUND 0xFC
|
||||
|
||||
static char* unique_id = "0123456789ABCDEF";
|
||||
static std::string unique_id = "0123456789ABCDEF";
|
||||
|
||||
static int load_server_status(PSERVER_DATA server) {
|
||||
static int load_server_status(PSERVER_DATA server, bool skip_https) {
|
||||
int ret;
|
||||
char url[4096];
|
||||
int i;
|
||||
int i = skip_https ? 1 : 0;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
char *pairedText = NULL;
|
||||
char *currentGameText = NULL;
|
||||
char *stateText = NULL;
|
||||
char *serverCodecModeSupportText = NULL;
|
||||
std::string pairedText;
|
||||
std::string currentGameText;
|
||||
std::string stateText;
|
||||
std::string serverCodecModeSupportText;
|
||||
|
||||
ret = GS_INVALID;
|
||||
|
||||
|
@ -55,8 +55,7 @@ static int load_server_status(PSERVER_DATA server) {
|
|||
// make another request over HTTP if the HTTPS request fails. We can't just use HTTP
|
||||
// for everything because it doesn't accurately tell us if we're paired.
|
||||
|
||||
snprintf(url, sizeof(url), "%s://%s:%d/serverinfo?uniqueid=%s",
|
||||
i == 0 ? "https" : "http", server->serverInfo.address, i == 0 ? 47984 : 47989, unique_id);
|
||||
snprintf(url, sizeof(url), "%s://%s:%d/serverinfo?uniqueid=%s", i == 0 ? "https" : "http", server->serverInfo.address, i == 0 ? 47984 : 47989, unique_id.c_str());
|
||||
|
||||
Data data;
|
||||
|
||||
|
@ -65,55 +64,57 @@ static int load_server_status(PSERVER_DATA server) {
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (xml_status(data.bytes(), data.size()) == GS_ERROR) {
|
||||
if (xml_status(data) == GS_ERROR) {
|
||||
ret = GS_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "currentgame", ¤tGameText) != GS_OK) {
|
||||
if (xml_search(data, "currentgame", ¤tGameText) != GS_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "PairStatus", &pairedText) != GS_OK)
|
||||
if (xml_search(data, "PairStatus", &pairedText) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "appversion", (char**) &server->serverInfo.serverInfoAppVersion) != GS_OK)
|
||||
if (xml_search(data, "appversion", &server->serverInfoAppVersion) != GS_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (xml_search(data, "state", &stateText) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "state", &stateText) != GS_OK)
|
||||
if (xml_search(data, "ServerCodecModeSupport", &serverCodecModeSupportText) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "ServerCodecModeSupport", &serverCodecModeSupportText) != GS_OK)
|
||||
if (xml_search(data, "gputype", &server->gpuType) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "gputype", &server->gpuType) != GS_OK)
|
||||
if (xml_search(data, "GsVersion", &server->gsVersion) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "GsVersion", &server->gsVersion) != GS_OK)
|
||||
if (xml_search(data, "hostname", &server->hostname) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "hostname", &server->hostname) != GS_OK)
|
||||
if (xml_search(data, "GfeVersion", &server->serverInfoGfeVersion) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "GfeVersion", (char**) &server->serverInfo.serverInfoGfeVersion) != GS_OK)
|
||||
if (xml_search(data, "mac", &server->mac) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "mac", &server->mac) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (xml_modelist(data.bytes(), data.size(), &server->modes) != GS_OK)
|
||||
if (xml_modelist(data, &server->modes) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
// These fields are present on all version of GFE that this client supports
|
||||
if (!strlen(currentGameText) || !strlen(pairedText) || !strlen(server->serverInfo.serverInfoAppVersion) || !strlen(stateText))
|
||||
if (currentGameText.empty() || pairedText.empty() || server->serverInfoAppVersion.empty() || stateText.empty()) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
server->paired = pairedText != NULL && strcmp(pairedText, "1") == 0;
|
||||
server->currentGame = currentGameText == NULL ? 0 : atoi(currentGameText);
|
||||
server->supports4K = serverCodecModeSupportText != NULL;
|
||||
server->serverMajorVersion = atoi(server->serverInfo.serverInfoAppVersion);
|
||||
server->paired = pairedText == "1";
|
||||
server->currentGame = currentGameText.empty() ? 0 : atoi(currentGameText.c_str());
|
||||
server->supports4K = !serverCodecModeSupportText.empty();
|
||||
server->serverMajorVersion = atoi(server->serverInfoAppVersion.c_str());
|
||||
|
||||
if (strstr(stateText, "_SERVER_BUSY") == NULL) {
|
||||
if (stateText == "_SERVER_BUSY") {
|
||||
// After GFE 2.8, current game remains set even after streaming
|
||||
// has ended. We emulate the old behavior by forcing it to zero
|
||||
// if streaming is not active.
|
||||
|
@ -122,15 +123,6 @@ static int load_server_status(PSERVER_DATA server) {
|
|||
ret = GS_OK;
|
||||
|
||||
cleanup:
|
||||
if (pairedText != NULL)
|
||||
free(pairedText);
|
||||
|
||||
if (currentGameText != NULL)
|
||||
free(currentGameText);
|
||||
|
||||
if (serverCodecModeSupportText != NULL)
|
||||
free(serverCodecModeSupportText);
|
||||
|
||||
i++;
|
||||
} while (ret != GS_OK && i < 2);
|
||||
|
||||
|
@ -166,21 +158,18 @@ int gs_unpair(PSERVER_DATA server) {
|
|||
|
||||
Data data;
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/unpair?uniqueid=%s", server->serverInfo.address, unique_id);
|
||||
snprintf(url, sizeof(url), "http://%s:47989/unpair?uniqueid=%s", server->serverInfo.address, unique_id.c_str());
|
||||
ret = http_request(url, &data, HTTPRequestTimeoutLow);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gs_pair_validate(Data &data, char** result) {
|
||||
if (*result) {
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
}
|
||||
static int gs_pair_validate(Data &data, std::string* result) {
|
||||
*result = "";
|
||||
|
||||
int ret = GS_OK;
|
||||
if ((ret = xml_status(data.bytes(), data.size()) != GS_OK)) {
|
||||
if ((ret = xml_status(data) != GS_OK)) {
|
||||
return ret;
|
||||
} else if ((ret = xml_search(data.bytes(), data.size(), "paired", result)) != GS_OK) {
|
||||
} else if ((ret = xml_search(data, "paired", result)) != GS_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -189,27 +178,20 @@ static int gs_pair_validate(Data &data, char** result) {
|
|||
// ret = GS_FAILED;
|
||||
// }
|
||||
|
||||
if (*result) {
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gs_pair_cleanup(int ret, PSERVER_DATA server, char** result) {
|
||||
static int gs_pair_cleanup(int ret, PSERVER_DATA server, std::string* result) {
|
||||
if (ret != GS_OK) {
|
||||
gs_unpair(server);
|
||||
}
|
||||
if (*result) {
|
||||
free(*result);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_pair(PSERVER_DATA server, char* pin) {
|
||||
int ret = GS_OK;
|
||||
Data data;
|
||||
char* result = NULL;
|
||||
std::string result;
|
||||
char url[4096];
|
||||
|
||||
if (server->paired) {
|
||||
|
@ -229,7 +211,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
Data salted_pin = salt.append(Data(pin, strlen(pin)));
|
||||
Logger::info("Client", "PIN: %s, salt %s", pin, salt.hex().bytes());
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, unique_id, salt.hex().bytes(), CryptoManager::cert_data().hex().bytes());
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, unique_id.c_str(), salt.hex().bytes(), CryptoManager::cert_data().hex().bytes());
|
||||
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
|
@ -239,13 +221,13 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
if ((ret = xml_search(data.bytes(), data.size(), "plaincert", &result)) != GS_OK) {
|
||||
if ((ret = xml_search(data, "plaincert", &result)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
Logger::info("Client", "Start pairing stage #2");
|
||||
|
||||
Data plainCert = Data(result, strlen(result));
|
||||
Data plainCert = Data((char *)result.c_str(), result.size());
|
||||
Data aesKey;
|
||||
|
||||
// Gen 7 servers use SHA256 to get the key
|
||||
|
@ -262,7 +244,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
Data randomChallenge = Data::random_bytes(16);
|
||||
Data encryptedChallenge = CryptoManager::aes_encrypt(randomChallenge, aesKey);
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, unique_id, encryptedChallenge.hex().bytes());
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, unique_id.c_str(), encryptedChallenge.hex().bytes());
|
||||
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
|
@ -272,14 +254,14 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "challengeresponse", &result) != GS_OK) {
|
||||
if (xml_search(data, "challengeresponse", &result) != GS_OK) {
|
||||
ret = GS_INVALID;
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
Logger::info("Client", "Start pairing stage #3");
|
||||
|
||||
Data encServerChallengeResp = Data(result, strlen(result)).hex_to_bytes();
|
||||
Data encServerChallengeResp = Data((char *)result.c_str(), result.size()).hex_to_bytes();
|
||||
Data decServerChallengeResp = CryptoManager::aes_decrypt(encServerChallengeResp, aesKey);
|
||||
Data serverResponse = decServerChallengeResp.subdata(0, hashLength);
|
||||
Data serverChallenge = decServerChallengeResp.subdata(hashLength, 16);
|
||||
|
@ -297,7 +279,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
}
|
||||
Data challengeRespEncrypted = CryptoManager::aes_encrypt(challengeRespHash, aesKey);
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, unique_id, challengeRespEncrypted.hex().bytes());
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, unique_id.c_str(), challengeRespEncrypted.hex().bytes());
|
||||
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
|
@ -307,14 +289,14 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
if (xml_search(data.bytes(), data.size(), "pairingsecret", &result) != GS_OK) {
|
||||
if (xml_search(data, "pairingsecret", &result) != GS_OK) {
|
||||
ret = GS_INVALID;
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
||||
Logger::info("Client", "Start pairing stage #4");
|
||||
|
||||
Data serverSecretResp = Data(result, strlen(result)).hex_to_bytes();
|
||||
Data serverSecretResp = Data((char *)result.c_str(), result.size()).hex_to_bytes();
|
||||
Data serverSecret = serverSecretResp.subdata(0, 16);
|
||||
Data serverSignature = serverSecretResp.subdata(16, 256);
|
||||
|
||||
|
@ -326,16 +308,16 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
|
||||
Data serverChallengeRespHashInput = randomChallenge.append(CryptoManager::signature(plainCert.hex_to_bytes())).append(serverSecret);
|
||||
Data serverChallengeRespHash;
|
||||
|
||||
if (server->serverMajorVersion >= 7) {
|
||||
serverChallengeRespHash = CryptoManager::SHA256_hash_data(serverChallengeRespHashInput);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
serverChallengeRespHash = CryptoManager::SHA1_hash_data(serverChallengeRespHashInput);
|
||||
}
|
||||
|
||||
Data clientPairingSecret = clientSecret.append(CryptoManager::sign_data(clientSecret, CryptoManager::key_data()));
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, unique_id, clientPairingSecret.hex().bytes());
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, unique_id.c_str(), clientPairingSecret.hex().bytes());
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
@ -346,7 +328,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
|||
|
||||
Logger::info("Client", "Start pairing stage #5");
|
||||
|
||||
snprintf(url, sizeof(url), "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, unique_id);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, unique_id.c_str());
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||
return gs_pair_cleanup(ret, server, &result);
|
||||
}
|
||||
|
@ -365,13 +347,13 @@ int gs_applist(PSERVER_DATA server, PAPP_LIST *list) {
|
|||
char url[4096];
|
||||
Data data;
|
||||
|
||||
snprintf(url, sizeof(url), "https://%s:47984/applist?uniqueid=%s", server->serverInfo.address, unique_id);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/applist?uniqueid=%s", server->serverInfo.address, unique_id.c_str());
|
||||
|
||||
if (http_request(url, &data, HTTPRequestTimeoutMedium) != GS_OK)
|
||||
ret = GS_IO_ERROR;
|
||||
else if (xml_status(data.bytes(), data.size()) == GS_ERROR)
|
||||
else if (xml_status(data) == GS_ERROR)
|
||||
ret = GS_ERROR;
|
||||
else if (xml_applist(data.bytes(), data.size(), list) != GS_OK)
|
||||
else if (xml_applist(data, list) != GS_OK)
|
||||
ret = GS_INVALID;
|
||||
return ret;
|
||||
}
|
||||
|
@ -381,21 +363,19 @@ int gs_app_boxart(PSERVER_DATA server, int app_id, Data* out) {
|
|||
char url[4096];
|
||||
Data data;
|
||||
|
||||
snprintf(url, sizeof(url), "https://%s:47984/appasset?uniqueid=%s&appid=%d&AssetType=2&AssetIdx=0", server->serverInfo.address, unique_id, app_id);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/appasset?uniqueid=%s&appid=%d&AssetType=2&AssetIdx=0", server->serverInfo.address, unique_id.c_str(), app_id);
|
||||
|
||||
if (http_request(url, &data, HTTPRequestTimeoutMedium) != GS_OK) {
|
||||
ret = GS_IO_ERROR;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
*out = data;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, bool sops, bool localaudio, int gamepad_mask) {
|
||||
int ret = GS_OK;
|
||||
char* result = NULL;
|
||||
std::string result;
|
||||
|
||||
PDISPLAY_MODE mode = server->modes;
|
||||
bool correct_mode = false;
|
||||
|
@ -438,61 +418,58 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b
|
|||
int channelCounnt = config->audioConfiguration == AUDIO_CONFIGURATION_STEREO ? CHANNEL_COUNT_STEREO : CHANNEL_COUNT_51_SURROUND;
|
||||
int mask = config->audioConfiguration == AUDIO_CONFIGURATION_STEREO ? CHANNEL_MASK_STEREO : CHANNEL_MASK_51_SURROUND;
|
||||
int fps = sops && config->fps > 60 ? 60 : config->fps;
|
||||
snprintf(url, sizeof(url), "https://%s:47984/launch?uniqueid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d", server->serverInfo.address, unique_id, appId, config->width, config->height, fps, sops, rand.hex().bytes(), rikeyid, localaudio, (mask << 16) + channelCounnt, gamepad_mask, gamepad_mask);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/launch?uniqueid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d", server->serverInfo.address, unique_id.c_str(), appId, config->width, config->height, fps, sops, rand.hex().bytes(), rikeyid, localaudio, (mask << 16) + channelCounnt, gamepad_mask, gamepad_mask);
|
||||
} else {
|
||||
snprintf(url, sizeof(url), "https://%s:47984/resume?uniqueid=%s&rikey=%s&rikeyid=%d", server->serverInfo.address, unique_id, rand.hex().bytes(), rikeyid);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/resume?uniqueid=%s&rikey=%s&rikeyid=%d", server->serverInfo.address, unique_id.c_str(), rand.hex().bytes(), rikeyid);
|
||||
}
|
||||
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) == GS_OK)
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) == GS_OK) {
|
||||
server->currentGame = appId;
|
||||
else
|
||||
goto cleanup;
|
||||
|
||||
if ((ret = xml_status(data.bytes(), data.size()) != GS_OK))
|
||||
goto cleanup;
|
||||
else if ((ret = xml_search(data.bytes(), data.size(), "gamesession", &result)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (!strcmp(result, "0")) {
|
||||
ret = GS_FAILED;
|
||||
goto cleanup;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (result != NULL)
|
||||
free(result);
|
||||
if ((ret = xml_status(data) != GS_OK)) {
|
||||
goto exit;
|
||||
} else if ((ret = xml_search(data, "gamesession", &result)) != GS_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (result == "0") {
|
||||
ret = GS_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_quit_app(PSERVER_DATA server) {
|
||||
int ret = GS_OK;
|
||||
char url[4096];
|
||||
char* result = NULL;
|
||||
std::string result;
|
||||
Data data;
|
||||
|
||||
snprintf(url, sizeof(url), "https://%s:47984/cancel?uniqueid=%s", server->serverInfo.address, unique_id);
|
||||
snprintf(url, sizeof(url), "https://%s:47984/cancel?uniqueid=%s", server->serverInfo.address, unique_id.c_str());
|
||||
if ((ret = http_request(url, &data, HTTPRequestTimeoutMedium)) != GS_OK)
|
||||
goto cleanup;
|
||||
goto exit;
|
||||
|
||||
if ((ret = xml_status(data.bytes(), data.size()) != GS_OK))
|
||||
goto cleanup;
|
||||
else if ((ret = xml_search(data.bytes(), data.size(), "cancel", &result)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if (strcmp(result, "0") == 0) {
|
||||
ret = GS_FAILED;
|
||||
goto cleanup;
|
||||
if ((ret = xml_status(data) != GS_OK)) {
|
||||
goto exit;
|
||||
} else if ((ret = xml_search(data, "cancel", &result)) != GS_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (result != NULL)
|
||||
free(result);
|
||||
if (result == "0") {
|
||||
ret = GS_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, bool unsupported) {
|
||||
int gs_init(PSERVER_DATA server, const std::string address, bool skip_https) {
|
||||
if (!CryptoManager::load_cert_key_pair()) {
|
||||
Logger::info("Client", "No certs, generate new...");
|
||||
|
||||
|
@ -502,10 +479,15 @@ int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, bool u
|
|||
}
|
||||
}
|
||||
|
||||
http_init(keyDirectory);
|
||||
http_init(Settings::instance().key_dir());
|
||||
|
||||
LiInitializeServerInformation(&server->serverInfo);
|
||||
server->serverInfo.address = address;
|
||||
server->unsupported = unsupported;
|
||||
return load_server_status(server);
|
||||
server->address = address;
|
||||
server->serverInfo.address = server->address.c_str();
|
||||
server->unsupported = Settings::instance().ignore_unsupported_resolutions();
|
||||
|
||||
int result = load_server_status(server, skip_https);
|
||||
server->serverInfo.serverInfoAppVersion = server->serverInfoAppVersion.c_str();
|
||||
server->serverInfo.serverInfoGfeVersion = server->serverInfoGfeVersion.c_str();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -28,16 +28,18 @@
|
|||
#define MAX_SUPPORTED_GFE_VERSION 7
|
||||
|
||||
typedef struct _SERVER_DATA {
|
||||
const char* address;
|
||||
char *mac;
|
||||
char* gpuType;
|
||||
std::string address;
|
||||
std::string serverInfoAppVersion;
|
||||
std::string serverInfoGfeVersion;
|
||||
std::string mac;
|
||||
std::string gpuType;
|
||||
bool paired;
|
||||
bool supports4K;
|
||||
bool unsupported;
|
||||
int currentGame;
|
||||
int serverMajorVersion;
|
||||
char* gsVersion;
|
||||
char* hostname;
|
||||
std::string gsVersion;
|
||||
std::string hostname;
|
||||
PDISPLAY_MODE modes;
|
||||
SERVER_INFORMATION serverInfo;
|
||||
} SERVER_DATA, *PSERVER_DATA;
|
||||
|
@ -45,7 +47,7 @@ typedef struct _SERVER_DATA {
|
|||
void gs_set_error(std::string error);
|
||||
std::string gs_error();
|
||||
|
||||
int gs_init(PSERVER_DATA server, char* address, const char *keyDirectory, bool unsupported);
|
||||
int gs_init(PSERVER_DATA server, const std::string address, bool skip_https = false);
|
||||
int gs_app_boxart(PSERVER_DATA server, int app_id, Data* out);
|
||||
int gs_start_app(PSERVER_DATA server, PSTREAM_CONFIGURATION config, int appId, bool sops, bool localaudio, int gamepad_mask);
|
||||
int gs_applist(PSERVER_DATA server, PAPP_LIST *app_list);
|
||||
|
|
|
@ -48,7 +48,7 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp
|
|||
return realsize;
|
||||
}
|
||||
|
||||
int http_init(const char* key_directory) {
|
||||
int http_init(const std::string key_directory) {
|
||||
if (!curl) {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
Logger::info("Curl", "%s", curl_version());
|
||||
|
@ -62,10 +62,10 @@ int http_init(const char* key_directory) {
|
|||
return GS_FAILED;
|
||||
|
||||
char certificateFilePath[4096];
|
||||
sprintf(certificateFilePath, "%s/%s", key_directory, CERTIFICATE_FILE_NAME);
|
||||
sprintf(certificateFilePath, "%s/%s", key_directory.c_str(), CERTIFICATE_FILE_NAME);
|
||||
|
||||
char keyFilePath[4096];
|
||||
sprintf(&keyFilePath[0], "%s/%s", key_directory, KEY_FILE_NAME);
|
||||
sprintf(&keyFilePath[0], "%s/%s", key_directory.c_str(), KEY_FILE_NAME);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
||||
|
@ -81,15 +81,15 @@ int http_init(const char* key_directory) {
|
|||
return GS_OK;
|
||||
}
|
||||
|
||||
int http_request(char* url, Data* data, HTTPRequestTimeout timeout) {
|
||||
Logger::info("Curl", "Request:\n%s", url);
|
||||
int http_request(const std::string url, Data* data, HTTPRequestTimeout timeout) {
|
||||
Logger::info("Curl", "Request:\n%s", url.c_str());
|
||||
|
||||
HTTP_DATA* http_data = (HTTP_DATA*)malloc(sizeof(HTTP_DATA));
|
||||
http_data->memory = (char*)malloc(1);
|
||||
http_data->size = 0;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_data);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Data.hpp"
|
||||
#pragma once
|
||||
|
||||
enum HTTPRequestTimeout: long {
|
||||
HTTPRequestTimeoutLow = 2,
|
||||
|
@ -27,5 +26,5 @@ enum HTTPRequestTimeout: long {
|
|||
HTTPRequestTimeoutLong = 120
|
||||
};
|
||||
|
||||
int http_init(const char* key_directory);
|
||||
int http_request(char* url, Data* data, HTTPRequestTimeout timeout);
|
||||
int http_init(const std::string key_directory);
|
||||
int http_request(const std::string url, Data* data, HTTPRequestTimeout timeout);
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
|
||||
#define STATUS_OK 200
|
||||
|
||||
static XML_Parser parser;
|
||||
|
||||
struct xml_query {
|
||||
char *memory;
|
||||
size_t size;
|
||||
|
@ -36,193 +34,202 @@ struct xml_query {
|
|||
};
|
||||
|
||||
static void XMLCALL _xml_start_element(void *userData, const char *name, const char **atts) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp((const char *)search->data, name) == 0)
|
||||
search->start++;
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp((const char *)search->data, name) == 0) {
|
||||
search->start++;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_end_element(void *userData, const char *name) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp((const char *)search->data, name) == 0)
|
||||
search->start--;
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp((const char *)search->data, name) == 0) {
|
||||
search->start--;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_start_applist_element(void *userData, const char *name, const char **atts) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp("App", name) == 0) {
|
||||
PAPP_LIST app = (PAPP_LIST)malloc(sizeof(APP_LIST));
|
||||
if (app == NULL)
|
||||
return;
|
||||
|
||||
app->id = 0;
|
||||
app->name = NULL;
|
||||
app->next = (PAPP_LIST) search->data;
|
||||
search->data = app;
|
||||
} else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) {
|
||||
search->memory = (char *)malloc(1);
|
||||
search->size = 0;
|
||||
search->start = 1;
|
||||
}
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp("App", name) == 0) {
|
||||
PAPP_LIST app = (PAPP_LIST)malloc(sizeof(APP_LIST));
|
||||
if (app == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
app->id = 0;
|
||||
app->name = NULL;
|
||||
app->next = (PAPP_LIST) search->data;
|
||||
search->data = app;
|
||||
} else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) {
|
||||
search->memory = (char *)malloc(1);
|
||||
search->size = 0;
|
||||
search->start = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_end_applist_element(void *userData, const char *name) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->start) {
|
||||
PAPP_LIST list = (PAPP_LIST) search->data;
|
||||
if (list == NULL)
|
||||
return;
|
||||
|
||||
if (strcmp("ID", name) == 0) {
|
||||
list->id = atoi(search->memory);
|
||||
free(search->memory);
|
||||
} else if (strcmp("AppTitle", name) == 0) {
|
||||
list->name = search->memory;
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->start) {
|
||||
PAPP_LIST list = (PAPP_LIST) search->data;
|
||||
if (list == NULL)
|
||||
return;
|
||||
|
||||
if (strcmp("ID", name) == 0) {
|
||||
list->id = atoi(search->memory);
|
||||
free(search->memory);
|
||||
} else if (strcmp("AppTitle", name) == 0) {
|
||||
list->name = search->memory;
|
||||
}
|
||||
search->start = 0;
|
||||
}
|
||||
search->start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_start_mode_element(void *userData, const char *name, const char **atts) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp("DisplayMode", name) == 0) {
|
||||
PDISPLAY_MODE mode = (PDISPLAY_MODE)calloc(1, sizeof(DISPLAY_MODE));
|
||||
if (mode != NULL) {
|
||||
mode->next = (PDISPLAY_MODE) search->data;
|
||||
search->data = mode;
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (strcmp("DisplayMode", name) == 0) {
|
||||
PDISPLAY_MODE mode = (PDISPLAY_MODE)calloc(1, sizeof(DISPLAY_MODE));
|
||||
if (mode != NULL) {
|
||||
mode->next = (PDISPLAY_MODE) search->data;
|
||||
search->data = mode;
|
||||
}
|
||||
} else if (search->data != NULL && (strcmp("Height", name) == 0 || strcmp("Width", name) == 0 || strcmp("RefreshRate", name) == 0)) {
|
||||
search->memory = (char *)malloc(1);
|
||||
search->size = 0;
|
||||
search->start = 1;
|
||||
}
|
||||
} else if (search->data != NULL && (strcmp("Height", name) == 0 || strcmp("Width", name) == 0 || strcmp("RefreshRate", name) == 0)) {
|
||||
search->memory = (char *)malloc(1);
|
||||
search->size = 0;
|
||||
search->start = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_end_mode_element(void *userData, const char *name) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->data != NULL && search->start) {
|
||||
PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data;
|
||||
if (strcmp("Width", name) == 0)
|
||||
mode->width = atoi(search->memory);
|
||||
else if (strcmp("Height", name) == 0)
|
||||
mode->height = atoi(search->memory);
|
||||
else if (strcmp("RefreshRate", name) == 0)
|
||||
mode->refresh = atoi(search->memory);
|
||||
|
||||
free(search->memory);
|
||||
search->start = 0;
|
||||
}
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->data != NULL && search->start) {
|
||||
PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data;
|
||||
if (strcmp("Width", name) == 0) {
|
||||
mode->width = atoi(search->memory);
|
||||
} else if (strcmp("Height", name) == 0) {
|
||||
mode->height = atoi(search->memory);
|
||||
} else if (strcmp("RefreshRate", name) == 0) {
|
||||
mode->refresh = atoi(search->memory);
|
||||
}
|
||||
|
||||
free(search->memory);
|
||||
search->start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_start_status_element(void *userData, const char *name, const char **atts) {
|
||||
if (strcmp("root", name) == 0) {
|
||||
int* status = (int*) userData;
|
||||
for (int i = 0; atts[i]; i += 2) {
|
||||
if (strcmp("status_code", atts[i]) == 0)
|
||||
*status = atoi(atts[i + 1]);
|
||||
else if (*status != STATUS_OK && strcmp("status_message", atts[i]) == 0)
|
||||
gs_set_error(strdup(atts[i + 1]));
|
||||
if (strcmp("root", name) == 0) {
|
||||
int* status = (int*) userData;
|
||||
for (int i = 0; atts[i]; i += 2) {
|
||||
if (strcmp("status_code", atts[i]) == 0) {
|
||||
*status = atoi(atts[i + 1]);
|
||||
} else if (*status != STATUS_OK && strcmp("status_message", atts[i]) == 0) {
|
||||
gs_set_error(strdup(atts[i + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void XMLCALL _xml_end_status_element(void *userData, const char *name) { }
|
||||
|
||||
static void XMLCALL _xml_write_data(void *userData, const XML_Char *s, int len) {
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->start > 0) {
|
||||
search->memory = (char *)realloc(search->memory, search->size + len + 1);
|
||||
if(search->memory == NULL)
|
||||
return;
|
||||
|
||||
memcpy(&(search->memory[search->size]), s, len);
|
||||
search->size += len;
|
||||
search->memory[search->size] = 0;
|
||||
}
|
||||
struct xml_query *search = (struct xml_query*) userData;
|
||||
if (search->start > 0) {
|
||||
search->memory = (char *)realloc(search->memory, search->size + len + 1);
|
||||
if (search->memory == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&(search->memory[search->size]), s, len);
|
||||
search->size += len;
|
||||
search->memory[search->size] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int xml_search(unsigned char* data, size_t len, char* node, char** result) {
|
||||
struct xml_query search;
|
||||
search.data = node;
|
||||
search.start = 0;
|
||||
search.memory = (char *)calloc(1, 1);
|
||||
search.size = 0;
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &search);
|
||||
XML_SetElementHandler(parser, _xml_start_element, _xml_end_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
if (! XML_Parse(parser, (const char *)data, len, 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
int xml_search(const Data& data, const std::string node, std::string* result) {
|
||||
struct xml_query search;
|
||||
search.data = (void *)node.c_str();
|
||||
search.start = 0;
|
||||
search.memory = (char *)calloc(1, 1);
|
||||
search.size = 0;
|
||||
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &search);
|
||||
XML_SetElementHandler(parser, _xml_start_element, _xml_end_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
|
||||
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
XML_ParserFree(parser);
|
||||
free(search.memory);
|
||||
return GS_INVALID;
|
||||
} else if (search.memory == NULL) {
|
||||
XML_ParserFree(parser);
|
||||
return GS_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
free(search.memory);
|
||||
return GS_INVALID;
|
||||
} else if (search.memory == NULL) {
|
||||
XML_ParserFree(parser);
|
||||
return GS_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
*result = search.memory;
|
||||
|
||||
return GS_OK;
|
||||
*result = std::string(search.memory);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
int xml_applist(unsigned char* data, size_t len, PAPP_LIST *app_list) {
|
||||
struct xml_query query;
|
||||
query.memory = (char *)calloc(1, 1);
|
||||
query.size = 0;
|
||||
query.start = 0;
|
||||
query.data = NULL;
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &query);
|
||||
XML_SetElementHandler(parser, _xml_start_applist_element, _xml_end_applist_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
if (! XML_Parse(parser, (const char *)data, len, 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
int xml_applist(const Data& data, PAPP_LIST *app_list) {
|
||||
struct xml_query query;
|
||||
query.memory = (char *)calloc(1, 1);
|
||||
query.size = 0;
|
||||
query.start = 0;
|
||||
query.data = NULL;
|
||||
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &query);
|
||||
XML_SetElementHandler(parser, _xml_start_applist_element, _xml_end_applist_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
|
||||
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
*app_list = (PAPP_LIST) query.data;
|
||||
|
||||
return GS_OK;
|
||||
*app_list = (PAPP_LIST) query.data;
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
int xml_modelist(unsigned char* data, size_t len, PDISPLAY_MODE *mode_list) {
|
||||
struct xml_query query = {0};
|
||||
query.memory = (char *)calloc(1, 1);
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &query);
|
||||
XML_SetElementHandler(parser, _xml_start_mode_element, _xml_end_mode_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
if (! XML_Parse(parser, (const char *)data, len, 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
int xml_modelist(const Data& data, PDISPLAY_MODE *mode_list) {
|
||||
struct xml_query query = {0};
|
||||
query.memory = (char *)calloc(1, 1);
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &query);
|
||||
XML_SetElementHandler(parser, _xml_start_mode_element, _xml_end_mode_element);
|
||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||
|
||||
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
*mode_list = (PDISPLAY_MODE) query.data;
|
||||
|
||||
return GS_OK;
|
||||
|
||||
*mode_list = (PDISPLAY_MODE) query.data;
|
||||
return GS_OK;
|
||||
|
||||
}
|
||||
|
||||
int xml_status(unsigned char* data, size_t len) {
|
||||
int status = 0;
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &status);
|
||||
XML_SetElementHandler(parser, _xml_start_status_element, _xml_end_status_element);
|
||||
if (!XML_Parse(parser, (const char *)data, len, 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
int xml_status(const Data& data) {
|
||||
int status = 0;
|
||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||
XML_SetUserData(parser, &status);
|
||||
XML_SetElementHandler(parser, _xml_start_status_element, _xml_end_status_element);
|
||||
|
||||
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||
XML_Error code = XML_GetErrorCode(parser);
|
||||
gs_set_error(XML_ErrorString(code));
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return GS_INVALID;
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
return status == STATUS_OK ? GS_OK : GS_ERROR;
|
||||
return status == STATUS_OK ? GS_OK : GS_ERROR;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include "Data.hpp"
|
||||
#pragma once
|
||||
|
||||
typedef struct _APP_LIST {
|
||||
char* name;
|
||||
|
@ -33,7 +33,7 @@ typedef struct _DISPLAY_MODE {
|
|||
struct _DISPLAY_MODE *next;
|
||||
} DISPLAY_MODE, *PDISPLAY_MODE;
|
||||
|
||||
int xml_search(unsigned char* data, size_t len, char* node, char** result);
|
||||
int xml_applist(unsigned char* data, size_t len, PAPP_LIST *app_list);
|
||||
int xml_modelist(unsigned char* data, size_t len, PDISPLAY_MODE *mode_list);
|
||||
int xml_status(unsigned char* data, size_t len);
|
||||
int xml_search(const Data& data, const std::string node, std::string* result);
|
||||
int xml_applist(const Data& data, PAPP_LIST *app_list);
|
||||
int xml_modelist(const Data& data, PDISPLAY_MODE *mode_list);
|
||||
int xml_status(const Data& data);
|
||||
|
|
|
@ -91,15 +91,14 @@ void GameStreamClient::connect(const std::string &address, ServerCallback<SERVER
|
|||
m_server_data[address] = SERVER_DATA();
|
||||
|
||||
perform_async([this, address, callback] {
|
||||
// TODO: mem leak here :(
|
||||
int status = gs_init(&m_server_data[address], (char *)(new std::string(address))->c_str(), Settings::instance().key_dir().c_str(), Settings::instance().ignore_unsupported_resolutions());
|
||||
int status = gs_init(&m_server_data[address], address);
|
||||
|
||||
nanogui::async([this, address, callback, status] {
|
||||
if (status == GS_OK) {
|
||||
Host host;
|
||||
host.address = address;
|
||||
host.hostname = m_server_data[address].hostname ?: "";
|
||||
host.mac = m_server_data[address].mac ?: "";
|
||||
host.hostname = m_server_data[address].hostname;
|
||||
host.mac = m_server_data[address].mac;
|
||||
Settings::instance().add_host(host);
|
||||
callback(GSResult<SERVER_DATA>::success(m_server_data[address]));
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue