Browse Source

Merge branch 'master' of git@github.com:pshep/cgminer.git

nfactor-troky
Paul Sheppard 13 years ago
parent
commit
f3a82a0d00
  1. 42
      API-README
  2. 2
      README
  3. 32
      adl.c
  4. 322
      api.c
  5. 46
      cgminer.c
  6. 17
      driver-bitforce.c
  7. 4
      miner.h
  8. 23
      util.c

42
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 Without a /prefix is the same as specifying /32
0/0 means all IP addresses. 0/0 means all IP addresses.
The 'W:' on the front gives that address/subnet privileged access to commands 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. 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 Privileged access is checked in the order the IP addresses were supplied to
"--api-allow" "--api-allow"
The first match determines the privilege level. The first match determines the privilege level.
@ -28,6 +29,26 @@ Using the "--api-allow" option overides the "--api-network" option if they
are both specified are both specified
With "--api-allow", 127.0.0.1 is not by default given access unless 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-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)
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:
--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. 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 If the request is JSON (starts with '{'), it will reply with a JSON formatted
@ -86,8 +107,8 @@ The list of requests - a (*) means it requires privileged access - and replies a
Request Reply Section Details Request Reply Section Details
------- ------------- ------- ------- ------------- -------
version VERSION CGMiner=cgminer version version VERSION CGMiner=cgminer, version
API=API version API=API| version
config CONFIG Some miner configuration information: config CONFIG Some miner configuration information:
GPU Count=N, <- the number of GPUs GPU Count=N, <- the number of GPUs
@ -243,6 +264,9 @@ The list of requests - a (*) means it requires privileged access - and replies a
Device drivers are also able to add stats to the Device drivers are also able to add stats to the
end of the details returned 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 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window in the cgminer status window
@ -285,7 +309,17 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.12 API V1.13
Added API commands:
'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
----------
API V1.12 (cgminer v2.4.3)
Modified API commands: Modified API commands:
'stats' - more pool stats added 'stats' - more pool stats added

2
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 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 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-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) --api-listen Listen for API requests (default: disabled)
By default any command that does not just display data returns access denied By default any command that does not just display data returns access denied
See --api-allow to overcome this See --api-allow to overcome this

32
adl.c

@ -13,6 +13,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h>
#ifdef HAVE_CURSES #ifdef HAVE_CURSES
#include <curses.h> #include <curses.h>
@ -692,7 +693,11 @@ int gpu_fanpercent(int gpu)
unlock_adl(); unlock_adl();
if (unlikely(ga->has_fanspeed && ret == -1)) { if (unlikely(ga->has_fanspeed && ret == -1)) {
applog(LOG_WARNING, "GPU %d stopped reporting fanspeed due to driver corruption", gpu); 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 attempt to 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"); applog(LOG_WARNING, "Disabling fanspeed monitoring on this device");
ga->has_fanspeed = false; ga->has_fanspeed = false;
if (ga->twin) { if (ga->twin) {
@ -1020,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) static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *fan_window)
{ {
struct cgpu_info *cgpu = &gpus[gpu]; struct cgpu_info *cgpu = &gpus[gpu];
int tdiff = round(temp - lasttemp);
struct gpu_adl *ga = &cgpu->adl; struct gpu_adl *ga = &cgpu->adl;
int top = gpus[gpu].gpu_fan; int top = gpus[gpu].gpu_fan;
int bot = gpus[gpu].min_fan; int bot = gpus[gpu].min_fan;
@ -1034,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_last_not_well = time(NULL);
cgpu->device_not_well_reason = REASON_DEV_OVER_HEAT; cgpu->device_not_well_reason = REASON_DEV_OVER_HEAT;
cgpu->dev_over_heat_count++; 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"); applog(LOG_DEBUG, "Temperature over target, increasing fanspeed");
if (temp > ga->targettemp + opt_hysteresis) if (temp > ga->targettemp + opt_hysteresis)
newpercent = ga->targetfan + 10; newpercent = ga->targetfan + 10;
@ -1042,18 +1048,26 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool *
newpercent = ga->targetfan + 5; newpercent = ga->targetfan + 5;
if (newpercent > top) if (newpercent > top)
newpercent = top; newpercent = top;
} else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis && temp <= lasttemp) { } else if (fanpercent > bot && temp < ga->targettemp - opt_hysteresis) {
applog(LOG_DEBUG, "Temperature %d degrees below target, decreasing fanspeed", opt_hysteresis); /* Detect large swings of 5 degrees or more and change fan by
newpercent = ga->targetfan - 1; * 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 { } else {
/* We're in the optimal range, make minor adjustments if the /* We're in the optimal range, make minor adjustments if the
* temp is still drifting */ * 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"); applog(LOG_DEBUG, "Temperature dropping while in target range, decreasing fanspeed");
newpercent = ga->targetfan - 1; newpercent = ga->targetfan + tdiff;
} else if (fanpercent < top && temp > lasttemp && temp > ga->targettemp - opt_hysteresis) { } else if (fanpercent < top && tdiff > 0 && temp > ga->targettemp - opt_hysteresis) {
applog(LOG_DEBUG, "Temperature rising while in target range, increasing fanspeed"); applog(LOG_DEBUG, "Temperature rising while in target range, increasing fanspeed");
newpercent = ga->targetfan + 1; newpercent = ga->targetfan + tdiff;
} }
} }

