summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOpenGnSys Support Team <soporte-og@soleta.eu>2019-05-18 14:24:58 +0200
committerOpenGnSys Support Team <soporte-og@soleta.eu>2019-05-27 13:02:37 +0200
commit95e6520c4f3ab53ab1491eafe38c932c66b7a4b8 (patch)
tree63b82206230ce496dfa2b5eb8f9adc4624df1afe
parent222637848bf96ba38a0153bf081649560b9153d7 (diff)
#915 add initial REST API for ogAdmServer
Add REST API for ogAdmServer, this API is exposed through port 8888 on the system that runs the ogAdmServer. The body of the HTTP message is expressed in JSON format. This patch implements the command "clients" that maps to the existing legacy "Sondeo" command, that is used by the web interface to poll refresh the client state. This patch also includes an initial test infrastructure using 'curl' to send commands to the new REST API. Request: POST /clients {"clients" : [ "192.168.2.1", "192.168.2.2" ]} Reply: 200 OK This allows to refresh the status of the list of clients.
-rw-r--r--Makefile2
-rw-r--r--sources/ogAdmServer.cpp182
-rw-r--r--tests/post_clients.json1
-rwxr-xr-xtests/run-tests.sh1
4 files changed, 181 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index 6af423f..bffa4dc 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -g -Wall -I../../Includes
CPPFLAGS := $(CFLAGS)
# Opciones de linkado
-LDFLAGS := -Wl,--no-as-needed $(shell mysql_config --libs) -lev
+LDFLAGS := -Wl,--no-as-needed $(shell mysql_config --libs) -lev -ljansson
# Ficheros objetos
OBJS := ../../Includes/Database.o sources/ogAdmServer.o
diff --git a/sources/ogAdmServer.cpp b/sources/ogAdmServer.cpp
index 6ec9c2d..1dab006 100644
--- a/sources/ogAdmServer.cpp
+++ b/sources/ogAdmServer.cpp
@@ -12,6 +12,7 @@
#include <syslog.h>
#include <sys/ioctl.h>
#include <ifaddrs.h>
+#include <jansson.h>
static char usuario[LONPRM]; // Usuario de acceso a la base de datos
static char pasguor[LONPRM]; // Password del usuario
@@ -126,6 +127,7 @@ struct og_client {
unsigned int buf_len;
unsigned int msg_len;
int keepalive_idx;
+ bool rest;
};
static inline int og_client_socket(const struct og_client *cli)
@@ -3616,6 +3618,160 @@ static int og_client_state_process_payload(struct og_client *cli)
return 1;
}
+struct og_msg_params {
+ const char *ips_array[64];
+ unsigned int ips_array_len;
+};
+
+static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
+{
+ unsigned int i;
+ json_t *k;
+
+ if (json_typeof(element) != JSON_ARRAY)
+ return -1;
+
+ for (i = 0; i < json_array_size(element); i++) {
+ k = json_array_get(element, i);
+ if (json_typeof(k) != JSON_STRING)
+ return -1;
+
+ params->ips_array[params->ips_array_len++] =
+ json_string_value(k);
+ }
+ return 0;
+}
+
+static int og_cmd_legacy_sondeo(struct og_msg_params *params)
+{
+ char buf[4096] = {};
+ int len, err = 0;
+ TRAMA *msg;
+
+ len = snprintf(buf, sizeof(buf), "nfn=Sondeo\r");
+
+ msg = og_msg_alloc(buf, len);
+ if (!msg)
+ return -1;
+
+ if (!og_send_cmd((char **)params->ips_array, params->ips_array_len,
+ CLIENTE_APAGADO, msg))
+ err = -1;
+
+ og_msg_free(msg);
+
+ return err;
+}
+
+static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
+{
+ const char *key;
+ json_t *value;
+ int err = 0;
+
+ if (json_typeof(element) != JSON_OBJECT)
+ return -1;
+
+ json_object_foreach(element, key, value) {
+ if (!strcmp(key, "clients"))
+ err = og_json_parse_clients(value, params);
+
+ if (err < 0)
+ break;
+ }
+
+ return og_cmd_legacy_sondeo(params);
+}
+
+static int og_client_not_found(struct og_client *cli)
+{
+ char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
+
+ send(og_client_socket(cli), buf, strlen(buf), 0);
+
+ return -1;
+}
+
+static int og_client_ok(struct og_client *cli)
+{
+ char buf[] = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
+
+ send(og_client_socket(cli), buf, strlen(buf), 0);
+
+ return 0;
+}
+
+enum og_rest_method {
+ OG_METHOD_GET = 0,
+ OG_METHOD_POST,
+};
+
+static int og_client_state_process_payload_rest(struct og_client *cli)
+{
+ struct og_msg_params params = {};
+ const char *cmd, *body, *ptr;
+ enum og_rest_method method;
+ int content_length = 0;
+ json_error_t json_err;
+ json_t *root = NULL;
+ int err = 0;
+
+ if (!strncmp(cli->buf, "GET", strlen("GET"))) {
+ method = OG_METHOD_GET;
+ cmd = cli->buf + strlen("GET") + 2;
+ } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
+ method = OG_METHOD_POST;
+ cmd = cli->buf + strlen("POST") + 2;
+ } else
+ return -1;
+
+ body = strstr(cli->buf, "\r\n\r\n") + 4;
+
+ ptr = strstr(cli->buf, "Content-Length: ");
+ if (ptr)
+ sscanf(ptr, "Content-Length: %i[^\r\n]", &content_length);
+
+ if (content_length) {
+ root = json_loads(body, 0, &json_err);
+ if (!root) {
+ syslog(LOG_ERR, "malformed json line %d: %s\n",
+ json_err.line, json_err.text);
+ return og_client_not_found(cli);
+ }
+ }
+
+ if (!strncmp(cmd, "clients", strlen("clients"))) {
+ if (method != OG_METHOD_POST)
+ return -1;
+ if (!root) {
+ syslog(LOG_ERR, "command clients with no payload\n");
+ return og_client_not_found(cli);
+ }
+ err = og_cmd_post_clients(root, &params);
+ } else {
+ syslog(LOG_ERR, "unknown command %s\n", cmd);
+ err = og_client_not_found(cli);
+ }
+
+ json_decref(root);
+
+ if (!err)
+ og_client_ok(cli);
+
+ return err;
+}
+
+static int og_client_state_recv_hdr_rest(struct og_client *cli)
+{
+ char *trailer;
+
+ trailer = strstr(cli->buf, "\r\n\r\n");
+ if (!trailer)
+ return 0;
+
+ return 1;
+}
+
static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
{
struct og_client *cli;
@@ -3653,7 +3809,11 @@ static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events
switch (cli->state) {
case OG_CLIENT_RECEIVING_HEADER:
- ret = og_client_state_recv_hdr(cli);
+ if (cli->rest)
+ ret = og_client_state_recv_hdr_rest(cli);
+ else
+ ret = og_client_state_recv_hdr(cli);
+
if (ret < 0)
goto close;
if (!ret)
@@ -3673,7 +3833,10 @@ static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events
inet_ntoa(cli->addr.sin_addr),
ntohs(cli->addr.sin_port));
- ret = og_client_state_process_payload(cli);
+ if (cli->rest)
+ ret = og_client_state_process_payload_rest(cli);
+ else
+ ret = og_client_state_process_payload(cli);
if (ret < 0)
goto close;
@@ -3714,6 +3877,8 @@ static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events
og_client_release(loop, cli);
}
+static int socket_s, socket_rest;
+
static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
int events)
{
@@ -3739,6 +3904,9 @@ static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
memcpy(&cli->addr, &client_addr, sizeof(client_addr));
cli->keepalive_idx = -1;
+ if (io->fd == socket_rest)
+ cli->rest = true;
+
syslog(LOG_DEBUG, "connection from client %s:%hu\n",
inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
@@ -3776,9 +3944,8 @@ static int og_socket_server_init(const char *port)
int main(int argc, char *argv[])
{
+ struct ev_io ev_io_server, ev_io_server_rest;
struct ev_loop *loop = ev_default_loop(0);
- struct ev_io ev_io_server;
- int socket_s;
int i;
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
@@ -3813,6 +3980,13 @@ int main(int argc, char *argv[])
ev_io_init(&ev_io_server, og_server_accept_cb, socket_s, EV_READ);
ev_io_start(loop, &ev_io_server);
+ socket_rest = og_socket_server_init("8888");
+ if (socket_rest < 0)
+ exit(EXIT_FAILURE);
+
+ ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
+ ev_io_start(loop, &ev_io_server_rest);
+
infoLog(1); // Inicio de sesiĆ³n
/* old log file has been deprecated. */
diff --git a/tests/post_clients.json b/tests/post_clients.json
new file mode 100644
index 0000000..4667303
--- /dev/null
+++ b/tests/post_clients.json
@@ -0,0 +1 @@
+{ "clients" : [ "192.168.2.1", "192.168.2.2" ] }
diff --git a/tests/run-tests.sh b/tests/run-tests.sh
new file mode 100755
index 0000000..e187abb
--- /dev/null
+++ b/tests/run-tests.sh
@@ -0,0 +1 @@
+curl -X POST http://127.0.0.1:8888/clients -d @post_clients.json