Browse Source

ckdb - add cmd_events for managing/viewing event info

master
kanoi 9 years ago
parent
commit
22292423e8
  1. 22
      src/ckdb.c
  2. 9
      src/ckdb.h
  3. 284
      src/ckdb_cmd.c
  4. 17
      src/ckdb_data.c
  5. 5
      src/ckdb_dbio.c

22
src/ckdb.c

@ -1216,7 +1216,7 @@ static void alloc_storage()
ips_free = k_new_list("IPs", sizeof(IPS), ALLOC_IPS, LIMIT_IPS, true);
ips_store = k_new_store(ips_free);
ips_root = new_ktree(NULL, cmp_ips, ips_free);
ips_add(IPS_GROUP_OK, "127.0.0.1", "local", false, true, 0);
ips_add(IPS_GROUP_OK, "127.0.0.1", "local", false, true, 0, false);
events_free = k_new_list("Events", sizeof(EVENTS),
ALLOC_EVENTS, LIMIT_EVENTS, true);
@ -1307,9 +1307,14 @@ static void alloc_storage()
DLPRIO(userinfo, 50);
// Needs to check users and ips and uses limits
// Uses event_limits
DLPRIO(optioncontrol, 48);
// Needs to check users and ips and uses events_limits
DLPRIO(events, 47);
// events_limits 46 (events-1) above users
DLPRIO(auths, 44);
DLPRIO(users, 43);
DLPRIO(useratts, 42);
@ -1327,9 +1332,6 @@ static void alloc_storage()
DLPRIO(poolstats, 11);
DLPRIO(userstats, 10);
// Uses limits lock for events_limits
DLPRIO(optioncontrol, 5);
// Don't currently nest any locks in these:
DLPRIO(workers, PRIO_TERMINAL);
DLPRIO(idcontrol, PRIO_TERMINAL);
@ -4393,6 +4395,7 @@ static void *socketer(__maybe_unused void *arg)
case CMD_SHSTA:
case CMD_USERINFO:
case CMD_LOCKS:
case CMD_EVENTS:
msgline->sockd = sockd;
sockd = -1;
K_WLOCK(workqueue_free);
@ -4651,6 +4654,7 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_BTCSET:
case CMD_QUERY:
case CMD_LOCKS:
case CMD_EVENTS:
LOGERR("%s() INVALID message line %"PRIu64
" ignored '%.42s...",
__func__, count,
@ -5810,6 +5814,7 @@ int main(int argc, char **argv)
char buf[512];
ckpool_t ckp;
int c, ret, i = 0, j;
size_t len;
char *kill;
tv_t now;
@ -5824,6 +5829,11 @@ int main(int argc, char **argv)
while ((c = getopt_long(argc, argv, "a:c:d:ghi:kl:mM:n:p:P:r:R:s:S:t:u:U:vw:yY:", long_options, &i)) != -1) {
switch(c) {
case 'a':
len = strlen(optarg);
if (len > MAX_ALERT_CMD)
quit(1, "ckdb_alert_cmd (%d) too large,"
" limit %d",
(int)len, MAX_ALERT_CMD);
ckdb_alert_cmd = strdup(optarg);
break;
case 'c':
@ -6057,7 +6067,7 @@ int main(int argc, char **argv)
#if LOCK_CHECK
DLPRIO(process_pplns, 99);
DLPRIO(workers_db, 98);
DLPRIO(event_limits, PRIO_TERMINAL);
DLPRIO(event_limits, 46); // events-1
#endif
if (confirm_sharesummary) {

9
src/ckdb.h

@ -51,7 +51,7 @@
#define DB_VLOCK "1"
#define DB_VERSION "1.0.4"
#define CKDB_VERSION DB_VERSION"-1.950"
#define CKDB_VERSION DB_VERSION"-1.951"
#define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -353,6 +353,9 @@ extern cklock_t last_lock;
#define STR_SHAREERRORS "shareerror"
#define STR_AGEWORKINFO "ageworkinfo"
// Fixed size required - increase if you need larger
#define MAX_ALERT_CMD 255
// Access using event_limits_free lock
extern char *ckdb_alert_cmd;
extern char *btc_server;
@ -676,6 +679,7 @@ enum cmd_values {
CMD_BTCSET,
CMD_QUERY,
CMD_LOCKS,
CMD_EVENTS,
CMD_END
};
@ -2981,7 +2985,8 @@ extern bool payouts_add(PGconn *conn, bool add, K_ITEM *p_item,
extern K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now,
bool lock);
extern bool payouts_fill(PGconn *conn);
extern void ips_add(char *group, char *ip, char *des, bool log, bool cclass, int life);
extern void ips_add(char *group, char *ip, char *des, bool log, bool cclass,
int life, bool locked);
extern int _events_add(int id, char *by, char *inet, tv_t *cd, K_TREE *trf_root);
#define events_add(_id, _trf_root) _events_add(_id, NULL, NULL, NULL, _trf_root)
extern bool auths_add(PGconn *conn, char *poolinstance, char *username,

284
src/ckdb_cmd.c

@ -7484,6 +7484,289 @@ static char *cmd_locks(__maybe_unused PGconn *conn, char *cmd, char *id,
return strdup(reply);
}
static void event_tree(K_TREE *event_tree, char *list, char *reply, size_t siz,
char *buf, size_t *off, size_t *len, int *rows)
{
K_TREE_CTX ctx[1];
K_ITEM *e_item;
EVENTS *e;
e_item = first_in_ktree(event_tree, ctx);
while (e_item) {
DATA_EVENTS(e, e_item);
if (CURRENT(&(e->expirydate))) {
snprintf(reply, siz, "list:%d=%s%c",
*rows, list, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
snprintf(reply, siz, "id:%d=%d%c",
*rows, e->id, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
snprintf(reply, siz, "user:%d=%s%c",
*rows, e->createby, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
if (event_tree == events_ipc_root) {
snprintf(reply, siz, "ipc:%d=%s%c",
*rows, e->ipc, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
} else {
snprintf(reply, siz, "ip:%d=%s%c",
*rows, e->createinet, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
}
if (event_tree == events_hash_root) {
snprintf(reply, siz, "hash:%d=%.8s%c",
*rows, e->hash, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
}
snprintf(reply, siz, CDTRF":%d=%ld%c",
(*rows)++, e->createdate.tv_sec, FLDSEP);
APPEND_REALLOC(buf, *off, *len, reply);
}
e_item = next_in_ktree(ctx);
}
}
// Events status/settings
static char *cmd_events(__maybe_unused PGconn *conn, char *cmd, char *id,
__maybe_unused tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *cd, K_TREE *trf_root)
{
K_ITEM *i_action, *i_cmd, *i_list, *i_ip, *i_lifetime, *i_des, *i_item;
K_TREE_CTX ctx[1];
IPS *ips;
char *action, *alert_cmd, *list, *ip, *des;
char reply[1024] = "";
size_t siz = sizeof(reply);
char tmp[1024] = "";
char *buf = NULL;
size_t len, off;
int i, rows, oldlife, lifetime;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_action = require_name(trf_root, "action", 1, NULL, reply, siz);
if (!i_action)
return strdup(reply);
action = transfer_data(i_action);
if (strcasecmp(action, "cmd") == 0) {
/* Change ckdb_alert_cmd to 'cmd'
* blank to disable it */
i_cmd = require_name(trf_root, "cmd", 0, NULL, reply, siz);
if (!i_cmd)
return strdup(reply);
alert_cmd = transfer_data(i_cmd);
if (strlen(alert_cmd) > MAX_ALERT_CMD)
return strdup("Invalid cmd length - limit " STRINT(MAX_ALERT_CMD));
K_WLOCK(event_limits_free);
FREENULL(ckdb_alert_cmd);
if (*alert_cmd)
ckdb_alert_cmd = strdup(alert_cmd);
K_WUNLOCK(event_limits_free);
APPEND_REALLOC_INIT(buf, off, len);
if (*alert_cmd)
APPEND_REALLOC(buf, off, len, "ok.cmd set");
else
APPEND_REALLOC(buf, off, len, "ok.cmd disabled");
} else if (strcasecmp(action, "settings") == 0) {
// Return all current event settings
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
K_RLOCK(event_limits_free);
i = -1;
while (e_limits[++i].name) {
#define EVENTFLD(_fld) do { \
snprintf(tmp, sizeof(tmp), "%s_" #_fld "=%d%c", \
e_limits[i].name, e_limits[i]._fld, FLDSEP); \
APPEND_REALLOC(buf, off, len, tmp); \
} while (0)
EVENTFLD(user_low_time);
EVENTFLD(user_low_time_limit);
EVENTFLD(user_hi_time);
EVENTFLD(user_hi_time_limit);
EVENTFLD(ip_low_time);
EVENTFLD(ip_low_time_limit);
EVENTFLD(ip_hi_time);
EVENTFLD(ip_hi_time_limit);
EVENTFLD(lifetime);
}
snprintf(tmp, sizeof(tmp), "event_limits_hash_lifetime=%d",
event_limits_hash_lifetime);
APPEND_REALLOC(buf, off, len, tmp);
K_RUNLOCK(event_limits_free);
} else if (strcasecmp(action, "events") == 0) {
/* List the event tree contents
* List is 'all' or one of: hash, user, ip or ipc <- tree names
* Output can be large - check web Admin->ckp for tree sizes */
bool all, one = false;
i_list = require_name(trf_root, "list", 1, NULL, reply, siz);
if (!i_list)
return strdup(reply);
list = transfer_data(i_list);
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
rows = 0;
all = (strcmp(list, "all") == 0);
K_RLOCK(events_free);
if (all || strcmp(list, "user") == 0) {
one = true;
event_tree(events_user_root, "user", reply, siz, buf,
&off, &len, &rows);
}
if (all || strcmp(list, "ip") == 0) {
one = true;
event_tree(events_ip_root, "ip", reply, siz, buf,
&off, &len, &rows);
}
if (all || strcmp(list, "ipc") == 0) {
one = true;
event_tree(events_ipc_root, "ipc", reply, siz, buf,
&off, &len, &rows);
}
if (all || strcmp(list, "hash") == 0) {
one = true;
event_tree(events_hash_root, "hash", reply, siz, buf,
&off, &len, &rows);
}
K_RUNLOCK(events_free);
if (!one) {
free(buf);
snprintf(reply, siz, "unknown stats list '%s'", list);
LOGERR("%s() %s.%s", __func__, id, reply);
return strdup(reply);
}
snprintf(tmp, sizeof(tmp), "rows=%d", rows);
APPEND_REALLOC(buf, off, len, tmp);
} else if (strcasecmp(action, "ips") == 0) {
// List the ips tree contents
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
rows = 0;
K_RLOCK(ips_free);
i_item = first_in_ktree(ips_root, ctx);
while (i_item) {
DATA_IPS(ips, i_item);
if (CURRENT(&(ips->expirydate))) {
snprintf(tmp, sizeof(tmp), "group:%d=%s%c",
rows, ips->group, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "ip:%d=%s%c",
rows, ips->ip, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "description:%d=%s%c",
rows, ips->description ? : EMPTY,
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "lifetime:%d=%d%c",
rows, ips->lifetime, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "log:%d=%c%c",
rows, ips->log ? TRUE_CHR : FALSE_CHR,
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(reply, siz, CDTRF":%d=%ld%c",
rows++, ips->createdate.tv_sec,
FLDSEP);
APPEND_REALLOC(buf, off, len, reply);
}
i_item = next_in_ktree(ctx);
}
K_RUNLOCK(ips_free);
snprintf(tmp, sizeof(tmp), "rows=%d", rows);
APPEND_REALLOC(buf, off, len, tmp);
} else if (strcasecmp(action, "ban") == 0) {
// Ban the ip with optional lifetime
bool found = false;
oldlife = 0;
i_ip = require_name(trf_root, "ip", 1, NULL, reply, siz);
if (!i_ip)
return strdup(reply);
ip = transfer_data(i_ip);
i_lifetime = optional_name(trf_root, "lifetime", 1,
(char *)intpatt, reply, siz);
if (i_lifetime)
lifetime = atoi(transfer_data(i_lifetime));
else {
if (*reply)
return strdup(reply);
// default to almost 42 years :)
lifetime = 60*60*24*365*42;
}
i_des = optional_name(trf_root, "des", 1, NULL, reply, siz);
if (i_des)
des = transfer_data(i_des);
else {
if (*reply)
return strdup(reply);
des = NULL;
}
K_WLOCK(ips_free);
i_item = find_ips(IPS_GROUP_BAN, ip);
if (i_item) {
found = true;
DATA_IPS(ips, i_item);
oldlife = ips->lifetime;
ips->lifetime = lifetime;
// Don't change it if it's not supplied
if (des) {
LIST_MEM_SUB(ips_free, ips->description);
FREENULL(ips->description);
ips->description = strdup(des);
LIST_MEM_ADD(ips_free, ips->description);
}
} else {
ips_add(IPS_GROUP_BAN, ip, des, true, false,
lifetime, true);
}
K_WUNLOCK(ips_free);
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
if (found) {
snprintf(tmp, sizeof(tmp), "already %s %d->%d",
ip, oldlife, lifetime);
} else
snprintf(tmp, sizeof(tmp), "ban %s %d", ip, lifetime);
APPEND_REALLOC(buf, off, len, tmp);
} else if (strcasecmp(action, "unban") == 0) {
/* Unban the ip - sets lifetime to 1 meaning
* it expires 1s after it was created */
bool found = false;
i_ip = require_name(trf_root, "ip", 1, NULL, reply, siz);
if (!i_ip)
return strdup(reply);
ip = transfer_data(i_ip);
K_WLOCK(ips_free);
i_item = find_ips(IPS_GROUP_BAN, ip);
if (i_item) {
found = true;
DATA_IPS(ips, i_item);
ips->lifetime = 1;
}
K_WUNLOCK(ips_free);
APPEND_REALLOC_INIT(buf, off, len);
if (found) {
APPEND_REALLOC(buf, off, len, "ok.");
APPEND_REALLOC(buf, off, len, ip);
APPEND_REALLOC(buf, off, len, " unbanned");
} else
APPEND_REALLOC(buf, off, len, "ERR.unknown ip");
} else {
snprintf(reply, siz, "unknown action '%s'", action);
LOGERR("%s() %s.%s", __func__, id, reply);
return strdup(reply);
}
return buf;
}
/* The socket command format is as follows:
* Basic structure:
* cmd.ID.fld1=value1 FLDSEP fld2=value2 FLDSEP fld3=...
@ -7594,5 +7877,6 @@ struct CMDS ckdb_cmds[] = {
{ CMD_BTCSET, "btcset", false, false, cmd_btcset, SEQ_NONE, ACCESS_SYSTEM },
{ CMD_QUERY, "query", false, false, cmd_query, SEQ_NONE, ACCESS_SYSTEM },
{ CMD_LOCKS, "locks", false, false, cmd_locks, SEQ_NONE, ACCESS_SYSTEM },
{ CMD_EVENTS, "events", false, false, cmd_events, SEQ_NONE, ACCESS_SYSTEM },
{ CMD_END, NULL, false, false, NULL, SEQ_NONE, 0 }
};

17
src/ckdb_data.c

@ -4507,14 +4507,21 @@ int check_events(EVENTS *events)
K_ITEM *i_item, *e_item = NULL, *tmp_item, *u_item;
K_TREE_CTX ctx[1];
EVENTS *e = NULL;
char cmd[MAX_ALERT_CMD+1];
int count, secs;
int tyme, limit, lifetime;
char name[TXT_SML+1];
pid_t pid;
tv_t now;
K_RLOCK(event_limits_free);
if (ckdb_alert_cmd)
STRNCPY(cmd, ckdb_alert_cmd);
else
cmd[0] = '\0';
K_RUNLOCK(event_limits_free);
// No way to send an alert, so don't test
if (!ckdb_alert_cmd)
if (!cmd[0])
return EVENT_OK;
K_RLOCK(ips_free);
@ -4757,7 +4764,7 @@ int check_events(EVENTS *events)
cause_str(cause));
FREENULL(st);
ips_add(IPS_GROUP_BAN, events->createinet,
(char *)cause_str(cause), true, false, lifetime);
(char *)cause_str(cause), true, false, lifetime, false);
pid = fork();
if (pid < 0) {
LOGERR("%s() ALERT failed to fork (%d)",
@ -4770,9 +4777,9 @@ int check_events(EVENTS *events)
snprintf(buf3, sizeof(buf3), "%d", tyme);
snprintf(buf4, sizeof(buf4), "%d", lifetime);
st = safe_text_nonull(events->createby);
execl(ckdb_alert_cmd, ckdb_alert_cmd, buf1, name,
buf2, buf3, buf4, events->createinet,
st, cause_str(cause), NULL);
execl(cmd, cmd, buf1, name, buf2, buf3, buf4,
events->createinet, st,
cause_str(cause), NULL);
LOGERR("%s() ALERT fork failed to execute (%d)",
__func__, errno);
FREENULL(st);

5
src/ckdb_dbio.c

@ -6253,7 +6253,8 @@ bool payouts_fill(PGconn *conn)
return ok;
}
void ips_add(char *group, char *ip, char *des, bool log, bool cclass, int life)
void ips_add(char *group, char *ip, char *des, bool log, bool cclass, int life,
bool locked)
{
K_ITEM *i_item, *i2_item;
IPS *ips, *ips2;
@ -6262,6 +6263,7 @@ void ips_add(char *group, char *ip, char *des, bool log, bool cclass, int life)
bool ok;
setnow(&now);
if (!locked)
K_WLOCK(ips_free);
i_item = k_unlink_head(ips_free);
DATA_IPS(ips, i_item);
@ -6304,6 +6306,7 @@ void ips_add(char *group, char *ip, char *des, bool log, bool cclass, int life)
} else
k_add_head(ips_free, i2_item);
}
if (!locked)
K_WUNLOCK(ips_free);
}

Loading…
Cancel
Save