diff --git a/src/datum_api.c b/src/datum_api.c index 798c2e4..0ebf38b 100644 --- a/src/datum_api.c +++ b/src/datum_api.c @@ -35,6 +35,8 @@ // This is quick and dirty for now. Will be improved over time. +#include +#include #include #include #include @@ -388,6 +390,30 @@ void datum_api_cmd_kill_client(int tid, int cid) { } } +static enum MHD_Result datum_api_cmd_formdata(void * const cls, const enum MHD_ValueKind kind, const char * const key, const char * const filename, const char * const content_type, const char * const transfer_encoding, const char * const data, const uint64_t off, const size_t size) { + assert(cls); + const char * * const redirect_p = cls; + if (!key) return MHD_YES; + if (off) return MHD_YES; + + if (!strcmp(key, "empty_thread")) { + const int tid = datum_atoi_strict(data, size); + if (tid == -1) return MHD_YES; + datum_api_cmd_empty_thread(tid); + *redirect_p = "/threads"; + } else if (!strcmp(key, "kill_client")) { + const char * const underscore_pos = memchr(data, '_', size); + if (!underscore_pos) return MHD_YES; + const size_t tid_size = underscore_pos - data; + const int tid = datum_atoi_strict(data, tid_size); + const int cid = datum_atoi_strict(&underscore_pos[1], size - tid_size - 1); + datum_api_cmd_kill_client(tid, cid); + *redirect_p = "/clients"; + } + + return MHD_YES; +} + int datum_api_cmd(struct MHD_Connection *connection, char *post, int len) { struct MHD_Response *response; char output[1024]; @@ -439,6 +465,29 @@ int datum_api_cmd(struct MHD_Connection *connection, char *post, int len) { } } } + } else { + const char *redirect; + struct MHD_PostProcessor * const cmd_pp = MHD_create_post_processor(connection, 32768, datum_api_cmd_formdata, &redirect); + if (!cmd_pp) { +err: + response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT); + http_resp_prevent_caching(response); + ret = MHD_queue_response(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, response); + MHD_destroy_response(response); + return ret; + } + if (MHD_YES != MHD_post_process(cmd_pp, post, len) || !redirect) { + MHD_destroy_post_processor(cmd_pp); + goto err; + } + MHD_destroy_post_processor(cmd_pp); + + response = MHD_create_response_from_buffer(0, "", MHD_RESPMEM_PERSISTENT); + http_resp_prevent_caching(response); + MHD_add_response_header(response, "Location", redirect); + ret = MHD_queue_response(connection, MHD_HTTP_FOUND, response); + MHD_destroy_response(response); + return ret; } } @@ -517,7 +566,7 @@ int datum_api_thread_dashboard(struct MHD_Connection *connection) { tsms = current_time_millis(); sz = snprintf(output, max_sz-1-sz, "%s", www_threads_top_html); - sz += snprintf(&output[sz], max_sz-1-sz, ""); + sz += snprintf(&output[sz], max_sz-1-sz, "
TID Connection Count Sub Count Approx. Hashrate Command
"); for(j=0;jmax_threads;j++) { thr = 0.0; subs = 0; @@ -541,10 +590,10 @@ int datum_api_thread_dashboard(struct MHD_Connection *connection) { } } if (conns) { - sz += snprintf(&output[sz], max_sz-1-sz, "", j, conns, subs, thr, j); + sz += snprintf(&output[sz], max_sz-1-sz, "", j, conns, subs, thr, j, j); } } - sz += snprintf(&output[sz], max_sz-1-sz, "
TID Connection Count Sub Count Approx. Hashrate Command
%d %d %d %.2f Th/s
%d %d %d %.2f Th/s
"); + sz += snprintf(&output[sz], max_sz-1-sz, ""); sz += snprintf(&output[sz], max_sz-1-sz, ""); sz += snprintf(&output[sz], max_sz-1-sz, "%s", www_foot_html); @@ -580,7 +629,7 @@ int datum_api_client_dashboard(struct MHD_Connection *connection) { tsms = current_time_millis(); sz = snprintf(output, max_sz-1-sz, "%s", www_clients_top_html); - sz += snprintf(&output[sz], max_sz-1-sz, ""); + sz += snprintf(&output[sz], max_sz-1-sz, "
TID/CID RemHost Auth Username Subbed Last Accepted VDiff DiffA (A) DiffR (R) Hashrate (age) Coinbase UserAgent Command
"); for(j=0;jmax_threads;j++) { for(ii=0;iimax_clients_thread;ii++) { @@ -639,12 +688,12 @@ int datum_api_client_dashboard(struct MHD_Connection *connection) { sz += snprintf(&output[sz], max_sz-1-sz, ""); } - sz += snprintf(&output[sz], max_sz-1-sz, "", j, ii); + sz += snprintf(&output[sz], max_sz-1-sz, "", j, ii, j, ii); } } } - sz += snprintf(&output[sz], max_sz-1-sz, "
TID/CID RemHost Auth Username Subbed Last Accepted VDiff DiffA (A) DiffR (R) Hashrate (age) Coinbase UserAgent Command
Not Subscribed

Total active hashrate estimate: %.2f Th/s

", thr); + sz += snprintf(&output[sz], max_sz-1-sz, "

Total active hashrate estimate: %.2f Th/s

", thr); sz += snprintf(&output[sz], max_sz-1-sz, ""); sz += snprintf(&output[sz], max_sz-1-sz, "%s", www_foot_html); diff --git a/src/datum_utils.c b/src/datum_utils.c index 2c00a4d..3aabba9 100644 --- a/src/datum_utils.c +++ b/src/datum_utils.c @@ -33,6 +33,7 @@ * */ +#include #include #include #include @@ -703,3 +704,18 @@ uint64_t datum_siphash_mod8(const void *src, uint64_t sz, const unsigned char ke SIPHASH_DOUBLE_ROUND(v0,v1,v2,v3); return (v0 ^ v1) ^ (v2 ^ v3); } + +// Uses a fixed-size buffer; positive only; digits only +// Returns -1 on failure +int datum_atoi_strict(const char * const s, const size_t size) { + if (!size) return -1; + assert(s); + int ret = 0; + for (size_t i = 0; i < size; ++i) { + if (s[i] < '0' || s[i] > '9') return -1; + int digit = s[i] - '0'; + if (ret > (INT_MAX - digit) / 10) return -1; + ret = (ret * 10) + digit; + } + return ret; +} diff --git a/src/datum_utils.h b/src/datum_utils.h index 363c35a..cb18c30 100644 --- a/src/datum_utils.h +++ b/src/datum_utils.h @@ -69,6 +69,7 @@ long double calc_network_difficulty(const char *bits_hex); unsigned char floorPoT(uint64_t x); uint64_t datum_siphash(const void *src, uint64_t sz, const unsigned char key[16]); uint64_t datum_siphash_mod8(const void *src, uint64_t sz, const unsigned char key[16]); +int datum_atoi_strict(const char *s, size_t size); static inline