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

View file

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

View file

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

View file

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

View file

@ -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;
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;
}
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;
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;
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);
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;
}
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;
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;
}
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));
XML_ParserFree(parser);
free(search.memory);
return GS_INVALID;
} else if (search.memory == NULL) {
XML_ParserFree(parser);
return GS_OUT_OF_MEMORY;
}
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_ParserFree(parser);
*result = search.memory;
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);
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) {
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));
XML_ParserFree(parser);
return GS_INVALID;
}
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);
XML_ParserFree(parser);
return status == STATUS_OK ? GS_OK : GS_ERROR;
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 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
* 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);

View file

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