Browse Source

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

Conflicts:
	cgminer.c
nfactor-troky
Paul Sheppard 13 years ago
parent
commit
baa480c137
  1. 42
      API-README
  2. 2
      README
  3. 30
      adl.c
  4. 322
      api.c
  5. 19
      cgminer.c
  6. 2
      miner.h
  7. 23
      util.c

42
API-README

@ -19,8 +19,9 @@ IP addresses are automatically padded with extra '.0's as needed @@ -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,26 @@ Using the "--api-allow" option overides the "--api-network" option if they @@ -28,6 +29,26 @@ 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-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.
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 @@ -86,8 +107,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 +264,9 @@ The list of requests - a (*) means it requires privileged access - and replies a @@ -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
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 +309,17 @@ miner.php - an example web page to access the API @@ -285,7 +309,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:
'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:
'stats' - more pool stats added

2
README

@ -119,6 +119,8 @@ Options for both config file and command line: @@ -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

30
adl.c

@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef HAVE_CURSES
#include <curses.h>
@ -692,7 +693,11 @@ int gpu_fanpercent(int gpu) @@ -692,7 +693,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 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");
ga->has_fanspeed = false;
if (ga->twin) {
@ -1020,6 +1025,7 @@ static int set_powertune(int gpu, int iPercentage) @@ -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)
{
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;
@ -1034,7 +1040,7 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool * @@ -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_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;
@ -1042,18 +1048,26 @@ static bool fan_autotune(int gpu, int temp, int fanpercent, int lasttemp, bool * @@ -1042,18 +1048,26 @@ 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) {
} 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;
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 {
/* 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;
}
}

322
api.c

@ -158,6 +158,7 @@ static char *msg_buffer = NULL; @@ -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 *INVAPIGROUPS = "Invalid --api-groups parameter";
static const char *BLANK = "";
static const char *COMMA = ",";
@ -165,7 +166,7 @@ static const char SEPARATOR = '|'; @@ -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 = @@ -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 = '{'; @@ -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"; @@ -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 { @@ -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,23 @@ static time_t when = 0; // when the request occurred @@ -525,9 +532,23 @@ 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 struct IP4ACCESS *ipaccess = NULL;
static int ips = 0;
@ -796,7 +817,7 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) @@ -796,7 +817,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 +826,7 @@ static void apiversion(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -805,7 +826,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 +1024,7 @@ static void cpustatus(int cpu, bool isjson) @@ -1003,7 +1024,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 +1090,7 @@ static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b @@ -1069,7 +1090,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 +1124,7 @@ static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1103,7 +1124,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 +1158,7 @@ static void pgadev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1137,7 +1158,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 +1214,7 @@ static void pgaenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1193,7 +1214,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 +1255,7 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1234,7 +1255,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 +1289,7 @@ static void cpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1268,7 +1289,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 +1366,7 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -1345,7 +1366,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 +1400,7 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo @@ -1379,7 +1400,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 +1446,7 @@ static void gpuenable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1425,7 +1446,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 +1476,7 @@ static void gpudisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1455,7 +1476,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 +1501,7 @@ static void gpurestart(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1480,7 +1501,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 +1520,7 @@ static void gpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo @@ -1499,8 +1520,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 +1539,7 @@ static void pgacount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo @@ -1519,7 +1539,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 +1558,7 @@ static void cpucount(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo @@ -1538,7 +1558,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 +1639,7 @@ exitsama: @@ -1619,7 +1639,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 +1667,7 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1647,7 +1667,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 +1701,7 @@ static void enablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1681,7 +1701,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 +1740,7 @@ static void disablepool(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1720,7 +1740,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 +1826,7 @@ static bool splitgpuvalue(char *param, int *gpu, char **value, bool isjson) @@ -1806,7 +1826,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 +1855,7 @@ static void gpuintensity(__maybe_unused SOCKETTYPE c, char *param, bool isjson) @@ -1835,7 +1855,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 +1876,7 @@ static void gpumem(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool @@ -1856,7 +1876,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 +1897,7 @@ static void gpuengine(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b @@ -1877,7 +1897,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 +1918,7 @@ static void gpufan(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool @@ -1898,7 +1918,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 +1939,7 @@ static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo @@ -1919,7 +1939,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 +1950,7 @@ void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson @@ -1930,7 +1950,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 +1961,12 @@ void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isj @@ -1941,12 +1961,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 +2020,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson) @@ -2000,7 +2020,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, char group)
{
int i;
@ -2017,13 +2037,13 @@ static void notify(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool @@ -2017,13 +2037,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 +2079,7 @@ static void devdetails(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -2059,7 +2079,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 +2155,8 @@ static int itemstats(int i, char *id, struct cgminer_stats *stats, struct cgmine @@ -2135,7 +2155,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 +2195,12 @@ static void minerstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -2174,10 +2195,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 +2243,47 @@ struct CMDS { @@ -2220,9 +2243,47 @@ 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);
}
static void send_result(SOCKETTYPE c, bool isjson)
{
int n;
@ -2277,7 +2338,153 @@ static void tidyup(__maybe_unused void *arg) @@ -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)
*/
#define ALLIP4 "0/0"
@ -2288,7 +2495,7 @@ static void setup_ipaccess() @@ -2288,7 +2495,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 +2529,16 @@ static void setup_ipaccess() @@ -2322,16 +2529,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 +2628,11 @@ void api(int api_thr_id) @@ -2421,10 +2628,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;
@ -2437,14 +2645,13 @@ void api(int api_thr_id) @@ -2437,14 +2645,13 @@ 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;
}
setup_groups();
if (opt_api_allow) {
setup_ipaccess();
@ -2454,6 +2661,10 @@ void api(int api_thr_id) @@ -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);
if (sock == INVSOCK) {
applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
@ -2523,12 +2734,12 @@ void api(int api_thr_id) @@ -2523,12 +2734,12 @@ 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;
group = ipaccess[i].group;
break;
}
}
@ -2622,12 +2833,13 @@ void api(int api_thr_id) @@ -2622,12 +2833,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;

19
cgminer.c

@ -100,6 +100,7 @@ int opt_scantime = 60; @@ -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;
@ -131,6 +132,7 @@ bool opt_autofan; @@ -131,6 +132,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;
@ -680,6 +682,13 @@ static char *set_api_allow(const char *arg) @@ -680,6 +682,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);
@ -730,10 +739,13 @@ static struct opt_table opt_config_table[] = { @@ -730,10 +739,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"),
@ -2872,6 +2884,8 @@ void write_config(FILE *fcfg) @@ -2872,6 +2884,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);
@ -3387,6 +3401,7 @@ static void hashmeter(int thr_id, struct timeval *diff, @@ -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);
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 +
@ -3649,7 +3664,7 @@ static inline bool should_roll(struct work *work) @@ -3649,7 +3664,7 @@ static inline bool should_roll(struct work *work)
static inline bool can_roll(struct work *work)
{
return (work->pool && work->rolltime && !work->clone &&
work->rolls < 7000 && !stale_work(work, false));
work->rolls < 7000 && !stale_work(work, false));
}
static void roll_work(struct work *work)

2
miner.h

@ -531,6 +531,7 @@ extern bool opt_autofan; @@ -531,6 +531,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;
@ -626,6 +627,7 @@ extern unsigned int local_work; @@ -626,6 +627,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 {

23
util.c

@ -256,17 +256,17 @@ json_t *json_rpc_call(CURL *curl, const char *url, @@ -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, @@ -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*/

Loading…
Cancel
Save