From c18bd2d1949a9137ddc1175a3e5161d0da031683 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Thu, 23 Jul 2015 11:43:48 +0200 Subject: [PATCH] Rename functions in libgamestream and provide better error handling --- libgamestream/client.c | 227 ++++++++++++++++++-------------- libgamestream/client.h | 25 ++-- libgamestream/discover.c | 14 +- libgamestream/discover.h | 6 +- libgamestream/errors.h | 27 ++++ libgamestream/http.c | 41 ++++-- libgamestream/http.h | 15 ++- libgamestream/mkcert.c | 8 +- libgamestream/mkcert.h | 15 +-- libgamestream/xml.c | 36 +++-- libgamestream/xml.h | 8 +- {libgamestream => src}/global.c | 0 {libgamestream => src}/global.h | 0 src/input/evdev.c | 2 +- src/main.c | 65 ++++++--- 15 files changed, 302 insertions(+), 187 deletions(-) create mode 100644 libgamestream/errors.h rename {libgamestream => src}/global.c (100%) rename {libgamestream => src}/global.h (100%) diff --git a/libgamestream/client.c b/libgamestream/client.c index e24dd27..6c3d569 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -21,6 +21,7 @@ #include "xml.h" #include "mkcert.h" #include "client.h" +#include "errors.h" #include "limelight-common/Limelight.h" @@ -48,11 +49,7 @@ static X509 *cert; static char cert_hex[4096]; static EVP_PKEY *privateKey; -static bool paired; -static int currentGame; -static int serverMajorVersion; - -static void client_load_unique_id() { +static void load_unique_id() { FILE *fd = fopen(uniqueFileName, "r"); if (fd == NULL) { unsigned char unique_data[UNIQUEID_BYTES]; @@ -69,14 +66,14 @@ static void client_load_unique_id() { unique_id[UNIQUEID_CHARS] = 0; } -static void client_load_cert() { +static void load_cert() { FILE *fd = fopen(certificateFileName, "r"); if (fd == NULL) { printf("Generating certificate..."); - struct CertKeyPair cert = generateCertKeyPair(); + CERT_KEY_PAIR cert = mkcert_generate(); printf("done\n"); - saveCertKeyPair(certificateFileName, p12FileName, keyFileName, cert); - freeCertKeyPair(cert); + mkcert_save(certificateFileName, p12FileName, keyFileName, cert); + mkcert_free(cert); fd = fopen(certificateFileName, "r"); } @@ -107,32 +104,57 @@ static void client_load_cert() { fclose(fd); } -static void client_load_server_status(const char *address) { +static int load_server_status(const char *address, PSERVER_DATA server) { + int ret = GS_INVALID; char url[4096]; sprintf(url, "https://%s:47984/serverinfo?uniqueid=%s", address, unique_id); - struct http_data *data = http_create_data(); - http_request(url, data); + PHTTP_DATA data = http_create_data(); + if (data == NULL) { + ret = GS_OUT_OF_MEMORY; + goto cleanup; + } + if (http_request(url, data) != GS_OK) { + ret = GS_IO_ERROR; + goto cleanup; + } char *pairedText = NULL; char *currentGameText = NULL; char *versionText = NULL; - xml_search(data->memory, data->size, "currentgame", ¤tGameText); - xml_search(data->memory, data->size, "PairStatus", &pairedText); - xml_search(data->memory, data->size, "appversion", &versionText); - http_free_data(data); + if (xml_search(data->memory, data->size, "currentgame", ¤tGameText) != GS_OK) { + goto cleanup; + } - paired = pairedText != NULL && strcmp(pairedText, "1") == 0; - currentGame = currentGameText == NULL ? 0 : atoi(currentGameText); + if (xml_search(data->memory, data->size, "PairStatus", &pairedText) != GS_OK) + goto cleanup; + + if (xml_search(data->memory, data->size, "appversion", &versionText) != GS_OK) + goto cleanup; + + server->paired = pairedText != NULL && strcmp(pairedText, "1") == 0; + server->currentGame = currentGameText == NULL ? 0 : atoi(currentGameText); char *versionSep = strstr(versionText, "."); if (versionSep != NULL) { *versionSep = 0; } - serverMajorVersion = atoi(versionText); + server->serverMajorVersion = atoi(versionText); + ret = GS_OK; - free(pairedText); - free(currentGameText); - free(versionText); + cleanup: + if (data != NULL) + http_free_data(data); + + if (pairedText != NULL) + free(pairedText); + + if (currentGameText != NULL) + free(currentGameText); + + if (versionText != NULL) + free(versionText); + + return ret; } static void bytes_to_hex(unsigned char *in, char *out, size_t len) { @@ -143,7 +165,7 @@ static void bytes_to_hex(unsigned char *in, char *out, size_t len) { } static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *slen, EVP_PKEY *pkey) { - int result = -1; + int result = GS_FAILED; *sig = NULL; *slen = 0; @@ -210,30 +232,29 @@ static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *sl goto cleanup; } - result = 1; + result = GS_OK; -cleanup: + cleanup: EVP_MD_CTX_destroy(ctx); ctx = NULL; - return !!result; + return result; } -void client_pair(const char *address) { +int gs_pair(PSERVER_DATA server, char* pin) { + int ret = GS_OK; char url[4096]; - if (client_is_paired(NULL)) { - printf("Already paired\n"); - return; + if (server->paired) { + fprintf(stderr, "Already paired\n"); + return GS_WRONG_STATE; } - if (currentGame != 0) { + if (server->currentGame != 0) { fprintf(stderr, "The computer is currently in a game. You must close the game before pairing.\n"); - exit(-1); + return GS_WRONG_STATE; } - char pin[5]; - sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10); printf("Please enter the following PIN on the target PC: %s\n", pin); unsigned char salt_data[16]; @@ -241,9 +262,12 @@ void client_pair(const char *address) { RAND_bytes(salt_data, 16); bytes_to_hex(salt_data, salt_hex, 16); - sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", address, unique_id, salt_hex, cert_hex); - struct http_data *data = http_create_data(); - http_request(url, data); + sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->address, unique_id, salt_hex, cert_hex); + PHTTP_DATA data = http_create_data(); + if (data == NULL) + return GS_OUT_OF_MEMORY; + else if ((ret = http_request(url, data)) != GS_OK) + goto cleanup; unsigned char salt_pin[20]; unsigned char aes_key_hash[20]; @@ -260,11 +284,15 @@ void client_pair(const char *address) { AES_encrypt(challenge_data, challenge_enc, &aes_key); bytes_to_hex(challenge_enc, challenge_hex, 16); - sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", address, unique_id, challenge_hex); - http_request(url, data); + sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->address, unique_id, challenge_hex); + if ((ret = http_request(url, data)) != GS_OK) + goto cleanup; char *result; - xml_search(data->memory, data->size, "challengeresponse", &result); + if (xml_search(data->memory, data->size, "challengeresponse", &result) != GS_OK) { + ret = GS_INVALID; + goto cleanup; + } char challenge_response_data_enc[48]; char challenge_response_data[48]; @@ -294,15 +322,21 @@ void client_pair(const char *address) { } bytes_to_hex(challenge_response_hash_enc, challenge_response_hex, 32); - sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", address, unique_id, challenge_response_hex); - http_request(url, data); - xml_search(data->memory, data->size, "pairingsecret", &result); + sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->address, unique_id, challenge_response_hex); + if ((ret = http_request(url, data)) != GS_OK) + goto cleanup; + + if (xml_search(data->memory, data->size, "pairingsecret", &result) != GS_OK) { + ret = GS_INVALID; + goto cleanup; + } unsigned char *signature = NULL; size_t s_len; - if (!sign_it(client_secret_data, 16, &signature, &s_len, privateKey)) { + if (sign_it(client_secret_data, 16, &signature, &s_len, privateKey) != GS_OK) { fprintf(stderr, "Failed to sign data\n"); - exit(-1); + ret = GS_FAILED; + goto cleanup; } char client_pairing_secret[16 + 256]; @@ -311,38 +345,41 @@ void client_pair(const char *address) { memcpy(client_pairing_secret + 16, signature, 256); bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, 16 + 256); - sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, unique_id, client_pairing_secret_hex); - http_request(url, data); + sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->address, unique_id, client_pairing_secret_hex); + if ((ret = http_request(url, data)) != GS_OK) + goto cleanup; - sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", address, unique_id); - http_request(url, data); - http_free_data(data); + sprintf(url, "https://%s:47984/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->address, unique_id); + if ((ret = http_request(url, data)) != GS_OK) + goto cleanup; printf("Paired\n"); -} + server->paired = true; -struct app_list *client_applist(const char *address) { - char url[4096]; - struct http_data *data = http_create_data(); - sprintf(url, "https://%s:47984/applist?uniqueid=%s", address, unique_id); - http_request(url, data); - struct app_list *list = xml_applist(data->memory, data->size); + cleanup: http_free_data(data); - return list; + + return ret; } -int client_get_app_id(const char *address, const char *name) { - struct app_list *list = client_applist(address); - while (list != NULL) { - if (strcmp(list->name, name) == 0) - return list->id; +int gs_applist(PSERVER_DATA server, PAPP_LIST list) { + int ret = GS_OK; + char url[4096]; + PHTTP_DATA data = http_create_data(); + if (data == NULL) + return GS_OUT_OF_MEMORY; - list = list->next; - } - return -1; + sprintf(url, "https://%s:47984/applist?uniqueid=%s", server->address, unique_id); + if (http_request(url, data) != GS_OK) + ret = GS_IO_ERROR; + else if (xml_applist(data->memory, data->size, list) != GS_OK) + ret = GS_INVALID; + + http_free_data(data); + return ret; } -void client_start_app(STREAM_CONFIGURATION *config, const char *address, int appId, bool sops, bool localaudio) { +int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, bool sops, bool localaudio) { RAND_bytes(config->remoteInputAesKey, 16); memset(config->remoteInputAesIv, 0, 16); @@ -352,46 +389,40 @@ void client_start_app(STREAM_CONFIGURATION *config, const char *address, int app char rikey_hex[33]; bytes_to_hex(config->remoteInputAesKey, rikey_hex, 16); - struct http_data *data = http_create_data(); - if (currentGame == 0) - sprintf(url, "https://%s:47984/launch?uniqueid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d", address, unique_id, appId, config->width, config->height, config->fps, sops, rikey_hex, rikeyid, localaudio); + PHTTP_DATA data = http_create_data(); + if (data == NULL) + return GS_OUT_OF_MEMORY; + + if (server->currentGame == 0) + sprintf(url, "https://%s:47984/launch?uniqueid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d", server->address, unique_id, appId, config->width, config->height, config->fps, sops, rikey_hex, rikeyid, localaudio); else - sprintf(url, "https://%s:47984/resume?uniqueid=%s&rikey=%s&rikeyid=%d", address, unique_id, rikey_hex, rikeyid); + sprintf(url, "https://%s:47984/resume?uniqueid=%s&rikey=%s&rikeyid=%d", server->address, unique_id, rikey_hex, rikeyid); + + int ret = http_request(url, data); + if (ret == GS_OK) + server->currentGame = appId; - http_request(url, data); http_free_data(data); + return ret; } -void client_quit_app(const char *address) { +int gs_quit_app(PSERVER_DATA server) { char url[4096]; - struct http_data *data = http_create_data(); - sprintf(url, "https://%s:47984/cancel?uniqueid=%s", address, unique_id); - http_request(url, data); + PHTTP_DATA data = http_create_data(); + if (data == NULL) + return GS_OUT_OF_MEMORY; + + sprintf(url, "https://%s:47984/cancel?uniqueid=%s", server->address, unique_id); + int ret = http_request(url, data); + http_free_data(data); + return ret; } -bool client_is_paired(const char *address) { - if (address != NULL) - client_load_server_status(address); - - return paired; -} - -int client_get_current_game(const char *address) { - if (address != NULL) - client_load_server_status(address); - - return currentGame; -} - -void client_init(const char *address) { +int gs_init(PSERVER_DATA server, const char *address) { http_init(); - client_load_unique_id(); - client_load_cert(); + load_unique_id(); + load_cert(); - client_load_server_status(address); -} - -int client_get_server_version(void) { - return serverMajorVersion; + return load_server_status(address, server); } diff --git a/libgamestream/client.h b/libgamestream/client.h index 38eb1ac..3cfaad6 100644 --- a/libgamestream/client.h +++ b/libgamestream/client.h @@ -17,18 +17,23 @@ * along with Moonlight; if not, see . */ +#pragma once + #include "xml.h" #include "limelight-common/Limelight.h" -#include "stdbool.h" +#include -void client_init(const char* serverAddress); -void client_start_app(STREAM_CONFIGURATION *config, const char* serverAddress, int appId, bool sops, bool localaudio); -struct app_list* client_applist(const char* serverAddress); -int client_get_app_id(const char* serverAddress, const char* name); -void client_pair(const char *address); -int client_get_server_version(void); -bool client_is_paired(const char *address); -int client_get_current_game(const char *address); -void client_quit_app(const char *address); +typedef struct _SERVER_DATA { + const char* address; + bool paired; + int currentGame; + int serverMajorVersion; +} SERVER_DATA, *PSERVER_DATA; + +int gs_init(PSERVER_DATA server, const char *address); +int gs_start_app(PSERVER_DATA server, PSTREAM_CONFIGURATION config, int appId, bool sops, bool localaudio); +int gs_applist(PSERVER_DATA server, PAPP_LIST app_list); +int gs_pair(PSERVER_DATA server, char* pin); +int gs_quit_app(PSERVER_DATA server); diff --git a/libgamestream/discover.c b/libgamestream/discover.c index 0bd3155..4550d4e 100644 --- a/libgamestream/discover.c +++ b/libgamestream/discover.c @@ -31,14 +31,14 @@ static AvahiSimplePoll *simple_poll = NULL; -static void discover_client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { +static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { if (state == AVAHI_CLIENT_FAILURE) { fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c))); avahi_simple_poll_quit(simple_poll); } } -static void discover_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { +static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata) { if (event == AVAHI_RESOLVER_FOUND) { if (userdata != NULL) { avahi_address_snprint(userdata, AVAHI_ADDRESS_STR_MAX, address); @@ -53,7 +53,7 @@ static void discover_resolve_callback(AvahiServiceResolver *r, AvahiIfIndex inte avahi_service_resolver_free(r); } -static void discover_browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) { +static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) { AvahiClient *c = avahi_service_browser_get_client(b); switch (event) { @@ -62,7 +62,7 @@ static void discover_browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interf avahi_simple_poll_quit(simple_poll); break; case AVAHI_BROWSER_NEW: - if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, discover_resolve_callback, userdata))) + if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata))) fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); break; @@ -71,7 +71,7 @@ static void discover_browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interf } } -void discover_server(char* dest) { +void gs_discover_server(char* dest) { AvahiClient *client = NULL; AvahiServiceBrowser *sb = NULL; @@ -81,13 +81,13 @@ void discover_server(char* dest) { } int error; - client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, discover_client_callback, NULL, &error); + client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error); if (!client) { fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error)); goto cleanup; } - if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_nvstream._tcp", NULL, 0, discover_browse_callback, dest))) { + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_nvstream._tcp", NULL, 0, browse_callback, dest))) { fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); goto cleanup; } diff --git a/libgamestream/discover.h b/libgamestream/discover.h index 3f2f72c..d5468da 100644 --- a/libgamestream/discover.h +++ b/libgamestream/discover.h @@ -15,6 +15,10 @@ * along with Moonlight; if not, see . */ +#pragma once + +#include "errors.h" + #define MAX_ADDRESS_SIZE 40 -void discover_server(char* dest); +void gs_discover_server(char* dest); diff --git a/libgamestream/errors.h b/libgamestream/errors.h new file mode 100644 index 0000000..2e428f9 --- /dev/null +++ b/libgamestream/errors.h @@ -0,0 +1,27 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015 Iwan Timmer + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#pragma once + +#define GS_OK 0 +#define GS_FAILED -1 +#define GS_OUT_OF_MEMORY -2 +#define GS_INVALID -3 +#define GS_WRONG_STATE -4 +#define GS_IO_ERROR -5 diff --git a/libgamestream/http.c b/libgamestream/http.c index ad414a3..8cd5202 100644 --- a/libgamestream/http.c +++ b/libgamestream/http.c @@ -18,6 +18,7 @@ */ #include "http.h" +#include "errors.h" #include #include @@ -30,12 +31,12 @@ static const char *pKeyFile = "./key.pem"; static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; - struct http_data *mem = (struct http_data *)userp; + PHTTP_DATA mem = (PHTTP_DATA)userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); if(mem->memory == NULL) { fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); + return 0; } memcpy(&(mem->memory[mem->size]), contents, realsize); @@ -45,8 +46,10 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp return realsize; } -void http_init() { +int http_init() { curl = curl_easy_init(); + if (curl) + return GS_FAILED; curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L); @@ -57,9 +60,11 @@ void http_init() { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + return GS_OK; } -int http_request(char* url, struct http_data* data) { +int http_request(char* url, PHTTP_DATA data) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, data); curl_easy_setopt(curl, CURLOPT_URL, url); @@ -68,7 +73,7 @@ int http_request(char* url, struct http_data* data) { data->memory = malloc(1); if(data->memory == NULL) { fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); + return GS_OUT_OF_MEMORY; } data->size = 0; } @@ -76,29 +81,39 @@ int http_request(char* url, struct http_data* data) { if(res != CURLE_OK) { fprintf(stderr, "Connection failed: %s\n", curl_easy_strerror(res)); - exit(EXIT_FAILURE); + return GS_FAILED; + } else if (data->memory == NULL) { + return GS_OUT_OF_MEMORY; } - return 0; + return GS_OK; } void http_cleanup() { curl_easy_cleanup(curl); } -struct http_data* http_create_data() { - struct http_data* data = malloc(sizeof(struct http_data)); +PHTTP_DATA http_create_data() { + PHTTP_DATA data = malloc(sizeof(HTTP_DATA)); + if (data == NULL) { + fprintf(stderr, "Not enough memory\n"); + return NULL; + } data->memory = malloc(1); if(data->memory == NULL) { fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); + free(data); + return NULL; } data->size = 0; return data; } -void http_free_data(struct http_data* data) { - free(data->memory); - free(data); +void http_free_data(PHTTP_DATA data) { + if (data != NULL) { + free(data); + if (data->memory != NULL) + free(data->memory); + } } diff --git a/libgamestream/http.h b/libgamestream/http.h index c7e3a6e..b0355a1 100644 --- a/libgamestream/http.h +++ b/libgamestream/http.h @@ -17,15 +17,16 @@ * along with Moonlight; if not, see . */ +#pragma once + #include -struct http_data { +typedef struct _HTTP_DATA { char *memory; size_t size; -}; +} HTTP_DATA, *PHTTP_DATA; -void http_init(); -int http_request(char* url, struct http_data* data); - -struct http_data* http_create_data(); -void http_free_data(struct http_data* data); +int http_init(); +PHTTP_DATA http_create_data(); +int http_request(char* url, PHTTP_DATA data); +void http_free_data(PHTTP_DATA data); diff --git a/libgamestream/mkcert.c b/libgamestream/mkcert.c index b2ad23d..c8e0369 100644 --- a/libgamestream/mkcert.c +++ b/libgamestream/mkcert.c @@ -33,7 +33,7 @@ static const int NUM_YEARS = 10; int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years); int add_ext(X509 *cert, int nid, char *value); -struct CertKeyPair generateCertKeyPair() { +CERT_KEY_PAIR mkcert_generate() { BIO *bio_err; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; @@ -60,16 +60,16 @@ struct CertKeyPair generateCertKeyPair() { CRYPTO_mem_leaks(bio_err); BIO_free(bio_err); - return (CertKeyPair){x509, pkey, p12}; + return (CERT_KEY_PAIR) {x509, pkey, p12}; } -void freeCertKeyPair(struct CertKeyPair certKeyPair) { +void mkcert_free(CERT_KEY_PAIR certKeyPair) { X509_free(certKeyPair.x509); EVP_PKEY_free(certKeyPair.pkey); PKCS12_free(certKeyPair.p12); } -void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair) { +void mkcert_save(const char* certFile, const char* p12File, const char* keyPairFile, CERT_KEY_PAIR certKeyPair) { FILE* certFilePtr = fopen(certFile, "w"); FILE* keyPairFilePtr = fopen(keyPairFile, "w"); FILE* p12FilePtr = fopen(p12File, "wb"); diff --git a/libgamestream/mkcert.h b/libgamestream/mkcert.h index 4e14b01..745aaa6 100644 --- a/libgamestream/mkcert.h +++ b/libgamestream/mkcert.h @@ -16,20 +16,17 @@ * along with Moonlight; if not, see . */ -#ifndef Limelight_mkcert_h -#define Limelight_mkcert_h +#pragma once #include #include -typedef struct CertKeyPair { +typedef struct _CERT_KEY_PAIR { X509 *x509; EVP_PKEY *pkey; PKCS12 *p12; -} CertKeyPair; - -struct CertKeyPair generateCertKeyPair(); -void freeCertKeyPair(CertKeyPair); -void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair); -#endif +} CERT_KEY_PAIR, *PCERT_KEY_PAIR; +CERT_KEY_PAIR mkcert_generate(); +void mkcert_free(CERT_KEY_PAIR); +void mkcert_save(const char* certFile, const char* p12File, const char* keyPairFile, CERT_KEY_PAIR certKeyPair); diff --git a/libgamestream/xml.c b/libgamestream/xml.c index 4dc1fb9..8842e86 100644 --- a/libgamestream/xml.c +++ b/libgamestream/xml.c @@ -18,9 +18,9 @@ */ #include "xml.h" +#include "errors.h" -#include "expat.h" - +#include #include struct xml_query { @@ -45,12 +45,13 @@ static void XMLCALL _xml_end_element(void *userData, const char *name) { 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) { - struct app_list* app = malloc(sizeof(struct app_list)); + PAPP_LIST app = malloc(sizeof(APP_LIST)); if (app == NULL) { - perror("Not enough memory"); - exit(EXIT_FAILURE); + fprintf(stderr, "Not enough memory\n"); + return; } - app->next = (struct app_list*) search->data; + + app->next = (PAPP_LIST) search->data; search->data = app; } else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) { search->memory = malloc(1); @@ -62,7 +63,10 @@ static void XMLCALL _xml_start_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; if (search->start) { - struct app_list* list = (struct app_list*) search->data; + PAPP_LIST list = (PAPP_LIST) search->data; + if (list == NULL) + return; + if (strcmp("ID", name) == 0) { list->id = atoi(search->memory); free(search->memory); @@ -79,7 +83,7 @@ static void XMLCALL _xml_write_data(void *userData, const XML_Char *s, int len) search->memory = realloc(search->memory, search->size + len + 1); if(search->memory == NULL) { fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); + return; } memcpy(&(search->memory[search->size]), s, len); @@ -101,14 +105,17 @@ int xml_search(char* data, size_t len, char* node, char** result) { if (! XML_Parse(parser, data, len, 1)) { int code = XML_GetErrorCode(parser); fprintf(stderr, "XML Error: %s\n", XML_ErrorString(code)); - return 1; - } + free(search.memory); + return GS_INVALID; + } else if (search.memory == NULL) + return GS_OUT_OF_MEMORY; + *result = search.memory; - return 0; + return GS_OK; } -struct app_list* xml_applist(char* data, size_t len) { +int xml_applist(char* data, size_t len, PAPP_LIST app_list) { struct xml_query query; query.memory = calloc(1, 1); query.size = 0; @@ -121,8 +128,9 @@ struct app_list* xml_applist(char* data, size_t len) { if (! XML_Parse(parser, data, len, 1)) { int code = XML_GetErrorCode(parser); fprintf(stderr, "XML Error %s\n", XML_ErrorString(code)); - exit(-1); + return GS_INVALID; } + app_list = (PAPP_LIST) query.data; - return (struct app_list*) query.data; + return GS_OK; } diff --git a/libgamestream/xml.h b/libgamestream/xml.h index 09f9f30..ca35489 100644 --- a/libgamestream/xml.h +++ b/libgamestream/xml.h @@ -20,11 +20,11 @@ #include -struct app_list { +typedef struct _APP_LIST { char* name; int id; - struct app_list* next; -}; + struct _APP_LIST *next; +} APP_LIST, *PAPP_LIST; int xml_search(char* data, size_t len, char* node, char** result); -struct app_list* xml_applist(char* data, size_t len); +int xml_applist(char* data, size_t len, PAPP_LIST app_list); diff --git a/libgamestream/global.c b/src/global.c similarity index 100% rename from libgamestream/global.c rename to src/global.c diff --git a/libgamestream/global.h b/src/global.h similarity index 100% rename from libgamestream/global.h rename to src/global.h diff --git a/src/input/evdev.c b/src/input/evdev.c index 66e4c44..724c342 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -18,10 +18,10 @@ */ #include "../loop.h" +#include "../global.h" #include "keyboard.h" #include "mapping.h" -#include "global.h" #include "libevdev/libevdev.h" #include "limelight-common/Limelight.h" diff --git a/src/main.c b/src/main.c index fd5225e..85e34d8 100644 --- a/src/main.c +++ b/src/main.c @@ -46,22 +46,43 @@ #define MOONLIGHT_PATH "/moonlight/" #define USER_PATHS ":~/.moonlight:./" -static void applist(const char* address) { - struct app_list* list = client_applist(address); +static void applist(PSERVER_DATA server) { + PAPP_LIST list; + if (gs_applist(server, list) != GS_OK) { + fprintf(stderr, "Can't get app list\n"); + return; + } + for (int i = 1;list != NULL;i++) { printf("%d. %s\n", i, list->name); list = list->next; } } -static void stream(STREAM_CONFIGURATION* config, const char* address, const char* app, bool sops, bool localaudio) { - int appId = client_get_app_id(address, app); +static int get_app_id(PSERVER_DATA server, const char *name) { + PAPP_LIST list; + if (gs_applist(server, list) != GS_OK) { + fprintf(stderr, "Can't get app list\n"); + return -1; + } + + while (list != NULL) { + if (strcmp(list->name, name) == 0) + return list->id; + + list = list->next; + } + return -1; +} + +static void stream(PSERVER_DATA server, PSTREAM_CONFIGURATION config, const char* app, bool sops, bool localaudio) { + int appId = get_app_id(server, app); if (appId<0) { fprintf(stderr, "Can't find app %s\n", app); exit(-1); } - client_start_app(config, address, appId, sops, localaudio); + gs_start_app(server, config, appId, sops, localaudio); video_init(); evdev_init(); @@ -69,7 +90,7 @@ static void stream(STREAM_CONFIGURATION* config, const char* address, const char cec_init(); #endif /* HAVE_LIBCEC */ - LiStartConnection(address, config, &connection_callbacks, decoder_callbacks, &audio_callbacks, NULL, NULL, 0, client_get_server_version()); + LiStartConnection(server->address, config, &connection_callbacks, decoder_callbacks, &audio_callbacks, NULL, NULL, 0, server->serverMajorVersion); loop_main(); @@ -140,8 +161,8 @@ char* get_path(char* name) { return NULL; } -static void pair_check(void) { - if (!client_is_paired(NULL)) { +static void pair_check(PSERVER_DATA server) { + if (!server->paired) { fprintf(stderr, "You must pair with the PC first\n"); exit(-1); } @@ -260,27 +281,33 @@ int main(int argc, char* argv[]) { exit(-1); } address[0] = 0; - discover_server(address); + gs_discover_server(address); if (address[0] == 0) { fprintf(stderr, "Autodiscovery failed. Specify an IP address next time.\n"); exit(-1); } } - client_init(address); + PSERVER_DATA server; + if (gs_init(server, address) != GS_OK) { + fprintf(stderr, "Can't connect to server %s\n", address); + exit(-1); + } if (strcmp("list", action) == 0) { - pair_check(); - applist(address); + pair_check(server); + applist(server); } else if (strcmp("stream", action) == 0) { udev_init(autoadd, mapping); - pair_check(); - stream(&config, address, app, sops, localaudio); - } else if (strcmp("pair", action) == 0) - client_pair(address); - else if (strcmp("quit", action) == 0) { - pair_check(); - client_quit_app(address); + pair_check(server); + stream(server, &config, app, sops, localaudio); + } else if (strcmp("pair", action) == 0) { + char pin[5]; + sprintf(pin, "%d%d%d%d", (int)random() % 10, (int)random() % 10, (int)random() % 10, (int)random() % 10); + gs_pair(server, &pin[0]); + } else if (strcmp("quit", action) == 0) { + pair_check(server); + gs_quit_app(server); } else fprintf(stderr, "%s is not a valid action\n", action); }