322
api.c

@ -158,6 +158,7 @@ static char *msg_buffer = NULL;
static SOCKETTYPE sock = INVSOCK; static SOCKETTYPE sock = INVSOCK;
static const char *UNAVAILABLE = " - API will not be available"; static const char *UNAVAILABLE = " - API will not be available";
static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
static const char *BLANK = ""; static const char *BLANK = "";
static const char *COMMA = ","; static const char *COMMA = ",";
@ -165,7 +166,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.12"; static const char *APIVERSION = "1.13";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
static const char *SICK = "Sick"; static const char *SICK = "Sick";
static const char *NOSTART = "NoStart"; static const char *NOSTART = "NoStart";
@ -243,6 +244,7 @@ static const char *OSINFO =
#define _BYE "BYE" #define _BYE "BYE"
#define _RESTART "RESTART" #define _RESTART "RESTART"
#define _MINESTATS "STATS" #define _MINESTATS "STATS"
#define _CHECK "CHECK"
static const char ISJSON = '{'; static const char ISJSON = '{';
#define JSON0 "{" #define JSON0 "{"
@ -277,6 +279,7 @@ static const char ISJSON = '{';
#define JSON_RESTART JSON1 _RESTART JSON1 #define JSON_RESTART JSON1 _RESTART JSON1
#define JSON_CLOSE JSON3 #define JSON_CLOSE JSON3
#define JSON_MINESTATS JSON1 _MINESTATS JSON2 #define JSON_MINESTATS JSON1 _MINESTATS JSON2
#define JSON_CHECK JSON1 _CHECK JSON2
#define JSON_END JSON4 #define JSON_END JSON4
static const char *JSON_COMMAND = "command"; static const char *JSON_COMMAND = "command";
@ -364,6 +367,8 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_REMPOOL 68 #define MSG_REMPOOL 68
#define MSG_DEVDETAILS 69 #define MSG_DEVDETAILS 69
#define MSG_MINESTATS 70 #define MSG_MINESTATS 70
#define MSG_MISCHK 71
#define MSG_CHECK 72
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
@ -507,6 +512,8 @@ struct CODES {
{ SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" }, { SEVERITY_SUCC, MSG_NOTIFY, PARAM_NONE, "Notify" },
{ SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" }, { SEVERITY_SUCC, MSG_DEVDETAILS,PARAM_NONE, "Device Details" },
{ SEVERITY_SUCC, MSG_MINESTATS,PARAM_NONE, "CGMiner stats" }, { 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 } { SEVERITY_FAIL, 0, 0, NULL }
}; };
@ -525,9 +532,23 @@ static time_t when = 0; // when the request occurred
struct IP4ACCESS { struct IP4ACCESS {
in_addr_t ip; in_addr_t ip;
in_addr_t mask; 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 struct IP4ACCESS *ipaccess = NULL; static struct IP4ACCESS *ipaccess = NULL;
static int ips = 0; static int ips = 0;
@ -796,7 +817,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
return msg_buffer; 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 sprintf(io_buffer, isjson
? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE ? "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE
@ -805,7 +826,7 @@ static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
VERSION, APIVERSION); 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]; char buf[TMPBUFSIZ];
int gpucount = 0; int gpucount = 0;
@ -1003,7 +1024,7 @@ static void cpustatus(int cpu, bool isjson)
} }
#endif #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 devcount = 0;
int numgpu = 0; int numgpu = 0;
@ -1069,7 +1090,7 @@ static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b
} }
#ifdef HAVE_OPENCL #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; int id;
@ -1103,7 +1124,7 @@ static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
} }
#endif #endif
#ifdef HAVE_AN_FPGA #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 numpga = numpgas();
int id; int id;
@ -1137,7 +1158,7 @@ static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcat(io_buffer, JSON_CLOSE); 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(); int numpga = numpgas();
struct thr_info *thr; struct thr_info *thr;
@ -1193,7 +1214,7 @@ static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_PGAENA, id, NULL, 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 numpga = numpgas();
int id; int id;
@ -1234,7 +1255,7 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
#endif #endif
#ifdef WANT_CPUMINE #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; int id;
@ -1268,7 +1289,7 @@ static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
} }
#endif #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 buf[TMPBUFSIZ];
char *status, *lp; char *status, *lp;
@ -1345,7 +1366,7 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
strcat(io_buffer, JSON_CLOSE); 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; double utility, mhs;
@ -1379,7 +1400,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
#endif #endif
} }
#ifdef HAVE_OPENCL #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; struct thr_info *thr;
int gpu; int gpu;
@ -1425,7 +1446,7 @@ static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_GPUREN, id, NULL, 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; int id;
@ -1455,7 +1476,7 @@ static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_GPUDIS, id, NULL, 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; int id;
@ -1480,7 +1501,7 @@ static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_GPUREI, id, NULL, isjson)); strcpy(io_buffer, message(MSG_GPUREI, id, NULL, isjson));
} }
#endif #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]; char buf[TMPBUFSIZ];
int numgpu = 0; int numgpu = 0;
@ -1499,8 +1520,7 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
strcat(io_buffer, buf); strcat(io_buffer, buf);
} }
static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
{ {
char buf[TMPBUFSIZ]; char buf[TMPBUFSIZ];
int count = 0; int count = 0;
@ -1519,7 +1539,7 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
strcat(io_buffer, buf); 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]; char buf[TMPBUFSIZ];
int count = 0; int count = 0;
@ -1538,7 +1558,7 @@ static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
strcat(io_buffer, buf); 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; struct pool *pool;
int id; int id;
@ -1619,7 +1639,7 @@ exitsama:
return false; 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 *url, *user, *pass;
char *ptr; char *ptr;
@ -1647,7 +1667,7 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
ptr = NULL; 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; struct pool *pool;
int id; int id;
@ -1681,7 +1701,7 @@ static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_ENAPOOL, id, NULL, 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; struct pool *pool;
int id; int id;
@ -1720,7 +1740,7 @@ static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_DISPOOL, id, NULL, 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; struct pool *pool;
char *rpc_url; char *rpc_url;
@ -1806,7 +1826,7 @@ static bool splitgpuvalue(char *param, int *gpu, char **value, bool isjson)
return true; 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; int id;
char *value; char *value;
@ -1835,7 +1855,7 @@ static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson)
strcpy(io_buffer, message(MSG_GPUINT, id, intensitystr, 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 #ifdef HAVE_ADL
int id; int id;
@ -1856,7 +1876,7 @@ static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
#endif #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 #ifdef HAVE_ADL
int id; int id;
@ -1877,7 +1897,7 @@ static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b
#endif #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 #ifdef HAVE_ADL
int id; int id;
@ -1898,7 +1918,7 @@ static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
#endif #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 #ifdef HAVE_ADL
int id; int id;
@ -1919,7 +1939,7 @@ static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
#endif #endif
} }
#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) if (isjson)
strcpy(io_buffer, JSON_START JSON_BYE); strcpy(io_buffer, JSON_START JSON_BYE);
@ -1930,7 +1950,7 @@ void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson
do_a_quit = true; 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) if (isjson)
strcpy(io_buffer, JSON_START JSON_RESTART); strcpy(io_buffer, JSON_START JSON_RESTART);
@ -1941,12 +1961,12 @@ void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isj
do_a_restart = true; 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)); 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 buf[TMPBUFSIZ];
char *reason; char *reason;
@ -2000,7 +2020,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson)
strcat(io_buffer, buf); 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, char group)
{ {
int i; int i;
@ -2017,13 +2037,13 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool
} }
for (i = 0; i < total_devices; i++) for (i = 0; i < total_devices; i++)
notifystatus(i, devices[i], isjson); notifystatus(i, devices[i], isjson, group);
if (isjson) if (isjson)
strcat(io_buffer, JSON_CLOSE); 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]; char buf[TMPBUFSIZ];
struct cgpu_info *cgpu; struct cgpu_info *cgpu;
@ -2059,7 +2079,7 @@ static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
strcat(io_buffer, JSON_CLOSE); 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]; char filename[PATH_MAX];
FILE *fcfg; FILE *fcfg;
@ -2135,7 +2155,8 @@ static int itemstats(int i, char *id, struct cgminer_stats *stats, struct cgmine
return i; 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 extra[TMPBUFSIZ];
char id[20]; char id[20];
@ -2174,10 +2195,12 @@ static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
strcat(io_buffer, JSON_CLOSE); strcat(io_buffer, JSON_CLOSE);
} }
static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS { struct CMDS {
char *name; char *name;
void (*func)(SOCKETTYPE, char *, bool); void (*func)(SOCKETTYPE, char *, bool, char);
bool requires_writemode; bool iswritemode;
} cmds[] = { } cmds[] = {
{ "version", apiversion, false }, { "version", apiversion, false },
{ "config", minerconfig, false }, { "config", minerconfig, false },
@ -2220,9 +2243,47 @@ struct CMDS {
{ "devdetails", devdetails, false }, { "devdetails", devdetails, false },
{ "restart", dorestart, true }, { "restart", dorestart, true },
{ "stats", minerstats, false }, { "stats", minerstats, false },
{ "check", checkcommand, false },
{ NULL, NULL, 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);
}
static void send_result(SOCKETTYPE c, bool isjson) static void send_result(SOCKETTYPE c, bool isjson)
{ {
int n; int n;
@ -2277,7 +2338,153 @@ 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 *api_groups = opt_api_groups ? opt_api_groups : (char *)BLANK;
char *buf, *ptr, *next, *colon;
char group;
char commands[TMPBUFSIZ];
char cmdbuf[100];
char *cmd;
bool addstar, did;
int i;
buf = malloc(strlen(api_groups) + 1);
if (unlikely(!buf))
quit(1, "Failed to malloc ipgroups buf");
strcpy(buf, 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'", ptr);
quit(1, INVAPIGROUPS);
}
group = GROUP(*ptr);
if (!VALIDGROUP(group)) {
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'", PRIVGROUP);
quit(1, INVAPIGROUPS);
}
if (group == NOPRIVGROUP) {
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'", *ptr);
quit(1, INVAPIGROUPS);
}
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'", ptr, group);
quit(1, INVAPIGROUPS);
}
}
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
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) * special case of 0/0 allows /0 (means all IP addresses)
*/ */
#define ALLIP4 "0/0" #define ALLIP4 "0/0"
@ -2288,7 +2495,7 @@ static void setup_ipaccess()
{ {
char *buf, *ptr, *comma, *slash, *dot; char *buf, *ptr, *comma, *slash, *dot;
int ipcount, mask, octet, i; int ipcount, mask, octet, i;
bool writemode; char group;
buf = malloc(strlen(opt_api_allow) + 1); buf = malloc(strlen(opt_api_allow) + 1);
if (unlikely(!buf)) if (unlikely(!buf))
@ -2322,16 +2529,16 @@ static void setup_ipaccess()
if (comma) if (comma)
*(comma++) = '\0'; *(comma++) = '\0';
writemode = false; group = NOPRIVGROUP;
if (isalpha(*ptr) && *(ptr+1) == ':') { if (isalpha(*ptr) && *(ptr+1) == ':') {
if (tolower(*ptr) == 'w') if (DEFINEDGROUP(*ptr))
writemode = true; group = GROUP(*ptr);
ptr += 2; ptr += 2;
} }
ipaccess[ips].writemode = writemode; ipaccess[ips].group = group;
if (strcmp(ptr, ALLIP4) == 0) if (strcmp(ptr, ALLIP4) == 0)
ipaccess[ips].ip = ipaccess[ips].mask = 0; ipaccess[ips].ip = ipaccess[ips].mask = 0;
@ -2421,10 +2628,11 @@ void api(int api_thr_id)
struct sockaddr_in serv; struct sockaddr_in serv;
struct sockaddr_in cli; struct sockaddr_in cli;
socklen_t clisiz; socklen_t clisiz;
char cmdbuf[100];
char *cmd; char *cmd;
char *param; char *param;
bool addrok; bool addrok;
bool writemode; char group;
json_error_t json_err; json_error_t json_err;
json_t *json_config; json_t *json_config;
json_t *json_val; json_t *json_val;
@ -2437,14 +2645,13 @@ void api(int api_thr_id)
pthread_cleanup_push(tidyup, NULL); pthread_cleanup_push(tidyup, NULL);
my_thr_id = api_thr_id; 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) { if (!opt_api_listen) {
applog(LOG_DEBUG, "API not running%s", UNAVAILABLE); applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
return; return;
} }
setup_groups();
if (opt_api_allow) { if (opt_api_allow) {
setup_ipaccess(); setup_ipaccess();
@ -2454,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); sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVSOCK) { if (sock == INVSOCK) {
applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE); applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
@ -2523,12 +2734,12 @@ void api(int api_thr_id)
connectaddr = inet_ntoa(cli.sin_addr); connectaddr = inet_ntoa(cli.sin_addr);
addrok = false; addrok = false;
writemode = false; group = NOPRIVGROUP;
if (opt_api_allow) { if (opt_api_allow) {
for (i = 0; i < ips; i++) { for (i = 0; i < ips; i++) {
if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) { if ((cli.sin_addr.s_addr & ipaccess[i].mask) == ipaccess[i].ip) {
addrok = true; addrok = true;
writemode = ipaccess[i].writemode; group = ipaccess[i].group;
break; break;
} }
} }
@ -2622,12 +2833,13 @@ void api(int api_thr_id)
if (!did) if (!did)
for (i = 0; cmds[i].name != NULL; i++) { for (i = 0; cmds[i].name != NULL; i++) {
if (strcmp(cmd, cmds[i].name) == 0) { 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)); 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); 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); send_result(c, isjson);
did = true; did = true;

46
cgminer.c

@ -100,6 +100,7 @@ int opt_scantime = 60;
int opt_expiry = 120; int opt_expiry = 120;
int opt_bench_algo = -1; int opt_bench_algo = -1;
static const bool opt_time = true; static const bool opt_time = true;
unsigned long long global_hashrate;
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
int opt_dynamic_interval = 7; int opt_dynamic_interval = 7;
@ -131,6 +132,7 @@ bool opt_autofan;
bool opt_autoengine; bool opt_autoengine;
bool opt_noadl; bool opt_noadl;
char *opt_api_allow = NULL; char *opt_api_allow = NULL;
char *opt_api_groups;
char *opt_api_description = PACKAGE_STRING; char *opt_api_description = PACKAGE_STRING;
int opt_api_port = 4028; int opt_api_port = 4028;
bool opt_api_listen; bool opt_api_listen;
@ -680,6 +682,13 @@ static char *set_api_allow(const char *arg)
return NULL; 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) static char *set_api_description(const char *arg)
{ {
opt_set_charp(arg, &opt_api_description); opt_set_charp(arg, &opt_api_description);
@ -730,10 +739,13 @@ static struct opt_table opt_config_table[] = {
#endif #endif
OPT_WITH_ARG("--api-allow", OPT_WITH_ARG("--api-allow",
set_api_allow, NULL, NULL, 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", OPT_WITH_ARG("--api-description",
set_api_description, NULL, NULL, set_api_description, NULL, NULL,
"Description placed in the API status header, default: cgminer version"), "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_WITHOUT_ARG("--api-listen",
opt_set_bool, &opt_api_listen, opt_set_bool, &opt_api_listen,
"Enable API, default: disabled"), "Enable API, default: disabled"),
@ -2872,6 +2884,8 @@ void write_config(FILE *fcfg)
fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow); fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", opt_api_allow);
if (strcmp(opt_api_description, PACKAGE_STRING) != 0) if (strcmp(opt_api_description, PACKAGE_STRING) != 0)
fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description); 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) if (opt_icarus_timing)
fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing); fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing);
fputs("\n}", fcfg); fputs("\n}", fcfg);
@ -3387,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); local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0);
decay_time(&rolling, local_mhashes_done / local_secs); decay_time(&rolling, local_mhashes_done / local_secs);
global_hashrate = roundl(rolling) * 1000000;
timeval_subtract(&total_diff, &total_tv_end, &total_tv_start); timeval_subtract(&total_diff, &total_tv_end, &total_tv_start);
total_secs = (double)total_diff.tv_sec + total_secs = (double)total_diff.tv_sec +
@ -4405,9 +4420,16 @@ static void age_work(void)
/* Makes sure the hashmeter keeps going even if mining threads stall, updates /* 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 * the screen at regular intervals, and restarts threads if they appear to have
* died. */ * 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) static void *watchdog_thread(void __maybe_unused *userdata)
{ {
const unsigned int interval = 3; const unsigned int interval = WATCHDOG_INTERVAL;
struct timeval zero_tv; struct timeval zero_tv;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@ -4511,11 +4533,24 @@ static void *watchdog_thread(void __maybe_unused *userdata)
if (thr->getwork || *denable == DEV_DISABLED) if (thr->getwork || *denable == DEV_DISABLED)
continue; 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); applog(LOG_ERR, "%s: Recovered, declaring WELL!", dev_str);
cgpu->status = LIFE_WELL; cgpu->status = LIFE_WELL;
cgpu->device_last_well = time(NULL); 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; thr->rolling = cgpu->rolling = 0;
cgpu->status = LIFE_SICK; cgpu->status = LIFE_SICK;
applog(LOG_ERR, "%s: Idle for more than 60 seconds, declaring SICK!", dev_str); applog(LOG_ERR, "%s: Idle for more than 60 seconds, declaring SICK!", dev_str);
@ -4534,7 +4569,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
applog(LOG_ERR, "%s: Attempting to restart", dev_str); applog(LOG_ERR, "%s: Attempting to restart", dev_str);
reinit_device(cgpu); 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; cgpu->status = LIFE_DEAD;
applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str); applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str);
gettimeofday(&thr->sick, NULL); gettimeofday(&thr->sick, NULL);
@ -5474,3 +5509,4 @@ begin_bench:
return 0; return 0;
} }

