mirror of
https://github.com/ntop/ntopng.git
synced 2026-04-30 16:09:32 +00:00
570 lines
16 KiB
C++
570 lines
16 KiB
C++
/*
|
|
*
|
|
* (C) 2013-23 - ntop.org
|
|
*
|
|
*
|
|
* 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, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
#include "ntop_includes.h"
|
|
|
|
Redis::Redis(const char *redis_host /* = NULL */,
|
|
const char *redis_password /* = NULL */,
|
|
u_int16_t redis_port /* = 0 */, u_int8_t _redis_db_id /* = 0 */,
|
|
bool giveup_on_failure /* = false */) {
|
|
this->redisVersion = "RedisStub";
|
|
this->localToResolve =
|
|
std::make_unique<StringFifoQueue>(MAX_NUM_QUEUED_ADDRS);
|
|
this->remoteToResolve =
|
|
std::make_unique<StringFifoQueue>(MAX_NUM_QUEUED_ADDRS);
|
|
|
|
memset(&stats, 0, sizeof(stats));
|
|
}
|
|
|
|
bool Redis::checkList(std::string key) {
|
|
return (this->store.find(key) == this->store.end() &&
|
|
this->setStore.find(key) == this->setStore.end());
|
|
}
|
|
|
|
bool Redis::checkSet(std::string key) {
|
|
return (this->store.find(key) == this->store.end() &&
|
|
this->listStore.find(key) == this->listStore.end());
|
|
}
|
|
|
|
char *Redis::getVersion() { return (char *)this->redisVersion.c_str(); }
|
|
|
|
u_int32_t Redis::getNumVersion() { return 1; }
|
|
|
|
bool Redis::hasRedisDump() { return false; }
|
|
|
|
void Redis::setDefaults() {}
|
|
|
|
bool Redis::isOperational() { return true; }
|
|
|
|
void Redis::setInitializationComplete() {}
|
|
|
|
int Redis::info(char *rsp, u_int rsp_len) {
|
|
if (rsp_len == 0) return -1;
|
|
|
|
stats.num_other++;
|
|
if(rsp_len == 0)
|
|
return -1;
|
|
|
|
rsp[0] = 0;
|
|
return 0;
|
|
}
|
|
|
|
u_int Redis::dbsize() {
|
|
stats.num_other++;
|
|
return this->store.size();
|
|
}
|
|
|
|
int Redis::expire(char *key, u_int expire_sec) {
|
|
stats.num_expire++;
|
|
return 0;
|
|
}
|
|
|
|
int Redis::get(char *key, char *rsp, u_int rsp_len,
|
|
bool cache_it /* = false */) {
|
|
if (rsp_len == 0) return -1;
|
|
|
|
stats.num_get++;
|
|
std::string strKey(key);
|
|
if (this->store.find(strKey) == this->store.end() ||
|
|
snprintf(rsp, rsp_len, "%s", this->store[strKey].c_str()) < 0) {
|
|
rsp[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::hashGet(const char *key, const char *member, char *const rsp,
|
|
u_int rsp_len) {
|
|
if (rsp_len == 0) return -1;
|
|
|
|
std::stringstream ss;
|
|
ss << key << "@" << member;
|
|
std::string strKey = ss.str();
|
|
if (this->store.find(strKey) == this->store.end() ||
|
|
snprintf(rsp, rsp_len, "%s", this->store[strKey].c_str()) < 0) {
|
|
rsp[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::hashDel(const char *key, const char *field) {
|
|
std::stringstream ss;
|
|
ss << key << "@" << field;
|
|
std::string strKey = ss.str();
|
|
this->store.erase(strKey);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::hashSet(const char *key, const char *field, const char *value) {
|
|
std::stringstream ss;
|
|
ss << key << "@" << field;
|
|
std::string strKey = ss.str();
|
|
this->store[strKey] = std::string(value);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::set(const char *key, const char *value,
|
|
u_int expire_secs /* = 0 */) {
|
|
std::string strKey(key);
|
|
this->store[strKey] = std::string(value);
|
|
return 0;
|
|
}
|
|
|
|
/* setnx = set if not existing */
|
|
int Redis::setnx(const char *key, const char *value,
|
|
u_int expire_secs /* = 0 */) {
|
|
std::string strKey(key);
|
|
if (this->store.find(strKey) != this->store.end()) return -1;
|
|
|
|
this->store[strKey] = std::string(value);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::keys(const char *pattern, char ***keys_p) {
|
|
*keys_p = (char **)malloc(0);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::hashKeys(const char *pattern, char ***keys_p) {
|
|
*keys_p = (char **)malloc(0);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::hashGetAll(const char *key, char ***keys_p, char ***values_p) {
|
|
*keys_p = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int Redis::del(char *key) {
|
|
std::string strKey(key);
|
|
stats.num_del++;
|
|
this->store.erase(strKey);
|
|
return 0;
|
|
}
|
|
|
|
int Redis::pushHostToResolve(char *hostname, bool dont_check_for_existence,
|
|
bool localHost) {
|
|
if (!ntop->getPrefs()->is_dns_resolution_enabled()) return 0;
|
|
if (hostname == NULL) return -1;
|
|
|
|
if (!Utils::shouldResolveHost(hostname)) return -1;
|
|
|
|
std::stringstream ss;
|
|
ss << DNS_CACHE << "." << hostname;
|
|
std::string strKey = ss.str();
|
|
|
|
/* Add only if the address has not been resolved yet */
|
|
if (dont_check_for_existence ||
|
|
this->store.find(strKey) == this->store.end()) {
|
|
auto &q = localHost ? localToResolve : remoteToResolve;
|
|
q->enqueue(hostname);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int Redis::popHostToResolve(char *hostname, u_int hostname_len) {
|
|
char *item = localToResolve->dequeue();
|
|
int rv = -1;
|
|
|
|
if (!item) item = remoteToResolve->dequeue();
|
|
|
|
if (item) {
|
|
strncpy(hostname, item, hostname_len);
|
|
hostname[hostname_len - 1] = 0;
|
|
free(item);
|
|
rv = 0;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
int Redis::getAddress(char *numeric_ip, char *rsp, u_int rsp_len,
|
|
bool queue_if_not_found) {
|
|
if (rsp_len == 0) return -1;
|
|
|
|
int rc;
|
|
char key[CONST_MAX_LEN_REDIS_KEY];
|
|
bool already_in_bloom;
|
|
|
|
rsp[0] = 0;
|
|
snprintf(key, sizeof(key), "%s.%s", DNS_CACHE, numeric_ip);
|
|
|
|
if (!ntop->getResolutionBloom()->isSetBit(numeric_ip)) {
|
|
already_in_bloom = false;
|
|
rc = -1; /* No way to find it */
|
|
} else {
|
|
already_in_bloom = true;
|
|
rc = this->get(key, rsp, rsp_len);
|
|
}
|
|
|
|
if (rc != 0) {
|
|
if (queue_if_not_found) {
|
|
if (already_in_bloom)
|
|
ntop->getResolutionBloom()->unsetBit(
|
|
numeric_ip); /* Expired key ? */
|
|
|
|
this->pushHostToResolve(numeric_ip, true, false);
|
|
}
|
|
} else {
|
|
/* We need to extend expire */
|
|
if (!already_in_bloom)
|
|
ntop->getResolutionBloom()->setBit(
|
|
numeric_ip); /* Previously cached ? */
|
|
|
|
this->expire(key, DNS_CACHE_DURATION /* expire */);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int Redis::setResolvedAddress(char *numeric_ip, char *symbolic_ip) {
|
|
char key[CONST_MAX_LEN_REDIS_KEY], numeric[256], *w, *h;
|
|
int rc = 0;
|
|
|
|
snprintf(numeric, sizeof(numeric), "%s", numeric_ip);
|
|
|
|
h = strtok_r(numeric, ";", &w);
|
|
|
|
while (h != NULL) {
|
|
snprintf(key, sizeof(key), "%s.%s", DNS_CACHE, h);
|
|
ntop->getResolutionBloom()->setBit(h);
|
|
rc = this->set(key, symbolic_ip, DNS_CACHE_DURATION);
|
|
h = strtok_r(NULL, ";", &w);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int Redis::sadd(const char *set_name, char *item) {
|
|
std::string strKey(set_name);
|
|
if (!this->checkSet(strKey)) return -1;
|
|
if (this->setStore.find(strKey) == this->setStore.end())
|
|
this->setStore[strKey] = std::set<std::string>();
|
|
|
|
auto result = this->setStore[strKey].insert(std::string(item));
|
|
return (result.second ? 1 : 0);
|
|
}
|
|
|
|
int Redis::srem(const char *set_name, char *item) {
|
|
std::string strKey(set_name);
|
|
if (!this->checkSet(strKey)) return -1;
|
|
if (this->setStore.find(strKey) == this->setStore.end()) return 0;
|
|
|
|
return this->setStore[strKey].erase(std::string(item));
|
|
}
|
|
|
|
int Redis::smembers(lua_State *vm, char *setName) {
|
|
stats.num_other++;
|
|
std::string strKey(setName);
|
|
if (!this->checkSet(strKey)) return -1;
|
|
if (this->setStore.find(strKey) == this->setStore.end()) return 0;
|
|
|
|
int k = 0;
|
|
const auto &values = this->setStore[strKey];
|
|
for (const auto &val : values) {
|
|
lua_pushstring(vm, val.c_str());
|
|
lua_rawseti(vm, -2, k + 1);
|
|
++k;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::smembers(const char *set_name, char ***members) {
|
|
std::string strKey(set_name);
|
|
if (this->setStore.find(strKey) == this->setStore.end()) {
|
|
*members = NULL;
|
|
return -1;
|
|
}
|
|
|
|
int k = 0;
|
|
const auto &values = this->setStore[strKey];
|
|
if ((*members = (char **)malloc(values.size() * sizeof(char *))) != NULL)
|
|
for (auto val : values) (*members)[k++] = strdup(val.c_str());
|
|
|
|
return values.size();
|
|
}
|
|
|
|
bool Redis::sismember(const char *set_name, const char *member) {
|
|
stats.num_other++;
|
|
std::string strKey(set_name);
|
|
if (this->setStore.find(strKey) == this->setStore.end()) return false;
|
|
|
|
return (this->setStore[strKey].find(std::string(member)) ==
|
|
this->setStore[strKey].end());
|
|
}
|
|
|
|
int Redis::lpush(const char *queue_name, const char *msg, u_int queue_trim_size,
|
|
bool trace_errors /* = true */) {
|
|
stats.num_lpush_rpush++;
|
|
std::string strKey(queue_name);
|
|
if (!this->checkList(strKey)) return -1;
|
|
|
|
if (this->listStore.find(strKey) == this->listStore.end())
|
|
this->listStore[strKey] = std::vector<std::string>();
|
|
|
|
this->listStore[strKey].insert(this->listStore[strKey].begin(),
|
|
std::string(msg));
|
|
|
|
if (queue_trim_size > 0) {
|
|
stats.num_trim++;
|
|
if (this->ltrim(queue_name, -queue_trim_size, -1) == -1) return -1;
|
|
}
|
|
|
|
return this->listStore[strKey].size();
|
|
}
|
|
|
|
int Redis::rpush(const char *queue_name, const char *msg,
|
|
u_int queue_trim_size) {
|
|
stats.num_lpush_rpush++;
|
|
std::string strKey(queue_name);
|
|
if (!this->checkList(strKey)) return -1;
|
|
|
|
if (this->listStore.find(strKey) == this->listStore.end())
|
|
this->listStore[strKey] = std::vector<std::string>();
|
|
|
|
this->listStore[strKey].push_back(std::string(msg));
|
|
|
|
if (queue_trim_size > 0) {
|
|
stats.num_trim++;
|
|
if (this->ltrim(queue_name, -queue_trim_size, -1) == -1) return -1;
|
|
}
|
|
|
|
return this->listStore[strKey].size();
|
|
}
|
|
|
|
int Redis::lindex(const char *queue_name, int idx, char *buf, u_int buf_len) {
|
|
if (buf_len == 0) return -1;
|
|
stats.num_other++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
const auto &list = this->listStore[strKey];
|
|
|
|
if (idx < 0) idx += (int)list.size();
|
|
if (idx < 0 || idx >= (int)list.size()) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
snprintf(buf, buf_len, "%s", list[idx].c_str());
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::ltrim(const char *queue_name, int start_idx, int end_idx) {
|
|
stats.num_other++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) return -1;
|
|
|
|
auto &list = this->listStore[strKey];
|
|
if (start_idx < 0) start_idx += list.size();
|
|
if (end_idx < 0) end_idx += list.size();
|
|
int k = 0;
|
|
for (auto it = list.begin(); it != list.end(); ++k) {
|
|
if (k < start_idx || k > end_idx)
|
|
list.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
u_int Redis::hstrlen(const char *key, const char *value) {
|
|
stats.num_other++;
|
|
std::stringstream ss;
|
|
ss << key << "@" << value;
|
|
std::string strKey = ss.str();
|
|
if (this->store.find(strKey) == this->store.end()) return 0;
|
|
|
|
return this->store[strKey].size();
|
|
}
|
|
|
|
u_int Redis::len(const char *key) {
|
|
std::string strKey(key);
|
|
if (this->store.find(strKey) == this->store.end()) return 0;
|
|
|
|
return this->store[strKey].size();
|
|
}
|
|
|
|
u_int Redis::llen(const char *queue_name) {
|
|
stats.num_llen++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) return 0;
|
|
|
|
return this->listStore[strKey].size();
|
|
}
|
|
|
|
int Redis::lset(const char *queue_name, u_int32_t idx, const char *value) {
|
|
return -1;
|
|
}
|
|
|
|
int Redis::lrem(const char *queue_name, const char *value) {
|
|
stats.num_other++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) return 0;
|
|
|
|
for (auto it = this->listStore[strKey].begin();
|
|
it != this->listStore[strKey].end();) {
|
|
if (strncmp(it->c_str(), value, it->size()) == 0)
|
|
this->listStore[strKey].erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Redis::lrange(const char *list_name, char ***elements, int start_offset,
|
|
int end_offset) {
|
|
stats.num_other++;
|
|
std::string strKey(list_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) return 0;
|
|
|
|
auto &list = this->listStore[strKey];
|
|
if (start_offset < 0) start_offset += list.size();
|
|
if (end_offset < 0) end_offset += list.size();
|
|
int k = 0;
|
|
vector<std::string> retList;
|
|
for (auto it = list.begin(); it != list.end(); ++k, ++it) {
|
|
if (k >= start_offset && k <= end_offset) retList.push_back(*it);
|
|
}
|
|
|
|
*elements = (char **)malloc(retList.size() * sizeof(char *));
|
|
for (int i = 0; i < (int)retList.size(); ++i)
|
|
(*elements)[i] = strdup(retList[i].c_str());
|
|
|
|
return retList.size();
|
|
}
|
|
|
|
int Redis::lpop(const char *queue_name, char *buf, u_int buf_len) {
|
|
stats.num_lpop_rpop++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
if (this->listStore[strKey].size() == 0) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
snprintf(buf, buf_len, "%s", this->listStore[strKey].front().c_str());
|
|
this->listStore[strKey].erase(this->listStore[strKey].begin());
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::rpop(const char *queue_name, char *buf, u_int buf_len) {
|
|
stats.num_lpop_rpop++;
|
|
std::string strKey(queue_name);
|
|
if (this->listStore.find(strKey) == this->listStore.end()) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
if (this->listStore[strKey].size() == 0) {
|
|
buf[0] = 0;
|
|
return -1;
|
|
}
|
|
|
|
snprintf(buf, buf_len, "%s", this->listStore[strKey].back().c_str());
|
|
this->listStore[strKey].pop_back();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Redis::incr(const char *key, int amount) {
|
|
std::string strKey(key);
|
|
if (this->store.find(strKey) == this->store.end()) return 0;
|
|
|
|
const auto &val = this->store[strKey];
|
|
try {
|
|
long l = std::stol(val);
|
|
l += amount;
|
|
std::stringstream ss;
|
|
ss << l;
|
|
this->store[strKey] = ss.str();
|
|
return l;
|
|
} catch (std::exception const &e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int Redis::flushDb() {
|
|
stats.num_other++;
|
|
this->store.clear();
|
|
return 0;
|
|
}
|
|
|
|
void Redis::flushCache() {}
|
|
|
|
void Redis::lua(lua_State *vm) {
|
|
lua_newtable(vm);
|
|
|
|
lua_push_uint64_table_entry(vm, "num_expire", stats.num_expire);
|
|
lua_push_uint64_table_entry(vm, "num_get", stats.num_get);
|
|
lua_push_uint64_table_entry(vm, "num_ttl", stats.num_ttl);
|
|
lua_push_uint64_table_entry(vm, "num_del", stats.num_del);
|
|
lua_push_uint64_table_entry(vm, "num_hget", stats.num_hget);
|
|
lua_push_uint64_table_entry(vm, "num_hset", stats.num_hset);
|
|
lua_push_uint64_table_entry(vm, "num_hdel", stats.num_hdel);
|
|
lua_push_uint64_table_entry(vm, "num_set", stats.num_set);
|
|
lua_push_uint64_table_entry(vm, "num_expire", stats.num_expire);
|
|
lua_push_uint64_table_entry(vm, "num_keys", stats.num_keys);
|
|
lua_push_uint64_table_entry(vm, "num_hkeys", stats.num_hkeys);
|
|
lua_push_uint64_table_entry(vm, "num_hgetall", stats.num_hgetall);
|
|
lua_push_uint64_table_entry(vm, "num_trim", stats.num_trim);
|
|
lua_push_uint64_table_entry(vm, "num_reconnections",
|
|
stats.num_reconnections);
|
|
lua_push_uint64_table_entry(vm, "num_lpush_rpush", stats.num_lpush_rpush);
|
|
lua_push_uint64_table_entry(vm, "num_lpop_rpop", stats.num_lpop_rpop);
|
|
lua_push_uint64_table_entry(vm, "num_llen", stats.num_llen);
|
|
lua_push_uint64_table_entry(vm, "num_strlen", stats.num_strlen);
|
|
lua_push_uint64_table_entry(vm, "num_other", stats.num_other);
|
|
|
|
/* Address resolution */
|
|
lua_push_uint64_table_entry(vm, "num_resolver_saved_lookups",
|
|
stats.num_saved_lookups);
|
|
lua_push_uint64_table_entry(vm, "num_resolver_get_address",
|
|
stats.num_get_address);
|
|
lua_push_uint64_table_entry(vm, "num_resolver_set_address",
|
|
stats.num_set_resolved_address);
|
|
}
|
|
|
|
char *Redis::dump(char *key) {
|
|
stats.num_other++;
|
|
char *ret = (char *)malloc(1);
|
|
ret[0] = 0;
|
|
return ret;
|
|
}
|
|
|
|
int Redis::restore(char *key, char *buf) { return 0; }
|