Use std::string and Data here - fix few memory leak errors

This commit is contained in:
rock88 2021-02-23 14:47:59 +03:00
parent 285416ba04
commit d3233d1ee0
7 changed files with 281 additions and 292 deletions

View file

@ -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", &currentGameText) != GS_OK) { if (xml_search(data, "currentgame", &currentGameText) != 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;
} }

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

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

View file

@ -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);

View file

@ -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 {