17
driver-bitforce.c

@ -144,13 +144,12 @@ void bitforce_init(struct cgpu_info *bitforce)
char pdevbuf[0x100]; char pdevbuf[0x100];
char *s; 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); mutex_lock(&bitforce->device_mutex);
if (fdDev) { if (fdDev)
BFclose(fdDev); BFclose(fdDev);
bitforce->device_fd = 0; bitforce->device_fd = 0;
}
fdDev = BFopen(devpath); fdDev = BFopen(devpath);
if (unlikely(fdDev == -1)) { 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>>>>>>>>"; unsigned char ob[61] = ">>>>>>>>12345678901234567890123456789012123456789012>>>>>>>>";
char *s; char *s;
if (!fdDev)
return false;
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZDX", 3); BFwrite(fdDev, "ZDX", 3);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
@ -277,6 +279,9 @@ static uint64_t bitforce_get_result(struct thr_info *thr, struct work *work)
char *pnoncebuf; char *pnoncebuf;
uint32_t nonce; uint32_t nonce;
if (!fdDev)
return 0;
while (bitforce->wait_ms < BITFORCE_TIMEOUT_MS) { while (bitforce->wait_ms < BITFORCE_TIMEOUT_MS) {
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3); 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); mutex_unlock(&bitforce->device_mutex);
if (unlikely(!pdevbuf[0])) { if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL%i: Error reading (ZFX)", bitforce->device_id); applog(LOG_ERR, "BFL%i: Error reading (ZFX)", bitforce->device_id);
mutex_unlock(&bitforce->device_mutex);
return 0; return 0;
} }
if (pdevbuf[0] != 'B') 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; bitforce->wait_ms += WORK_CHECK_INTERVAL_MS;
if (work_restart[thr->id].restart) { if (work_restart[thr->id].restart) {
applog(LOG_DEBUG, "BFL%i: Work restart, discarding after %dms", bitforce->device_id, bitforce->wait_ms); 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 { } else {
@ -420,3 +424,4 @@ struct device_api bitforce_api = {
.thread_enable = biforce_thread_enable .thread_enable = biforce_thread_enable
}; };

4
miner.h

@ -326,6 +326,7 @@ struct cgpu_info {
int accepted; int accepted;
int rejected; int rejected;
int hw_errors; int hw_errors;
unsigned int low_count;
double rolling; double rolling;
double total_mhashes; double total_mhashes;
double utility; double utility;
@ -530,6 +531,7 @@ extern bool opt_autofan;
extern bool opt_autoengine; extern bool opt_autoengine;
extern bool use_curses; extern bool use_curses;
extern char *opt_api_allow; extern char *opt_api_allow;
extern char *opt_api_groups;
extern char *opt_api_description; extern char *opt_api_description;
extern int opt_api_port; extern int opt_api_port;
extern bool opt_api_listen; extern bool opt_api_listen;
@ -625,6 +627,7 @@ extern unsigned int local_work;
extern unsigned int total_go, total_ro; extern unsigned int total_go, total_ro;
extern const int opt_cutofftemp; extern const int opt_cutofftemp;
extern int opt_log_interval; extern int opt_log_interval;
extern unsigned long long global_hashrate;
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
typedef struct { typedef struct {
@ -796,3 +799,4 @@ extern void adl(void);
extern void app_restart(void); extern void app_restart(void);
#endif /* __MINER_H__ */ #endif /* __MINER_H__ */

23
util.c

@ -256,17 +256,17 @@ json_t *json_rpc_call(CURL *curl, const char *url,
bool probe, bool longpoll, int *rolltime, bool probe, bool longpoll, int *rolltime,
struct pool *pool, bool share) struct pool *pool, bool share)
{ {
json_t *val, *err_val, *res_val; char len_hdr[64], user_agent_hdr[128], *ghashrate;
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];
long timeout = longpoll ? (60 * 60) : 60; long timeout = longpoll ? (60 * 60) : 60;
struct data_buffer all_data = {NULL, 0};
struct header_info hi = {NULL, 0, NULL}; 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; bool probing = false;
json_error_t err;
int rc;
memset(&err, 0, sizeof(err)); memset(&err, 0, sizeof(err));
@ -325,6 +325,13 @@ json_t *json_rpc_call(CURL *curl, const char *url,
"Content-type: application/json"); "Content-type: application/json");
headers = curl_slist_append(headers, headers = curl_slist_append(headers,
"X-Mining-Extensions: longpoll midstate rollntime submitold"); "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, len_hdr);
headers = curl_slist_append(headers, user_agent_hdr); headers = curl_slist_append(headers, user_agent_hdr);
headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/ headers = curl_slist_append(headers, "Expect:"); /* disable Expect hdr*/

Loading…
Cancel
Save