123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- #ifndef CLIENT_GAMEMODE_H
- #define CLIENT_GAMEMODE_H
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <dlfcn.h>
- #include <errno.h>
- #include <string.h>
- static char internal_gamemode_client_error_string[512] = { 0 };
- static volatile int internal_libgamemode_loaded = 1;
- typedef int (*internal_gamemode_request_start)(void);
- typedef int (*internal_gamemode_request_end)(void);
- typedef int (*internal_gamemode_query_status)(void);
- typedef const char *(*internal_gamemode_error_string)(void);
- static internal_gamemode_request_start REAL_internal_gamemode_request_start = NULL;
- static internal_gamemode_request_end REAL_internal_gamemode_request_end = NULL;
- static internal_gamemode_query_status REAL_internal_gamemode_query_status = NULL;
- static internal_gamemode_error_string REAL_internal_gamemode_error_string = NULL;
- __attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol(void *handle,
- const char *name,
- void **out_func,
- size_t func_size)
- {
- void *symbol_lookup = NULL;
- char *dl_error = NULL;
-
- symbol_lookup = dlsym(handle, name);
- dl_error = dlerror();
- if (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 },
- };
- void *libgamemode = NULL;
-
- libgamemode = dlopen("libgamemode.so", RTLD_NOW);
- if (!libgamemode) {
- snprintf(internal_gamemode_client_error_string,
- sizeof(internal_gamemode_client_error_string),
- "dylopen 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) != 0 &&
- 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;
- }
- 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;
- }
- 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;
- }
- 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();
- }
- #endif
|