diff options
author | OpenGnSys Support Team <soporte-og@soleta.eu> | 2019-05-18 14:24:58 +0200 |
---|---|---|
committer | OpenGnSys Support Team <soporte-og@soleta.eu> | 2019-05-27 13:02:37 +0200 |
commit | 95e6520c4f3ab53ab1491eafe38c932c66b7a4b8 (patch) | |
tree | 63b82206230ce496dfa2b5eb8f9adc4624df1afe | |
parent | 222637848bf96ba38a0153bf081649560b9153d7 (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-- | Makefile | 2 | ||||
-rw-r--r-- | sources/ogAdmServer.cpp | 182 | ||||
-rw-r--r-- | tests/post_clients.json | 1 | ||||
-rwxr-xr-x | tests/run-tests.sh | 1 |
4 files changed, 181 insertions, 5 deletions
@@ -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, ¶ms); + } 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 |