X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ffrontend%2Fquery.c;h=15e81b8f06613fcf6deb469ea92fe3d376df49d2;hb=ebfd78eb79806777c3de889d75a62665ff78eaca;hp=52d27ec3c47ba7e7dc940ba552e76b43cf0b38a2;hpb=ee8df3b190c2eb49e460dcf03f81288a5d825c39;p=sysdb.git diff --git a/src/frontend/query.c b/src/frontend/query.c index 52d27ec..15e81b8 100644 --- a/src/frontend/query.c +++ b/src/frontend/query.c @@ -31,6 +31,7 @@ #include "frontend/connection-private.h" #include "frontend/parser.h" #include "utils/error.h" +#include "utils/proto.h" #include "utils/strbuf.h" #include @@ -91,7 +92,8 @@ sdb_fe_query(sdb_conn_t *conn) switch (sdb_llist_len(parsetree)) { case 0: - /* skipping empty command */ + /* skipping empty command; send back an empty reply */ + sdb_connection_send(conn, CONNECTION_DATA, 0, NULL); break; case 1: node = SDB_CONN_NODE(sdb_llist_get(parsetree, 0)); @@ -112,7 +114,16 @@ sdb_fe_query(sdb_conn_t *conn) } if (node) { - status = sdb_fe_exec(conn, node); + if (sdb_fe_analyze(node)) { + char query[conn->cmd_len + 1]; + strncpy(query, sdb_strbuf_string(conn->buf), conn->cmd_len); + query[sizeof(query) - 1] = '\0'; + sdb_log(SDB_LOG_ERR, "frontend: Failed to verify query '%s'", + query); + status = -1; + } + else + status = sdb_fe_exec(conn, node); sdb_object_deref(SDB_OBJ(node)); } @@ -123,43 +134,102 @@ sdb_fe_query(sdb_conn_t *conn) int sdb_fe_fetch(sdb_conn_t *conn) { - char hostname[conn->cmd_len + 1]; + char name[conn->cmd_len + 1]; + int type; + if ((! conn) || (conn->cmd != CONNECTION_FETCH)) return -1; - strncpy(hostname, sdb_strbuf_string(conn->buf), conn->cmd_len); - hostname[sizeof(hostname) - 1] = '\0'; - return sdb_fe_exec_fetch(conn, hostname, /* filter = */ NULL); + + if (conn->cmd_len < sizeof(type)) { + sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for " + "FETCH command", conn->cmd_len); + sdb_strbuf_sprintf(conn->errbuf, "FETCH: Invalid command length %d", + conn->cmd_len); + return -1; + } + + type = sdb_proto_get_int(conn->buf, 0); + strncpy(name, sdb_strbuf_string(conn->buf) + sizeof(type), + conn->cmd_len - sizeof(type)); + name[sizeof(name) - 1] = '\0'; + return sdb_fe_exec_fetch(conn, type, name, /* filter = */ NULL); } /* sdb_fe_fetch */ int sdb_fe_list(sdb_conn_t *conn) { + int type = SDB_HOST; + if ((! conn) || (conn->cmd != CONNECTION_LIST)) return -1; - return sdb_fe_exec_list(conn, /* filter = */ NULL); + + if (conn->cmd_len == sizeof(uint32_t)) + type = sdb_proto_get_int(conn->buf, 0); + else if (conn->cmd_len) { + sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for " + "LIST command", conn->cmd_len); + sdb_strbuf_sprintf(conn->errbuf, "LIST: Invalid command length %d", + conn->cmd_len); + return -1; + } + return sdb_fe_exec_list(conn, type, /* filter = */ NULL); } /* sdb_fe_list */ int sdb_fe_lookup(sdb_conn_t *conn) { sdb_store_matcher_t *m; + const char *matcher; + size_t matcher_len; + + uint32_t type; int status; + conn_matcher_t m_node = { + { SDB_OBJECT_INIT, CONNECTION_MATCHER }, NULL + }; + conn_lookup_t node = { + { SDB_OBJECT_INIT, CONNECTION_LOOKUP }, + -1, &m_node, NULL + }; + if ((! conn) || (conn->cmd != CONNECTION_LOOKUP)) return -1; - m = sdb_fe_parse_matcher(sdb_strbuf_string(conn->buf), - (int)conn->cmd_len); + if (conn->cmd_len < sizeof(type)) { + sdb_log(SDB_LOG_ERR, "frontend: Invalid command length %d for " + "LOOKUP command", conn->cmd_len); + sdb_strbuf_sprintf(conn->errbuf, "LOOKUP: Invalid command length %d", + conn->cmd_len); + return -1; + } + type = sdb_proto_get_int(conn->buf, 0); + + matcher = sdb_strbuf_string(conn->buf) + sizeof(type); + matcher_len = conn->cmd_len - sizeof(type); + m = sdb_fe_parse_matcher(matcher, (int)matcher_len); if (! m) { - char expr[conn->cmd_len + 1]; - strncpy(expr, sdb_strbuf_string(conn->buf), conn->cmd_len); + char expr[matcher_len + 1]; + strncpy(expr, matcher, sizeof(expr)); expr[sizeof(expr) - 1] = '\0'; sdb_log(SDB_LOG_ERR, "frontend: Failed to parse " "lookup condition '%s'", expr); return -1; } - status = sdb_fe_exec_lookup(conn, m, /* filter = */ NULL); + node.type = type; + m_node.matcher = m; + + if (sdb_fe_analyze(SDB_CONN_NODE(&node))) { + char expr[matcher_len + 1]; + strncpy(expr, matcher, sizeof(expr)); + expr[sizeof(expr) - 1] = '\0'; + sdb_log(SDB_LOG_ERR, "frontend: Failed to verify " + "lookup condition '%s'", expr); + status = -1; + } + else + status = sdb_fe_exec_lookup(conn, type, m, /* filter = */ NULL); sdb_object_deref(SDB_OBJ(m)); return status; } /* sdb_fe_lookup */ @@ -176,17 +246,19 @@ sdb_fe_exec(sdb_conn_t *conn, sdb_conn_node_t *node) case CONNECTION_FETCH: if (CONN_FETCH(node)->filter) filter = CONN_FETCH(node)->filter->matcher; - return sdb_fe_exec_fetch(conn, CONN_FETCH(node)->name, filter); + return sdb_fe_exec_fetch(conn, CONN_FETCH(node)->type, + CONN_FETCH(node)->name, filter); case CONNECTION_LIST: if (CONN_LIST(node)->filter) filter = CONN_LIST(node)->filter->matcher; - return sdb_fe_exec_list(conn, filter); + return sdb_fe_exec_list(conn, CONN_LIST(node)->type, filter); case CONNECTION_LOOKUP: if (CONN_LOOKUP(node)->matcher) m = CONN_LOOKUP(node)->matcher->matcher; if (CONN_LOOKUP(node)->filter) filter = CONN_LOOKUP(node)->filter->matcher; - return sdb_fe_exec_lookup(conn, m, filter); + return sdb_fe_exec_lookup(conn, + CONN_LOOKUP(node)->type, m, filter); case CONNECTION_TIMESERIES: return sdb_fe_exec_timeseries(conn, CONN_TS(node)->hostname, CONN_TS(node)->metric, @@ -200,12 +272,21 @@ sdb_fe_exec(sdb_conn_t *conn, sdb_conn_node_t *node) } /* sdb_fe_exec */ int -sdb_fe_exec_fetch(sdb_conn_t *conn, const char *name, +sdb_fe_exec_fetch(sdb_conn_t *conn, int type, const char *name, sdb_store_matcher_t *filter) { sdb_strbuf_t *buf; sdb_store_obj_t *host; - uint32_t type = htonl(CONNECTION_FETCH); + uint32_t res_type = htonl(CONNECTION_FETCH); + + /* XXX: support other types */ + if (type != SDB_HOST) { + sdb_log(SDB_LOG_ERR, "frontend: Invalid object type %d " + "in FETCH command", type); + sdb_strbuf_sprintf(conn->errbuf, + "FETCH: Invalid object type %d", type); + return -1; + } host = sdb_store_get_host(name); if (! host) { @@ -229,7 +310,7 @@ sdb_fe_exec_fetch(sdb_conn_t *conn, const char *name, return -1; } - sdb_strbuf_memcpy(buf, &type, sizeof(uint32_t)); + sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t)); if (sdb_store_host_tojson(host, buf, filter, /* flags = */ 0)) { sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize " "host '%s' to JSON", name); @@ -247,10 +328,28 @@ sdb_fe_exec_fetch(sdb_conn_t *conn, const char *name, } /* sdb_fe_exec_fetch */ int -sdb_fe_exec_list(sdb_conn_t *conn, sdb_store_matcher_t *filter) +sdb_fe_exec_list(sdb_conn_t *conn, int type, sdb_store_matcher_t *filter) { sdb_strbuf_t *buf; - uint32_t type = htonl(CONNECTION_LIST); + uint32_t res_type = htonl(CONNECTION_LIST); + + int flags; + + if (type == SDB_HOST) + flags = SDB_SKIP_ALL; + else if (type == SDB_SERVICE) + flags = (SDB_SKIP_ALL & (~SDB_SKIP_SERVICES)) + | SDB_SKIP_EMPTY_SERVICES; + else if (type == SDB_METRIC) + flags = (SDB_SKIP_ALL & (~SDB_SKIP_METRICS)) + | SDB_SKIP_EMPTY_METRICS; + else { + sdb_log(SDB_LOG_ERR, "frontend: Invalid object type %d " + "for LIST command", type); + sdb_strbuf_sprintf(conn->errbuf, + "LIST: Invalid object type %d", type); + return -1; + } buf = sdb_strbuf_create(1024); if (! buf) { @@ -264,8 +363,8 @@ sdb_fe_exec_list(sdb_conn_t *conn, sdb_store_matcher_t *filter) return -1; } - sdb_strbuf_memcpy(buf, &type, sizeof(uint32_t)); - if (sdb_store_tojson(buf, filter, /* flags = */ SDB_SKIP_ALL)) { + sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t)); + if (sdb_store_tojson(buf, filter, flags)) { sdb_log(SDB_LOG_ERR, "frontend: Failed to serialize " "store to JSON"); sdb_strbuf_sprintf(conn->errbuf, "Out of memory"); @@ -280,11 +379,20 @@ sdb_fe_exec_list(sdb_conn_t *conn, sdb_store_matcher_t *filter) } /* sdb_fe_exec_list */ int -sdb_fe_exec_lookup(sdb_conn_t *conn, sdb_store_matcher_t *m, - sdb_store_matcher_t *filter) +sdb_fe_exec_lookup(sdb_conn_t *conn, int type, + sdb_store_matcher_t *m, sdb_store_matcher_t *filter) { tojson_data_t data = { NULL, filter, 0 }; - uint32_t type = htonl(CONNECTION_LOOKUP); + uint32_t res_type = htonl(CONNECTION_LOOKUP); + + /* XXX: support other types */ + if (type != SDB_HOST) { + sdb_log(SDB_LOG_ERR, "frontend: Invalid object type %d " + "in LOOKUP command", type); + sdb_strbuf_sprintf(conn->errbuf, + "LOOKUP: Invalid object type %d", type); + return -1; + } data.buf = sdb_strbuf_create(1024); if (! data.buf) { @@ -298,14 +406,14 @@ sdb_fe_exec_lookup(sdb_conn_t *conn, sdb_store_matcher_t *m, return -1; } - sdb_strbuf_memcpy(data.buf, &type, sizeof(uint32_t)); + sdb_strbuf_memcpy(data.buf, &res_type, sizeof(uint32_t)); sdb_strbuf_append(data.buf, "["); /* Let the JSON serializer handle the filter instead of the scanner. Else, * we'd have to filter twice -- once in the scanner and then again in the * serializer. */ data.last_len = sdb_strbuf_len(data.buf); - if (sdb_store_scan(m, /* filter */ NULL, lookup_tojson, &data)) { + if (sdb_store_scan(SDB_HOST, m, /* filter */ NULL, lookup_tojson, &data)) { sdb_log(SDB_LOG_ERR, "frontend: Failed to lookup hosts"); sdb_strbuf_sprintf(conn->errbuf, "Failed to lookup hosts"); sdb_strbuf_destroy(data.buf); @@ -326,7 +434,7 @@ sdb_fe_exec_timeseries(sdb_conn_t *conn, sdb_timeseries_opts_t *opts) { sdb_strbuf_t *buf; - uint32_t type = htonl(CONNECTION_TIMESERIES); + uint32_t res_type = htonl(CONNECTION_TIMESERIES); buf = sdb_strbuf_create(1024); if (! buf) { @@ -339,7 +447,7 @@ sdb_fe_exec_timeseries(sdb_conn_t *conn, return -1; } - sdb_strbuf_memcpy(buf, &type, sizeof(uint32_t)); + sdb_strbuf_memcpy(buf, &res_type, sizeof(uint32_t)); if (sdb_store_fetch_timeseries(hostname, metric, opts, buf)) { sdb_log(SDB_LOG_ERR, "frontend: Failed to fetch time-series"); sdb_strbuf_sprintf(conn->errbuf, "Failed to fetch time-series");