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 <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
#include "Settings.hpp"
|
||||||
#include "CryptoManager.hpp"
|
#include "CryptoManager.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
@ -34,19 +35,18 @@
|
||||||
#define CHANNEL_MASK_STEREO 0x3
|
#define CHANNEL_MASK_STEREO 0x3
|
||||||
#define CHANNEL_MASK_51_SURROUND 0xFC
|
#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;
|
int ret;
|
||||||
char url[4096];
|
char url[4096];
|
||||||
int i;
|
int i = skip_https ? 1 : 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
do {
|
||||||
char *pairedText = NULL;
|
std::string pairedText;
|
||||||
char *currentGameText = NULL;
|
std::string currentGameText;
|
||||||
char *stateText = NULL;
|
std::string stateText;
|
||||||
char *serverCodecModeSupportText = NULL;
|
std::string serverCodecModeSupportText;
|
||||||
|
|
||||||
ret = GS_INVALID;
|
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
|
// 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.
|
// for everything because it doesn't accurately tell us if we're paired.
|
||||||
|
|
||||||
snprintf(url, sizeof(url), "%s://%s:%d/serverinfo?uniqueid=%s",
|
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());
|
||||||
i == 0 ? "https" : "http", server->serverInfo.address, i == 0 ? 47984 : 47989, unique_id);
|
|
||||||
|
|
||||||
Data data;
|
Data data;
|
||||||
|
|
||||||
|
@ -65,55 +64,57 @@ static int load_server_status(PSERVER_DATA server) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xml_status(data.bytes(), data.size()) == GS_ERROR) {
|
if (xml_status(data) == GS_ERROR) {
|
||||||
ret = GS_ERROR;
|
ret = GS_ERROR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xml_search(data.bytes(), data.size(), "currentgame", ¤tGameText) != GS_OK) {
|
if (xml_search(data, "currentgame", ¤tGameText) != GS_OK) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xml_search(data.bytes(), data.size(), "PairStatus", &pairedText) != GS_OK)
|
if (xml_search(data, "PairStatus", &pairedText) != GS_OK)
|
||||||
goto cleanup;
|
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;
|
goto cleanup;
|
||||||
|
|
||||||
if (xml_search(data.bytes(), data.size(), "state", &stateText) != GS_OK)
|
if (xml_search(data, "ServerCodecModeSupport", &serverCodecModeSupportText) != GS_OK)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (xml_search(data.bytes(), data.size(), "ServerCodecModeSupport", &serverCodecModeSupportText) != GS_OK)
|
if (xml_search(data, "gputype", &server->gpuType) != GS_OK)
|
||||||
goto cleanup;
|
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;
|
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;
|
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;
|
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;
|
goto cleanup;
|
||||||
|
|
||||||
if (xml_search(data.bytes(), data.size(), "mac", &server->mac) != GS_OK)
|
if (xml_modelist(data, &server->modes) != GS_OK)
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (xml_modelist(data.bytes(), data.size(), &server->modes) != GS_OK)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
// These fields are present on all version of GFE that this client supports
|
// 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;
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
server->paired = pairedText != NULL && strcmp(pairedText, "1") == 0;
|
server->paired = pairedText == "1";
|
||||||
server->currentGame = currentGameText == NULL ? 0 : atoi(currentGameText);
|
server->currentGame = currentGameText.empty() ? 0 : atoi(currentGameText.c_str());
|
||||||
server->supports4K = serverCodecModeSupportText != NULL;
|
server->supports4K = !serverCodecModeSupportText.empty();
|
||||||
server->serverMajorVersion = atoi(server->serverInfo.serverInfoAppVersion);
|
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
|
// After GFE 2.8, current game remains set even after streaming
|
||||||
// has ended. We emulate the old behavior by forcing it to zero
|
// has ended. We emulate the old behavior by forcing it to zero
|
||||||
// if streaming is not active.
|
// if streaming is not active.
|
||||||
|
@ -122,15 +123,6 @@ static int load_server_status(PSERVER_DATA server) {
|
||||||
ret = GS_OK;
|
ret = GS_OK;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (pairedText != NULL)
|
|
||||||
free(pairedText);
|
|
||||||
|
|
||||||
if (currentGameText != NULL)
|
|
||||||
free(currentGameText);
|
|
||||||
|
|
||||||
if (serverCodecModeSupportText != NULL)
|
|
||||||
free(serverCodecModeSupportText);
|
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
} while (ret != GS_OK && i < 2);
|
} while (ret != GS_OK && i < 2);
|
||||||
|
|
||||||
|
@ -166,21 +158,18 @@ int gs_unpair(PSERVER_DATA server) {
|
||||||
|
|
||||||
Data data;
|
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);
|
ret = http_request(url, &data, HTTPRequestTimeoutLow);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gs_pair_validate(Data &data, char** result) {
|
static int gs_pair_validate(Data &data, std::string* result) {
|
||||||
if (*result) {
|
*result = "";
|
||||||
free(*result);
|
|
||||||
*result = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = GS_OK;
|
int ret = GS_OK;
|
||||||
if ((ret = xml_status(data.bytes(), data.size()) != GS_OK)) {
|
if ((ret = xml_status(data) != GS_OK)) {
|
||||||
return ret;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,27 +178,20 @@ static int gs_pair_validate(Data &data, char** result) {
|
||||||
// ret = GS_FAILED;
|
// ret = GS_FAILED;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (*result) {
|
|
||||||
free(*result);
|
|
||||||
*result = NULL;
|
|
||||||
}
|
|
||||||
return ret;
|
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) {
|
if (ret != GS_OK) {
|
||||||
gs_unpair(server);
|
gs_unpair(server);
|
||||||
}
|
}
|
||||||
if (*result) {
|
|
||||||
free(*result);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gs_pair(PSERVER_DATA server, char* pin) {
|
int gs_pair(PSERVER_DATA server, char* pin) {
|
||||||
int ret = GS_OK;
|
int ret = GS_OK;
|
||||||
Data data;
|
Data data;
|
||||||
char* result = NULL;
|
std::string result;
|
||||||
char url[4096];
|
char url[4096];
|
||||||
|
|
||||||
if (server->paired) {
|
if (server->paired) {
|
||||||
|
@ -229,7 +211,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
|
||||||
Data salted_pin = salt.append(Data(pin, strlen(pin)));
|
Data salted_pin = salt.append(Data(pin, strlen(pin)));
|
||||||
Logger::info("Client", "PIN: %s, salt %s", pin, salt.hex().bytes());
|
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) {
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
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);
|
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);
|
return gs_pair_cleanup(ret, server, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info("Client", "Start pairing stage #2");
|
Logger::info("Client", "Start pairing stage #2");
|
||||||
|
|
||||||
Data plainCert = Data(result, strlen(result));
|
Data plainCert = Data((char *)result.c_str(), result.size());
|
||||||
Data aesKey;
|
Data aesKey;
|
||||||
|
|
||||||
// Gen 7 servers use SHA256 to get the key
|
// 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 randomChallenge = Data::random_bytes(16);
|
||||||
Data encryptedChallenge = CryptoManager::aes_encrypt(randomChallenge, aesKey);
|
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) {
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
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);
|
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;
|
ret = GS_INVALID;
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
return gs_pair_cleanup(ret, server, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info("Client", "Start pairing stage #3");
|
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 decServerChallengeResp = CryptoManager::aes_decrypt(encServerChallengeResp, aesKey);
|
||||||
Data serverResponse = decServerChallengeResp.subdata(0, hashLength);
|
Data serverResponse = decServerChallengeResp.subdata(0, hashLength);
|
||||||
Data serverChallenge = decServerChallengeResp.subdata(hashLength, 16);
|
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);
|
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) {
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
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);
|
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;
|
ret = GS_INVALID;
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
return gs_pair_cleanup(ret, server, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::info("Client", "Start pairing stage #4");
|
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 serverSecret = serverSecretResp.subdata(0, 16);
|
||||||
Data serverSignature = serverSecretResp.subdata(16, 256);
|
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 serverChallengeRespHashInput = randomChallenge.append(CryptoManager::signature(plainCert.hex_to_bytes())).append(serverSecret);
|
||||||
Data serverChallengeRespHash;
|
Data serverChallengeRespHash;
|
||||||
|
|
||||||
if (server->serverMajorVersion >= 7) {
|
if (server->serverMajorVersion >= 7) {
|
||||||
serverChallengeRespHash = CryptoManager::SHA256_hash_data(serverChallengeRespHashInput);
|
serverChallengeRespHash = CryptoManager::SHA256_hash_data(serverChallengeRespHashInput);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
serverChallengeRespHash = CryptoManager::SHA1_hash_data(serverChallengeRespHashInput);
|
serverChallengeRespHash = CryptoManager::SHA1_hash_data(serverChallengeRespHashInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
Data clientPairingSecret = clientSecret.append(CryptoManager::sign_data(clientSecret, CryptoManager::key_data()));
|
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) {
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
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");
|
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) {
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutLong)) != GS_OK) {
|
||||||
return gs_pair_cleanup(ret, server, &result);
|
return gs_pair_cleanup(ret, server, &result);
|
||||||
}
|
}
|
||||||
|
@ -365,13 +347,13 @@ int gs_applist(PSERVER_DATA server, PAPP_LIST *list) {
|
||||||
char url[4096];
|
char url[4096];
|
||||||
Data data;
|
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)
|
if (http_request(url, &data, HTTPRequestTimeoutMedium) != GS_OK)
|
||||||
ret = GS_IO_ERROR;
|
ret = GS_IO_ERROR;
|
||||||
else if (xml_status(data.bytes(), data.size()) == GS_ERROR)
|
else if (xml_status(data) == GS_ERROR)
|
||||||
ret = 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;
|
ret = GS_INVALID;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -381,21 +363,19 @@ int gs_app_boxart(PSERVER_DATA server, int app_id, Data* out) {
|
||||||
char url[4096];
|
char url[4096];
|
||||||
Data data;
|
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) {
|
if (http_request(url, &data, HTTPRequestTimeoutMedium) != GS_OK) {
|
||||||
ret = GS_IO_ERROR;
|
ret = GS_IO_ERROR;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
*out = data;
|
*out = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, bool sops, bool localaudio, int gamepad_mask) {
|
int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, bool sops, bool localaudio, int gamepad_mask) {
|
||||||
int ret = GS_OK;
|
int ret = GS_OK;
|
||||||
char* result = NULL;
|
std::string result;
|
||||||
|
|
||||||
PDISPLAY_MODE mode = server->modes;
|
PDISPLAY_MODE mode = server->modes;
|
||||||
bool correct_mode = false;
|
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 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 mask = config->audioConfiguration == AUDIO_CONFIGURATION_STEREO ? CHANNEL_MASK_STEREO : CHANNEL_MASK_51_SURROUND;
|
||||||
int fps = sops && config->fps > 60 ? 60 : config->fps;
|
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 {
|
} 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;
|
server->currentGame = appId;
|
||||||
else
|
} else {
|
||||||
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(), "gamesession", &result)) != GS_OK)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (!strcmp(result, "0")) {
|
|
||||||
ret = GS_FAILED;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
if ((ret = xml_status(data) != GS_OK)) {
|
||||||
if (result != NULL)
|
goto exit;
|
||||||
free(result);
|
} else if ((ret = xml_search(data, "gamesession", &result)) != GS_OK) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == "0") {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gs_quit_app(PSERVER_DATA server) {
|
int gs_quit_app(PSERVER_DATA server) {
|
||||||
int ret = GS_OK;
|
int ret = GS_OK;
|
||||||
char url[4096];
|
char url[4096];
|
||||||
char* result = NULL;
|
std::string result;
|
||||||
Data data;
|
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)
|
if ((ret = http_request(url, &data, HTTPRequestTimeoutMedium)) != GS_OK)
|
||||||
goto cleanup;
|
goto exit;
|
||||||
|
|
||||||
if ((ret = xml_status(data.bytes(), data.size()) != GS_OK))
|
if ((ret = xml_status(data) != GS_OK)) {
|
||||||
goto cleanup;
|
goto exit;
|
||||||
else if ((ret = xml_search(data.bytes(), data.size(), "cancel", &result)) != GS_OK)
|
} else if ((ret = xml_search(data, "cancel", &result)) != GS_OK) {
|
||||||
goto cleanup;
|
goto exit;
|
||||||
|
|
||||||
if (strcmp(result, "0") == 0) {
|
|
||||||
ret = GS_FAILED;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
if (result == "0") {
|
||||||
if (result != NULL)
|
ret = GS_FAILED;
|
||||||
free(result);
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
return ret;
|
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()) {
|
if (!CryptoManager::load_cert_key_pair()) {
|
||||||
Logger::info("Client", "No certs, generate new...");
|
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);
|
LiInitializeServerInformation(&server->serverInfo);
|
||||||
server->serverInfo.address = address;
|
server->address = address;
|
||||||
server->unsupported = unsupported;
|
server->serverInfo.address = server->address.c_str();
|
||||||
return load_server_status(server);
|
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
|
#define MAX_SUPPORTED_GFE_VERSION 7
|
||||||
|
|
||||||
typedef struct _SERVER_DATA {
|
typedef struct _SERVER_DATA {
|
||||||
const char* address;
|
std::string address;
|
||||||
char *mac;
|
std::string serverInfoAppVersion;
|
||||||
char* gpuType;
|
std::string serverInfoGfeVersion;
|
||||||
|
std::string mac;
|
||||||
|
std::string gpuType;
|
||||||
bool paired;
|
bool paired;
|
||||||
bool supports4K;
|
bool supports4K;
|
||||||
bool unsupported;
|
bool unsupported;
|
||||||
int currentGame;
|
int currentGame;
|
||||||
int serverMajorVersion;
|
int serverMajorVersion;
|
||||||
char* gsVersion;
|
std::string gsVersion;
|
||||||
char* hostname;
|
std::string hostname;
|
||||||
PDISPLAY_MODE modes;
|
PDISPLAY_MODE modes;
|
||||||
SERVER_INFORMATION serverInfo;
|
SERVER_INFORMATION serverInfo;
|
||||||
} SERVER_DATA, *PSERVER_DATA;
|
} SERVER_DATA, *PSERVER_DATA;
|
||||||
|
@ -45,7 +47,7 @@ typedef struct _SERVER_DATA {
|
||||||
void gs_set_error(std::string error);
|
void gs_set_error(std::string error);
|
||||||
std::string gs_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_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_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);
|
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;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_init(const char* key_directory) {
|
int http_init(const std::string key_directory) {
|
||||||
if (!curl) {
|
if (!curl) {
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
Logger::info("Curl", "%s", curl_version());
|
Logger::info("Curl", "%s", curl_version());
|
||||||
|
@ -62,10 +62,10 @@ int http_init(const char* key_directory) {
|
||||||
return GS_FAILED;
|
return GS_FAILED;
|
||||||
|
|
||||||
char certificateFilePath[4096];
|
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];
|
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_SSL_VERIFYHOST, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
||||||
|
@ -81,15 +81,15 @@ int http_init(const char* key_directory) {
|
||||||
return GS_OK;
|
return GS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request(char* url, Data* data, HTTPRequestTimeout timeout) {
|
int http_request(const std::string url, Data* data, HTTPRequestTimeout timeout) {
|
||||||
Logger::info("Curl", "Request:\n%s", url);
|
Logger::info("Curl", "Request:\n%s", url.c_str());
|
||||||
|
|
||||||
HTTP_DATA* http_data = (HTTP_DATA*)malloc(sizeof(HTTP_DATA));
|
HTTP_DATA* http_data = (HTTP_DATA*)malloc(sizeof(HTTP_DATA));
|
||||||
http_data->memory = (char*)malloc(1);
|
http_data->memory = (char*)malloc(1);
|
||||||
http_data->size = 0;
|
http_data->size = 0;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_data);
|
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);
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
|
||||||
|
|
||||||
CURLcode res = curl_easy_perform(curl);
|
CURLcode res = curl_easy_perform(curl);
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Data.hpp"
|
#include "Data.hpp"
|
||||||
|
#pragma once
|
||||||
|
|
||||||
enum HTTPRequestTimeout: long {
|
enum HTTPRequestTimeout: long {
|
||||||
HTTPRequestTimeoutLow = 2,
|
HTTPRequestTimeoutLow = 2,
|
||||||
|
@ -27,5 +26,5 @@ enum HTTPRequestTimeout: long {
|
||||||
HTTPRequestTimeoutLong = 120
|
HTTPRequestTimeoutLong = 120
|
||||||
};
|
};
|
||||||
|
|
||||||
int http_init(const char* key_directory);
|
int http_init(const std::string key_directory);
|
||||||
int http_request(char* url, Data* data, HTTPRequestTimeout timeout);
|
int http_request(const std::string url, Data* data, HTTPRequestTimeout timeout);
|
||||||
|
|
|
@ -26,8 +26,6 @@
|
||||||
|
|
||||||
#define STATUS_OK 200
|
#define STATUS_OK 200
|
||||||
|
|
||||||
static XML_Parser parser;
|
|
||||||
|
|
||||||
struct xml_query {
|
struct xml_query {
|
||||||
char *memory;
|
char *memory;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -36,193 +34,202 @@ struct xml_query {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void XMLCALL _xml_start_element(void *userData, const char *name, const char **atts) {
|
static void XMLCALL _xml_start_element(void *userData, const char *name, const char **atts) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (strcmp((const char *)search->data, name) == 0)
|
if (strcmp((const char *)search->data, name) == 0) {
|
||||||
search->start++;
|
search->start++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XMLCALL _xml_end_element(void *userData, const char *name) {
|
static void XMLCALL _xml_end_element(void *userData, const char *name) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (strcmp((const char *)search->data, name) == 0)
|
if (strcmp((const char *)search->data, name) == 0) {
|
||||||
search->start--;
|
search->start--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XMLCALL _xml_start_applist_element(void *userData, const char *name, const char **atts) {
|
static void XMLCALL _xml_start_applist_element(void *userData, const char *name, const char **atts) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (strcmp("App", name) == 0) {
|
if (strcmp("App", name) == 0) {
|
||||||
PAPP_LIST app = (PAPP_LIST)malloc(sizeof(APP_LIST));
|
PAPP_LIST app = (PAPP_LIST)malloc(sizeof(APP_LIST));
|
||||||
if (app == NULL)
|
if (app == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
app->id = 0;
|
app->id = 0;
|
||||||
app->name = NULL;
|
app->name = NULL;
|
||||||
app->next = (PAPP_LIST) search->data;
|
app->next = (PAPP_LIST) search->data;
|
||||||
search->data = app;
|
search->data = app;
|
||||||
} else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) {
|
} else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) {
|
||||||
search->memory = (char *)malloc(1);
|
search->memory = (char *)malloc(1);
|
||||||
search->size = 0;
|
search->size = 0;
|
||||||
search->start = 1;
|
search->start = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XMLCALL _xml_end_applist_element(void *userData, const char *name) {
|
static void XMLCALL _xml_end_applist_element(void *userData, const char *name) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (search->start) {
|
if (search->start) {
|
||||||
PAPP_LIST list = (PAPP_LIST) search->data;
|
PAPP_LIST list = (PAPP_LIST) search->data;
|
||||||
if (list == NULL)
|
if (list == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (strcmp("ID", name) == 0) {
|
if (strcmp("ID", name) == 0) {
|
||||||
list->id = atoi(search->memory);
|
list->id = atoi(search->memory);
|
||||||
free(search->memory);
|
free(search->memory);
|
||||||
} else if (strcmp("AppTitle", name) == 0) {
|
} else if (strcmp("AppTitle", name) == 0) {
|
||||||
list->name = search->memory;
|
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) {
|
static void XMLCALL _xml_start_mode_element(void *userData, const char *name, const char **atts) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (strcmp("DisplayMode", name) == 0) {
|
if (strcmp("DisplayMode", name) == 0) {
|
||||||
PDISPLAY_MODE mode = (PDISPLAY_MODE)calloc(1, sizeof(DISPLAY_MODE));
|
PDISPLAY_MODE mode = (PDISPLAY_MODE)calloc(1, sizeof(DISPLAY_MODE));
|
||||||
if (mode != NULL) {
|
if (mode != NULL) {
|
||||||
mode->next = (PDISPLAY_MODE) search->data;
|
mode->next = (PDISPLAY_MODE) search->data;
|
||||||
search->data = mode;
|
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) {
|
static void XMLCALL _xml_end_mode_element(void *userData, const char *name) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (search->data != NULL && search->start) {
|
if (search->data != NULL && search->start) {
|
||||||
PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data;
|
PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data;
|
||||||
if (strcmp("Width", name) == 0)
|
if (strcmp("Width", name) == 0) {
|
||||||
mode->width = atoi(search->memory);
|
mode->width = atoi(search->memory);
|
||||||
else if (strcmp("Height", name) == 0)
|
} else if (strcmp("Height", name) == 0) {
|
||||||
mode->height = atoi(search->memory);
|
mode->height = atoi(search->memory);
|
||||||
else if (strcmp("RefreshRate", name) == 0)
|
} else if (strcmp("RefreshRate", name) == 0) {
|
||||||
mode->refresh = atoi(search->memory);
|
mode->refresh = atoi(search->memory);
|
||||||
|
}
|
||||||
|
|
||||||
free(search->memory);
|
free(search->memory);
|
||||||
search->start = 0;
|
search->start = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XMLCALL _xml_start_status_element(void *userData, const char *name, const char **atts) {
|
static void XMLCALL _xml_start_status_element(void *userData, const char *name, const char **atts) {
|
||||||
if (strcmp("root", name) == 0) {
|
if (strcmp("root", name) == 0) {
|
||||||
int* status = (int*) userData;
|
int* status = (int*) userData;
|
||||||
for (int i = 0; atts[i]; i += 2) {
|
for (int i = 0; atts[i]; i += 2) {
|
||||||
if (strcmp("status_code", atts[i]) == 0)
|
if (strcmp("status_code", atts[i]) == 0) {
|
||||||
*status = atoi(atts[i + 1]);
|
*status = atoi(atts[i + 1]);
|
||||||
else if (*status != STATUS_OK && strcmp("status_message", atts[i]) == 0)
|
} else if (*status != STATUS_OK && strcmp("status_message", atts[i]) == 0) {
|
||||||
gs_set_error(strdup(atts[i + 1]));
|
gs_set_error(strdup(atts[i + 1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void XMLCALL _xml_end_status_element(void *userData, const char *name) { }
|
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) {
|
static void XMLCALL _xml_write_data(void *userData, const XML_Char *s, int len) {
|
||||||
struct xml_query *search = (struct xml_query*) userData;
|
struct xml_query *search = (struct xml_query*) userData;
|
||||||
if (search->start > 0) {
|
if (search->start > 0) {
|
||||||
search->memory = (char *)realloc(search->memory, search->size + len + 1);
|
search->memory = (char *)realloc(search->memory, search->size + len + 1);
|
||||||
if(search->memory == NULL)
|
if (search->memory == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&(search->memory[search->size]), s, len);
|
memcpy(&(search->memory[search->size]), s, len);
|
||||||
search->size += len;
|
search->size += len;
|
||||||
search->memory[search->size] = 0;
|
search->memory[search->size] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_search(unsigned char* data, size_t len, char* node, char** result) {
|
int xml_search(const Data& data, const std::string node, std::string* result) {
|
||||||
struct xml_query search;
|
struct xml_query search;
|
||||||
search.data = node;
|
search.data = (void *)node.c_str();
|
||||||
search.start = 0;
|
search.start = 0;
|
||||||
search.memory = (char *)calloc(1, 1);
|
search.memory = (char *)calloc(1, 1);
|
||||||
search.size = 0;
|
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));
|
|
||||||
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);
|
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||||
*result = search.memory;
|
XML_SetUserData(parser, &search);
|
||||||
|
XML_SetElementHandler(parser, _xml_start_element, _xml_end_element);
|
||||||
|
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||||
|
|
||||||
return GS_OK;
|
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);
|
||||||
|
*result = std::string(search.memory);
|
||||||
|
return GS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_applist(unsigned char* data, size_t len, PAPP_LIST *app_list) {
|
int xml_applist(const Data& data, PAPP_LIST *app_list) {
|
||||||
struct xml_query query;
|
struct xml_query query;
|
||||||
query.memory = (char *)calloc(1, 1);
|
query.memory = (char *)calloc(1, 1);
|
||||||
query.size = 0;
|
query.size = 0;
|
||||||
query.start = 0;
|
query.start = 0;
|
||||||
query.data = NULL;
|
query.data = NULL;
|
||||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
|
||||||
XML_SetUserData(parser, &query);
|
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||||
XML_SetElementHandler(parser, _xml_start_applist_element, _xml_end_applist_element);
|
XML_SetUserData(parser, &query);
|
||||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
XML_SetElementHandler(parser, _xml_start_applist_element, _xml_end_applist_element);
|
||||||
if (! XML_Parse(parser, (const char *)data, len, 1)) {
|
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||||
XML_Error code = XML_GetErrorCode(parser);
|
|
||||||
gs_set_error(XML_ErrorString(code));
|
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);
|
XML_ParserFree(parser);
|
||||||
return GS_INVALID;
|
*app_list = (PAPP_LIST) query.data;
|
||||||
}
|
return GS_OK;
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
|
||||||
*app_list = (PAPP_LIST) query.data;
|
|
||||||
|
|
||||||
return GS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_modelist(unsigned char* data, size_t len, PDISPLAY_MODE *mode_list) {
|
int xml_modelist(const Data& data, PDISPLAY_MODE *mode_list) {
|
||||||
struct xml_query query = {0};
|
struct xml_query query = {0};
|
||||||
query.memory = (char *)calloc(1, 1);
|
query.memory = (char *)calloc(1, 1);
|
||||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||||
XML_SetUserData(parser, &query);
|
XML_SetUserData(parser, &query);
|
||||||
XML_SetElementHandler(parser, _xml_start_mode_element, _xml_end_mode_element);
|
XML_SetElementHandler(parser, _xml_start_mode_element, _xml_end_mode_element);
|
||||||
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
XML_SetCharacterDataHandler(parser, _xml_write_data);
|
||||||
if (! XML_Parse(parser, (const char *)data, len, 1)) {
|
|
||||||
XML_Error code = XML_GetErrorCode(parser);
|
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||||
gs_set_error(XML_ErrorString(code));
|
XML_Error code = XML_GetErrorCode(parser);
|
||||||
|
gs_set_error(XML_ErrorString(code));
|
||||||
|
XML_ParserFree(parser);
|
||||||
|
return GS_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
return GS_INVALID;
|
*mode_list = (PDISPLAY_MODE) query.data;
|
||||||
}
|
return GS_OK;
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
|
||||||
*mode_list = (PDISPLAY_MODE) query.data;
|
|
||||||
|
|
||||||
return GS_OK;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xml_status(unsigned char* data, size_t len) {
|
int xml_status(const Data& data) {
|
||||||
int status = 0;
|
int status = 0;
|
||||||
XML_Parser parser = XML_ParserCreate("UTF-8");
|
XML_Parser parser = XML_ParserCreate("UTF-8");
|
||||||
XML_SetUserData(parser, &status);
|
XML_SetUserData(parser, &status);
|
||||||
XML_SetElementHandler(parser, _xml_start_status_element, _xml_end_status_element);
|
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));
|
|
||||||
XML_ParserFree(parser);
|
|
||||||
return GS_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
if (!XML_Parse(parser, (const char *)data.bytes(), (int)data.size(), 1)) {
|
||||||
return status == STATUS_OK ? GS_OK : GS_ERROR;
|
XML_Error code = XML_GetErrorCode(parser);
|
||||||
|
gs_set_error(XML_ErrorString(code));
|
||||||
|
XML_ParserFree(parser);
|
||||||
|
return GS_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
XML_ParserFree(parser);
|
||||||
|
return status == STATUS_OK ? GS_OK : GS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
* 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 {
|
typedef struct _APP_LIST {
|
||||||
char* name;
|
char* name;
|
||||||
|
@ -33,7 +33,7 @@ typedef struct _DISPLAY_MODE {
|
||||||
struct _DISPLAY_MODE *next;
|
struct _DISPLAY_MODE *next;
|
||||||
} DISPLAY_MODE, *PDISPLAY_MODE;
|
} DISPLAY_MODE, *PDISPLAY_MODE;
|
||||||
|
|
||||||
int xml_search(unsigned char* data, size_t len, char* node, char** result);
|
int xml_search(const Data& data, const std::string node, std::string* result);
|
||||||
int xml_applist(unsigned char* data, size_t len, PAPP_LIST *app_list);
|
int xml_applist(const Data& data, PAPP_LIST *app_list);
|
||||||
int xml_modelist(unsigned char* data, size_t len, PDISPLAY_MODE *mode_list);
|
int xml_modelist(const Data& data, PDISPLAY_MODE *mode_list);
|
||||||
int xml_status(unsigned char* data, size_t len);
|
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();
|
m_server_data[address] = SERVER_DATA();
|
||||||
|
|
||||||
perform_async([this, address, callback] {
|
perform_async([this, address, callback] {
|
||||||
// TODO: mem leak here :(
|
int status = gs_init(&m_server_data[address], address);
|
||||||
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());
|
|
||||||
|
|
||||||
nanogui::async([this, address, callback, status] {
|
nanogui::async([this, address, callback, status] {
|
||||||
if (status == GS_OK) {
|
if (status == GS_OK) {
|
||||||
Host host;
|
Host host;
|
||||||
host.address = address;
|
host.address = address;
|
||||||
host.hostname = m_server_data[address].hostname ?: "";
|
host.hostname = m_server_data[address].hostname;
|
||||||
host.mac = m_server_data[address].mac ?: "";
|
host.mac = m_server_data[address].mac;
|
||||||
Settings::instance().add_host(host);
|
Settings::instance().add_host(host);
|
||||||
callback(GSResult<SERVER_DATA>::success(m_server_data[address]));
|
callback(GSResult<SERVER_DATA>::success(m_server_data[address]));
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue