| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifndef CLIENT_GAMEMODE_H |
| | #define CLIENT_GAMEMODE_H |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <stdbool.h> |
| | #include <stdio.h> |
| |
|
| | #include <dlfcn.h> |
| | #include <string.h> |
| |
|
| | #include <assert.h> |
| |
|
| | #include <sys/types.h> |
| |
|
| | static char internal_gamemode_client_error_string[512] = { 0 }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static volatile int internal_libgamemode_loaded = 1; |
| |
|
| | |
| | typedef int (*api_call_return_int)(void); |
| | typedef const char *(*api_call_return_cstring)(void); |
| | typedef int (*api_call_pid_return_int)(pid_t); |
| |
|
| | |
| | static api_call_return_int REAL_internal_gamemode_request_start = NULL; |
| | static api_call_return_int REAL_internal_gamemode_request_end = NULL; |
| | static api_call_return_int REAL_internal_gamemode_query_status = NULL; |
| | static api_call_return_cstring REAL_internal_gamemode_error_string = NULL; |
| | static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL; |
| | static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL; |
| | static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | __attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol( |
| | void *handle, const char *name, void **out_func, size_t func_size, bool required) |
| | { |
| | void *symbol_lookup = NULL; |
| | char *dl_error = NULL; |
| |
|
| | |
| | symbol_lookup = dlsym(handle, name); |
| | dl_error = dlerror(); |
| | if (required && (dl_error || !symbol_lookup)) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "dlsym failed - %s", |
| | dl_error); |
| | return -1; |
| | } |
| |
|
| | |
| | memcpy(out_func, &symbol_lookup, func_size); |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | __attribute__((always_inline)) static inline int internal_load_libgamemode(void) |
| | { |
| | |
| | if (internal_libgamemode_loaded != 1) { |
| | return internal_libgamemode_loaded; |
| | } |
| |
|
| | |
| | struct binding { |
| | const char *name; |
| | void **functor; |
| | size_t func_size; |
| | bool required; |
| | } bindings[] = { |
| | { "real_gamemode_request_start", |
| | (void **)&REAL_internal_gamemode_request_start, |
| | sizeof(REAL_internal_gamemode_request_start), |
| | true }, |
| | { "real_gamemode_request_end", |
| | (void **)&REAL_internal_gamemode_request_end, |
| | sizeof(REAL_internal_gamemode_request_end), |
| | true }, |
| | { "real_gamemode_query_status", |
| | (void **)&REAL_internal_gamemode_query_status, |
| | sizeof(REAL_internal_gamemode_query_status), |
| | false }, |
| | { "real_gamemode_error_string", |
| | (void **)&REAL_internal_gamemode_error_string, |
| | sizeof(REAL_internal_gamemode_error_string), |
| | true }, |
| | { "real_gamemode_request_start_for", |
| | (void **)&REAL_internal_gamemode_request_start_for, |
| | sizeof(REAL_internal_gamemode_request_start_for), |
| | false }, |
| | { "real_gamemode_request_end_for", |
| | (void **)&REAL_internal_gamemode_request_end_for, |
| | sizeof(REAL_internal_gamemode_request_end_for), |
| | false }, |
| | { "real_gamemode_query_status_for", |
| | (void **)&REAL_internal_gamemode_query_status_for, |
| | sizeof(REAL_internal_gamemode_query_status_for), |
| | false }, |
| | }; |
| |
|
| | void *libgamemode = NULL; |
| |
|
| | |
| | libgamemode = dlopen("libgamemode.so.0", RTLD_NOW); |
| | if (!libgamemode) { |
| | |
| | |
| | |
| | libgamemode = dlopen("libgamemode.so", RTLD_NOW); |
| | if (!libgamemode) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "dlopen failed - %s", |
| | dlerror()); |
| | internal_libgamemode_loaded = -1; |
| | return -1; |
| | } |
| | } |
| |
|
| | |
| | for (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) { |
| | struct binding *binder = &bindings[i]; |
| |
|
| | if (internal_bind_libgamemode_symbol(libgamemode, |
| | binder->name, |
| | binder->functor, |
| | binder->func_size, |
| | binder->required)) { |
| | internal_libgamemode_loaded = -1; |
| | return -1; |
| | }; |
| | } |
| |
|
| | |
| | internal_libgamemode_loaded = 0; |
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | __attribute__((always_inline)) static inline const char *gamemode_error_string(void) |
| | { |
| | |
| | |
| | if (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\0') { |
| | return internal_gamemode_client_error_string; |
| | } |
| |
|
| | |
| | assert(REAL_internal_gamemode_error_string != NULL); |
| |
|
| | return REAL_internal_gamemode_error_string(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #ifdef GAMEMODE_AUTO |
| | __attribute__((constructor)) |
| | #else |
| | __attribute__((always_inline)) static inline |
| | #endif |
| | int gamemode_request_start(void) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | #ifdef GAMEMODE_AUTO |
| | fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); |
| | #endif |
| | return -1; |
| | } |
| |
|
| | |
| | assert(REAL_internal_gamemode_request_start != NULL); |
| |
|
| | if (REAL_internal_gamemode_request_start() < 0) { |
| | #ifdef GAMEMODE_AUTO |
| | fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); |
| | #endif |
| | return -1; |
| | } |
| |
|
| | return 0; |
| | } |
| |
|
| | |
| | #ifdef GAMEMODE_AUTO |
| | __attribute__((destructor)) |
| | #else |
| | __attribute__((always_inline)) static inline |
| | #endif |
| | int gamemode_request_end(void) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | #ifdef GAMEMODE_AUTO |
| | fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); |
| | #endif |
| | return -1; |
| | } |
| |
|
| | |
| | assert(REAL_internal_gamemode_request_end != NULL); |
| |
|
| | if (REAL_internal_gamemode_request_end() < 0) { |
| | #ifdef GAMEMODE_AUTO |
| | fprintf(stderr, "gamemodeauto: %s\n", gamemode_error_string()); |
| | #endif |
| | return -1; |
| | } |
| |
|
| | return 0; |
| | } |
| |
|
| | |
| | __attribute__((always_inline)) static inline int gamemode_query_status(void) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | return -1; |
| | } |
| |
|
| | if (REAL_internal_gamemode_query_status == NULL) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "gamemode_query_status missing (older host?)"); |
| | return -1; |
| | } |
| |
|
| | return REAL_internal_gamemode_query_status(); |
| | } |
| |
|
| | |
| | __attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | return -1; |
| | } |
| |
|
| | if (REAL_internal_gamemode_request_start_for == NULL) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "gamemode_request_start_for missing (older host?)"); |
| | return -1; |
| | } |
| |
|
| | return REAL_internal_gamemode_request_start_for(pid); |
| | } |
| |
|
| | |
| | __attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | return -1; |
| | } |
| |
|
| | if (REAL_internal_gamemode_request_end_for == NULL) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "gamemode_request_end_for missing (older host?)"); |
| | return -1; |
| | } |
| |
|
| | return REAL_internal_gamemode_request_end_for(pid); |
| | } |
| |
|
| | |
| | __attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid) |
| | { |
| | |
| | if (internal_load_libgamemode() < 0) { |
| | return -1; |
| | } |
| |
|
| | if (REAL_internal_gamemode_query_status_for == NULL) { |
| | snprintf(internal_gamemode_client_error_string, |
| | sizeof(internal_gamemode_client_error_string), |
| | "gamemode_query_status_for missing (older host?)"); |
| | return -1; |
| | } |
| |
|
| | return REAL_internal_gamemode_query_status_for(pid); |
| | } |
| |
|
| | #endif |
| |
|