From c21fc065608894f53356626f751d62ceb19cf251 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 27 Jun 2012 21:28:18 +1000 Subject: [PATCH 01/12] define API option --api-groups --- cgminer.c | 15 ++++++++++++++- miner.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cgminer.c b/cgminer.c index 69181b00..c946b6a4 100644 --- a/cgminer.c +++ b/cgminer.c @@ -133,6 +133,7 @@ bool opt_autofan; bool opt_autoengine; bool opt_noadl; char *opt_api_allow = NULL; +char *opt_api_groups; char *opt_api_description = PACKAGE_STRING; int opt_api_port = 4028; bool opt_api_listen; @@ -682,6 +683,13 @@ static char *set_api_allow(const char *arg) return NULL; } +static char *set_api_groups(const char *arg) +{ + opt_set_charp(arg, &opt_api_groups); + + return NULL; +} + static char *set_api_description(const char *arg) { opt_set_charp(arg, &opt_api_description); @@ -732,10 +740,13 @@ static struct opt_table opt_config_table[] = { #endif OPT_WITH_ARG("--api-allow", set_api_allow, NULL, NULL, - "Allow API access only to the given list of IP[/Prefix] addresses[/subnets]"), + "Allow API access only to the given list of [G:]IP[/Prefix] addresses[/subnets]"), OPT_WITH_ARG("--api-description", set_api_description, NULL, NULL, "Description placed in the API status header, default: cgminer version"), + OPT_WITH_ARG("--api-groups", + set_api_groups, NULL, NULL, + "API one letter groups G:cmd:cmd[,P:cmd:*...] defining the cmds a groups can use"), OPT_WITHOUT_ARG("--api-listen", opt_set_bool, &opt_api_listen, "Enable API, default: disabled"), @@ -2871,6 +2882,8 @@ void write_config(FILE *fcfg) fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow); if (strcmp(opt_api_description, PACKAGE_STRING) != 0) fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description); + if (opt_api_groups) + fprintf(fcfg, ",\n\"api-groups\" : \"%s\"", opt_api_groups); if (opt_icarus_timing) fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing); fputs("\n}", fcfg); diff --git a/miner.h b/miner.h index 5b44ceef..bb567598 100644 --- a/miner.h +++ b/miner.h @@ -524,6 +524,7 @@ extern bool opt_autofan; extern bool opt_autoengine; extern bool use_curses; extern char *opt_api_allow; +extern char *opt_api_groups; extern char *opt_api_description; extern int opt_api_port; extern bool opt_api_listen; From 659e50434ea2c84181d822bdd9719d5c35a9ef5b Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 28 Jun 2012 02:29:58 +1000 Subject: [PATCH 02/12] implement and document API option --api-groups --- API-README | 39 ++++++- README | 2 + api.c | 333 ++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 313 insertions(+), 61 deletions(-) diff --git a/API-README b/API-README index 6f5fbe12..fc71271e 100644 --- a/API-README +++ b/API-README @@ -19,8 +19,9 @@ IP addresses are automatically padded with extra '.0's as needed Without a /prefix is the same as specifying /32 0/0 means all IP addresses. The 'W:' on the front gives that address/subnet privileged access to commands -that modify cgminer. +that modify cgminer (thus all API commands) Without it those commands return an access denied status. +See --api-groups below to define other groups like W: Privileged access is checked in the order the IP addresses were supplied to "--api-allow" The first match determines the privilege level. @@ -28,6 +29,23 @@ Using the "--api-allow" option overides the "--api-network" option if they are both specified With "--api-allow", 127.0.0.1 is not by default given access unless specified +More groups (like the privileged group W:) can be defined using the +--api-groups command +Valid groups are only the letters A-V,X-Z and are not case sensitive +To give an IP address/subnet access to a group you the use group letter +in front of the IP address instead of W: e.g. P:192.168.0/32 +An IP address/subnet can only be a member of one group +A sample API group would be: + --api-groups P:switchpool:enablepool:addpool:disablepool:removepool:* +This would create a group 'P' that can do all current pool commands and all +non-priviliged commands - the '*' means all non-priviledged commands +Without the '*' the group would only have access to the pool commands +Defining multiple groups example: + --api-groups Q:quit:restart:*,S:save +This would define 2 groups: + Q: that can 'quit' and 'restart' as well as all non-priviledged commands + S: that can only 'save' and no other commands + The RPC API request can be either simple text or JSON. If the request is JSON (starts with '{'), it will reply with a JSON formatted @@ -86,8 +104,8 @@ The list of requests - a (*) means it requires privileged access - and replies a Request Reply Section Details ------- ------------- ------- - version VERSION CGMiner=cgminer version - API=API version + version VERSION CGMiner=cgminer, version + API=API| version config CONFIG Some miner configuration information: GPU Count=N, <- the number of GPUs @@ -243,6 +261,9 @@ The list of requests - a (*) means it requires privileged access - and replies a Device drivers are also able to add stats to the end of the details returned + check|cmd COMMAND Exists=Y/N, <- 'cmd' exists in this version + Access=Y/N| <- you have access to use 'cmd' + When you enable, disable or restart a GPU or PGA, you will also get Thread messages in the cgminer status window @@ -285,7 +306,17 @@ miner.php - an example web page to access the API Feature Changelog for external applications using the API: -API V1.12 +API V1.13 + +Added API commands: + 'checkcommand' + +Support was added to cgminer for API access groups with the --api-groups option +It's 100% backwards compatible with previous --api-access commands + +---------- + +API V1.12 (cgminer v2.4.3) Modified API commands: 'stats' - more pool stats added diff --git a/README b/README index 862ec544..58e89b93 100644 --- a/README +++ b/README @@ -119,6 +119,8 @@ Options for both config file and command line: This overrides --api-network and you must specify 127.0.0.1 if it is required W: in front of the IP address gives that address privileged access to all api commands --api-description Description placed in the API status header (default: cgminer version) +--api-groups API one letter groups G:cmd:cmd[,P:cmd:*...] + See API-README for usage --api-listen Listen for API requests (default: disabled) By default any command that does not just display data returns access denied See --api-allow to overcome this diff --git a/api.c b/api.c index ac5b9a6b..13cb11c9 100644 --- a/api.c +++ b/api.c @@ -158,6 +158,7 @@ static char *msg_buffer = NULL; static SOCKETTYPE sock = INVSOCK; static const char *UNAVAILABLE = " - API will not be available"; +static const char *GROUPDIS = " - groups will be disabled"; static const char *BLANK = ""; static const char *COMMA = ","; @@ -165,7 +166,7 @@ static const char SEPARATOR = '|'; #define SEPSTR "|" static const char GPUSEP = ','; -static const char *APIVERSION = "1.12"; +static const char *APIVERSION = "1.13"; static const char *DEAD = "Dead"; static const char *SICK = "Sick"; static const char *NOSTART = "NoStart"; @@ -243,6 +244,7 @@ static const char *OSINFO = #define _BYE "BYE" #define _RESTART "RESTART" #define _MINESTATS "STATS" +#define _CHECK "CHECK" static const char ISJSON = '{'; #define JSON0 "{" @@ -277,6 +279,7 @@ static const char ISJSON = '{'; #define JSON_RESTART JSON1 _RESTART JSON1 #define JSON_CLOSE JSON3 #define JSON_MINESTATS JSON1 _MINESTATS JSON2 +#define JSON_CHECK JSON1 _CHECK JSON2 #define JSON_END JSON4 static const char *JSON_COMMAND = "command"; @@ -364,6 +367,8 @@ static const char *JSON_PARAMETER = "parameter"; #define MSG_REMPOOL 68 #define MSG_DEVDETAILS 69 #define MSG_MINESTATS 70 +#define MSG_MISCHK 71 +#define MSG_CHECK 72 enum code_severity { SEVERITY_ERR, @@ -507,6 +512,8 @@ struct CODES { { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, { SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "CGMiner stats" }, + { SEVERITY_ERR, MSG_MISCHK, PARAM_NONE, "Missing check cmd" }, + { SEVERITY_SUCC, MSG_CHECK, PARAM_NONE, "Check command" }, { SEVERITY_FAIL, 0, 0, NULL } }; @@ -525,9 +532,25 @@ static time_t when = 0; // when the request occurred struct IP4ACCESS { in_addr_t ip; in_addr_t mask; - bool writemode; + char group; }; +#define GROUP(g) (toupper(g)) +#define PRIVGROUP GROUP('W') +#define NOPRIVGROUP GROUP('R') +#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) +#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) +#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) +#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) +#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) + +struct APIGROUPS { + // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search + char *commands; +} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) + +static bool groups_enabled = false; + static struct IP4ACCESS *ipaccess = NULL; static int ips = 0; @@ -796,7 +819,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) return msg_buffer; } -static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { sprintf(io_buffer, isjson ? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE @@ -805,7 +828,7 @@ static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, VERSION, APIVERSION); } -static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; int gpucount = 0; @@ -1003,7 +1026,7 @@ static void cpustatus(int cpu, bool isjson) } #endif -static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { int devcount = 0; int numgpu = 0; @@ -1069,7 +1092,7 @@ static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b } #ifdef HAVE_OPENCL -static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int id; @@ -1103,7 +1126,7 @@ static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) } #endif #ifdef HAVE_AN_FPGA -static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int numpga = numpgas(); int id; @@ -1137,7 +1160,7 @@ static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcat(io_buffer, JSON_CLOSE); } -static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int numpga = numpgas(); struct thr_info *thr; @@ -1193,7 +1216,7 @@ static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_PGAENA, id, NULL, isjson)); } -static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int numpga = numpgas(); int id; @@ -1234,7 +1257,7 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) #endif #ifdef WANT_CPUMINE -static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int id; @@ -1268,7 +1291,7 @@ static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) } #endif -static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; char *status, *lp; @@ -1345,7 +1368,7 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, strcat(io_buffer, JSON_CLOSE); } -static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { double utility, mhs; @@ -1379,7 +1402,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo #endif } #ifdef HAVE_OPENCL -static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { struct thr_info *thr; int gpu; @@ -1425,7 +1448,7 @@ static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_GPUREN, id, NULL, isjson)); } -static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int id; @@ -1455,7 +1478,7 @@ static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_GPUDIS, id, NULL, isjson)); } -static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int id; @@ -1480,7 +1503,7 @@ static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_GPUREI, id, NULL, isjson)); } #endif -static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; int numgpu = 0; @@ -1499,8 +1522,7 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo strcat(io_buffer, buf); } - -static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; int count = 0; @@ -1519,7 +1541,7 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo strcat(io_buffer, buf); } -static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; int count = 0; @@ -1538,7 +1560,7 @@ static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo strcat(io_buffer, buf); } -static void switchpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void switchpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { struct pool *pool; int id; @@ -1619,7 +1641,7 @@ exitsama: return false; } -static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char *url, *user, *pass; char *ptr; @@ -1647,7 +1669,7 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) ptr = NULL; } -static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { struct pool *pool; int id; @@ -1681,7 +1703,7 @@ static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_ENAPOOL, id, NULL, isjson)); } -static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { struct pool *pool; int id; @@ -1720,7 +1742,7 @@ static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_DISPOOL, id, NULL, isjson)); } -static void removepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void removepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { struct pool *pool; char *rpc_url; @@ -1806,7 +1828,7 @@ static bool splitgpuvalue(char *param, int *gpu, char **value, bool isjson) return true; } -static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { int id; char *value; @@ -1835,7 +1857,7 @@ static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson) strcpy(io_buffer, message(MSG_GPUINT, id, intensitystr, isjson)); } -static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #ifdef HAVE_ADL int id; @@ -1856,7 +1878,7 @@ static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool #endif } -static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #ifdef HAVE_ADL int id; @@ -1877,7 +1899,7 @@ static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b #endif } -static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #ifdef HAVE_ADL int id; @@ -1898,7 +1920,7 @@ static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool #endif } -static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #ifdef HAVE_ADL int id; @@ -1919,7 +1941,7 @@ static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo #endif } #endif -void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { if (isjson) strcpy(io_buffer, JSON_START JSON_BYE); @@ -1930,7 +1952,7 @@ void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson do_a_quit = true; } -void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { if (isjson) strcpy(io_buffer, JSON_START JSON_RESTART); @@ -1941,12 +1963,12 @@ void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isj do_a_restart = true; } -void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { strcpy(io_buffer, message(MSG_ACCOK, 0, NULL, isjson)); } -void notifystatus(int device, struct cgpu_info *cgpu, bool isjson) +void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; char *reason; @@ -2000,7 +2022,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson) strcat(io_buffer, buf); } -static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { int i; @@ -2017,13 +2039,13 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool } for (i = 0; i < total_devices; i++) - notifystatus(i, devices[i], isjson); + notifystatus(i, devices[i], isjson, group); if (isjson) strcat(io_buffer, JSON_CLOSE); } -static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char buf[TMPBUFSIZ]; struct cgpu_info *cgpu; @@ -2059,7 +2081,7 @@ static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, strcat(io_buffer, JSON_CLOSE); } -void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson) +void dosave(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char filename[PATH_MAX]; FILE *fcfg; @@ -2135,7 +2157,8 @@ static int itemstats(int i, char *id, struct cgminer_stats *stats, struct cgmine return i; } -static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) + +static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { char extra[TMPBUFSIZ]; char id[20]; @@ -2174,10 +2197,12 @@ static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, strcat(io_buffer, JSON_CLOSE); } +static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); + struct CMDS { char *name; - void (*func)(SOCKETTYPE, char *, bool); - bool requires_writemode; + void (*func)(SOCKETTYPE, char *, bool, char); + bool iswritemode; } cmds[] = { { "version", apiversion, false }, { "config", minerconfig, false }, @@ -2220,9 +2245,50 @@ struct CMDS { { "devdetails", devdetails, false }, { "restart", dorestart, true }, { "stats", minerstats, false }, + { "check", checkcommand, false }, { NULL, NULL, false } }; +static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group) +{ + char buf[TMPBUFSIZ]; + char cmdbuf[100]; + bool found, access; + int i; + + if (param == NULL || *param == '\0') { + strcpy(io_buffer, message(MSG_MISCHK, 0, NULL, isjson)); + return; + } + + found = false; + access = false; + for (i = 0; cmds[i].name != NULL; i++) { + if (strcmp(cmds[i].name, param) == 0) { + found = true; + + sprintf(cmdbuf, "|%s|", param); + if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) + access = true; + + break; + } + } + + strcpy(io_buffer, message(MSG_CHECK, 0, NULL, isjson)); + + sprintf(buf, isjson + ? "," JSON_CHECK "{\"Exists\":\"%s\",\"Access\":\"%s\"}" JSON_CLOSE + : _CHECK ",Exists=%s,Access=%s" SEPSTR, + found ? YES : NO, + access ? YES : NO); + + strcat(io_buffer, buf); + + if (isjson) + strcat(io_buffer, JSON_CLOSE); +} + static void send_result(SOCKETTYPE c, bool isjson) { int n; @@ -2277,7 +2343,154 @@ static void tidyup(__maybe_unused void *arg) } /* - * Interpret [R|W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option + * Interpret --api-groups G:cmd1:cmd2:cmd3,P:cmd4,*,... + */ +static void setup_groups() +{ + char *buf, *ptr, *next, *colon; + char group; + char commands[TMPBUFSIZ]; + char cmdbuf[100]; + char *cmd; + bool addstar, did; + int i; + + buf = malloc(strlen(opt_api_groups) + 1); + if (unlikely(!buf)) + quit(1, "Failed to malloc ipgroups buf"); + + strcpy(buf, opt_api_groups); + + next = buf; + // for each group defined + while (next && *next) { + ptr = next; + next = strchr(ptr, ','); + if (next) + *(next++) = '\0'; + + // Validate the group + if (*(ptr+1) != ':') { + colon = strchr(ptr, ':'); + if (colon) + *colon = '\0'; + applog(LOG_WARNING, "API invalid group name '%s'%s", ptr, GROUPDIS); + goto shin; + } + + group = GROUP(*ptr); + if (!VALIDGROUP(group)) { + applog(LOG_WARNING, "API invalid group name '%c'%s", *ptr, GROUPDIS); + goto shin; + } + + if (group == PRIVGROUP) { + applog(LOG_WARNING, "API group name can't be '%c'%s", PRIVGROUP, GROUPDIS); + goto shin; + } + + if (group == NOPRIVGROUP) { + applog(LOG_WARNING, "API group name can't be '%c'%s", NOPRIVGROUP, GROUPDIS); + goto shin; + } + + if (apigroups[GROUPOFFSET(group)].commands != NULL) { + applog(LOG_WARNING, "API duplicate group name '%c'%s", *ptr, GROUPDIS); + goto shin; + } + + ptr += 2; + + // Validate the command list (and handle '*') + cmd = &(commands[0]); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + addstar = false; + while (ptr && *ptr) { + colon = strchr(ptr, ':'); + if (colon) + *(colon++) = '\0'; + + if (strcmp(ptr, "*") == 0) + addstar = true; + else { + did = false; + for (i = 0; cmds[i].name != NULL; i++) { + if (strcasecmp(ptr, cmds[i].name) == 0) { + did = true; + break; + } + } + if (did) { + // skip duplicates + sprintf(cmdbuf, "|%s|", cmds[i].name); + if (strstr(commands, cmdbuf) == NULL) { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } else { + applog(LOG_WARNING, "API unknown command '%s' in group '%c'%s", ptr, group, GROUPDIS); + goto shin; + } + } + + ptr = colon; + } + + // * = allow all non-iswritemode commands + if (addstar) { + for (i = 0; cmds[i].name != NULL; i++) { + if (cmds[i].iswritemode == false) { + // skip duplicates + sprintf(cmdbuf, "|%s|", cmds[i].name); + if (strstr(commands, cmdbuf) == NULL) { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } + } + } + + ptr = apigroups[GROUPOFFSET(group)].commands = malloc(strlen(commands) + 1); + if (unlikely(!ptr)) + quit(1, "Failed to malloc group commands buf"); + + strcpy(ptr, commands); + } + + // Now define R (NOPRIVGROUP) as all non-iswritemode commands + cmd = &(commands[0]); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + for (i = 0; cmds[i].name != NULL; i++) { + if (cmds[i].iswritemode == false) { + strcpy(cmd, cmds[i].name); + cmd += strlen(cmds[i].name); + *(cmd++) = SEPARATOR; + *cmd = '\0'; + } + } + + ptr = apigroups[GROUPOFFSET(NOPRIVGROUP)].commands = malloc(strlen(commands) + 1); + if (unlikely(!ptr)) + quit(1, "Failed to malloc noprivgroup commands buf"); + + strcpy(ptr, commands); + + // W (PRIVGROUP) is handled as a special case since it simply means all commands + + groups_enabled = true; +shin: + free(buf); + return; +} + +/* + * Interpret [W:]IP[/Prefix][,[R|W:]IP2[/Prefix2][,...]] --api-allow option * special case of 0/0 allows /0 (means all IP addresses) */ #define ALLIP4 "0/0" @@ -2288,7 +2501,7 @@ static void setup_ipaccess() { char *buf, *ptr, *comma, *slash, *dot; int ipcount, mask, octet, i; - bool writemode; + char group; buf = malloc(strlen(opt_api_allow) + 1); if (unlikely(!buf)) @@ -2322,16 +2535,16 @@ static void setup_ipaccess() if (comma) *(comma++) = '\0'; - writemode = false; + group = NOPRIVGROUP; if (isalpha(*ptr) && *(ptr+1) == ':') { - if (tolower(*ptr) == 'w') - writemode = true; + if (DEFINEDGROUP(*ptr)) + group = GROUP(*ptr); ptr += 2; } - ipaccess[ips].writemode = writemode; + ipaccess[ips].group = group; if (strcmp(ptr, ALLIP4) == 0) ipaccess[ips].ip = ipaccess[ips].mask = 0; @@ -2421,10 +2634,11 @@ void api(int api_thr_id) struct sockaddr_in serv; struct sockaddr_in cli; socklen_t clisiz; + char cmdbuf[100]; char *cmd; char *param; bool addrok; - bool writemode; + char group; json_error_t json_err; json_t *json_config; json_t *json_val; @@ -2445,6 +2659,9 @@ void api(int api_thr_id) return; } + if (opt_api_groups) + setup_groups(); + if (opt_api_allow) { setup_ipaccess(); @@ -2523,15 +2740,16 @@ void api(int api_thr_id) connectaddr = inet_ntoa(cli.sin_addr); addrok = false; - writemode = false; + group = NOPRIVGROUP; if (opt_api_allow) { - for (i = 0; i < ips; i++) { - if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) { - addrok = true; - writemode = ipaccess[i].writemode; - break; + if (groups_enabled) + for (i = 0; i < ips; i++) { + if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) { + addrok = true; + group = ipaccess[i].group; + break; + } } - } } else { if (opt_api_network) addrok = true; @@ -2622,12 +2840,13 @@ void api(int api_thr_id) if (!did) for (i = 0; cmds[i].name != NULL; i++) { if (strcmp(cmd, cmds[i].name) == 0) { - if (cmds[i].requires_writemode && !writemode) { + sprintf(cmdbuf, "|%s|", cmd); + if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) + (cmds[i].func)(c, param, isjson, group); + else { strcpy(io_buffer, message(MSG_ACCDENY, 0, cmds[i].name, isjson)); applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name); } - else - (cmds[i].func)(c, param, isjson); send_result(c, isjson); did = true; From 39ff15753cd863aceae7f578ad203de1ed4039fc Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 28 Jun 2012 03:34:16 +1000 Subject: [PATCH 03/12] API-README --api-groups corrections --- API-README | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/API-README b/API-README index fc71271e..e523f4ea 100644 --- a/API-README +++ b/API-README @@ -31,8 +31,11 @@ With "--api-allow", 127.0.0.1 is not by default given access unless specified More groups (like the privileged group W:) can be defined using the --api-groups command -Valid groups are only the letters A-V,X-Z and are not case sensitive -To give an IP address/subnet access to a group you the use group letter +Valid groups are only the letters A-Z (except R & W are predfined) and are +not case sensitive +The R: group is the same as not privileged access +The W: group is (as stated) privileged access (thus all API commands) +To give an IP address/subnet access to a group you use the group letter in front of the IP address instead of W: e.g. P:192.168.0/32 An IP address/subnet can only be a member of one group A sample API group would be: @@ -309,7 +312,7 @@ Feature Changelog for external applications using the API: API V1.13 Added API commands: - 'checkcommand' + 'check' Support was added to cgminer for API access groups with the --api-groups option It's 100% backwards compatible with previous --api-access commands From 05b8f5b0996e20cca41bbac8088b9f65409c42e3 Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 28 Jun 2012 05:59:31 +1000 Subject: [PATCH 04/12] api.c fix json already closed --- api.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/api.c b/api.c index 13cb11c9..c4a0b9f9 100644 --- a/api.c +++ b/api.c @@ -2284,9 +2284,6 @@ static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, access ? YES : NO); strcat(io_buffer, buf); - - if (isjson) - strcat(io_buffer, JSON_CLOSE); } static void send_result(SOCKETTYPE c, bool isjson) From f0c2f8dd93d586e7d3b97767eab141399594f7c9 Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 28 Jun 2012 07:43:25 +1000 Subject: [PATCH 05/12] API-README spelling --- API-README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API-README b/API-README index e523f4ea..52f67ae4 100644 --- a/API-README +++ b/API-README @@ -31,7 +31,7 @@ With "--api-allow", 127.0.0.1 is not by default given access unless specified More groups (like the privileged group W:) can be defined using the --api-groups command -Valid groups are only the letters A-Z (except R & W are predfined) and are +Valid groups are only the letters A-Z (except R & W are predefined) and are not case sensitive The R: group is the same as not privileged access The W: group is (as stated) privileged access (thus all API commands) From 07045055e94839fff8ffb02d7739ba854b14b889 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 28 Jun 2012 09:07:22 +1000 Subject: [PATCH 06/12] Revert "Restarting cgminer from within after ADL has been corrupted only leads to a crash. Display a warning only and disable fanspeed monitoring." This reverts commit 07212db106a1cc654affe3b95bf8acff7b8ed752. Reverting this did not fix the crashes people were having with ADL failing after a week and removed the functionality this patch originally intended. --- adl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adl.c b/adl.c index c7393f48..1d7a5577 100644 --- a/adl.c +++ b/adl.c @@ -692,7 +692,11 @@ int gpu_fanpercent(int gpu) unlock_adl(); if (unlikely(ga->has_fanspeed && ret == -1)) { applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu); - applog(LOG_WARNING, "You will need to start cgminer from scratch to correct this"); + if (opt_restart) { + applog(LOG_WARNING, "Restart enabled, will restart cgminer"); + applog(LOG_WARNING, "You can disable this with the --no-restart option"); + app_restart(); + } applog(LOG_WARNING, "Disabling fanspeed monitoring on this device"); ga->has_fanspeed = false; if (ga->twin) { From 55aaa7c1ccec49f6c2fcba5d2bcd099434485f85 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 28 Jun 2012 09:11:29 +1000 Subject: [PATCH 07/12] Slightly different message since restart may not be successful. --- adl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adl.c b/adl.c index 1d7a5577..4c75f3fc 100644 --- a/adl.c +++ b/adl.c @@ -693,7 +693,7 @@ int gpu_fanpercent(int gpu) if (unlikely(ga->has_fanspeed && ret == -1)) { applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu); if (opt_restart) { - applog(LOG_WARNING, "Restart enabled, will restart cgminer"); + applog(LOG_WARNING, "Restart enabled, will attempt to restart cgminer"); applog(LOG_WARNING, "You can disable this with the --no-restart option"); app_restart(); } From e16452f09f78ed69cd8da6275ef05cf2b09b012f Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 28 Jun 2012 09:26:33 +1000 Subject: [PATCH 08/12] Adjust the fanspeed by the magnitude of the temperature difference when in the optimal range. --- adl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/adl.c b/adl.c index 4c75f3fc..7c2bbdea 100644 --- a/adl.c +++ b/adl.c @@ -13,6 +13,7 @@ #include #include +#include #ifdef HAVE_CURSES #include @@ -1050,14 +1051,16 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool * applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis); newpercent = ga->targetfan - 1; } else { + int tdiff = round(temp - lasttemp); + /* We're in the optimal range, make minor adjustments if the * temp is still drifting */ - if (fanpercent > bot && temp < lasttemp && lasttemp < ga->targettemp) { + if (fanpercent > bot && tdiff < 0 && lasttemp < ga->targettemp) { applog(LOG_DEBUG, "Temperature dropping while in target range, decreasing fanspeed"); - newpercent = ga->targetfan - 1; - } else if (fanpercent < top && temp > lasttemp && temp > ga->targettemp - opt_hysteresis) { + newpercent = ga->targetfan + tdiff; + } else if (fanpercent < top && tdiff > 0 && temp > ga->targettemp - opt_hysteresis) { applog(LOG_DEBUG, "Temperature rising while in target range, increasing fanspeed"); - newpercent = ga->targetfan + 1; + newpercent = ga->targetfan + tdiff; } } From 29c0f7bd37a591a15fb79eece7761fb300293cf0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 28 Jun 2012 09:42:24 +1000 Subject: [PATCH 09/12] Detect large swings in temperature when below the target temperature range and change fan by amounts dependant on the value of tdiff. --- adl.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/adl.c b/adl.c index 7c2bbdea..8573e16f 100644 --- a/adl.c +++ b/adl.c @@ -1025,6 +1025,7 @@ static int set_powertune(int gpu, int iPercentage) static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *fan_window) { struct cgpu_info *cgpu = &gpus[gpu]; + int tdiff = round(temp - lasttemp); struct gpu_adl *ga = &cgpu->adl; int top = gpus[gpu].gpu_fan; int bot = gpus[gpu].min_fan; @@ -1039,7 +1040,7 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool * cgpu->device_last_not_well = time(NULL); cgpu->device_not_well_reason = REASON_DEV_OVER_HEAT; cgpu->dev_over_heat_count++; - } else if (temp > ga->targettemp && fanpercent < top && temp >= lasttemp) { + } else if (temp > ga->targettemp && fanpercent < top && tdiff >= 0) { applog(LOG_DEBUG, "Temperature over target, increasing fanspeed"); if (temp > ga->targettemp + opt_hysteresis) newpercent = ga->targetfan + 10; @@ -1047,11 +1048,17 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool * newpercent = ga->targetfan + 5; if (newpercent > top) newpercent = top; - } else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis && temp <= lasttemp) { - applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis); - newpercent = ga->targetfan - 1; + } else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis) { + /* Detect large swings of 5 degrees or more and change fan by + * a proportion more */ + if (tdiff <= 0) { + applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis); + newpercent = ga->targetfan - 1 + tdiff / 5; + } else if (tdiff >= 5) { + applog(LOG_DEBUG, "Temperature climbed %d while below target, increasing fanspeed", tdiff); + newpercent = ga->targetfan + tdiff / 5; + } } else { - int tdiff = round(temp - lasttemp); /* We're in the optimal range, make minor adjustments if the * temp is still drifting */ From 3267b534a81110ecda4abbd6aa485f5cbfdaa3cd Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 28 Jun 2012 10:43:52 +1000 Subject: [PATCH 10/12] Implement rudimentary X-Mining-Hashrate support. --- cgminer.c | 2 ++ miner.h | 1 + util.c | 23 +++++++++++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/cgminer.c b/cgminer.c index 25a2a772..cbb730cc 100644 --- a/cgminer.c +++ b/cgminer.c @@ -100,6 +100,7 @@ int opt_scantime = 60; int opt_expiry = 120; int opt_bench_algo = -1; static const bool opt_time = true; +unsigned long long global_hashrate; #ifdef HAVE_OPENCL int opt_dynamic_interval = 7; @@ -3400,6 +3401,7 @@ static void hashmeter(int thr_id, struct timeval *diff, local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0); decay_time(&rolling, local_mhashes_done / local_secs); + global_hashrate = roundl(rolling) * 1000000; timeval_subtract(&total_diff, &total_tv_end, &total_tv_start); total_secs = (double)total_diff.tv_sec + diff --git a/miner.h b/miner.h index bb567598..57fa774f 100644 --- a/miner.h +++ b/miner.h @@ -620,6 +620,7 @@ extern unsigned int local_work; extern unsigned int total_go, total_ro; extern const int opt_cutofftemp; extern int opt_log_interval; +extern unsigned long long global_hashrate; #ifdef HAVE_OPENCL typedef struct { diff --git a/util.c b/util.c index 703be545..ffc6a70a 100644 --- a/util.c +++ b/util.c @@ -256,17 +256,17 @@ json_t *json_rpc_call(CURL *curl, const char *url, bool probe, bool longpoll, int *rolltime, struct pool *pool, bool share) { - json_t *val, *err_val, *res_val; - int rc; - struct data_buffer all_data = {NULL, 0}; - struct upload_buffer upload_data; - json_error_t err; - struct curl_slist *headers = NULL; - char len_hdr[64], user_agent_hdr[128]; - char curl_err_str[CURL_ERROR_SIZE]; + char len_hdr[64], user_agent_hdr[128], *ghashrate; long timeout = longpoll ? (60 * 60) : 60; + struct data_buffer all_data = {NULL, 0}; struct header_info hi = {NULL, 0, NULL}; + char curl_err_str[CURL_ERROR_SIZE]; + struct curl_slist *headers = NULL; + struct upload_buffer upload_data; + json_t *val, *err_val, *res_val; bool probing = false; + json_error_t err; + int rc; memset(&err, 0, sizeof(err)); @@ -325,6 +325,13 @@ json_t *json_rpc_call(CURL *curl, const char *url, "Content-type: application/json"); headers = curl_slist_append(headers, "X-Mining-Extensions: longpoll midstate rollntime submitold"); + + if (likely(global_hashrate)) { + asprintf(&ghashrate, "X-Mining-Hashrate: %llu", global_hashrate); + headers = curl_slist_append(headers, ghashrate); + free(ghashrate); + } + headers = curl_slist_append(headers, len_hdr); headers = curl_slist_append(headers, user_agent_hdr); headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/ From b63a374de250e0540db4e8b1ba6241f673f2d989 Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 28 Jun 2012 11:59:11 +1000 Subject: [PATCH 11/12] api.c ensure old mode is always available when not using --api-groups + quit() on param errors --- api.c | 60 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/api.c b/api.c index c4a0b9f9..c88c9155 100644 --- a/api.c +++ b/api.c @@ -158,7 +158,7 @@ static char *msg_buffer = NULL; static SOCKETTYPE sock = INVSOCK; static const char *UNAVAILABLE = " - API will not be available"; -static const char *GROUPDIS = " - groups will be disabled"; +static const char *INVAPIGROUPS = "Invalid --api-groups parameter"; static const char *BLANK = ""; static const char *COMMA = ","; @@ -549,8 +549,6 @@ struct APIGROUPS { char *commands; } apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) -static bool groups_enabled = false; - static struct IP4ACCESS *ipaccess = NULL; static int ips = 0; @@ -2022,7 +2020,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unuse strcat(io_buffer, buf); } -static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group) { int i; @@ -2344,6 +2342,7 @@ static void tidyup(__maybe_unused void *arg) */ static void setup_groups() { + char *api_groups = opt_api_groups ? opt_api_groups : (char *)BLANK; char *buf, *ptr, *next, *colon; char group; char commands[TMPBUFSIZ]; @@ -2352,11 +2351,11 @@ static void setup_groups() bool addstar, did; int i; - buf = malloc(strlen(opt_api_groups) + 1); + buf = malloc(strlen(api_groups) + 1); if (unlikely(!buf)) quit(1, "Failed to malloc ipgroups buf"); - strcpy(buf, opt_api_groups); + strcpy(buf, api_groups); next = buf; // for each group defined @@ -2371,29 +2370,29 @@ static void setup_groups() colon = strchr(ptr, ':'); if (colon) *colon = '\0'; - applog(LOG_WARNING, "API invalid group name '%s'%s", ptr, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API invalid group name '%s'", ptr); + quit(1, INVAPIGROUPS); } group = GROUP(*ptr); if (!VALIDGROUP(group)) { - applog(LOG_WARNING, "API invalid group name '%c'%s", *ptr, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API invalid group name '%c'", *ptr); + quit(1, INVAPIGROUPS); } if (group == PRIVGROUP) { - applog(LOG_WARNING, "API group name can't be '%c'%s", PRIVGROUP, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API group name can't be '%c'", PRIVGROUP); + quit(1, INVAPIGROUPS); } if (group == NOPRIVGROUP) { - applog(LOG_WARNING, "API group name can't be '%c'%s", NOPRIVGROUP, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API group name can't be '%c'", NOPRIVGROUP); + quit(1, INVAPIGROUPS); } if (apigroups[GROUPOFFSET(group)].commands != NULL) { - applog(LOG_WARNING, "API duplicate group name '%c'%s", *ptr, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API duplicate group name '%c'", *ptr); + quit(1, INVAPIGROUPS); } ptr += 2; @@ -2428,8 +2427,8 @@ static void setup_groups() *cmd = '\0'; } } else { - applog(LOG_WARNING, "API unknown command '%s' in group '%c'%s", ptr, group, GROUPDIS); - goto shin; + applog(LOG_WARNING, "API unknown command '%s' in group '%c'", ptr, group); + quit(1, INVAPIGROUPS); } } @@ -2480,8 +2479,6 @@ static void setup_groups() // W (PRIVGROUP) is handled as a special case since it simply means all commands - groups_enabled = true; -shin: free(buf); return; } @@ -2648,16 +2645,12 @@ void api(int api_thr_id) pthread_cleanup_push(tidyup, NULL); my_thr_id = api_thr_id; - /* This should be done first to ensure curl has already called WSAStartup() in windows */ - sleep(opt_log_interval); - if (!opt_api_listen) { applog(LOG_DEBUG, "API not running%s", UNAVAILABLE); return; } - if (opt_api_groups) - setup_groups(); + setup_groups(); if (opt_api_allow) { setup_ipaccess(); @@ -2668,6 +2661,10 @@ void api(int api_thr_id) } } + /* This should be done before curl in needed + * to ensure curl has already called WSAStartup() in windows */ + sleep(opt_log_interval); + sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == INVSOCK) { applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); @@ -2739,14 +2736,13 @@ void api(int api_thr_id) addrok = false; group = NOPRIVGROUP; if (opt_api_allow) { - if (groups_enabled) - for (i = 0; i < ips; i++) { - if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) { - addrok = true; - group = ipaccess[i].group; - break; - } + for (i = 0; i < ips; i++) { + if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) { + addrok = true; + group = ipaccess[i].group; + break; } + } } else { if (opt_api_network) addrok = true; From f2253929903a04af719b6636d51a20b87439d91a Mon Sep 17 00:00:00 2001 From: Paul Sheppard Date: Thu, 28 Jun 2012 08:20:45 -0700 Subject: [PATCH 12/12] Add low hash threshold in sick/dead processing Add check for fd in comms procedures --- cgminer.c | 32 +++++++++++++++++++++++++++----- driver-bitforce.c | 17 +++++++++++------ miner.h | 2 ++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/cgminer.c b/cgminer.c index 8b7de73f..ced66636 100644 --- a/cgminer.c +++ b/cgminer.c @@ -3648,7 +3648,8 @@ static inline bool should_roll(struct work *work) * reject blocks as invalid. */ static inline bool can_roll(struct work *work) { - return (work->pool && work->rolltime && !work->clone && work->rolls < 7000); + return (work->pool && work->rolltime && !work->clone && +work->rolls < 7000 && !stale_work(work, false)); } static void roll_work(struct work *work) @@ -4404,9 +4405,16 @@ static void age_work(void) /* Makes sure the hashmeter keeps going even if mining threads stall, updates * the screen at regular intervals, and restarts threads if they appear to have * died. */ +#define WATCHDOG_INTERVAL 3 +#define WATCHDOG_SICK_TIME 60 +#define WATCHDOG_DEAD_TIME 600 +#define WATCHDOG_SICK_COUNT (WATCHDOG_SICK_TIME/WATCHDOG_INTERVAL) +#define WATCHDOG_DEAD_COUNT (WATCHDOG_DEAD_TIME/WATCHDOG_INTERVAL) +#define WATCHDOG_LOW_HASH 1.0 /* consider < 1MH too low for any device */ + static void *watchdog_thread(void __maybe_unused *userdata) { - const unsigned int interval = 3; + const unsigned int interval = WATCHDOG_INTERVAL; struct timeval zero_tv; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -4510,11 +4518,24 @@ static void *watchdog_thread(void __maybe_unused *userdata) if (thr->getwork || *denable == DEV_DISABLED) continue; - if (cgpu->status != LIFE_WELL && now.tv_sec - thr->last.tv_sec < 60) { + if (cgpu->rolling < WATCHDOG_LOW_HASH) + cgpu->low_count++; + else + cgpu->low_count = 0; + + uint64_t hashtime = now.tv_sec - thr->last.tv_sec; + bool dev_time_well = hashtime < WATCHDOG_SICK_TIME; + bool dev_time_sick = hashtime > WATCHDOG_SICK_TIME; + bool dev_time_dead = hashtime > WATCHDOG_DEAD_TIME; + bool dev_count_well = cgpu->low_count < WATCHDOG_SICK_COUNT; + bool dev_count_sick = cgpu->low_count > WATCHDOG_SICK_COUNT; + bool dev_count_dead = cgpu->low_count > WATCHDOG_DEAD_COUNT; + + if (cgpu->status != LIFE_WELL && dev_time_well && dev_count_well) { applog(LOG_ERR, "%s: Recovered, declaring WELL!", dev_str); cgpu->status = LIFE_WELL; cgpu->device_last_well = time(NULL); - } else if (now.tv_sec - thr->last.tv_sec > 60 && cgpu->status == LIFE_WELL) { + } else if (cgpu->status == LIFE_WELL && (dev_time_sick || dev_count_sick)) { thr->rolling = cgpu->rolling = 0; cgpu->status = LIFE_SICK; applog(LOG_ERR, "%s: Idle for more than 60 seconds, declaring SICK!", dev_str); @@ -4533,7 +4554,7 @@ static void *watchdog_thread(void __maybe_unused *userdata) applog(LOG_ERR, "%s: Attempting to restart", dev_str); reinit_device(cgpu); } - } else if (now.tv_sec - thr->last.tv_sec > 600 && cgpu->status == LIFE_SICK) { + } else if (cgpu->status == LIFE_SICK && (dev_time_dead || dev_count_dead)) { cgpu->status = LIFE_DEAD; applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str); gettimeofday(&thr->sick, NULL); @@ -5473,3 +5494,4 @@ begin_bench: return 0; } + diff --git a/driver-bitforce.c b/driver-bitforce.c index 63729446..0a47df55 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -144,13 +144,12 @@ void bitforce_init(struct cgpu_info *bitforce) char pdevbuf[0x100]; char *s; - applog(LOG_INFO, "BFL%i: Re-initalizing", bitforce->device_id); + applog(LOG_WARNING, "BFL%i: Re-initalizing", bitforce->device_id); mutex_lock(&bitforce->device_mutex); - if (fdDev) { + if (fdDev) BFclose(fdDev); - bitforce->device_fd = 0; - } + bitforce->device_fd = 0; fdDev = BFopen(devpath); if (unlikely(fdDev == -1)) { @@ -228,6 +227,9 @@ static bool bitforce_send_work(struct thr_info *thr, struct work *work) unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>"; char *s; + if (!fdDev) + return false; + mutex_lock(&bitforce->device_mutex); BFwrite(fdDev, "ZDX", 3); BFgets(pdevbuf, sizeof(pdevbuf), fdDev); @@ -277,6 +279,9 @@ static uint64_t bitforce_get_result(struct thr_info *thr, struct work *work) char *pnoncebuf; uint32_t nonce; + if (!fdDev) + return 0; + while (bitforce->wait_ms < BITFORCE_TIMEOUT_MS) { mutex_lock(&bitforce->device_mutex); BFwrite(fdDev, "ZFX", 3); @@ -284,7 +289,6 @@ static uint64_t bitforce_get_result(struct thr_info *thr, struct work *work) mutex_unlock(&bitforce->device_mutex); if (unlikely(!pdevbuf[0])) { applog(LOG_ERR, "BFL%i: Error reading (ZFX)", bitforce->device_id); - mutex_unlock(&bitforce->device_mutex); return 0; } if (pdevbuf[0] != 'B') @@ -366,7 +370,7 @@ static uint64_t bitforce_scanhash(struct thr_info *thr, struct work *work, uint6 bitforce->wait_ms += WORK_CHECK_INTERVAL_MS; if (work_restart[thr->id].restart) { applog(LOG_DEBUG, "BFL%i: Work restart, discarding after %dms", bitforce->device_id, bitforce->wait_ms); - return 1; //we have discarded all work; equivilent to 0 hashes done. + return 1; //we have discarded all work; equivalent to 0 hashes done. } } } else { @@ -420,3 +424,4 @@ struct device_api bitforce_api = { .thread_enable = biforce_thread_enable }; + diff --git a/miner.h b/miner.h index 9347d191..d32f6f02 100644 --- a/miner.h +++ b/miner.h @@ -326,6 +326,7 @@ struct cgpu_info { int accepted; int rejected; int hw_errors; + unsigned int low_count; double rolling; double total_mhashes; double utility; @@ -796,3 +797,4 @@ extern void adl(void); extern void app_restart(void); #endif /* __MINER_H__ */ +