From d4ba4a5f8f5764816695c5e8c175c3a6809259d0 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 27 Jun 2015 17:29:54 +0200 Subject: [PATCH 1/6] Split application in client and library --- CMakeLists.txt | 32 +++++++++++++------------------ libgamestream/CMakeLists.txt | 20 +++++++++++++++++++ {src => libgamestream}/client.c | 0 {src => libgamestream}/client.h | 0 {src => libgamestream}/discover.c | 0 {src => libgamestream}/discover.h | 0 {src => libgamestream}/global.c | 0 {src => libgamestream}/global.h | 0 {src => libgamestream}/http.c | 0 {src => libgamestream}/http.h | 0 {src => libgamestream}/mkcert.c | 0 {src => libgamestream}/mkcert.h | 0 {src => libgamestream}/xml.c | 0 {src => libgamestream}/xml.h | 0 14 files changed, 33 insertions(+), 19 deletions(-) create mode 100644 libgamestream/CMakeLists.txt rename {src => libgamestream}/client.c (100%) rename {src => libgamestream}/client.h (100%) rename {src => libgamestream}/discover.c (100%) rename {src => libgamestream}/discover.h (100%) rename {src => libgamestream}/global.c (100%) rename {src => libgamestream}/global.h (100%) rename {src => libgamestream}/http.c (100%) rename {src => libgamestream}/http.h (100%) rename {src => libgamestream}/mkcert.c (100%) rename {src => libgamestream}/mkcert.h (100%) rename {src => libgamestream}/xml.c (100%) rename {src => libgamestream}/xml.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb342a4..919b3ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,17 +6,8 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") aux_source_directory(./src SRC_LIST) list(APPEND SRC_LIST ./src/video/fake.c) -aux_source_directory(./third_party/moonlight-common-c/limelight-common SRC_LIST) -aux_source_directory(./third_party/moonlight-common-c/limelight-common/OpenAES SRC_LIST) - -include_directories(./third_party/moonlight-common-c) - set(MOONLIGHT_DEFINITIONS) -find_package(Threads REQUIRED) -find_package(CURL REQUIRED) -find_package(OpenSSL REQUIRED) -find_package(EXPAT REQUIRED) find_package(ALSA REQUIRED) find_package(Opus REQUIRED) find_package(Broadcom) @@ -25,14 +16,8 @@ find_package(CEC) find_package(PkgConfig REQUIRED) pkg_check_modules(EVDEV REQUIRED libevdev) -pkg_check_modules(AVAHI REQUIRED avahi-client) pkg_check_modules(UDEV REQUIRED libudev) -if(CEC_FOUND) - include_directories(./third_party/libcec) - list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC) -endif() - if(BROADCOM_FOUND) aux_source_directory(./third_party/ilclient SRC_LIST) aux_source_directory(./third_party/h264bitstream SRC_LIST) @@ -45,23 +30,32 @@ if(FREESCALE_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_IMX) endif() +add_subdirectory(libgamestream) + add_executable(moonlight ${SRC_LIST}) +target_link_libraries(moonlight PUBLIC gamestream) set_property(TARGET moonlight PROPERTY C_STANDARD 11) +if (CEC_FOUND) + list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC) + target_include_directories(moonlight PRIVATE ./third_party/libcec ${CEC_INCLUDE_DIRS}) + target_link_libraries (moonlight PUBLIC ${CEC_LIBRARIES}) +endif() + if(BROADCOM_FOUND) - include_directories(./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS}) + target_include_directories(moonlight PRIVATE ./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS}) target_link_libraries (moonlight PUBLIC ${BROADCOM_LIBRARIES}) list(APPEND MOONLIGHT_DEFINITIONS ${BROADCOM_DEFINITIONS}) endif() if(FREESCALE_FOUND) - include_directories(${FREESCALE_INCLUDE_DIRS}) + target_include_directories(moonlight PRIVATE ${FREESCALE_INCLUDE_DIRS}) target_link_libraries (moonlight PUBLIC ${FREESCALE_LIBRARIES}) endif() set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${MOONLIGHT_DEFINITIONS}) -include_directories(./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${AVAHI_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ${CEC_INCLUDE_DIRS}) -target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS} ${CEC_LIBRARIES}) +target_include_directories(moonlight PRIVATE ./libgamestream ./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS}) +target_link_libraries (moonlight PUBLIC ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS}) include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake) install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/libgamestream/CMakeLists.txt b/libgamestream/CMakeLists.txt new file mode 100644 index 0000000..46682ad --- /dev/null +++ b/libgamestream/CMakeLists.txt @@ -0,0 +1,20 @@ +find_package(Threads REQUIRED) +find_package(CURL REQUIRED) +find_package(OpenSSL REQUIRED) +find_package(EXPAT REQUIRED) + +pkg_check_modules(AVAHI REQUIRED avahi-client) + +aux_source_directory(./ GAMESTREAM_SRC_LIST) + +aux_source_directory(../third_party/moonlight-common-c/limelight-common GAMESTREAM_SRC_LIST) +aux_source_directory(../third_party/moonlight-common-c/limelight-common/OpenAES GAMESTREAM_SRC_LIST) + +add_library(gamestream SHARED ${GAMESTREAM_SRC_LIST}) +set_property(TARGET gamestream PROPERTY C_STANDARD 11) +set_target_properties(gamestream PROPERTIES SOVERSION 0 VERSION 2.1.0) + +target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c ${AVAHI_INCLUDE_DIRS}) +target_link_libraries (gamestream PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${CMAKE_DL_LIBS}) + +#install(TARGETS gamestream DESTINATION ${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file diff --git a/src/client.c b/libgamestream/client.c similarity index 100% rename from src/client.c rename to libgamestream/client.c diff --git a/src/client.h b/libgamestream/client.h similarity index 100% rename from src/client.h rename to libgamestream/client.h diff --git a/src/discover.c b/libgamestream/discover.c similarity index 100% rename from src/discover.c rename to libgamestream/discover.c diff --git a/src/discover.h b/libgamestream/discover.h similarity index 100% rename from src/discover.h rename to libgamestream/discover.h diff --git a/src/global.c b/libgamestream/global.c similarity index 100% rename from src/global.c rename to libgamestream/global.c diff --git a/src/global.h b/libgamestream/global.h similarity index 100% rename from src/global.h rename to libgamestream/global.h diff --git a/src/http.c b/libgamestream/http.c similarity index 100% rename from src/http.c rename to libgamestream/http.c diff --git a/src/http.h b/libgamestream/http.h similarity index 100% rename from src/http.h rename to libgamestream/http.h diff --git a/src/mkcert.c b/libgamestream/mkcert.c similarity index 100% rename from src/mkcert.c rename to libgamestream/mkcert.c diff --git a/src/mkcert.h b/libgamestream/mkcert.h similarity index 100% rename from src/mkcert.h rename to libgamestream/mkcert.h diff --git a/src/xml.c b/libgamestream/xml.c similarity index 100% rename from src/xml.c rename to libgamestream/xml.c diff --git a/src/xml.h b/libgamestream/xml.h similarity index 100% rename from src/xml.h rename to libgamestream/xml.h From 0b02016a6cafeddaf0178548ee7950889850943d Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 27 Jun 2015 19:34:01 +0200 Subject: [PATCH 2/6] Split input code in multiple files --- CMakeLists.txt | 1 + src/input/cec.c | 103 ++++++++ src/input/cec.h | 20 ++ src/{input.c => input/evdev.c} | 449 +++++++++------------------------ src/{input.h => input/evdev.h} | 9 +- src/{ => input}/keyboard.h | 0 src/{ => input}/mapping.c | 0 src/{ => input}/mapping.h | 0 src/input/udev.c | 97 +++++++ src/input/udev.h | 21 ++ src/loop.c | 113 +++++++++ src/loop.h | 28 ++ src/main.c | 22 +- 13 files changed, 519 insertions(+), 344 deletions(-) create mode 100644 src/input/cec.c create mode 100644 src/input/cec.h rename src/{input.c => input/evdev.c} (52%) rename src/{input.h => input/evdev.h} (82%) rename src/{ => input}/keyboard.h (100%) rename src/{ => input}/mapping.c (100%) rename src/{ => input}/mapping.h (100%) create mode 100644 src/input/udev.c create mode 100644 src/input/udev.h create mode 100644 src/loop.c create mode 100644 src/loop.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 919b3ff..074ed68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 3.1) SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") aux_source_directory(./src SRC_LIST) +aux_source_directory(./src/input SRC_LIST) list(APPEND SRC_LIST ./src/video/fake.c) set(MOONLIGHT_DEFINITIONS) diff --git a/src/input/cec.c b/src/input/cec.c new file mode 100644 index 0000000..b7af990 --- /dev/null +++ b/src/input/cec.c @@ -0,0 +1,103 @@ +/* + * 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 . + */ + +#ifdef HAVE_LIBCEC +#include + +static libcec_configuration g_config; +static char g_strPort[50] = { 0 }; +static libcec_interface_t g_iface; +static ICECCallbacks g_callbacks; + +static int on_cec_keypress(void* userdata, const cec_keypress key) { + char value; + switch (key.keycode) { + case CEC_USER_CONTROL_CODE_UP: + value = KEY_UP; + break; + case CEC_USER_CONTROL_CODE_DOWN: + value = KEY_DOWN; + break; + case CEC_USER_CONTROL_CODE_LEFT: + value = KEY_LEFT; + break; + case CEC_USER_CONTROL_CODE_RIGHT: + value = KEY_RIGHT; + break; + case CEC_USER_CONTROL_CODE_ENTER: + case CEC_USER_CONTROL_CODE_SELECT: + value = KEY_ENTER; + break; + case CEC_USER_CONTROL_CODE_ROOT_MENU: + value = KEY_TAB; + break; + case CEC_USER_CONTROL_CODE_AN_RETURN: + case CEC_USER_CONTROL_CODE_EXIT: + value = KEY_ESC; + break; + default: + value = 0; + break; + } + + if (value != 0) { + short code = 0x80 << 8 | keyCodes[value]; + LiSendKeyboardEvent(code, (key.duration > 0)?KEY_ACTION_DOWN:KEY_ACTION_UP, 0); + } +} + +void init_cec() { + libcecc_reset_configuration(&g_config); + g_config.clientVersion = LIBCEC_VERSION_CURRENT; + g_config.bActivateSource = 0; + g_callbacks.CBCecKeyPress = &on_cec_keypress; + g_config.callbacks = &g_callbacks; + snprintf(g_config.strDeviceName, sizeof(g_config.strDeviceName), "Moonlight"); + g_config.callbacks = &g_callbacks; + g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_PLAYBACK_DEVICE; + + if (libcecc_initialise(&g_config, &g_iface, NULL) != 1) { + fprintf(stderr, "Failed to initialize libcec interface\n"); + fflush(stderr); + return; + } + + g_iface.init_video_standalone(g_iface.connection); + + cec_adapter devices[10]; + int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL); + + if (iDevicesFound <= 0) { + fprintf(stderr, "No CEC devices found\n"); + fflush(stderr); + libcecc_destroy(&g_iface); + return; + } + + strcpy(g_strPort, devices[0].comm); + if (!g_iface.open(g_iface.connection, g_strPort, 5000)) { + fprintf(stderr, "Unable to open the device on port %s\n", g_strPort); + fflush(stderr); + libcecc_destroy(&g_iface); + return; + } + + g_iface.set_active_source(g_iface.connection, g_config.deviceTypes.types[0]); +} +#endif /* HAVE_LIBCEC */ \ No newline at end of file diff --git a/src/input/cec.h b/src/input/cec.h new file mode 100644 index 0000000..298ca44 --- /dev/null +++ b/src/input/cec.h @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +void init_cec(); \ No newline at end of file diff --git a/src/input.c b/src/input/evdev.c similarity index 52% rename from src/input.c rename to src/input/evdev.c index 5c63c58..66e4c44 100644 --- a/src/input.c +++ b/src/input/evdev.c @@ -17,6 +17,8 @@ * along with Moonlight; if not, see . */ +#include "../loop.h" + #include "keyboard.h" #include "mapping.h" #include "global.h" @@ -24,20 +26,13 @@ #include "libevdev/libevdev.h" #include "limelight-common/Limelight.h" -#ifdef HAVE_LIBCEC -#include -#endif - #include #include #include #include #include -#include #include #include -#include -#include #include #include #include @@ -55,7 +50,6 @@ struct input_device { struct libevdev *dev; struct mapping map; int fd; - int fdindex; char modifiers; __s32 mouseDeltaX, mouseDeltaY, mouseScroll; short controllerId; @@ -68,107 +62,17 @@ struct input_device { struct input_abs_parms dpadxParms, dpadyParms; }; -static struct pollfd* fds = NULL; static struct input_device* devices = NULL; -static int numDevices = 0, numFds = 0; +static int numDevices = 0; static int assignedControllerIds = 0; static short* currentKey; static short* currentAbs; static bool* currentReverse; -static bool autoadd; -static char* defaultMapfile; -static struct udev *udev; -static struct udev_monitor *udev_mon; -static int udev_fdindex; +static bool (*handler) (struct input_event*, struct input_device*); -static int sig_fdindex; - -#ifdef HAVE_LIBCEC -static libcec_configuration g_config; -static char g_strPort[50] = { 0 }; -static libcec_interface_t g_iface; -static ICECCallbacks g_callbacks; - -static int on_cec_keypress(void* userdata, const cec_keypress key) { - char value; - switch (key.keycode) { - case CEC_USER_CONTROL_CODE_UP: - value = KEY_UP; - break; - case CEC_USER_CONTROL_CODE_DOWN: - value = KEY_DOWN; - break; - case CEC_USER_CONTROL_CODE_LEFT: - value = KEY_LEFT; - break; - case CEC_USER_CONTROL_CODE_RIGHT: - value = KEY_RIGHT; - break; - case CEC_USER_CONTROL_CODE_ENTER: - case CEC_USER_CONTROL_CODE_SELECT: - value = KEY_ENTER; - break; - case CEC_USER_CONTROL_CODE_ROOT_MENU: - value = KEY_TAB; - break; - case CEC_USER_CONTROL_CODE_AN_RETURN: - case CEC_USER_CONTROL_CODE_EXIT: - value = KEY_ESC; - break; - default: - value = 0; - break; - } - - if (value != 0) { - short code = 0x80 << 8 | keyCodes[value]; - LiSendKeyboardEvent(code, (key.duration > 0)?KEY_ACTION_DOWN:KEY_ACTION_UP, 0); - } -} - -static void init_cec() { - libcecc_reset_configuration(&g_config); - g_config.clientVersion = LIBCEC_VERSION_CURRENT; - g_config.bActivateSource = 0; - g_callbacks.CBCecKeyPress = &on_cec_keypress; - g_config.callbacks = &g_callbacks; - snprintf(g_config.strDeviceName, sizeof(g_config.strDeviceName), "Moonlight"); - g_config.callbacks = &g_callbacks; - g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_PLAYBACK_DEVICE; - - if (libcecc_initialise(&g_config, &g_iface, NULL) != 1) { - fprintf(stderr, "Failed to initialize libcec interface\n"); - fflush(stderr); - return; - } - - g_iface.init_video_standalone(g_iface.connection); - - cec_adapter devices[10]; - int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL); - - if (iDevicesFound <= 0) { - fprintf(stderr, "No CEC devices found\n"); - fflush(stderr); - libcecc_destroy(&g_iface); - return; - } - - strcpy(g_strPort, devices[0].comm); - if (!g_iface.open(g_iface.connection, g_strPort, 5000)) { - fprintf(stderr, "Unable to open the device on port %s\n", g_strPort); - fflush(stderr); - libcecc_destroy(&g_iface); - return; - } - - g_iface.set_active_source(g_iface.connection, g_config.deviceTypes.types[0]); -} -#endif - -static void input_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) { +static void evdev_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) { parms->flat = libevdev_get_abs_flat(dev->dev, code); parms->min = libevdev_get_abs_minimum(dev->dev, code); parms->max = libevdev_get_abs_maximum(dev->dev, code); @@ -177,154 +81,19 @@ static void input_init_parms(struct input_device *dev, struct input_abs_parms *p parms->diff = parms->max - parms->min; } -void input_create(const char* device, char* mapFile) { - int fd = open(device, O_RDONLY|O_NONBLOCK); - if (fd <= 0) { - fprintf(stderr, "Failed to open device %s\n", device); - fflush(stderr); - return; - } - - int dev = numDevices; - int fdindex = numFds; - numDevices++; - numFds++; - - if (fds == NULL) { - fds = malloc(sizeof(struct pollfd)); - devices = malloc(sizeof(struct input_device)); - } else { - fds = realloc(fds, sizeof(struct pollfd)*numFds); - devices = realloc(devices, sizeof(struct input_device)*numDevices); - } - - if (fds == NULL || devices == NULL) { - fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); - } - - memset(&devices[dev], 0, sizeof(devices[0])); - devices[dev].fd = fd; - devices[dev].dev = libevdev_new(); - libevdev_set_fd(devices[dev].dev, devices[dev].fd); - devices[dev].fdindex = fdindex; - fds[fdindex].fd = devices[dev].fd; - fds[fdindex].events = POLLIN; - - if (mapFile != NULL) - mapping_load(mapFile, &(devices[dev].map)); - - devices[dev].controllerId = -1; - input_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_x); - input_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_y); - input_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_z); - input_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rx); - input_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_ry); - input_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_rz); - input_init_parms(&devices[dev], &(devices[dev].dpadxParms), devices[dev].map.abs_dpad_x); - input_init_parms(&devices[dev], &(devices[dev].dpadyParms), devices[dev].map.abs_dpad_y); -} - -static void input_remove(int devindex) { +static void evdev_remove(int devindex) { numDevices--; - numFds--; if (devices[devindex].controllerId >= 0) assignedControllerIds &= ~(1 << devices[devindex].controllerId); - int fdindex = devices[devindex].fdindex; - if (fdindex != numFds && numFds > 0) { - memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd)); - if (numFds == udev_fdindex) - udev_fdindex = fdindex; - else if (numFds == sig_fdindex) - sig_fdindex = fdindex; - else { - for (int i=0;i 0) memcpy(&devices[devindex], &devices[numDevices], sizeof(struct input_device)); fprintf(stderr, "Removed input device\n"); } -void input_init(char* mapfile) { - #ifdef HAVE_LIBCEC - init_cec(); - #endif - - udev = udev_new(); - if (!udev) { - fprintf(stderr, "Can't create udev\n"); - exit(1); - } - - autoadd = (numDevices == 0); - if (autoadd) { - struct udev_enumerate *enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, "input"); - udev_enumerate_scan_devices(enumerate); - struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); - - struct udev_list_entry *dev_list_entry; - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path = udev_list_entry_get_name(dev_list_entry); - struct udev_device *dev = udev_device_new_from_syspath(udev, path); - const char *devnode = udev_device_get_devnode(dev); - int id; - if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) { - input_create(devnode, mapfile); - } - udev_device_unref(dev); - } - - udev_enumerate_unref(enumerate); - } - - udev_mon = udev_monitor_new_from_netlink(udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "input", NULL); - udev_monitor_enable_receiving(udev_mon); - - udev_fdindex = numFds++; - sig_fdindex = numFds++; - - if (fds == NULL) - fds = malloc(sizeof(struct pollfd)*numFds); - else - fds = realloc(fds, sizeof(struct pollfd)*numFds); - - if (fds == NULL) { - fprintf(stderr, "Not enough memory\n"); - exit(EXIT_FAILURE); - } - - defaultMapfile = mapfile; - fds[udev_fdindex].fd = udev_monitor_get_fd(udev_mon); - fds[udev_fdindex].events = POLLIN; - - main_thread_id = pthread_self(); - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGHUP); - sigaddset(&sigset, SIGTERM); - sigaddset(&sigset, SIGINT); - sigaddset(&sigset, SIGQUIT); - sigprocmask(SIG_BLOCK, &sigset, NULL); - fds[sig_fdindex].fd = signalfd(-1, &sigset, 0); - fds[sig_fdindex].events = POLLIN | POLLERR | POLLHUP; -} - -void input_destroy() { - udev_unref(udev); -} - -static short input_convert_value(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) { +static short evdev_convert_value(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) { if (abs(ev->value - parms->avg) < parms->flat) return 0; else if (ev->value > parms->max) @@ -337,7 +106,7 @@ static short input_convert_value(struct input_event *ev, struct input_device *de return (ev->value - (ev->value>parms->avg?parms->flat*2:0) - parms->min) * (SHRT_MAX-SHRT_MIN) / (parms->max-parms->min-parms->flat*2) - SHRT_MIN; } -static char input_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) { +static char evdev_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) { if (abs(ev->value-parms->min)flat) return 0; else if (ev->value>parms->max) @@ -348,7 +117,7 @@ static char input_convert_value_byte(struct input_event *ev, struct input_device } } -static int input_convert_value_direction(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) { +static int evdev_convert_value_direction(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) { if (ev->value > (parms->avg+parms->range/4)) return reverse?-1:1; else if (ev->value < (parms->avg-parms->range/4)) @@ -357,7 +126,7 @@ static int input_convert_value_direction(struct input_event *ev, struct input_de return 0; } -static bool input_handle_event(struct input_event *ev, struct input_device *dev) { +static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) { bool gamepadModified = false; switch (ev->type) { @@ -495,19 +264,19 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev) case EV_ABS: gamepadModified = true; if (ev->code == dev->map.abs_x) - dev->leftStickX = input_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x); + dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x); else if (ev->code == dev->map.abs_y) - dev->leftStickY = input_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y); + dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y); else if (ev->code == dev->map.abs_rx) - dev->rightStickX = input_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx); + dev->rightStickX = evdev_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx); else if (ev->code == dev->map.abs_ry) - dev->rightStickY = input_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry); + dev->rightStickY = evdev_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry); else if (ev->code == dev->map.abs_z) - dev->leftTrigger = input_convert_value_byte(ev, dev, &dev->zParms); + dev->leftTrigger = evdev_convert_value_byte(ev, dev, &dev->zParms); else if (ev->code == dev->map.abs_rz) - dev->rightTrigger = input_convert_value_byte(ev, dev, &dev->rzParms); + dev->rightTrigger = evdev_convert_value_byte(ev, dev, &dev->rzParms); else if (ev->code == dev->map.abs_dpad_x) { - int dir = input_convert_value_direction(ev, dev, &dev->dpadxParms, dev->map.reverse_dpad_x); + int dir = evdev_convert_value_direction(ev, dev, &dev->dpadxParms, dev->map.reverse_dpad_x); if (dir == 1) { dev->buttonFlags |= RIGHT_FLAG; dev->buttonFlags &= ~LEFT_FLAG; @@ -519,7 +288,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev) dev->buttonFlags |= LEFT_FLAG; } } else if (ev->code == dev->map.abs_dpad_y) { - int dir = input_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y); + int dir = evdev_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y); if (dir == 1) { dev->buttonFlags |= DOWN_FLAG; dev->buttonFlags &= ~UP_FLAG; @@ -540,7 +309,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev) return true; } -static bool input_handle_mapping_event(struct input_event *ev, struct input_device *dev) { +static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) { switch (ev->type) { case EV_KEY: if (currentKey != NULL) { @@ -553,7 +322,7 @@ static bool input_handle_mapping_event(struct input_event *ev, struct input_devi case EV_ABS: if (currentAbs != NULL) { struct input_abs_parms parms; - input_init_parms(dev, &parms, ev->code); + evdev_init_parms(dev, &parms, ev->code); if (ev->value > parms.avg + parms.range/2) { *currentAbs = ev->code; @@ -569,91 +338,104 @@ static bool input_handle_mapping_event(struct input_event *ev, struct input_devi return true; } -static void input_drain(void) { +static void evdev_drain(void) { for (int i = 0; i < numDevices; i++) { struct input_event ev; while (libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev) >= 0); } } -static bool input_poll(bool (*handler) (struct input_event*, struct input_device*)) { - while (poll(fds, numFds, -1)) { - if (fds[udev_fdindex].revents > 0) { - struct udev_device *dev = udev_monitor_receive_device(udev_mon); - const char *action = udev_device_get_action(dev); - if (action != NULL) { - if (autoadd && strcmp("add", action) == 0) { - const char *devnode = udev_device_get_devnode(dev); - int id; - if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) { - input_create(devnode, defaultMapfile); - } +static int evdev_handle(int fd) { + for (int i=0;i= 0) { + if (rc == LIBEVDEV_READ_STATUS_SYNC) + fprintf(stderr, "Error: cannot keep up\n"); + else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { + if (!handler(&ev, &devices[i])) + return LOOP_RETURN; } - udev_device_unref(dev); } - } else if (fds[sig_fdindex].revents > 0) { - struct signalfd_siginfo info; - read(fds[sig_fdindex].fd, &info, sizeof(info)); - - switch (info.ssi_signo) { - case SIGINT: - case SIGTERM: - case SIGQUIT: - case SIGHUP: - return false; - } - } - for (int i=0;i 0) { - int rc; - struct input_event ev; - while ((rc = libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev)) >= 0) { - if (rc == LIBEVDEV_READ_STATUS_SYNC) - fprintf(stderr, "Error: cannot keep up\n"); - else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { - if (!handler(&ev, &devices[i])) - return true; - } - } - if (rc == -ENODEV) { - input_remove(i); - } else if (rc != -EAGAIN && rc < 0) { - fprintf(stderr, "Error: %s\n", strerror(-rc)); - exit(EXIT_FAILURE); - } + if (rc == -ENODEV) { + evdev_remove(i); + } else if (rc != -EAGAIN && rc < 0) { + fprintf(stderr, "Error: %s\n", strerror(-rc)); + exit(EXIT_FAILURE); } } } - - return false; + return LOOP_OK; } -static void input_map_key(char* keyName, short* key) { +void evdev_create(const char* device, char* mapFile) { + int fd = open(device, O_RDONLY|O_NONBLOCK); + if (fd <= 0) { + fprintf(stderr, "Failed to open device %s\n", device); + fflush(stderr); + return; + } + + int dev = numDevices; + numDevices++; + + if (devices == NULL) { + devices = malloc(sizeof(struct input_device)); + } else { + devices = realloc(devices, sizeof(struct input_device)*numDevices); + } + + if (devices == NULL) { + fprintf(stderr, "Not enough memory\n"); + exit(EXIT_FAILURE); + } + + memset(&devices[dev], 0, sizeof(devices[0])); + devices[dev].fd = fd; + devices[dev].dev = libevdev_new(); + libevdev_set_fd(devices[dev].dev, devices[dev].fd); + + if (mapFile != NULL) + mapping_load(mapFile, &(devices[dev].map)); + + devices[dev].controllerId = -1; + evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_x); + evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_y); + evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_z); + evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rx); + evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_ry); + evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_rz); + evdev_init_parms(&devices[dev], &(devices[dev].dpadxParms), devices[dev].map.abs_dpad_x); + evdev_init_parms(&devices[dev], &(devices[dev].dpadyParms), devices[dev].map.abs_dpad_y); + + loop_add_fd(devices[dev].fd, &evdev_handle, POLLIN); +} + +static void evdev_map_key(char* keyName, short* key) { printf("Press %s\n", keyName); currentKey = key; currentAbs = NULL; *key = -1; - if (!input_poll(input_handle_mapping_event)) - exit(1); + loop_main(); usleep(250000); - input_drain(); + evdev_drain(); } -static void input_map_abs(char* keyName, short* abs, bool* reverse) { +static void evdev_map_abs(char* keyName, short* abs, bool* reverse) { printf("Move %s\n", keyName); currentKey = NULL; currentAbs = abs; currentReverse = reverse; *abs = -1; - if (!input_poll(input_handle_mapping_event)) - exit(1); + loop_main(); usleep(250000); - input_drain(); + evdev_drain(); } -static void input_map_abskey(char* keyName, short* key, short* abs, bool* reverse) { +static void evdev_map_abskey(char* keyName, short* key, short* abs, bool* reverse) { printf("Press %s\n", keyName); currentKey = key; currentAbs = abs; @@ -661,53 +443,54 @@ static void input_map_abskey(char* keyName, short* key, short* abs, bool* revers *key = -1; *abs = -1; *currentReverse = false; - if (!input_poll(input_handle_mapping_event)) - exit(1); + loop_main(); usleep(250000); - input_drain(); + evdev_drain(); } -void input_map(char* fileName) { +void evdev_map(char* fileName) { struct mapping map; - input_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x)); - input_map_abs("Left Stick Up", &(map.abs_y), &(map.reverse_y)); - input_map_key("Left Stick Button", &(map.btn_thumbl)); + handler = evdev_handle_mapping_event; - input_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx)); - input_map_abs("Right Stick Up", &(map.abs_ry), &(map.reverse_ry)); - input_map_key("Right Stick Button", &(map.btn_thumbr)); + evdev_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x)); + evdev_map_abs("Left Stick Up", &(map.abs_y), &(map.reverse_y)); + evdev_map_key("Left Stick Button", &(map.btn_thumbl)); - input_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x)); + evdev_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx)); + evdev_map_abs("Right Stick Up", &(map.abs_ry), &(map.reverse_ry)); + evdev_map_key("Right Stick Button", &(map.btn_thumbr)); + + evdev_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x)); if (map.btn_dpad_right >= 0) - input_map_key("D-Pad Left", &(map.btn_dpad_left)); + evdev_map_key("D-Pad Left", &(map.btn_dpad_left)); else map.btn_dpad_left = -1; - input_map_abskey("D-Pad Down", &(map.btn_dpad_down), &(map.abs_dpad_y), &(map.reverse_dpad_y)); + evdev_map_abskey("D-Pad Down", &(map.btn_dpad_down), &(map.abs_dpad_y), &(map.reverse_dpad_y)); if (map.btn_dpad_down >= 0) - input_map_key("D-Pad Up", &(map.btn_dpad_up)); + evdev_map_key("D-Pad Up", &(map.btn_dpad_up)); else map.btn_dpad_up = -1; - input_map_key("Button X (1)", &(map.btn_west)); - input_map_key("Button A (2)", &(map.btn_south)); - input_map_key("Button B (3)", &(map.btn_east)); - input_map_key("Button Y (4)", &(map.btn_north)); - input_map_key("Back Button", &(map.btn_select)); - input_map_key("Start Button", &(map.btn_start)); - input_map_key("Special Button", &(map.btn_mode)); + evdev_map_key("Button X (1)", &(map.btn_west)); + evdev_map_key("Button A (2)", &(map.btn_south)); + evdev_map_key("Button B (3)", &(map.btn_east)); + evdev_map_key("Button Y (4)", &(map.btn_north)); + evdev_map_key("Back Button", &(map.btn_select)); + evdev_map_key("Start Button", &(map.btn_start)); + evdev_map_key("Special Button", &(map.btn_mode)); bool ignored; - input_map_abskey("Left Trigger", &(map.btn_tl2), &(map.abs_z), &ignored); - input_map_abskey("Right Trigger", &(map.btn_tr2), &(map.abs_rz), &ignored); + evdev_map_abskey("Left Trigger", &(map.btn_tl2), &(map.abs_z), &ignored); + evdev_map_abskey("Right Trigger", &(map.btn_tr2), &(map.abs_rz), &ignored); - input_map_key("Left Bumper", &(map.btn_tl)); - input_map_key("Right Bumper", &(map.btn_tr)); + evdev_map_key("Left Bumper", &(map.btn_tl)); + evdev_map_key("Right Bumper", &(map.btn_tr)); mapping_save(fileName, &map); } -void input_loop() { - input_poll(input_handle_event); +void evdev_init() { + handler = evdev_handle_event; } diff --git a/src/input.h b/src/input/evdev.h similarity index 82% rename from src/input.h rename to src/input/evdev.h index f77d075..bb9b178 100644 --- a/src/input.h +++ b/src/input/evdev.h @@ -17,9 +17,8 @@ * along with Moonlight; if not, see . */ -void input_init(char* mapfile); -void input_create(char* device, char* mapFile); -void input_loop(); -void input_map(char* fileName); +void evdev_create(const char* device, char* mapFile); +void evdev_loop(); +void evdev_map(char* fileName); -void input_destroy(); +void evdev_init(); diff --git a/src/keyboard.h b/src/input/keyboard.h similarity index 100% rename from src/keyboard.h rename to src/input/keyboard.h diff --git a/src/mapping.c b/src/input/mapping.c similarity index 100% rename from src/mapping.c rename to src/input/mapping.c diff --git a/src/mapping.h b/src/input/mapping.h similarity index 100% rename from src/mapping.h rename to src/input/mapping.h diff --git a/src/input/udev.c b/src/input/udev.c new file mode 100644 index 0000000..b587cd9 --- /dev/null +++ b/src/input/udev.c @@ -0,0 +1,97 @@ +/* + * 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 . + */ + +#include "../loop.h" + +#include "evdev.h" + +#include + +#include +#include +#include +#include +#include +#include + +static bool autoadd; +static char* defaultMapfile; + +static struct udev *udev; +static struct udev_monitor *udev_mon; +static int udev_fd; + +static int udev_handle(int fd) { + struct udev_device *dev = udev_monitor_receive_device(udev_mon); + const char *action = udev_device_get_action(dev); + if (action != NULL) { + if (autoadd && strcmp("add", action) == 0) { + const char *devnode = udev_device_get_devnode(dev); + int id; + if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) { + evdev_create(devnode, defaultMapfile); + } + } + udev_device_unref(dev); + } + return LOOP_OK; +} + +void udev_init(bool autoload, char* mapfile) { + udev = udev_new(); + if (!udev) { + fprintf(stderr, "Can't create udev\n"); + exit(1); + } + + autoadd = autoload; + if (autoload) { + struct udev_enumerate *enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "input"); + udev_enumerate_scan_devices(enumerate); + struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); + + struct udev_list_entry *dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path = udev_list_entry_get_name(dev_list_entry); + struct udev_device *dev = udev_device_new_from_syspath(udev, path); + const char *devnode = udev_device_get_devnode(dev); + int id; + if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) { + evdev_create(devnode, mapfile); + } + udev_device_unref(dev); + } + + udev_enumerate_unref(enumerate); + } + + udev_mon = udev_monitor_new_from_netlink(udev, "udev"); + udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "input", NULL); + udev_monitor_enable_receiving(udev_mon); + + defaultMapfile = mapfile; + + int udev_fd = udev_monitor_get_fd(udev_mon); + loop_add_fd(udev_fd, &udev_handle, POLLIN); +} + +void evdev_destroy() { + udev_unref(udev); +} diff --git a/src/input/udev.h b/src/input/udev.h new file mode 100644 index 0000000..b834adc --- /dev/null +++ b/src/input/udev.h @@ -0,0 +1,21 @@ +/* + * 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 . + */ + +void udev_init(bool autoload, char* mapfile); +void evdev_destroy(); diff --git a/src/loop.c b/src/loop.c new file mode 100644 index 0000000..d00097b --- /dev/null +++ b/src/loop.c @@ -0,0 +1,113 @@ +/* + * 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 . + */ + +#include "loop.h" + +#include "global.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct pollfd* fds = NULL; +static FdHandler* fdHandlers = NULL; +static int numFds = 0; + +static int sigFd; + +static int loop_sig_handler(int fd) { + struct signalfd_siginfo info; + read(fd, &info, sizeof(info)); + switch (info.ssi_signo) { + case SIGINT: + case SIGTERM: + case SIGQUIT: + case SIGHUP: + return LOOP_RETURN; + } + return LOOP_OK; +} + +void loop_add_fd(int fd, FdHandler handler, int events) { + int fdindex = numFds; + numFds++; + + if (fds == NULL) { + fds = malloc(sizeof(struct pollfd)); + fdHandlers = malloc(sizeof(FdHandler*)); + } else { + fds = realloc(fds, sizeof(struct pollfd)*numFds); + fdHandlers = realloc(fdHandlers, sizeof(FdHandler*)*numFds); + } + + if (fds == NULL || fdHandlers == NULL) { + fprintf(stderr, "Not enough memory\n"); + exit(EXIT_FAILURE); + } + + fds[fdindex].fd = fd; + fds[fdindex].events = events; +} + +void loop_remove_fd(int fd) { + numFds--; + int fdindex; + + for (int i=0;i 0) { + memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd)); + memcpy(&fdHandlers[fdindex], &fdHandlers[numFds], sizeof(FdHandler*)); + } +} + +void loop_main() { + main_thread_id = pthread_self(); + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGHUP); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); + sigaddset(&sigset, SIGQUIT); + sigprocmask(SIG_BLOCK, &sigset, NULL); + sigFd = signalfd(-1, &sigset, 0); + loop_add_fd(sigFd, loop_sig_handler, POLLIN | POLLERR | POLLHUP); + +//static bool evdev_poll(bool (*handler) (struct input_event*, struct input_device*)) { + while (poll(fds, numFds, -1)) { + for (int i=0;i 0) { + int ret = fdHandlers[i](fds[i].fd); + if (ret == LOOP_RETURN) { + return; + } + break; + } + } + } +} diff --git a/src/loop.h b/src/loop.h new file mode 100644 index 0000000..e4550ca --- /dev/null +++ b/src/loop.h @@ -0,0 +1,28 @@ +/* + * 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 . + */ + +#define LOOP_RETURN 1 +#define LOOP_OK 0 + +typedef int(*FdHandler)(int fd); + +void loop_add_fd(int fd, FdHandler handler, int events); +void loop_remove_fd(int fd); + +void loop_main(); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 621f661..fd5225e 100644 --- a/src/main.c +++ b/src/main.c @@ -17,13 +17,17 @@ * along with Moonlight; if not, see . */ +#include "loop.h" #include "client.h" #include "connection.h" #include "video.h" #include "audio.h" -#include "input.h" #include "discover.h" +#include "input/evdev.h" +#include "input/udev.h" +#include "input/cec.h" + #include "limelight-common/Limelight.h" #include @@ -60,10 +64,14 @@ static void stream(STREAM_CONFIGURATION* config, const char* address, const char client_start_app(config, address, appId, sops, localaudio); video_init(); + evdev_init(); + #ifdef HAVE_LIBCEC + cec_init(); + #endif /* HAVE_LIBCEC */ LiStartConnection(address, config, &connection_callbacks, decoder_callbacks, &audio_callbacks, NULL, NULL, 0, client_get_server_version()); - input_loop(); + loop_main(); LiStopConnection(); } @@ -172,6 +180,7 @@ int main(int argc, char* argv[]) { int option_index = 0; bool sops = true; bool localaudio = false; + bool autoadd = true; int c; while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:n", long_options, &option_index)) != -1) { switch (c) { @@ -205,7 +214,8 @@ int main(int argc, char* argv[]) { app = optarg; break; case 'j': - input_create(optarg, mapping); + evdev_create(optarg, mapping); + autoadd = false; break; case 'k': mapping = get_path(optarg); @@ -238,8 +248,8 @@ int main(int argc, char* argv[]) { perror("No filename for mapping"); exit(-1); } - input_init(mapping); - input_map(address); + udev_init(autoadd, mapping); + evdev_map(address); exit(0); } @@ -263,7 +273,7 @@ int main(int argc, char* argv[]) { pair_check(); applist(address); } else if (strcmp("stream", action) == 0) { - input_init(mapping); + udev_init(autoadd, mapping); pair_check(); stream(&config, address, app, sops, localaudio); } else if (strcmp("pair", action) == 0) From c18bd2d1949a9137ddc1175a3e5161d0da031683 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Thu, 23 Jul 2015 11:43:48 +0200 Subject: [PATCH 3/6] 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); } From ebd54bc5cc93ccf5ee415121e06d65da71024241 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Thu, 23 Jul 2015 12:09:41 +0200 Subject: [PATCH 4/6] Split libgamestream in libgamestream and libmoonlight-common --- CMakeLists.txt | 4 ++++ libgamestream/CMakeLists.txt | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 074ed68..6cb2f4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ project(moonlight-embedded C) cmake_minimum_required(VERSION 3.1) +set(MOONLIGHT_MAJOR_VERSION 0) +set(MOONLIGHT_MINOR_VERSION 1) +set(MOONLIGHT_PATCH_VERSION 0) +set(MOONLIGHT_VERSION ${MOONLIGHT_MAJOR_VERSION}.${MOONLIGHT_MINOR_VERSION}.${MOONLIGHT_PATCH_VERSION}) SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") diff --git a/libgamestream/CMakeLists.txt b/libgamestream/CMakeLists.txt index 46682ad..aa61ebb 100644 --- a/libgamestream/CMakeLists.txt +++ b/libgamestream/CMakeLists.txt @@ -7,14 +7,21 @@ pkg_check_modules(AVAHI REQUIRED avahi-client) aux_source_directory(./ GAMESTREAM_SRC_LIST) -aux_source_directory(../third_party/moonlight-common-c/limelight-common GAMESTREAM_SRC_LIST) -aux_source_directory(../third_party/moonlight-common-c/limelight-common/OpenAES GAMESTREAM_SRC_LIST) +aux_source_directory(../third_party/moonlight-common-c/limelight-common MOONLIGHT_COMMON_SRC_LIST) +aux_source_directory(../third_party/moonlight-common-c/limelight-common/OpenAES MOONLIGHT_COMMON_SRC_LIST) + +add_library(moonlight-common SHARED ${MOONLIGHT_COMMON_SRC_LIST}) add_library(gamestream SHARED ${GAMESTREAM_SRC_LIST}) set_property(TARGET gamestream PROPERTY C_STANDARD 11) -set_target_properties(gamestream PROPERTIES SOVERSION 0 VERSION 2.1.0) +target_link_libraries(gamestream LINK_PUBLIC moonlight-common) + +set_target_properties(gamestream PROPERTIES SOVERSION 0 VERSION ${MOONLIGHT_VERSION}) +set_target_properties(moonlight-common PROPERTIES SOVERSION 0 VERSION ${MOONLIGHT_VERSION}) target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c ${AVAHI_INCLUDE_DIRS}) -target_link_libraries (gamestream PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${CMAKE_DL_LIBS}) +target_link_libraries (gamestream PUBLIC ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES}) -#install(TARGETS gamestream DESTINATION ${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file +target_link_libraries (gamestream PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) + +install(TARGETS gamestream moonlight-common DESTINATION ${CMAKE_INSTALL_LIBDIR}) From 06265eddad24618d9f464c56887f5ab79a792815 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Thu, 23 Jul 2015 12:47:04 +0200 Subject: [PATCH 5/6] Specify directory to load certificate data from --- libgamestream/client.c | 62 ++++++++++++++++++++++++++++++------------ libgamestream/client.h | 2 +- libgamestream/http.c | 31 +++++++++++---------- libgamestream/http.h | 5 +++- src/main.c | 2 +- 5 files changed, 66 insertions(+), 36 deletions(-) diff --git a/libgamestream/client.c b/libgamestream/client.c index 6c3d569..0070806 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -36,10 +36,8 @@ #include #include -static const char *uniqueFileName = "uniqueid.dat"; -static const char *certificateFileName = "client.pem"; -static const char *p12FileName = "client.p12"; -static const char *keyFileName = "key.pem"; +#define UNIQUE_FILE_NAME "uniqueid.dat" +#define P12_FILE_NAME "client.p12" #define UNIQUEID_BYTES 8 #define UNIQUEID_CHARS (UNIQUEID_BYTES*2) @@ -49,42 +47,60 @@ static X509 *cert; static char cert_hex[4096]; static EVP_PKEY *privateKey; -static void load_unique_id() { - FILE *fd = fopen(uniqueFileName, "r"); +static int load_unique_id(const char* keyDirectory) { + char uniqueFilePath[4096]; + sprintf(uniqueFilePath, "%s/%s", keyDirectory, UNIQUE_FILE_NAME); + + FILE *fd = fopen(uniqueFilePath, "r"); if (fd == NULL) { unsigned char unique_data[UNIQUEID_BYTES]; RAND_bytes(unique_data, UNIQUEID_BYTES); for (int i = 0; i < UNIQUEID_BYTES; i++) { sprintf(unique_id + (i * 2), "%02x", unique_data[i]); } - fd = fopen(uniqueFileName, "w"); + fd = fopen(uniqueFilePath, "w"); + if (fd == NULL) + return GS_FAILED; + fwrite(unique_id, UNIQUEID_CHARS, 1, fd); } else { fread(unique_id, UNIQUEID_CHARS, 1, fd); } fclose(fd); unique_id[UNIQUEID_CHARS] = 0; + + return GS_OK; } -static void load_cert() { - FILE *fd = fopen(certificateFileName, "r"); +static int load_cert(const char* keyDirectory) { + char certificateFilePath[4096]; + sprintf(certificateFilePath, "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME); + + char keyFilePath[4096]; + sprintf(&keyFilePath[0], "%s/%s", keyDirectory, KEY_FILE_NAME); + + FILE *fd = fopen(certificateFilePath, "r"); if (fd == NULL) { printf("Generating certificate..."); CERT_KEY_PAIR cert = mkcert_generate(); printf("done\n"); - mkcert_save(certificateFileName, p12FileName, keyFileName, cert); + + char p12FilePath[4096]; + sprintf(p12FilePath, "%s/%s", keyDirectory, P12_FILE_NAME); + + mkcert_save(certificateFilePath, p12FilePath, keyFilePath, cert); mkcert_free(cert); - fd = fopen(certificateFileName, "r"); + fd = fopen(certificateFilePath, "r"); } if (fd == NULL) { fprintf(stderr, "Can't open certificate file\n"); - exit(-1); + return GS_FAILED; } if (!(cert = PEM_read_X509(fd, NULL, NULL, NULL))) { fprintf(stderr, "Error loading cert into memory.\n"); - exit(-1); + return GS_FAILED; } rewind(fd); @@ -99,9 +115,16 @@ static void load_cert() { fclose(fd); - fd = fopen(keyFileName, "r"); + fd = fopen(keyFilePath, "r"); + if (fd == NULL) { + fprintf(stderr, "Error loading key into memory.\n"); + return GS_FAILED; + } + PEM_read_PrivateKey(fd, &privateKey, NULL, NULL); fclose(fd); + + return GS_OK; } static int load_server_status(const char *address, PSERVER_DATA server) { @@ -419,10 +442,13 @@ int gs_quit_app(PSERVER_DATA server) { return ret; } -int gs_init(PSERVER_DATA server, const char *address) { - http_init(); - load_unique_id(); - load_cert(); +int gs_init(PSERVER_DATA server, const char *address, const char *keyDirectory) { + if (load_unique_id(keyDirectory) != GS_OK) + return GS_FAILED; + if (load_cert(keyDirectory)) + return GS_FAILED; + + http_init(keyDirectory); return load_server_status(address, server); } diff --git a/libgamestream/client.h b/libgamestream/client.h index 3cfaad6..f0b3064 100644 --- a/libgamestream/client.h +++ b/libgamestream/client.h @@ -32,7 +32,7 @@ typedef struct _SERVER_DATA { int serverMajorVersion; } SERVER_DATA, *PSERVER_DATA; -int gs_init(PSERVER_DATA server, const char *address); +int gs_init(PSERVER_DATA server, const char *address, const char *keyDirectory); 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); diff --git a/libgamestream/http.c b/libgamestream/http.c index 8cd5202..64c7fc3 100644 --- a/libgamestream/http.c +++ b/libgamestream/http.c @@ -34,10 +34,8 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *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"); + if(mem->memory == NULL) return 0; - } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; @@ -46,17 +44,23 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp return realsize; } -int http_init() { +int http_init(const char* keyDirectory) { curl = curl_easy_init(); if (curl) return GS_FAILED; - + + char certificateFilePath[4096]; + sprintf(certificateFilePath, "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME); + + char keyFilePath[4096]; + sprintf(&keyFilePath[0], "%s/%s", keyDirectory, KEY_FILE_NAME); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L); curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE,"PEM"); - curl_easy_setopt(curl, CURLOPT_SSLCERT, pCertFile); + curl_easy_setopt(curl, CURLOPT_SSLCERT, certificateFilePath); curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); - curl_easy_setopt(curl, CURLOPT_SSLKEY, pKeyFile); + curl_easy_setopt(curl, CURLOPT_SSLKEY, keyFilePath); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); @@ -71,16 +75,15 @@ int http_request(char* url, PHTTP_DATA data) { if (data->size > 0) { free(data->memory); data->memory = malloc(1); - if(data->memory == NULL) { - fprintf(stderr, "Not enough memory\n"); + if(data->memory == NULL) return GS_OUT_OF_MEMORY; - } + data->size = 0; } CURLcode res = curl_easy_perform(curl); if(res != CURLE_OK) { - fprintf(stderr, "Connection failed: %s\n", curl_easy_strerror(res)); + gs_error = curl_easy_strerror(res); return GS_FAILED; } else if (data->memory == NULL) { return GS_OUT_OF_MEMORY; @@ -95,13 +98,11 @@ void http_cleanup() { PHTTP_DATA http_create_data() { PHTTP_DATA data = malloc(sizeof(HTTP_DATA)); - if (data == NULL) { - fprintf(stderr, "Not enough memory\n"); + if (data == NULL) return NULL; - } + data->memory = malloc(1); if(data->memory == NULL) { - fprintf(stderr, "Not enough memory\n"); free(data); return NULL; } diff --git a/libgamestream/http.h b/libgamestream/http.h index b0355a1..be28344 100644 --- a/libgamestream/http.h +++ b/libgamestream/http.h @@ -21,12 +21,15 @@ #include +#define CERTIFICATE_FILE_NAME "client.pem" +#define KEY_FILE_NAME "key.pem" + typedef struct _HTTP_DATA { char *memory; size_t size; } HTTP_DATA, *PHTTP_DATA; -int http_init(); +int http_init(const char* keyDirectory); PHTTP_DATA http_create_data(); int http_request(char* url, PHTTP_DATA data); void http_free_data(PHTTP_DATA data); diff --git a/src/main.c b/src/main.c index 85e34d8..6ba1e73 100644 --- a/src/main.c +++ b/src/main.c @@ -289,7 +289,7 @@ int main(int argc, char* argv[]) { } PSERVER_DATA server; - if (gs_init(server, address) != GS_OK) { + if (gs_init(server, address, ".") != GS_OK) { fprintf(stderr, "Can't connect to server %s\n", address); exit(-1); } From 6c087f40dc9db2e85af1c721e3efce84b4ca6bf3 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Thu, 23 Jul 2015 13:06:47 +0200 Subject: [PATCH 6/6] Libgamestream doesn't print to console --- libgamestream/client.c | 62 +++++++++++----------------------------- libgamestream/discover.c | 14 +++++---- libgamestream/errors.h | 2 ++ libgamestream/mkcert.c | 3 -- libgamestream/xml.c | 12 +++----- src/main.c | 7 ++++- 6 files changed, 37 insertions(+), 63 deletions(-) diff --git a/libgamestream/client.c b/libgamestream/client.c index 0070806..f427c1a 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -47,6 +47,8 @@ static X509 *cert; static char cert_hex[4096]; static EVP_PKEY *privateKey; +const char* gs_error; + static int load_unique_id(const char* keyDirectory) { char uniqueFilePath[4096]; sprintf(uniqueFilePath, "%s/%s", keyDirectory, UNIQUE_FILE_NAME); @@ -94,12 +96,12 @@ static int load_cert(const char* keyDirectory) { } if (fd == NULL) { - fprintf(stderr, "Can't open certificate file\n"); + gs_error = "Can't open certificate file"; return GS_FAILED; } if (!(cert = PEM_read_X509(fd, NULL, NULL, NULL))) { - fprintf(stderr, "Error loading cert into memory.\n"); + gs_error = "Error loading cert into memory"; return GS_FAILED; } @@ -117,7 +119,7 @@ static int load_cert(const char* keyDirectory) { fd = fopen(keyFilePath, "r"); if (fd == NULL) { - fprintf(stderr, "Error loading key into memory.\n"); + gs_error = "Error loading key into memory"; return GS_FAILED; } @@ -194,66 +196,38 @@ static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *sl *slen = 0; EVP_MD_CTX *ctx = EVP_MD_CTX_create(); - if (ctx == NULL) { - fprintf(stderr, "EVP_MD_CTX_create failed, error 0x%lx\n", ERR_get_error()); - return -1; - } + if (ctx == NULL) + return GS_FAILED; const EVP_MD *md = EVP_get_digestbyname("SHA256"); - if (md == NULL) { - fprintf(stderr, "EVP_get_digestbyname failed, error 0x%lx\n", ERR_get_error()); + if (md == NULL) goto cleanup; - } int rc = EVP_DigestInit_ex(ctx, md, NULL); - if (rc != 1) { - fprintf(stderr, "EVP_DigestInit_ex failed, error 0x%lx\n", ERR_get_error()); + if (rc != 1) goto cleanup; - } rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey); - if (rc != 1) { - fprintf(stderr, "EVP_DigestSignInit failed, error 0x%lx\n", ERR_get_error()); + if (rc != 1) goto cleanup; - } rc = EVP_DigestSignUpdate(ctx, msg, mlen); - if (rc != 1) { - fprintf(stderr, "EVP_DigestSignUpdate failed, error 0x%lx\n", ERR_get_error()); + if (rc != 1) goto cleanup; - } size_t req = 0; rc = EVP_DigestSignFinal(ctx, NULL, &req); - if (rc != 1) { - fprintf(stderr, "EVP_DigestSignFinal failed (1), error 0x%lx\n", ERR_get_error()); + if (rc != 1 || !(req > 0)) goto cleanup; - } - - if (!(req > 0)) { - fprintf(stderr, "EVP_DigestSignFinal failed (2), error 0x%lx\n", ERR_get_error()); - goto cleanup; - } *sig = OPENSSL_malloc(req); - if (*sig == NULL) { - fprintf(stderr, "OPENSSL_malloc failed, error 0x%lx\n", ERR_get_error()); + if (*sig == NULL) goto cleanup; - } *slen = req; rc = EVP_DigestSignFinal(ctx, *sig, slen); - if (rc != 1) { - fprintf(stderr, "EVP_DigestSignFinal failed (3), return code %d, error 0x%lx\n", rc, - ERR_get_error()); + if (rc != 1 || req != *slen) goto cleanup; - } - - if (req != *slen) { - fprintf(stderr, "EVP_DigestSignFinal failed, mismatched signature sizes %ld, %ld\n", - req, *slen); - goto cleanup; - } result = GS_OK; @@ -269,17 +243,15 @@ int gs_pair(PSERVER_DATA server, char* pin) { char url[4096]; if (server->paired) { - fprintf(stderr, "Already paired\n"); + gs_error = "Already paired"; return GS_WRONG_STATE; } if (server->currentGame != 0) { - fprintf(stderr, "The computer is currently in a game. You must close the game before pairing.\n"); + gs_error = "The computer is currently in a game. You must close the game before pairing"; return GS_WRONG_STATE; } - printf("Please enter the following PIN on the target PC: %s\n", pin); - unsigned char salt_data[16]; char salt_hex[33]; RAND_bytes(salt_data, 16); @@ -357,7 +329,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { unsigned char *signature = NULL; size_t s_len; if (sign_it(client_secret_data, 16, &signature, &s_len, privateKey) != GS_OK) { - fprintf(stderr, "Failed to sign data\n"); + gs_error = "Failed to sign data"; ret = GS_FAILED; goto cleanup; } diff --git a/libgamestream/discover.c b/libgamestream/discover.c index 4550d4e..89d59c0 100644 --- a/libgamestream/discover.c +++ b/libgamestream/discover.c @@ -17,6 +17,8 @@ * along with Moonlight; if not, see . */ +#include "errors.h" + #include #include @@ -33,7 +35,7 @@ static AvahiSimplePoll *simple_poll = NULL; 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))); + gs_error = "Server connection failure"; avahi_simple_poll_quit(simple_poll); } } @@ -58,12 +60,12 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah switch (event) { case AVAHI_BROWSER_FAILURE: - fprintf(stderr, "(Discover) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b)))); + gs_error = "Server browser failure"; 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, resolve_callback, userdata))) - fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c))); + gs_error = "Failed to resolve service"; break; case AVAHI_BROWSER_REMOVE: @@ -76,19 +78,19 @@ void gs_discover_server(char* dest) { AvahiServiceBrowser *sb = NULL; if (!(simple_poll = avahi_simple_poll_new())) { - fprintf(stderr, "Failed to create simple poll object.\n"); + gs_error = "Failed to create simple poll object"; goto cleanup; } int 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)); + gs_error = "Failed to create client"; goto cleanup; } 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))); + gs_error = "Failed to create service browser"; goto cleanup; } diff --git a/libgamestream/errors.h b/libgamestream/errors.h index 2e428f9..a68510c 100644 --- a/libgamestream/errors.h +++ b/libgamestream/errors.h @@ -25,3 +25,5 @@ #define GS_INVALID -3 #define GS_WRONG_STATE -4 #define GS_IO_ERROR -5 + +const char* gs_error; diff --git a/libgamestream/mkcert.c b/libgamestream/mkcert.c index c8e0369..0b95a84 100644 --- a/libgamestream/mkcert.c +++ b/libgamestream/mkcert.c @@ -48,9 +48,6 @@ CERT_KEY_PAIR mkcert_generate() { mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS); p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0); - if (p12 == NULL) { - fprintf(stderr, "Error generating a valid PKCS12 certificate.\n"); - } #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); diff --git a/libgamestream/xml.c b/libgamestream/xml.c index 8842e86..3f4ea7f 100644 --- a/libgamestream/xml.c +++ b/libgamestream/xml.c @@ -46,10 +46,8 @@ static void XMLCALL _xml_start_applist_element(void *userData, const char *name, struct xml_query *search = (struct xml_query*) userData; if (strcmp("App", name) == 0) { PAPP_LIST app = malloc(sizeof(APP_LIST)); - if (app == NULL) { - fprintf(stderr, "Not enough memory\n"); + if (app == NULL) return; - } app->next = (PAPP_LIST) search->data; search->data = app; @@ -81,10 +79,8 @@ 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 = realloc(search->memory, search->size + len + 1); - if(search->memory == NULL) { - fprintf(stderr, "Not enough memory\n"); + if(search->memory == NULL) return; - } memcpy(&(search->memory[search->size]), s, len); search->size += len; @@ -104,7 +100,7 @@ int xml_search(char* data, size_t len, char* node, char** result) { XML_SetCharacterDataHandler(parser, _xml_write_data); if (! XML_Parse(parser, data, len, 1)) { int code = XML_GetErrorCode(parser); - fprintf(stderr, "XML Error: %s\n", XML_ErrorString(code)); + gs_error = XML_ErrorString(code); free(search.memory); return GS_INVALID; } else if (search.memory == NULL) @@ -127,7 +123,7 @@ int xml_applist(char* data, size_t len, PAPP_LIST app_list) { XML_SetCharacterDataHandler(parser, _xml_write_data); if (! XML_Parse(parser, data, len, 1)) { int code = XML_GetErrorCode(parser); - fprintf(stderr, "XML Error %s\n", XML_ErrorString(code)); + gs_error = XML_ErrorString(code); return GS_INVALID; } app_list = (PAPP_LIST) query.data; diff --git a/src/main.c b/src/main.c index 6ba1e73..34abd9e 100644 --- a/src/main.c +++ b/src/main.c @@ -304,7 +304,12 @@ int main(int argc, char* argv[]) { } 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]); + printf("Please enter the following PIN on the target PC: %s\n", pin); + if (gs_pair(server, &pin[0]) != GS_OK) { + fprintf("Failed to pair to server: %s\n", gs_error); + } else { + printf("Succesfully paired\n"); + } } else if (strcmp("quit", action) == 0) { pair_check(server); gs_quit_app(server);