Game server now reads configuration settings from web server.
This commit is contained in:
parent
6e1e458613
commit
597284e28f
13 changed files with 343 additions and 159 deletions
16
LICENSE
16
LICENSE
|
@ -95,11 +95,26 @@ ENet
|
||||||
https://github.com/zpl-c/enet
|
https://github.com/zpl-c/enet
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
GnuTLS
|
||||||
|
------
|
||||||
|
https://gnutls.org/
|
||||||
|
LGPL 2.1
|
||||||
|
|
||||||
ini
|
ini
|
||||||
---
|
---
|
||||||
https://github.com/rxi/ini
|
https://github.com/rxi/ini
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
json-c
|
||||||
|
------
|
||||||
|
https://github.com/json-c/json-c
|
||||||
|
Attribution
|
||||||
|
|
||||||
|
MariaDB Client Library
|
||||||
|
----------------------
|
||||||
|
https://mariadb.org/
|
||||||
|
LGPL 2.1
|
||||||
|
|
||||||
MemWatch
|
MemWatch
|
||||||
--------
|
--------
|
||||||
http://www.linkdata.se/sourcecode/memwatch/
|
http://www.linkdata.se/sourcecode/memwatch/
|
||||||
|
@ -119,3 +134,4 @@ tiny-AES128-C
|
||||||
-------------
|
-------------
|
||||||
https://github.com/bonybrown/tiny-AES128-C
|
https://github.com/bonybrown/tiny-AES128-C
|
||||||
Unlicense
|
Unlicense
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require __DIR__ . '/user.php';
|
require __DIR__ . '/api/config.php';
|
||||||
|
require __DIR__ . '/api/user.php';
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -21,6 +22,10 @@ return [
|
||||||
|
|
||||||
switch (get('command')) {
|
switch (get('command')) {
|
||||||
|
|
||||||
|
case 'CONFIG_GET_CONFIG':
|
||||||
|
kpApiConfigGetConfig($response);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'USER_CREATE':
|
case 'USER_CREATE':
|
||||||
kpApiUserCreate(get('name'), get('email'), get('password'), $response);
|
kpApiUserCreate(get('name'), get('email'), get('password'), $response);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function kpApiConfigGetConfig(&$response) {
|
||||||
|
$response['config'] = collection('kwconfig')->filterBy('type', 'config');
|
||||||
|
$response['result'] = 'true';
|
||||||
|
$response['reason'] = 'Configuration entries returned.';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -1,8 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
load(['KangarooPunch\KwConfig' => __DIR__ . '/classes/KwConfig.php']);
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'kwconfig' => [
|
'kwconfig' => [
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use KangarooPunch\KwConfig;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'kwconfig' => function($site) {
|
||||||
|
return new Collection(KwConfig::list());
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
?>
|
|
@ -1,9 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
load([
|
||||||
|
'KangarooPunch\KwConfig' => __DIR__ . '/classes/KwConfig.php'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
Kirby::plugin('kangaroopunch/kangaworld-integration', [
|
Kirby::plugin('kangaroopunch/kangaworld-integration', [
|
||||||
|
|
||||||
'api' => require __DIR__ . '/api.php',
|
'api' => require __DIR__ . '/api.php',
|
||||||
'areas' => require __DIR__ . '/areas.php'
|
'areas' => require __DIR__ . '/areas.php',
|
||||||
|
'collections' => require __DIR__ . '/collections.php'
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ TEMPLATE = subdirs
|
||||||
CONFIG *= ORDERED
|
CONFIG *= ORDERED
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
client \
|
# client \
|
||||||
server
|
server
|
||||||
# font \
|
# font \
|
||||||
# primes
|
# primes
|
||||||
|
|
|
@ -51,9 +51,9 @@ HEADERS = \
|
||||||
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \
|
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \
|
||||||
src/client.h \
|
src/client.h \
|
||||||
src/console.h \
|
src/console.h \
|
||||||
src/database.h \
|
|
||||||
src/network.h \
|
src/network.h \
|
||||||
src/os.h \
|
src/os.h \
|
||||||
|
src/rest.h \
|
||||||
src/server.h
|
src/server.h
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
|
@ -68,18 +68,19 @@ SOURCES = \
|
||||||
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
|
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
|
||||||
src/client.c \
|
src/client.c \
|
||||||
src/console.c \
|
src/console.c \
|
||||||
src/database.c \
|
|
||||||
src/main.c \
|
src/main.c \
|
||||||
src/network.c \
|
src/network.c \
|
||||||
|
src/rest.c \
|
||||||
src/server.c
|
src/server.c
|
||||||
|
|
||||||
LIBS = \
|
LIBS = \
|
||||||
-L/usr/lib/x86_64-linux-gnu/ \
|
-L/usr/lib/x86_64-linux-gnu/ \
|
||||||
-lmariadb \
|
|
||||||
-ldl \
|
-ldl \
|
||||||
-lm \
|
-lm \
|
||||||
-lpthread \
|
-lpthread \
|
||||||
-lgnutls \
|
-lgnutls \
|
||||||
-lcrypt
|
-lcrypt \
|
||||||
|
-lcurl \
|
||||||
|
-ljson-c
|
||||||
|
|
||||||
OTHER_FILES =
|
OTHER_FILES =
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* Kangaroo Punch MultiPlayer Game Server Mark II
|
|
||||||
* Copyright (C) 2020-2021 Scott Duensing
|
|
||||||
*
|
|
||||||
* This program 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.
|
|
||||||
*
|
|
||||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <mysql.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include "database.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define STATEMENT_MAX 2048
|
|
||||||
|
|
||||||
|
|
||||||
static MYSQL *_sql = NULL;
|
|
||||||
static char _statement[STATEMENT_MAX];
|
|
||||||
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *password) {
|
|
||||||
uint8_t reconnect = 1;
|
|
||||||
|
|
||||||
if (_sql == NULL) {
|
|
||||||
_sql = mysql_init(NULL);
|
|
||||||
mysql_options(_sql, MYSQL_OPT_RECONNECT, (const void *)&reconnect);
|
|
||||||
if (mysql_real_connect(_sql, host, user, password, database, port, NULL, 0) == NULL) {
|
|
||||||
logWrite("dbConnect: %s\n", mysql_error(_sql));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
if (pthread_mutex_init(&_mutex, NULL)) {
|
|
||||||
logWrite("dbConnect: SQL mutex creation failed.\n");
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbDisconnect(void) {
|
|
||||||
if (_sql) {
|
|
||||||
mysql_close(_sql);
|
|
||||||
_sql = NULL;
|
|
||||||
pthread_mutex_destroy(&_mutex);
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbSettingsValueGet(char *key, int32_t *value) {
|
|
||||||
char *p = _statement;
|
|
||||||
MYSQL_RES *result = NULL;
|
|
||||||
MYSQL_ROW row;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&_mutex);
|
|
||||||
|
|
||||||
if (!_sql) {
|
|
||||||
pthread_mutex_unlock(&_mutex);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
p += sprintf(p, "SELECT data FROM config where NAME='");
|
|
||||||
p += mysql_real_escape_string(_sql, p, key, strlen(key));
|
|
||||||
p += sprintf(p, "'");
|
|
||||||
if (mysql_real_query(_sql, _statement, p - _statement) != 0) {
|
|
||||||
logWrite("dbConfigValueGet: %s\n", mysql_error(_sql));
|
|
||||||
pthread_mutex_unlock(&_mutex);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = mysql_store_result(_sql);
|
|
||||||
count = mysql_num_rows(result);
|
|
||||||
if (count != 1) {
|
|
||||||
logWrite("dbConfigValueGet: Too many rows returned: %d.\n", count);
|
|
||||||
mysql_free_result(result);
|
|
||||||
pthread_mutex_unlock(&_mutex);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((row = mysql_fetch_row(result)) == NULL) {
|
|
||||||
logWrite("dbConfigValueGet: %s\n", mysql_error(_sql));
|
|
||||||
pthread_mutex_unlock(&_mutex);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*value = atoi(row[0]);
|
|
||||||
|
|
||||||
mysql_free_result(result);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&_mutex);
|
|
||||||
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
|
@ -20,9 +20,9 @@
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "database.h"
|
|
||||||
#include "stddclmr.h"
|
#include "stddclmr.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#include "rest.h"
|
||||||
|
|
||||||
#include "thirdparty/ini/src/ini.h"
|
#include "thirdparty/ini/src/ini.h"
|
||||||
|
|
||||||
|
@ -32,11 +32,9 @@ uint8_t _running = 1; // Exported in os.h
|
||||||
|
|
||||||
// "Config" items come from the INI file. "Settings" are from the database.
|
// "Config" items come from the INI file. "Settings" are from the database.
|
||||||
|
|
||||||
static char *_configServer = NULL;
|
|
||||||
static uint16_t _configPort = 0;
|
|
||||||
static char *_configDatabase = NULL;
|
|
||||||
static char *_configUser = NULL;
|
static char *_configUser = NULL;
|
||||||
static char *_configPassword = NULL;
|
static char *_configPassword = NULL;
|
||||||
|
static char *_configREST = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void configRead(char *file);
|
static void configRead(char *file);
|
||||||
|
@ -46,24 +44,18 @@ static void configWrite(char *file);
|
||||||
static void configRead(char *file) {
|
static void configRead(char *file) {
|
||||||
ini_t *ini = NULL;
|
ini_t *ini = NULL;
|
||||||
|
|
||||||
// Numeric defaults.
|
|
||||||
_configPort = 16550;
|
|
||||||
|
|
||||||
ini = ini_load(file);
|
ini = ini_load(file);
|
||||||
if (ini) {
|
if (ini) {
|
||||||
ini_sget(ini, "SERVER", "PORT", "%d", &_configPort);
|
|
||||||
_configServer = strdup(ini_get(ini, "SERVER", "HOST"));
|
|
||||||
_configDatabase = strdup(ini_get(ini, "SERVER", "DATA"));
|
|
||||||
_configUser = strdup(ini_get(ini, "SERVER", "USER"));
|
_configUser = strdup(ini_get(ini, "SERVER", "USER"));
|
||||||
_configPassword = strdup(ini_get(ini, "SERVER", "PASS"));
|
_configPassword = strdup(ini_get(ini, "SERVER", "PASS"));
|
||||||
|
_configREST = strdup(ini_get(ini, "SERVER", "REST"));
|
||||||
ini_free(ini);
|
ini_free(ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
// String defaults.
|
// String defaults.
|
||||||
if (!_configServer) strdup("kanga.world");
|
|
||||||
if (!_configDatabase) strdup("kpmpgsmkii");
|
|
||||||
if (!_configUser) strdup("");
|
if (!_configUser) strdup("");
|
||||||
if (!_configPassword) strdup("");
|
if (!_configPassword) strdup("");
|
||||||
|
if (!_configREST) strdup("http://localhost:8000/api/kp/kangaworld/v1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,22 +66,17 @@ static void configWrite(char *file) {
|
||||||
if (out) {
|
if (out) {
|
||||||
fprintf(out,
|
fprintf(out,
|
||||||
"[SERVER]\n"
|
"[SERVER]\n"
|
||||||
"HOST=%s\n"
|
"REST=%s\n"
|
||||||
"PORT=%d\n"
|
|
||||||
"DATA=%s\n"
|
|
||||||
"USER=%s\n"
|
"USER=%s\n"
|
||||||
"PASS=%s\n",
|
"PASS=%s\n",
|
||||||
_configServer,
|
_configREST,
|
||||||
_configPort,
|
|
||||||
_configDatabase,
|
|
||||||
_configUser,
|
_configUser,
|
||||||
_configPassword
|
_configPassword
|
||||||
);
|
);
|
||||||
fclose(out);
|
fclose(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEL(_configServer);
|
DEL(_configREST);
|
||||||
DEL(_configDatabase);
|
|
||||||
DEL(_configUser);
|
DEL(_configUser);
|
||||||
DEL(_configPassword);
|
DEL(_configPassword);
|
||||||
}
|
}
|
||||||
|
@ -98,9 +85,10 @@ static void configWrite(char *file) {
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
char *configFile = NULL;
|
char *configFile = NULL;
|
||||||
uint32_t settingsMaxClients = 0;
|
int64_t settingsMaxClients = 0;
|
||||||
uint32_t settingsPortNumber = 0;
|
int64_t settingsPortNumber = 0;
|
||||||
uint32_t settingsClientVersion = 0;
|
int64_t settingsClientVersion = 0;
|
||||||
|
json_object *response = NULL;
|
||||||
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
|
|
||||||
|
@ -111,14 +99,15 @@ int main(int argc, char *argv[]) {
|
||||||
configFile = utilAppNameWithNewExtensionGet(argv[0], "ini");
|
configFile = utilAppNameWithNewExtensionGet(argv[0], "ini");
|
||||||
configRead(configFile);
|
configRead(configFile);
|
||||||
|
|
||||||
if (!dbConnect(_configServer, _configPort, _configDatabase, _configUser, _configPassword)) {
|
if (!restStartup(_configREST, _configUser, _configPassword)) {
|
||||||
utilDie("Unable to connect to database.\n");
|
utilDie("Unable to start REST.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch settings needed to start server.
|
response = restRequest("CONFIG_GET_CONFIG", NULL);
|
||||||
if (!dbSettingsValueGet("maxClients", (int32_t *)&settingsMaxClients)) utilDie("Unable to load maxClients.\n");
|
settingsMaxClients = restHelperConfigIntegerGet(response, "maxClients", 2);
|
||||||
if (!dbSettingsValueGet("portNumber", (int32_t *)&settingsPortNumber)) utilDie("Unable to load portNumber.\n");
|
settingsPortNumber = restHelperConfigIntegerGet(response, "portNumber", 16550);
|
||||||
if (!dbSettingsValueGet("clientVersion", (int32_t *)&settingsClientVersion)) utilDie("Unable to load clientVersion.\n");
|
settingsClientVersion = restHelperConfigIntegerGet(response, "clientVersion", 1);
|
||||||
|
restRelease(response);
|
||||||
|
|
||||||
serverStartup(settingsPortNumber, settingsMaxClients);
|
serverStartup(settingsPortNumber, settingsMaxClients);
|
||||||
logWrite("Server online.\n");
|
logWrite("Server online.\n");
|
||||||
|
@ -134,7 +123,7 @@ int main(int argc, char *argv[]) {
|
||||||
serverShutdown();
|
serverShutdown();
|
||||||
|
|
||||||
// Shut down.
|
// Shut down.
|
||||||
dbDisconnect();
|
restShutdown();
|
||||||
configWrite(configFile);
|
configWrite(configFile);
|
||||||
DEL(configFile);
|
DEL(configFile);
|
||||||
logWrite("Shutdown complete.\n");
|
logWrite("Shutdown complete.\n");
|
||||||
|
|
259
server/src/rest.c
Normal file
259
server/src/rest.c
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
/*
|
||||||
|
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||||
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
#include "rest.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct RestResponseS {
|
||||||
|
uint64_t length;
|
||||||
|
char *data;
|
||||||
|
} RestResponseT;
|
||||||
|
|
||||||
|
|
||||||
|
static char *_restURL = NULL;
|
||||||
|
static char *_restUser = NULL;
|
||||||
|
static char *_restPass = NULL;
|
||||||
|
static pthread_mutex_t *_restMutexBuffer = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void restMutexLocker(int mode, int n, const char *file, int line);
|
||||||
|
static size_t restResponseWrite(void *ptr, size_t size, size_t nmemb, RestResponseT *s);
|
||||||
|
static unsigned long restThreadtIdGet(void);
|
||||||
|
static json_object *restUrlPost(json_object *request);
|
||||||
|
|
||||||
|
|
||||||
|
int64_t restHelperConfigIntegerGet(json_object *object, char *name, int64_t defaultValue) {
|
||||||
|
uint64_t i = 0;
|
||||||
|
json_object *config = NULL;
|
||||||
|
json_object *data = NULL;
|
||||||
|
json_object *item = NULL;
|
||||||
|
int64_t result = defaultValue;
|
||||||
|
|
||||||
|
config = json_object_object_get(object, "config");
|
||||||
|
//logWrite("Config: %d %s\n", json_object_get_type(config), json_object_to_json_string_ext(config, JSON_C_TO_STRING_PRETTY));
|
||||||
|
if (config) {
|
||||||
|
data = json_object_object_get(config, "data");
|
||||||
|
//logWrite("Data: %d %s\n", json_object_get_type(data), json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY));
|
||||||
|
if (data) {
|
||||||
|
for (i=0; i<json_object_array_length(data); i++) {
|
||||||
|
item = json_object_array_get_idx(data, i);
|
||||||
|
if (strcmp(name, json_object_get_string(json_object_object_get(item, "name"))) == 0) {
|
||||||
|
result = atol(json_object_get_string(json_object_object_get(item, "data")));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function" // It's used, but the compiler isn't picking it up because it's via a callback.
|
||||||
|
static void restMutexLocker(int mode, int n, const char *file, int line) {
|
||||||
|
(void)file;
|
||||||
|
(void)line;
|
||||||
|
|
||||||
|
if (mode & CRYPTO_LOCK) {
|
||||||
|
pthread_mutex_lock(&_restMutexBuffer[n]);
|
||||||
|
} else {
|
||||||
|
pthread_mutex_unlock(&_restMutexBuffer[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
|
void restRelease(json_object *object) {
|
||||||
|
json_object_put(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
json_object *restRequest(char *command, char *format, ...) {
|
||||||
|
va_list args = { 0 };
|
||||||
|
json_object *request = json_object_new_object();
|
||||||
|
json_object *response = NULL;
|
||||||
|
|
||||||
|
json_object_object_add(request, "command", json_object_new_string(command));
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
if (format) {
|
||||||
|
while (*format != 0) {
|
||||||
|
switch (*format) {
|
||||||
|
case 's':
|
||||||
|
json_object_object_add(request, va_arg(args, char *), json_object_new_string(va_arg(args, char *)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
json_object_object_add(request, va_arg(args, char *), json_object_new_int64(va_arg(args, int64_t)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
utilDie("restRequest: Unknown format option '%c'.\n", *format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
//logWrite("Request: %s\n", json_object_to_json_string_ext(request, JSON_C_TO_STRING_PRETTY));
|
||||||
|
response = restUrlPost(request);
|
||||||
|
json_object_put(request);
|
||||||
|
//logWrite("Response: %s\n", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY));
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
if (json_object_get_boolean(json_object_object_get(response, "result")) != TRUE) {
|
||||||
|
logWrite("restRequest: %s\n", json_object_get_string(json_object_object_get(response, "reason")));
|
||||||
|
json_object_put(response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logWrite("restRequest: No response.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static size_t restResponseWrite(void *ptr, size_t size, size_t nmemb, RestResponseT *s) {
|
||||||
|
size_t newLength = s->length + size * nmemb;
|
||||||
|
|
||||||
|
s->data = realloc(s->data, newLength + 1);
|
||||||
|
if (s->data == NULL) {
|
||||||
|
utilDie("restResponseWrite: realloc() failed.\n");
|
||||||
|
}
|
||||||
|
memcpy(s->data + s->length, ptr, size*nmemb);
|
||||||
|
s->data[newLength] = 0;
|
||||||
|
s->length = newLength;
|
||||||
|
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void restShutdown(void) {
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
DEL(_restPass);
|
||||||
|
DEL(_restUser);
|
||||||
|
DEL(_restURL);
|
||||||
|
|
||||||
|
if (_restMutexBuffer) {
|
||||||
|
CRYPTO_set_id_callback(NULL);
|
||||||
|
CRYPTO_set_locking_callback(NULL);
|
||||||
|
for (i=0; i<CRYPTO_num_locks(); i++) {
|
||||||
|
pthread_mutex_destroy(&_restMutexBuffer[i]);
|
||||||
|
}
|
||||||
|
DEL(_restMutexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_global_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t restStartup(char *url, char *user, char *password) {
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
|
_restMutexBuffer = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
|
||||||
|
if (!_restMutexBuffer) {
|
||||||
|
logWrite("restSetup: Mutex buffer creation failed.\n");
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<CRYPTO_num_locks(); i++) {
|
||||||
|
if (pthread_mutex_init(&_restMutexBuffer[i], NULL)) {
|
||||||
|
logWrite("restSetup: Mutex creation failed.\n");
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRYPTO_set_id_callback(restThreadtIdGet);
|
||||||
|
CRYPTO_set_locking_callback(restMutexLocker);
|
||||||
|
|
||||||
|
_restURL = strdup(url);
|
||||||
|
_restUser = strdup(user);
|
||||||
|
_restPass = strdup(password);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function" // It's used, but the compiler isn't picking it up because it's via a callback.
|
||||||
|
static unsigned long restThreadtIdGet(void) {
|
||||||
|
return ((unsigned long)pthread_self());
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
|
||||||
|
static json_object *restUrlPost(json_object *request) {
|
||||||
|
CURL *curl = NULL;
|
||||||
|
CURLcode res = 0;
|
||||||
|
RestResponseT data = { 0 };
|
||||||
|
json_object *response = NULL;
|
||||||
|
struct curl_slist *headers = NULL;
|
||||||
|
enum json_tokener_error error = json_tokener_success;
|
||||||
|
|
||||||
|
data.length = 0;
|
||||||
|
data.data = malloc(data.length + 1);
|
||||||
|
if (data.data == NULL) {
|
||||||
|
logWrite("restUrlPost: malloc() failed.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
data.data[0] = 0;
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, _restURL);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, restResponseWrite);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERNAME, _restUser);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PASSWORD, _restPass);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_to_json_string(request));
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // Make the URL work even if your CA bundle is missing.
|
||||||
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
|
||||||
|
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if (res != CURLE_OK) {
|
||||||
|
logWrite("restUrlPost: %s\n", curl_easy_strerror(res));
|
||||||
|
} else {
|
||||||
|
response = json_tokener_parse_verbose(data.data, &error);
|
||||||
|
if (error) {
|
||||||
|
logWrite("Error: %s\n", json_tokener_error_desc(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_slist_free_all(headers);
|
||||||
|
DEL(data.data);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
|
@ -18,16 +18,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef DATABASE_H
|
#ifndef REST_H
|
||||||
#define DATABASE_H
|
#define REST_H
|
||||||
|
|
||||||
|
|
||||||
#include "os.h"
|
#include <json-c/json.h>
|
||||||
|
|
||||||
|
|
||||||
uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *password);
|
int64_t restHelperConfigIntegerGet(json_object *object, char *name, int64_t defaultValue);
|
||||||
uint8_t dbDisconnect(void);
|
void restRelease(json_object *object);
|
||||||
uint8_t dbSettingsValueGet(char *key, int32_t *value);
|
json_object *restRequest(char *command, char *format, ...);
|
||||||
|
void restShutdown(void);
|
||||||
|
uint8_t restStartup(char *url, char *user, char *password);
|
||||||
|
|
||||||
|
|
||||||
#endif // DATABASE_H
|
#endif // REST_H
|
Loading…
Add table
Reference in a new issue