Browse Source

Merge pull request #310 from kanoi/master

API debug, API-README, API Correct diff1 name, Device diff1, API diff1 etc.
nfactor-troky
Con Kolivas 12 years ago
parent
commit
3243b91e2d
  1. 83
      API-README
  2. 72
      README
  3. 230
      api.c
  4. 230
      cgminer.c
  5. 62
      driver-bitforce.c
  6. 4
      driver-cpu.c
  7. 12
      driver-icarus.c
  8. 14
      driver-modminer.c
  9. 16
      findnonce.c
  10. 53
      fpgautils.c
  11. 26
      fpgautils.h
  12. 2
      logging.h
  13. 42
      miner.h
  14. 79
      miner.php
  15. 73
      util.c

83
API-README

@ -124,7 +124,10 @@ The list of requests - a (*) means it requires privileged access - and replies a @@ -124,7 +124,10 @@ The list of requests - a (*) means it requires privileged access - and replies a
Log Interval=N, <- log interval (--log N)
Device Code=GPU ICA , <- spaced list of compiled devices
OS=Linux/Apple/..., <- operating System
Failover-Only=true/false | <- failover-only setting
Failover-Only=true/false, <- failover-only setting
ScanTime=N, <- --scan-time setting
Queue=N, <- --queue setting
Expiry=N| <- --expiry setting
summary SUMMARY The status summary of the miner
e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
@ -259,6 +262,22 @@ The list of requests - a (*) means it requires privileged access - and replies a @@ -259,6 +262,22 @@ The list of requests - a (*) means it requires privileged access - and replies a
stating the results of the disable request
This is only available if PGA mining is enabled
pgaidentify|N (*)
none There is no reply section just the STATUS section
stating the results of the identify request
This is only available if PGA mining is enabled
and currently only BFL singles support this command
On a BFL single it will flash the led on the front
of the device for appoximately 4s
All other non BFL PGA devices will return a warning
status message stating that they dont support it
This adds a 4s delay to the BFL share being processed
so you may get a message stating that procssing took
longer than 7000ms if the request was sent towards
the end of the timing of any work being worked on
e.g.: BFL0: took 8438ms - longer than 7000ms
You should ignore this
devdetails DEVDETAILS Each device with a list of their static details
This lists all devices including those not supported
by the 'devs' command
@ -287,6 +306,30 @@ The list of requests - a (*) means it requires privileged access - and replies a @@ -287,6 +306,30 @@ The list of requests - a (*) means it requires privileged access - and replies a
Current Block Hash=XXXX..., <- blank if none
LP=true/false| <- LP is in use on at least 1 pool
debug|setting (*)
DEBUG Debug settings
The optional commands for 'setting' are the same as
the screen curses debug settings
You can only specify one setting
Only the first character is checked (case insensitive):
Silent, Quiet, Verbose, Debug, RPCProto, PerDevice,
WorkTime, Normal
The output fields are (as above):
Silent=true/false,
Quiet=true/false,
Verbose=true/false,
Debug=true/false,
RPCProto=true/false,
PerDevice=true/false,
WorkTime=true/false|
setconfig|name,N (*)
none There is no reply section just the STATUS section
stating the results of setting 'name' to N
The valid values for name are currently:
queue, scantime, expiry
N is an integer in the range 0 to 9999
When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window
@ -306,8 +349,9 @@ windows @@ -306,8 +349,9 @@ windows
Obviously, the JSON format is simply just the names as given before the '='
with the values after the '='
If you enable cgminer debug (-D or --debug) you will also get messages showing
details of the requests received and the replies
If you enable cgminer debug (-D or --debug) or, when cgminer debug is off,
turn on debug with the API command 'debug|debug' you will also get messages
showing some details of the requests received and the replies
There are included 4 program examples for accessing the API:
@ -339,13 +383,32 @@ miner.php - an example web page to access the API @@ -339,13 +383,32 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API:
API V1.18
API V1.19
Added API commands:
'debug'
'pgaidentify|N' (only works for BFL Singles so far)
'setconfig|name,N'
Modified API commands:
'stats' - add 'Work Had Roll Time', 'Work Can Roll', 'Work Had Expire',
'Work Roll Time' to the pool stats
'devs' - add 'Diff1 Work', 'Difficulty Accepted', 'Difficulty Rejected',
'Last Share Difficulty' to all devices
'gpu|N' - add 'Diff1 Work', 'Difficulty Accepted',
'Difficulty Rejected', 'Last Share Difficulty'
'pga|N' - add 'Diff1 Work', 'Difficulty Accepted',
'Difficulty Rejected', 'Last Share Difficulty'
'notify' - add '*Dev Throttle' (for BFL Singles)
'pools' - add 'Proxy Type', 'Proxy', 'Difficulty Accepted', 'Difficulty Rejected',
'Difficulty Stale', 'Last Share Difficulty'
'config' - add 'Queue', 'Expiry'
----------
API V1.18 (cgminer v2.7.4)
Modified API commands:
'stats' - add 'Work Had Roll Time', 'Work Can Roll', 'Work Had Expire',
'Work Roll Time' to the pool stats
'config' - include 'ScanTime'
----------
@ -866,6 +929,14 @@ e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi'); @@ -866,6 +929,14 @@ e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi');
---------
Default:
$rigipsecurity = true;
Set $rigipsecurity to false to show the IP/Port of the rig
in the socket error messages and also show the full socket message
---------
Default:
$rigtotals = true;
$forcerigtotals = false;

72
README

@ -168,7 +168,7 @@ Options for both config file and command line: @@ -168,7 +168,7 @@ Options for both config file and command line:
--scrypt Use the scrypt algorithm for mining (litecoin only)
--sharelog <arg> Append share log to file
--shares <arg> Quit after mining N shares (default: unlimited)
--socks-proxy <arg> Set socks4 proxy (host:port)
--socks-proxy <arg> Set socks4 proxy (host:port) for all pools without a proxy specified
--syslog Use system log for output messages (default: standard error)
--temp-cutoff <arg> Temperature where a device will be automatically disabled, one value or comma separated list (default: 95)
--text-only|-T Disable ncurses formatted screen output
@ -239,6 +239,7 @@ The official supplied binaries are compiled with support for all FPGAs. @@ -239,6 +239,7 @@ The official supplied binaries are compiled with support for all FPGAs.
To force the code to only attempt detection with a specific driver,
prepend the argument with the driver name followed by a colon.
For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5"
or using the short name: "ica:/dev/ttyUSB0" or "bfl:\\.\COM5"
For other FPGA details see the FPGA-README
@ -295,6 +296,28 @@ Add overclocking settings, GPU and fan control with different engine settings fo @@ -295,6 +296,28 @@ Add overclocking settings, GPU and fan control with different engine settings fo
cgminer -o http://pool:port -u username -p password -I 9 --auto-fan --auto-gpu --gpu-engine 750-950,945,700-930,960 --gpu-memclock 300
Single pool with a standard http proxy, regular desktop:
cgminer -o "http:proxy:port|http://pool:port" -u username -p password
Single pool with a socks5 proxy, regular desktop:
cgminer -o "socks5:proxy:port|http://pool:port" -u username -p password
The list of proxy types are:
http: standard http 1.1 proxy
http0: http 1.0 proxy
socks4: socks4 proxy
socks5: socks5 proxy
socks4a: socks4a proxy
socks5h: socks5 proxy using a hostname
If you compile cgminer with a version of CURL before 7.19.4 then some of the above will
not be available. All are available since CURL version 7.19.4
If you specify the --socks-proxy option to cgminer, it will only be applied to all pools
that don't specify their own proxy setting like above
READ WARNINGS AND DOCUMENTATION BELOW ABOUT OVERCLOCKING
On Linux you virtually always need to export your display settings before
@ -451,6 +474,26 @@ it will log to a file called logfile.txt and otherwise work the same. @@ -451,6 +474,26 @@ it will log to a file called logfile.txt and otherwise work the same.
There is also the -m option on linux which will spawn a command of your choice
and pipe the output directly to that command.
The WorkTime details 'debug' option adds details on the end of each line
displayed for Accepted or Rejected work done. An example would be:
<-00000059.ed4834a3 M:X D:1.0 G:17:02:38:0.405 C:1.855 (2.995) W:3.440 (0.000) S:0.461 R:17:02:47
The first 2 hex codes are the previous block hash, the rest are reported in
seconds unless stated otherwise:
The previous hash is followed by the getwork mode used M:X where X is one of
P:Pool, T:Test Pool, L:LP or B:Benchmark,
then D:d.ddd is the difficulty required to get a share from the work,
then G:hh:mm:ss:n.nnn, which is when the getwork or LP was sent to the pool and
the n.nnn is how long it took to reply,
followed by 'O' on it's own if it is an original getwork, or 'C:n.nnn' if it was
a clone with n.nnn stating how long after the work was recieved that it was cloned,
(m.mmm) is how long from when the original work was received until work started,
W:n.nnn is how long the work took to process until it was ready to submit,
(m.mmm) is how long from ready to submit to actually doing the submit, this is
usually 0.000 unless there was a problem with submitting the work,
S:n.nnn is how long it took to submit the completed work and await the reply,
R:hh:mm:ss is the actual time the work submit reply was received
If you start cgminer with the --sharelog option, you can get detailed
information for each share found. The argument to the option may be "-" for
@ -816,7 +859,7 @@ driver version and ATI stream version. @@ -816,7 +859,7 @@ driver version and ATI stream version.
Q: cgminer reports no devices or only one device on startup on Linux although
I have multiple devices and drivers+SDK installed properly?
A: Try 'export DISPLAY=:0" before running cgminer.
A: Try "export DISPLAY=:0" before running cgminer.
Q: My network gets slower and slower and then dies for a minute?
A; Try the --net-delay option.
@ -843,10 +886,27 @@ They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin @@ -843,10 +886,27 @@ They are Field-Programmable Gate Arrays that have been programmed to do Bitcoin
mining. Since the acronym needs to be only 3 characters, the "Field-" part has
been skipped.
Q: How do I get my BFL device to auto-recognise?
A: The only thing that needs to be done is to load the driver for them, which
on linux would require:
sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
Q: How do I get my BFL/Icarus/Lancelot/Cairnsmore device to auto-recognise?
A: On linux, if the /dev/ttyUSB* devices don't automatically appear, the only
thing that needs to be done is to load the driver for them:
BFL: sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
Icarus: sudo modprobe pl2303 vendor=0x067b product=0x230
Lancelot: sudo modprobe ftdi_sio vendor=0x0403 product=0x6001
Cairnsmore: sudo modprobe ftdi_sio product=0x8350 vendor=0x0403
On windows you must install the pl2303 or ftdi driver required for the device
pl2303: http://prolificusa.com/pl-2303hx-drivers/
ftdi: http://www.ftdichip.com/Drivers/VCP.htm
Q: On linux I can see the /dev/ttyUSB* devices for my ICA/BFL/MMQ FPGA, but
cgminer can't mine on them
A: Make sure you have the required priviledges to access the /dev/ttyUSB* devices:
sudo ls -las /dev/ttyUSB*
will give output like:
0 crw-rw---- 1 root dialout 188, 0 2012-09-11 13:49 /dev/ttyUSB0
This means your account must have the group 'dialout' or root priviledges
To permanently give your account the 'dialout' group:
sudo usermod -G dialout `whoami`
Then logout and back in again
---

230
api.c

@ -166,11 +166,13 @@ static const char SEPARATOR = '|'; @@ -166,11 +166,13 @@ static const char SEPARATOR = '|';
#define SEPSTR "|"
static const char GPUSEP = ',';
static const char *APIVERSION = "1.18";
static const char *APIVERSION = "1.19";
static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *SICK = "Sick";
static const char *NOSTART = "NoStart";
static const char *INIT = "Initialising";
#endif
static const char *DISABLED = "Disabled";
static const char *ALIVE = "Alive";
static const char *REJECTING = "Rejecting";
@ -258,6 +260,8 @@ static const char *OSINFO = @@ -258,6 +260,8 @@ static const char *OSINFO =
#define _MINESTATS "STATS"
#define _CHECK "CHECK"
#define _MINECOIN "COIN"
#define _DEBUGSET "DEBUG"
#define _SETCONFIG "SETCONFIG"
static const char ISJSON = '{';
#define JSON0 "{"
@ -295,6 +299,8 @@ static const char ISJSON = '{'; @@ -295,6 +299,8 @@ static const char ISJSON = '{';
#define JSON_MINESTATS JSON1 _MINESTATS JSON2
#define JSON_CHECK JSON1 _CHECK JSON2
#define JSON_MINECOIN JSON1 _MINECOIN JSON2
#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2
#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2
#define JSON_END JSON4 JSON5
static const char *JSON_COMMAND = "command";
@ -390,6 +396,14 @@ static const char *JSON_PARAMETER = "parameter"; @@ -390,6 +396,14 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_INVBOOL 76
#define MSG_FOO 77
#define MSG_MINECOIN 78
#define MSG_DEBUGSET 79
#define MSG_PGAIDENT 80
#define MSG_PGANOID 81
#define MSG_SETCONFIG 82
#define MSG_UNKCON 83
#define MSG_INVNUM 84
#define MSG_CONPAR 85
#define MSG_CONVAL 86
enum code_severity {
SEVERITY_ERR,
@ -418,6 +432,7 @@ enum code_parameters { @@ -418,6 +432,7 @@ enum code_parameters {
PARAM_STR,
PARAM_BOTH,
PARAM_BOOL,
PARAM_SET,
PARAM_NONE
};
@ -543,12 +558,24 @@ struct CODES { @@ -543,12 +558,24 @@ struct CODES {
{ SEVERITY_ERR, MSG_INVBOOL, PARAM_NONE, "Invalid parameter should be true or false" },
{ SEVERITY_SUCC, MSG_FOO, PARAM_BOOL, "Failover-Only set to %s" },
{ SEVERITY_SUCC, MSG_MINECOIN,PARAM_NONE, "CGMiner coin" },
{ SEVERITY_SUCC, MSG_DEBUGSET,PARAM_STR, "Debug settings" },
#ifdef HAVE_AN_FPGA
{ SEVERITY_SUCC, MSG_PGAIDENT,PARAM_PGA, "Identify command sent to PGA%d" },
{ SEVERITY_WARN, MSG_PGANOID, PARAM_PGA, "PGA%d does not support identify" },
#endif
{ SEVERITY_SUCC, MSG_SETCONFIG,PARAM_SET, "Set config '%s' to %d" },
{ SEVERITY_ERR, MSG_UNKCON, PARAM_STR, "Unknown config '%s'" },
{ SEVERITY_ERR, MSG_INVNUM, PARAM_BOTH, "Invalid number (%d) for '%s' range is 0-9999" },
{ SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" },
{ SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" },
{ SEVERITY_FAIL, 0, 0, NULL }
};
static int my_thr_id = 0;
static bool bye;
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static bool ping = true;
#endif
// Used to control quit restart access to shutdown variables
static pthread_mutex_t quit_restart_lock;
@ -749,6 +776,7 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu @@ -749,6 +776,7 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
case API_UTILITY:
case API_FREQ:
case API_HS:
case API_DIFF:
api_data->data = (void *)malloc(sizeof(double));
*((double *)(api_data->data)) = *((double *)data);
break;
@ -875,6 +903,11 @@ struct api_data *api_add_hs(struct api_data *root, char *name, double *data, boo @@ -875,6 +903,11 @@ struct api_data *api_add_hs(struct api_data *root, char *name, double *data, boo
return api_add_data_full(root, name, API_HS, (void *)data, copy_data);
}
struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data)
{
return api_add_data_full(root, name, API_DIFF, (void *)data, copy_data);
}
static struct api_data *print_data(struct api_data *root, char *buf, bool isjson)
{
struct api_data *tmp;
@ -946,6 +979,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson @@ -946,6 +979,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
case API_HS:
sprintf(buf, "%.15f", *((double *)(root->data)));
break;
case API_DIFF:
sprintf(buf, "%.8f", *((double *)(root->data)));
break;
case API_BOOL:
sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
break;
@ -1155,6 +1191,9 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) @@ -1155,6 +1191,9 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
case PARAM_BOOL:
sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR);
break;
case PARAM_SET:
sprintf(buf, codes[i].description, param2, paramid);
break;
case PARAM_NONE:
default:
strcpy(buf, codes[i].description);
@ -1163,8 +1202,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) @@ -1163,8 +1202,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
root = api_add_string(root, _STATUS, severity, false);
root = api_add_time(root, "When", &when, false);
root = api_add_int(root, "Code", &messageid, false);
root = api_add_string(root, "Msg", buf, false);
root = api_add_string(root, "Description", opt_api_description, false);
root = api_add_escape(root, "Msg", buf, false);
root = api_add_escape(root, "Description", opt_api_description, false);
root = print_data(root, ptr, isjson);
if (isjson)
@ -1178,8 +1217,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson) @@ -1178,8 +1217,8 @@ static char *message(int messageid, int paramid, char *param2, bool isjson)
int id = -1;
root = api_add_int(root, "Code", &id, false);
sprintf(buf, "%d", messageid);
root = api_add_string(root, "Msg", buf, false);
root = api_add_string(root, "Description", opt_api_description, false);
root = api_add_escape(root, "Msg", buf, false);
root = api_add_escape(root, "Description", opt_api_description, false);
root = print_data(root, ptr, isjson);
if (isjson)
@ -1257,6 +1296,8 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -1257,6 +1296,8 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
root = api_add_const(root, "OS", OSINFO, false);
root = api_add_bool(root, "Failover-Only", &opt_fail_only, false);
root = api_add_int(root, "ScanTime", &opt_scantime, false);
root = api_add_int(root, "Queue", &opt_queue, false);
root = api_add_int(root, "Expiry", &opt_expiry, false);
root = print_data(root, buf, isjson);
if (isjson)
@ -1264,6 +1305,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -1264,6 +1305,7 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
strcat(io_buffer, buf);
}
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *status2str(enum alive status)
{
switch (status) {
@ -1281,6 +1323,7 @@ static const char *status2str(enum alive status) @@ -1281,6 +1323,7 @@ static const char *status2str(enum alive status)
return UNKNOWN;
}
}
#endif
#ifdef HAVE_OPENCL
static void gpustatus(int gpu, bool isjson)
@ -1341,6 +1384,10 @@ static void gpustatus(int gpu, bool isjson) @@ -1341,6 +1384,10 @@ static void gpustatus(int gpu, bool isjson)
root = api_add_int(root, "Last Share Pool", &last_share_pool, false);
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson);
strcat(io_buffer, buf);
@ -1424,6 +1471,10 @@ static void pgastatus(int pga, bool isjson) @@ -1424,6 +1471,10 @@ static void pgastatus(int pga, bool isjson)
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_freq(root, "Frequency", &frequency, false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson);
strcat(io_buffer, buf);
@ -1456,6 +1507,10 @@ static void cpustatus(int cpu, bool isjson) @@ -1456,6 +1507,10 @@ static void cpustatus(int cpu, bool isjson)
root = api_add_int(root, "Last Share Pool", &last_share_pool, false);
root = api_add_time(root, "Last Share Time", &(cgpu->last_share_pool_time), false);
root = api_add_mhtotal(root, "Total MH", &(cgpu->total_mhashes), false);
root = api_add_int(root, "Diff1 Work", &(cgpu->diff1), false);
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
root = print_data(root, buf, isjson);
strcat(io_buffer, buf);
@ -1693,6 +1748,44 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __ @@ -1693,6 +1748,44 @@ static void pgadisable(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __
strcpy(io_buffer, message(MSG_PGADIS, id, NULL, isjson));
}
static void pgaidentify(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
int numpga = numpgas();
int id;
if (numpga == 0) {
strcpy(io_buffer, message(MSG_PGANON, 0, NULL, isjson));
return;
}
if (param == NULL || *param == '\0') {
strcpy(io_buffer, message(MSG_MISID, 0, NULL, isjson));
return;
}
id = atoi(param);
if (id < 0 || id >= numpga) {
strcpy(io_buffer, message(MSG_INVPGA, id, NULL, isjson));
return;
}
int dev = pgadevice(id);
if (dev < 0) { // Should never happen
strcpy(io_buffer, message(MSG_INVPGA, id, NULL, isjson));
return;
}
struct cgpu_info *cgpu = devices[dev];
struct device_api *api = cgpu->api;
if (!api->identify_device)
strcpy(io_buffer, message(MSG_PGANOID, id, NULL, isjson));
else {
api->identify_device(cgpu);
strcpy(io_buffer, message(MSG_PGAIDENT, id, NULL, isjson));
}
}
#endif
#ifdef WANT_CPUMINE
@ -1790,6 +1883,17 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, @@ -1790,6 +1883,17 @@ static void poolstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param,
root = api_add_escape(root, "User", pool->rpc_user, false);
root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false);
root = api_add_int(root, "Diff1 Shares", &(pool->diff1), false);
if (pool->rpc_proxy) {
root = api_add_const(root, "Proxy Type", proxytype(pool->rpc_proxytype), false);
root = api_add_escape(root, "Proxy", pool->rpc_proxy, false);
} else {
root = api_add_const(root, "Proxy Type", BLANK, false);
root = api_add_const(root, "Proxy", BLANK, false);
}
root = api_add_diff(root, "Difficulty Accepted", &(pool->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(pool->diff_rejected), false);
root = api_add_diff(root, "Difficulty Stale", &(pool->diff_stale), false);
root = api_add_diff(root, "Last Share Difficulty", &(pool->last_share_diff), false);
if (isjson && (i > 0))
strcat(io_buffer, COMMA);
@ -1842,6 +1946,9 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo @@ -1842,6 +1946,9 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
root = api_add_uint(root, "Network Blocks", &(new_blocks), false);
root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), false);
root = api_add_utility(root, "Work Utility", &(work_utility), false);
root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), false);
root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), false);
root = print_data(root, buf, isjson);
if (isjson)
@ -2554,6 +2661,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unuse @@ -2554,6 +2661,7 @@ void notifystatus(int device, struct cgpu_info *cgpu, bool isjson, __maybe_unuse
root = api_add_int(root, "*Dev Over Heat", &(cgpu->dev_over_heat_count), false);
root = api_add_int(root, "*Dev Thermal Cutoff", &(cgpu->dev_thermal_cutoff_count), false);
root = api_add_int(root, "*Dev Comms Error", &(cgpu->dev_comms_error_count), false);
root = api_add_int(root, "*Dev Throttle", &(cgpu->dev_throttle_count), false);
if (isjson && (device > 0))
strcat(io_buffer, COMMA);
@ -2791,6 +2899,115 @@ static void minecoin(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo @@ -2791,6 +2899,115 @@ static void minecoin(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bo
strcat(io_buffer, buf);
}
static void debugstate(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
struct api_data *root = NULL;
char buf[TMPBUFSIZ];
if (param == NULL)
param = (char *)BLANK;
else
*param = tolower(*param);
switch(*param) {
case 's':
opt_realquiet = true;
break;
case 'q':
opt_quiet ^= true;
break;
case 'v':
opt_log_output ^= true;
if (opt_log_output)
opt_quiet = false;
break;
case 'd':
opt_debug ^= true;
opt_log_output = opt_debug;
if (opt_debug)
opt_quiet = false;
break;
case 'r':
opt_protocol ^= true;
if (opt_protocol)
opt_quiet = false;
break;
case 'p':
want_per_device_stats ^= true;
opt_log_output = want_per_device_stats;
break;
case 'n':
opt_log_output = false;
opt_debug = false;
opt_quiet = false;
opt_protocol = false;
want_per_device_stats = false;
opt_worktime = false;
break;
case 'w':
opt_worktime ^= true;
break;
default:
// anything else just reports the settings
break;
}
sprintf(io_buffer, isjson
? "%s," JSON_DEBUGSET
: "%s" _DEBUGSET ",",
message(MSG_DEBUGSET, 0, NULL, isjson));
root = api_add_bool(root, "Silent", &opt_realquiet, false);
root = api_add_bool(root, "Quiet", &opt_quiet, false);
root = api_add_bool(root, "Verbose", &opt_log_output, false);
root = api_add_bool(root, "Debug", &opt_debug, false);
root = api_add_bool(root, "RPCProto", &opt_protocol, false);
root = api_add_bool(root, "PerDevice", &want_per_device_stats, false);
root = api_add_bool(root, "WorkTime", &opt_worktime, false);
root = print_data(root, buf, isjson);
if (isjson)
strcat(buf, JSON_CLOSE);
strcat(io_buffer, buf);
}
static void setconfig(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
char *comma;
int value;
if (param == NULL || *param == '\0') {
strcpy(io_buffer, message(MSG_CONPAR, 0, NULL, isjson));
return;
}
comma = strchr(param, ',');
if (!comma) {
strcpy(io_buffer, message(MSG_CONVAL, 0, param, isjson));
return;
}
*(comma++) = '\0';
value = atoi(comma);
if (value < 0 || value > 9999) {
strcpy(io_buffer, message(MSG_INVNUM, value, param, isjson));
return;
}
if (strcasecmp(param, "queue") == 0)
opt_queue = value;
else if (strcasecmp(param, "scantime") == 0)
opt_scantime = value;
else if (strcasecmp(param, "expiry") == 0)
opt_expiry = value;
else {
strcpy(io_buffer, message(MSG_UNKCON, 0, param, isjson));
return;
}
strcpy(io_buffer, message(MSG_SETCONFIG, value, param, isjson));
}
static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS {
@ -2813,6 +3030,7 @@ struct CMDS { @@ -2813,6 +3030,7 @@ struct CMDS {
{ "pga", pgadev, false },
{ "pgaenable", pgaenable, true },
{ "pgadisable", pgadisable, true },
{ "pgaidentify", pgaidentify, true },
#endif
#ifdef WANT_CPUMINE
{ "cpu", cpudev, false },
@ -2843,6 +3061,8 @@ struct CMDS { @@ -2843,6 +3061,8 @@ struct CMDS {
{ "check", checkcommand, false },
{ "failover-only", failoveronly, true },
{ "coin", minecoin, false },
{ "debug", debugstate, true },
{ "setconfig", setconfig, true },
{ NULL, NULL, false }
};

230
cgminer.c

@ -86,14 +86,14 @@ static char packagename[255]; @@ -86,14 +86,14 @@ static char packagename[255];
bool opt_protocol;
static bool opt_benchmark;
bool have_longpoll;
static bool want_per_device_stats;
bool want_per_device_stats;
bool use_syslog;
bool opt_quiet;
static bool opt_realquiet;
bool opt_realquiet;
bool opt_loginput;
const int opt_cutofftemp = 95;
int opt_log_interval = 5;
static int opt_queue = 1;
int opt_queue = 1;
int opt_scantime = 60;
int opt_expiry = 120;
int opt_bench_algo = -1;
@ -142,6 +142,7 @@ bool opt_delaynet; @@ -142,6 +142,7 @@ bool opt_delaynet;
bool opt_disable_pool = true;
char *opt_icarus_options = NULL;
char *opt_icarus_timing = NULL;
bool opt_worktime;
char *opt_kernel_path;
char *cgminer_path;
@ -186,6 +187,7 @@ pthread_mutex_t control_lock; @@ -186,6 +187,7 @@ pthread_mutex_t control_lock;
int hw_errors;
int total_accepted, total_rejected, total_diff1;
int total_getworks, total_stale, total_discarded;
double total_diff_accepted, total_diff_rejected, total_diff_stale;
static int total_queued, staged_rollable;
unsigned int new_blocks;
static unsigned int work_block;
@ -226,6 +228,7 @@ static struct block *blocks = NULL; @@ -226,6 +228,7 @@ static struct block *blocks = NULL;
char *opt_socks_proxy = NULL;
static const char def_conf[] = "cgminer.conf";
static char *default_config;
static bool config_loaded;
static int include_count;
#define JSON_INCLUDE_CONF "include"
@ -357,7 +360,7 @@ static void sharelog(const char*disposition, const struct work*work) @@ -357,7 +360,7 @@ static void sharelog(const char*disposition, const struct work*work)
thr_id = work->thr_id;
cgpu = thr_info[thr_id].cgpu;
pool = work->pool;
t = (unsigned long int)work->share_found_time;
t = (unsigned long int)(work->tv_work_found.tv_sec);
target = bin2hex(work->target, sizeof(work->target));
if (unlikely(!target)) {
applog(LOG_ERR, "sharelog target OOM");
@ -419,6 +422,8 @@ static struct pool *add_pool(void) @@ -419,6 +422,8 @@ static struct pool *add_pool(void)
/* Make sure the pool doesn't think we've been idle since time 0 */
pool->tv_idle.tv_sec = ~0UL;
pool->rpc_proxy = NULL;
return pool;
}
@ -547,6 +552,8 @@ static char *set_url(char *arg) @@ -547,6 +552,8 @@ static char *set_url(char *arg)
add_pool();
pool = pools[total_urls - 1];
arg = get_proxy(arg, pool);
opt_set_charp(arg, &pool->rpc_url);
if (strncmp(arg, "http://", 7) &&
strncmp(arg, "https://", 8)) {
@ -1058,6 +1065,9 @@ static struct opt_table opt_config_table[] = { @@ -1058,6 +1065,9 @@ static struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--userpass|-O",
set_userpass, NULL, NULL,
"Username:Password pair for bitcoin JSON-RPC server"),
OPT_WITHOUT_ARG("--worktime",
opt_set_bool, &opt_worktime,
"Display extra work time debug information"),
OPT_WITH_ARG("--pools",
opt_set_bool, NULL, NULL, opt_hidden),
OPT_ENDTABLE
@ -1171,21 +1181,21 @@ static char *load_config(const char *arg, void __maybe_unused *unused) @@ -1171,21 +1181,21 @@ static char *load_config(const char *arg, void __maybe_unused *unused)
return parse_config(config, true);
}
static char *set_default_config(const char *arg)
{
opt_set_charp(arg, &default_config);
return NULL;
}
void default_save_file(char *filename);
static void load_default_config(void)
{
cnfbuf = malloc(PATH_MAX);
#if defined(unix)
if (getenv("HOME") && *getenv("HOME")) {
strcpy(cnfbuf, getenv("HOME"));
strcat(cnfbuf, "/");
} else
strcpy(cnfbuf, "");
strcat(cnfbuf, ".cgminer/");
#else
strcpy(cnfbuf, "");
#endif
strcat(cnfbuf, def_conf);
default_save_file(cnfbuf);
if (!access(cnfbuf, R_OK))
load_config(cnfbuf, NULL);
else {
@ -1233,6 +1243,10 @@ static struct opt_table opt_cmdline_table[] = { @@ -1233,6 +1243,10 @@ static struct opt_table opt_cmdline_table[] = {
load_config, NULL, NULL,
"Load a JSON-format configuration file\n"
"See example.conf for an example configuration."),
OPT_WITH_ARG("--default-config",
set_default_config, NULL, NULL,
"Specify the filename of the default config file\n"
"Loaded at start and used when saving without a name."),
OPT_WITHOUT_ARG("--help|-h",
opt_verusage_and_exit, NULL,
"Print this message"),
@ -1755,7 +1769,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1755,7 +1769,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
struct pool *pool = work->pool;
int rolltime;
uint32_t *hash32;
struct timeval tv_submit, tv_submit_reply;
char hashshow[64+1] = "";
char worktime[200] = "";
#ifdef __BIG_ENDIAN__
int swapcounter = 0;
@ -1780,8 +1796,10 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1780,8 +1796,10 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd);
gettimeofday(&tv_submit, NULL);
/* issue JSON-RPC request */
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true);
gettimeofday(&tv_submit_reply, NULL);
if (unlikely(!val)) {
applog(LOG_INFO, "submit_upstream_work json_rpc_call failed");
if (!pool_tset(pool, &pool->submit_fail)) {
@ -1803,6 +1821,47 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1803,6 +1821,47 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
sprintf(hashshow, "%08lx.%08lx%s", (unsigned long)(hash32[6]), (unsigned long)(hash32[5]),
work->block? " BLOCK!" : "");
}
if (opt_worktime) {
char workclone[20];
struct tm *tm, tm_getwork, tm_submit_reply;
double getwork_time = tdiff((struct timeval *)&(work->tv_getwork_reply),
(struct timeval *)&(work->tv_getwork));
double getwork_to_work = tdiff((struct timeval *)&(work->tv_work_start),
(struct timeval *)&(work->tv_getwork_reply));
double work_time = tdiff((struct timeval *)&(work->tv_work_found),
(struct timeval *)&(work->tv_work_start));
double work_to_submit = tdiff(&tv_submit,
(struct timeval *)&(work->tv_work_found));
double submit_time = tdiff(&tv_submit_reply, &tv_submit);
int diffplaces = 3;
tm = localtime(&(work->tv_getwork.tv_sec));
memcpy(&tm_getwork, tm, sizeof(struct tm));
tm = localtime(&(tv_submit_reply.tv_sec));
memcpy(&tm_submit_reply, tm, sizeof(struct tm));
if (work->clone) {
sprintf(workclone, "C:%1.3f",
tdiff((struct timeval *)&(work->tv_cloned),
(struct timeval *)&(work->tv_getwork_reply)));
}
else
strcpy(workclone, "O");
if (work->work_difficulty < 1)
diffplaces = 6;
sprintf(worktime, " <-%08lx.%08lx M:%c D:%1.*f G:%02d:%02d:%02d:%1.3f %s (%1.3f) W:%1.3f (%1.3f) S:%1.3f R:%02d:%02d:%02d",
(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 32 : 28])),
(unsigned long)swab32(*(uint32_t *)&(work->data[opt_scrypt ? 28 : 24])),
work->getwork_mode, diffplaces, work->work_difficulty,
tm_getwork.tm_hour, tm_getwork.tm_min,
tm_getwork.tm_sec, getwork_time, workclone,
getwork_to_work, work_time, work_to_submit, submit_time,
tm_submit_reply.tm_hour, tm_submit_reply.tm_min,
tm_submit_reply.tm_sec);
}
}
/* Theoretically threads could race when modifying accepted and
@ -1812,18 +1871,23 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1812,18 +1871,23 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
cgpu->accepted++;
total_accepted++;
pool->accepted++;
cgpu->diff_accepted += work->work_difficulty;
total_diff_accepted += work->work_difficulty;
pool->diff_accepted += work->work_difficulty;
pool->seq_rejects = 0;
cgpu->last_share_pool = pool->pool_no;
cgpu->last_share_pool_time = time(NULL);
cgpu->last_share_diff = work->work_difficulty;
pool->last_share_time = cgpu->last_share_pool_time;
pool->last_share_diff = work->work_difficulty;
applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)");
if (!QUIET) {
if (total_pools > 1)
applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s",
hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "");
applog(LOG_NOTICE, "Accepted %s %s %d pool %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, work->pool->pool_no, resubmit ? "(resubmit)" : "", worktime);
else
applog(LOG_NOTICE, "Accepted %s %s %d %s",
hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "");
applog(LOG_NOTICE, "Accepted %s %s %d %s%s",
hashshow, cgpu->api->name, cgpu->device_id, resubmit ? "(resubmit)" : "", worktime);
}
sharelog("accept", work);
if (opt_shares && total_accepted >= opt_shares) {
@ -1845,6 +1909,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1845,6 +1909,9 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
cgpu->rejected++;
total_rejected++;
pool->rejected++;
cgpu->diff_rejected += work->work_difficulty;
total_diff_rejected += work->work_difficulty;
pool->diff_rejected += work->work_difficulty;
pool->seq_rejects++;
applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)");
if (!QUIET) {
@ -1872,8 +1939,8 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub @@ -1872,8 +1939,8 @@ static bool submit_upstream_work(const struct work *work, CURL *curl, bool resub
} else
strcpy(reason, "");
applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s",
hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "");
applog(LOG_NOTICE, "Rejected %s %s %d %s%s %s%s",
hashshow, cgpu->api->name, cgpu->device_id, where, reason, resubmit ? "(resubmit)" : "", worktime);
sharelog(disposition, work);
}
@ -1973,6 +2040,25 @@ static inline struct pool *select_pool(bool lagging) @@ -1973,6 +2040,25 @@ static inline struct pool *select_pool(bool lagging)
return pool;
}
static double DIFFEXACTONE = 26959946667150639794667015087019630673637144422540572481103610249216.0;
/*
* Calculate the work share difficulty
*/
static void calc_diff(struct work *work)
{
double targ;
int i;
targ = 0;
for (i = 31; i >= 0; i--) {
targ *= 256;
targ += work->target[i];
}
work->work_difficulty = DIFFEXACTONE / (targ ? : DIFFEXACTONE);
}
static void get_benchmark_work(struct work *work)
{
// Use a random work block pulled from a pool
@ -1985,13 +2071,17 @@ static void get_benchmark_work(struct work *work) @@ -1985,13 +2071,17 @@ static void get_benchmark_work(struct work *work)
memcpy(work, &bench_block, min_size);
work->mandatory = true;
work->pool = pools[0];
gettimeofday(&(work->tv_getwork), NULL);
memcpy(&(work->tv_getwork_reply), &(work->tv_getwork), sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_BENCHMARK;
calc_diff(work);
}
static bool get_upstream_work(struct work *work, CURL *curl)
{
struct pool *pool = work->pool;
struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats);
struct timeval tv_start, tv_end, tv_elapsed;
struct timeval tv_elapsed;
json_t *val = NULL;
bool rc = false;
char *url;
@ -2000,7 +2090,7 @@ static bool get_upstream_work(struct work *work, CURL *curl) @@ -2000,7 +2090,7 @@ static bool get_upstream_work(struct work *work, CURL *curl)
url = pool->rpc_url;
gettimeofday(&tv_start, NULL);
gettimeofday(&(work->tv_getwork), NULL);
val = json_rpc_call(curl, url, pool->rpc_userpass, rpc_req, false,
false, &work->rolltime, pool, false);
@ -2013,8 +2103,8 @@ static bool get_upstream_work(struct work *work, CURL *curl) @@ -2013,8 +2103,8 @@ static bool get_upstream_work(struct work *work, CURL *curl)
} else
applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work");
gettimeofday(&tv_end, NULL);
timersub(&tv_end, &tv_start, &tv_elapsed);
gettimeofday(&(work->tv_getwork_reply), NULL);
timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed);
pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63;
pool_stats->getwork_wait_rolling /= 1.63;
@ -2031,6 +2121,8 @@ static bool get_upstream_work(struct work *work, CURL *curl) @@ -2031,6 +2121,8 @@ static bool get_upstream_work(struct work *work, CURL *curl)
work->pool = pool;
work->longpoll = false;
work->getwork_mode = GETWORK_MODE_POOL;
calc_diff(work);
total_getworks++;
pool->getwork_requested++;
@ -2339,6 +2431,7 @@ static struct work *make_clone(struct work *work) @@ -2339,6 +2431,7 @@ static struct work *make_clone(struct work *work)
memcpy(work_clone, work, sizeof(struct work));
work_clone->clone = true;
gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
work_clone->longpoll = false;
work_clone->mandatory = false;
/* Make cloned work appear slightly older to bias towards keeping the
@ -2537,6 +2630,8 @@ static void *submit_work_thread(void *userdata) @@ -2537,6 +2630,8 @@ static void *submit_work_thread(void *userdata)
sharelog("discard", work);
total_stale++;
pool->stale_shares++;
total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty;
goto out;
}
work->stale = true;
@ -2550,6 +2645,8 @@ static void *submit_work_thread(void *userdata) @@ -2550,6 +2645,8 @@ static void *submit_work_thread(void *userdata)
applog(LOG_NOTICE, "Share became stale while retrying submit, discarding");
total_stale++;
pool->stale_shares++;
total_diff_stale += work->work_difficulty;
pool->diff_stale += work->work_difficulty;
break;
}
@ -2996,6 +3093,8 @@ static void display_pool_summary(struct pool *pool) @@ -2996,6 +3093,8 @@ static void display_pool_summary(struct pool *pool)
wlog(" Share submissions: %d\n", pool->accepted + pool->rejected);
wlog(" Accepted shares: %d\n", pool->accepted);
wlog(" Rejected shares: %d\n", pool->rejected);
wlog(" Accepted difficulty shares: %1.f\n", pool->diff_accepted);
wlog(" Rejected difficulty shares: %1.f\n", pool->diff_rejected);
if (pool->accepted || pool->rejected)
wlog(" Reject ratio: %.1f%%\n", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected));
efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0;
@ -3089,7 +3188,11 @@ void write_config(FILE *fcfg) @@ -3089,7 +3188,11 @@ void write_config(FILE *fcfg)
/* Write pool values */
fputs("{\n\"pools\" : [", fcfg);
for(i = 0; i < total_pools; i++) {
fprintf(fcfg, "%s\n\t{\n\t\t\"url\" : \"%s\",", i > 0 ? "," : "", json_escape(pools[i]->rpc_url));
fprintf(fcfg, "%s\n\t{\n\t\t\"url\" : \"%s%s%s%s\",", i > 0 ? "," : "",
pools[i]->rpc_proxy ? json_escape((char *)proxytype(pools[i]->rpc_proxytype)) : "",
pools[i]->rpc_proxy ? json_escape(pools[i]->rpc_proxy) : "",
pools[i]->rpc_proxy ? "|" : "",
json_escape(pools[i]->rpc_url));
fprintf(fcfg, "\n\t\t\"user\" : \"%s\",", json_escape(pools[i]->rpc_user));
fprintf(fcfg, "\n\t\t\"pass\" : \"%s\"\n\t}", json_escape(pools[i]->rpc_pass));
}
@ -3412,12 +3515,13 @@ static void display_options(void) @@ -3412,12 +3515,13 @@ static void display_options(void)
clear_logwin();
retry:
wlogprint("[N]ormal [C]lear [S]ilent mode (disable all output)\n");
wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n[R]PC debug:%s\n[L]og interval:%d\n",
wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n[R]PC debug:%s\n[W]orkTime details:%s\n[L]og interval:%d\n",
opt_debug ? "on" : "off",
want_per_device_stats? "on" : "off",
opt_quiet ? "on" : "off",
opt_log_output ? "on" : "off",
opt_protocol ? "on" : "off",
opt_worktime ? "on" : "off",
opt_log_interval);
wlogprint("Select an option or any other key to return\n");
input = getch();
@ -3470,6 +3574,10 @@ retry: @@ -3470,6 +3574,10 @@ retry:
goto retry;
} else if (!strncasecmp(&input, "s", 1)) {
opt_realquiet = true;
} else if (!strncasecmp(&input, "w", 1)) {
opt_worktime ^= true;
wlogprint("WorkTime details %s\n", opt_worktime ? "enabled" : "disabled");
goto retry;
} else
clear_logwin();
@ -3480,6 +3588,11 @@ retry: @@ -3480,6 +3588,11 @@ retry:
void default_save_file(char *filename)
{
if (default_config && *default_config) {
strcpy(filename, default_config);
return;
}
#if defined(unix)
if (getenv("HOME") && *getenv("HOME")) {
strcpy(filename, getenv("HOME"));
@ -3794,6 +3907,7 @@ static void *longpoll_thread(void *userdata); @@ -3794,6 +3907,7 @@ static void *longpoll_thread(void *userdata);
static bool pool_active(struct pool *pool, bool pinging)
{
struct timeval tv_getwork, tv_getwork_reply;
bool ret = false;
json_t *val;
CURL *curl;
@ -3806,8 +3920,10 @@ static bool pool_active(struct pool *pool, bool pinging) @@ -3806,8 +3920,10 @@ static bool pool_active(struct pool *pool, bool pinging)
}
applog(LOG_INFO, "Testing pool %s", pool->rpc_url);
gettimeofday(&tv_getwork, NULL);
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, rpc_req,
true, false, &rolltime, pool, false);
gettimeofday(&tv_getwork_reply, NULL);
if (val) {
struct work *work = make_work();
@ -3819,6 +3935,10 @@ static bool pool_active(struct pool *pool, bool pinging) @@ -3819,6 +3935,10 @@ static bool pool_active(struct pool *pool, bool pinging)
pool->pool_no, pool->rpc_url);
work->pool = pool;
work->rolltime = rolltime;
memcpy(&(work->tv_getwork), &tv_getwork, sizeof(struct timeval));
memcpy(&(work->tv_getwork_reply), &tv_getwork_reply, sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_TESTPOOL;
calc_diff(work);
applog(LOG_DEBUG, "Pushing pooltest work to base pool");
tq_push(thr_info[stage_thr_id].q, work);
@ -4110,7 +4230,7 @@ out: @@ -4110,7 +4230,7 @@ out:
work->mined = true;
}
bool submit_work_sync(struct thr_info *thr, const struct work *work_in)
bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found)
{
struct workio_cmd *wc;
@ -4125,7 +4245,8 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in) @@ -4125,7 +4245,8 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in)
wc->cmd = WC_SUBMIT_WORK;
wc->thr = thr;
memcpy(wc->work, work_in, sizeof(*work_in));
wc->work->share_found_time = time(NULL);
if (tv_work_found)
memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));
applog(LOG_DEBUG, "Pushing submit work to work thread");
@ -4141,7 +4262,7 @@ err_out: @@ -4141,7 +4262,7 @@ err_out:
return false;
}
bool hashtest(const struct work *work)
static bool hashtest(struct thr_info *thr, const struct work *work)
{
uint32_t *data32 = (uint32_t *)(work->data);
unsigned char swap[128];
@ -4162,11 +4283,22 @@ bool hashtest(const struct work *work) @@ -4162,11 +4283,22 @@ bool hashtest(const struct work *work)
memcpy((void*)work->hash, hash2, 32);
return fulltest(work->hash, work->target);
if (hash2_32[7] != 0) {
applog(LOG_WARNING, "%s%d: invalid nonce - HW error",
thr->cgpu->api->name, thr->cgpu->device_id);
hw_errors++;
thr->cgpu->hw_errors++;
return false;
}
bool test = fulltest(work->hash, work->target);
if (!test)
applog(LOG_INFO, "Share below target");
return test;
}
bool test_nonce(struct work *work, uint32_t nonce)
static bool test_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{
if (opt_scrypt) {
uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12);
@ -4180,21 +4312,24 @@ bool test_nonce(struct work *work, uint32_t nonce) @@ -4180,21 +4312,24 @@ bool test_nonce(struct work *work, uint32_t nonce)
work->data[64 + 12 + 2] = (nonce >> 16) & 0xff;
work->data[64 + 12 + 3] = (nonce >> 24) & 0xff;
return hashtest(work);
return hashtest(thr, work);
}
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{
struct timeval tv_work_found;
gettimeofday(&tv_work_found, NULL);
total_diff1++;
thr->cgpu->diff1++;
work->pool->diff1++;
/* Do one last check before attempting to submit the work */
/* Side effect: sets work->data for us */
if (!test_nonce(work, nonce)) {
applog(LOG_INFO, "Share below target");
if (!test_nonce(thr, work, nonce))
return true;
}
return submit_work_sync(thr, work);
return submit_work_sync(thr, work, &tv_work_found);
}
static inline bool abandon_work(struct work *work, struct timeval *wdiff, uint64_t hashes)
@ -4309,6 +4444,8 @@ void *miner_thread(void *userdata) @@ -4309,6 +4444,8 @@ void *miner_thread(void *userdata)
}
pool_stats->getwork_calls++;
gettimeofday(&(work->tv_work_start), NULL);
thread_reportin(mythr);
hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
thread_reportin(mythr);
@ -4405,7 +4542,7 @@ enum { @@ -4405,7 +4542,7 @@ enum {
};
/* Stage another work item from the work returned in a longpoll */
static void convert_to_work(json_t *val, int rolltime, struct pool *pool)
static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct timeval *tv_lp, struct timeval *tv_lp_reply)
{
struct work *work;
bool rc;
@ -4421,6 +4558,10 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool) @@ -4421,6 +4558,10 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool)
work->pool = pool;
work->rolltime = rolltime;
work->longpoll = true;
memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval));
memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_LP;
calc_diff(work);
if (pool->enabled == POOL_REJECTING)
work->mandatory = true;
@ -4489,7 +4630,7 @@ static void *longpoll_thread(void *userdata) @@ -4489,7 +4630,7 @@ static void *longpoll_thread(void *userdata)
/* This *pool is the source of the actual longpoll, not the pool we've
* tied it to */
struct pool *pool = NULL;
struct timeval start, end;
struct timeval start, reply, end;
CURL *curl = NULL;
int failures = 0;
int rolltime;
@ -4534,13 +4675,16 @@ retry_pool: @@ -4534,13 +4675,16 @@ retry_pool:
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, rpc_req,
false, true, &rolltime, pool, false);
gettimeofday(&reply, NULL);
if (likely(val)) {
soval = json_object_get(json_object_get(val, "result"), "submitold");
if (soval)
pool->submit_old = json_is_true(soval);
else
pool->submit_old = false;
convert_to_work(val, rolltime, pool);
convert_to_work(val, rolltime, pool, &start, &reply);
failures = 0;
json_decref(val);
} else {
@ -4867,6 +5011,8 @@ static void print_summary(void) @@ -4867,6 +5011,8 @@ static void print_summary(void)
applog(LOG_WARNING, "Share submissions: %d", total_accepted + total_rejected);
applog(LOG_WARNING, "Accepted shares: %d", total_accepted);
applog(LOG_WARNING, "Rejected shares: %d", total_rejected);
applog(LOG_WARNING, "Accepted difficulty shares: %1.f", total_diff_accepted);
applog(LOG_WARNING, "Rejected difficulty shares: %1.f", total_diff_rejected);
if (total_accepted || total_rejected)
applog(LOG_WARNING, "Reject ratio: %.1f%%", (double)(total_rejected * 100) / (double)(total_accepted + total_rejected));
applog(LOG_WARNING, "Hardware errors: %d", hw_errors);
@ -4892,6 +5038,8 @@ static void print_summary(void) @@ -4892,6 +5038,8 @@ static void print_summary(void)
applog(LOG_WARNING, " Share submissions: %d", pool->accepted + pool->rejected);
applog(LOG_WARNING, " Accepted shares: %d", pool->accepted);
applog(LOG_WARNING, " Rejected shares: %d", pool->rejected);
applog(LOG_WARNING, " Accepted difficulty shares: %1.f", pool->diff_accepted);
applog(LOG_WARNING, " Rejected difficulty shares: %1.f", pool->diff_rejected);
if (pool->accepted || pool->rejected)
applog(LOG_WARNING, " Reject ratio: %.1f%%", (double)(pool->rejected * 100) / (double)(pool->accepted + pool->rejected));
efficiency = pool->getwork_requested ? pool->accepted * 100.0 / pool->getwork_requested : 0.0;
@ -4988,6 +5136,8 @@ void add_pool_details(bool live, char *url, char *user, char *pass) @@ -4988,6 +5136,8 @@ void add_pool_details(bool live, char *url, char *user, char *pass)
pool = add_pool();
url = get_proxy(url, pool);
pool->rpc_url = url;
pool->rpc_user = user;
pool->rpc_pass = pass;

62
driver-bitforce.c

@ -45,8 +45,8 @@ enum { @@ -45,8 +45,8 @@ enum {
#endif /* WIN32 */
#include "compat.h"
#include "fpgautils.h"
#include "miner.h"
#include "fpgautils.h"
#define BITFORCE_SLEEP_MS 500
#define BITFORCE_TIMEOUT_S 7
@ -99,6 +99,7 @@ static bool bitforce_detect_one(const char *devpath) @@ -99,6 +99,7 @@ static bool bitforce_detect_one(const char *devpath)
}
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
@ -229,7 +230,7 @@ static int bitforce_detect_auto(void) @@ -229,7 +230,7 @@ static int bitforce_detect_auto(void)
static void bitforce_detect(void)
{
serial_detect_auto(bitforce_api.dname, bitforce_detect_one, bitforce_detect_auto);
serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto);
}
static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
@ -309,6 +310,7 @@ void bitforce_init(struct cgpu_info *bitforce) @@ -309,6 +310,7 @@ void bitforce_init(struct cgpu_info *bitforce)
do {
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
@ -338,6 +340,37 @@ void bitforce_init(struct cgpu_info *bitforce) @@ -338,6 +340,37 @@ void bitforce_init(struct cgpu_info *bitforce)
mutex_unlock(&bitforce->device_mutex);
}
static void bitforce_flash_led(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
if (!fdDev)
return;
/* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */
if (bitforce->polling)
return;
/* It is not critical flashing the led so don't get stuck if we
* can't grab the mutex here */
if (mutex_trylock(&bitforce->device_mutex))
return;
BFwrite(fdDev, "ZMX", 3);
/* Once we've tried - don't do it until told to again */
bitforce->flash_led = false;
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
mutex_unlock(&bitforce->device_mutex);
return; // nothing is returned by the BFL
}
static bool bitforce_get_temp(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
@ -348,16 +381,23 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -348,16 +381,23 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
return false;
/* Do not try to get the temperature if we're polling for a result to
* minimise the change of interleaved results */
* minimise the chance of interleaved results */
if (bitforce->polling)
return true;
// Flash instead of Temp - doing both can be too slow
if (bitforce->flash_led) {
bitforce_flash_led(bitforce);
return true;
}
/* It is not critical getting temperature so don't get stuck if we
* can't grab the mutex here */
if (mutex_trylock(&bitforce->device_mutex))
return false;
BFwrite(fdDev, "ZLX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
@ -385,11 +425,14 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -385,11 +425,14 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
/* Use the temperature monitor as a kind of watchdog for when
* our responses are out of sync and flush the buffer to
* hopefully recover */
applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer");
applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer", bitforce->device_id);
bitforce->device_last_not_well = time(NULL);
bitforce->device_not_well_reason = REASON_DEV_THROTTLE;
bitforce->dev_throttle_count++;
/* Count throttling episodes as hardware errors */
bitforce->hw_errors++;
bitforce_clear_buffer(bitforce);
return false;;
return false;
}
return true;
@ -411,6 +454,7 @@ re_send: @@ -411,6 +454,7 @@ re_send:
BFwrite(fdDev, "ZPX", 3);
else
BFwrite(fdDev, "ZDX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
mutex_unlock(&bitforce->device_mutex);
@ -450,6 +494,7 @@ re_send: @@ -450,6 +494,7 @@ re_send:
BFwrite(fdDev, ob, 68);
}
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
@ -493,6 +538,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) @@ -493,6 +538,7 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
@ -637,6 +683,11 @@ static bool bitforce_get_stats(struct cgpu_info *bitforce) @@ -637,6 +683,11 @@ static bool bitforce_get_stats(struct cgpu_info *bitforce)
return bitforce_get_temp(bitforce);
}
static void bitforce_identify(struct cgpu_info *bitforce)
{
bitforce->flash_led = true;
}
static bool bitforce_thread_init(struct thr_info *thr)
{
struct cgpu_info *bitforce = thr->cgpu;
@ -673,6 +724,7 @@ struct device_api bitforce_api = { @@ -673,6 +724,7 @@ struct device_api bitforce_api = {
.reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats,
.identify_device = bitforce_identify,
.thread_prepare = bitforce_thread_prepare,
.thread_init = bitforce_thread_init,
.scanhash = bitforce_scanhash,

4
driver-cpu.c

@ -75,7 +75,7 @@ static inline void affine_to_cpu(int id, int cpu) @@ -75,7 +75,7 @@ static inline void affine_to_cpu(int id, int cpu)
/* TODO: resolve externals */
extern bool submit_work_sync(struct thr_info *thr, const struct work *work_in);
extern bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv);
extern char *set_int_range(const char *arg, int *i, int min, int max);
extern int dev_from_id(int thr_id);
@ -827,7 +827,7 @@ CPUSearch: @@ -827,7 +827,7 @@ CPUSearch:
/* if nonce found, submit work */
if (unlikely(rc)) {
applog(LOG_DEBUG, "CPU %d found something?", dev_from_id(thr_id));
if (unlikely(!submit_work_sync(thr, work))) {
if (unlikely(!submit_work_sync(thr, work, NULL))) {
applog(LOG_ERR, "Failed to submit_work_sync in miner_thread %d", thr_id);
}
work->blk.nonce = last_nonce + 1;

12
driver-icarus.c

@ -49,8 +49,8 @@ @@ -49,8 +49,8 @@
#endif
#include "elist.h"
#include "fpgautils.h"
#include "miner.h"
#include "fpgautils.h"
// The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
#define ICARUS_IO_SPEED 115200
@ -598,7 +598,7 @@ static bool icarus_detect_one(const char *devpath) @@ -598,7 +598,7 @@ static bool icarus_detect_one(const char *devpath)
static void icarus_detect()
{
serial_detect(icarus_api.dname, icarus_detect_one);
serial_detect(&icarus_api, icarus_detect_one);
}
static bool icarus_prepare(struct thr_info *thr)
@ -639,7 +639,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -639,7 +639,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
struct timeval tv_start, tv_finish, elapsed;
struct timeval tv_history_start, tv_history_finish;
double Ti, Xi;
int i;
int curr_hw_errors, i;
bool was_hw_error;
struct ICARUS_HISTORY *history0, *history;
int count;
@ -712,7 +713,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -712,7 +713,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
nonce = swab32(nonce);
#endif
curr_hw_errors = icarus->hw_errors;
submit_nonce(thr, work, nonce);
was_hw_error = (curr_hw_errors > icarus->hw_errors);
hash_count = (nonce & info->nonce_mask);
hash_count++;
@ -726,8 +729,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -726,8 +729,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
}
// ignore possible end condition values
// ignore possible end condition values ... and hw errors
if (info->do_icarus_timing
&& !was_hw_error
&& ((nonce & info->nonce_mask) > END_CONDITION)
&& ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) {
gettimeofday(&tv_history_start, NULL);

14
driver-modminer.c

@ -13,9 +13,9 @@ @@ -13,9 +13,9 @@
#include <stdio.h>
#include <unistd.h>
#include "fpgautils.h"
#include "logging.h"
#include "miner.h"
#include "fpgautils.h"
#define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd"
#define BISTREAM_USER_ID "\2\4$B"
@ -103,7 +103,7 @@ modminer_detect_auto() @@ -103,7 +103,7 @@ modminer_detect_auto()
static void
modminer_detect()
{
serial_detect_auto(modminer_api.dname, modminer_detect_one, modminer_detect_auto);
serial_detect_auto(&modminer_api, modminer_detect_one, modminer_detect_auto);
}
#define bailout(...) return _bailout(-1, modminer, __VA_ARGS__);
@ -404,7 +404,7 @@ modminer_process_results(struct thr_info*thr) @@ -404,7 +404,7 @@ modminer_process_results(struct thr_info*thr)
char cmd[2], temperature;
uint32_t nonce;
long iter;
bool bad;
int curr_hw_errors;
cmd[0] = '\x0a';
cmd[1] = fpgaid;
@ -441,12 +441,10 @@ modminer_process_results(struct thr_info*thr) @@ -441,12 +441,10 @@ modminer_process_results(struct thr_info*thr)
mutex_unlock(&modminer->device_mutex);
if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) {
state->no_nonce_counter = 0;
bad = !test_nonce(work, nonce);
if (!bad)
curr_hw_errors = modminer->hw_errors;
submit_nonce(thr, work, nonce);
else {
++hw_errors;
if (++modminer->hw_errors * 100 > 1000 + state->good_share_counter)
if (modminer->hw_errors > curr_hw_errors) {
if (modminer->hw_errors * 100 > 1000 + state->good_share_counter)
// Only reduce clocks if hardware errors are more than ~1% of results
modminer_reduce_clock(thr, true);
}

16
findnonce.c

@ -131,6 +131,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data) @@ -131,6 +131,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data)
blk->sevenA = blk->ctx_h + SHA256_K[7];
}
#if 0 // not used any more
#define P(t) (W[(t)&0xF] = W[(t-16)&0xF] + (rotate(W[(t-15)&0xF], 25) ^ rotate(W[(t-15)&0xF], 14) ^ (W[(t-15)&0xF] >> 3)) + W[(t-7)&0xF] + (rotate(W[(t-2)&0xF], 15) ^ rotate(W[(t-2)&0xF], 13) ^ (W[(t-2)&0xF] >> 10)))
#define IR(u) \
@ -167,6 +169,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data) @@ -167,6 +169,8 @@ void precalc_hash(dev_blk_ctx *blk, uint32_t *state, uint32_t *data)
R(E, F, G, H, A, B, C, D, P(u+4), SHA256_K[u+4]); \
R(D, E, F, G, H, A, B, C, P(u+5), SHA256_K[u+5])
#endif
struct pc_data {
struct thr_info *thr;
struct work *work;
@ -175,6 +179,8 @@ struct pc_data { @@ -175,6 +179,8 @@ struct pc_data {
int found;
};
#if 0 // not used any more
static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce)
{
dev_blk_ctx *blk = &pcd->work->blk;
@ -222,6 +228,8 @@ static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce) @@ -222,6 +228,8 @@ static void send_sha_nonce(struct pc_data *pcd, cl_uint nonce)
}
}
#endif
static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce)
{
struct thr_info *thr = pcd->thr;
@ -238,6 +246,8 @@ static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce) @@ -238,6 +246,8 @@ static void send_scrypt_nonce(struct pc_data *pcd, uint32_t nonce)
static void *postcalc_hash(void *userdata)
{
struct pc_data *pcd = (struct pc_data *)userdata;
struct thr_info *thr = pcd->thr;
struct work *work = pcd->work;
unsigned int entry = 0;
pthread_detach(pthread_self());
@ -248,8 +258,10 @@ static void *postcalc_hash(void *userdata) @@ -248,8 +258,10 @@ static void *postcalc_hash(void *userdata)
applog(LOG_DEBUG, "OCL NONCE %u found in slot %d", nonce, entry);
if (opt_scrypt)
send_scrypt_nonce(pcd, nonce);
else
send_sha_nonce(pcd, nonce);
else {
if (unlikely(submit_nonce(thr, work, nonce) == false))
applog(LOG_ERR, "Failed to submit work, exiting");
}
}
free(pcd);

53
fpgautils.c

@ -33,13 +33,12 @@ @@ -33,13 +33,12 @@
#endif
#include "elist.h"
#include "fpgautils.h"
#include "logging.h"
#include "miner.h"
#include "fpgautils.h"
#ifdef HAVE_LIBUDEV
int
serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
int serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
{
struct udev *udev = udev_new();
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
@ -69,15 +68,13 @@ serial_autodetect_udev(detectone_func_t detectone, const char*prodname) @@ -69,15 +68,13 @@ serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
return found;
}
#else
int
serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
{
return 0;
}
#endif
int
serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
int serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
{
#ifndef WIN32
DIR *D;
@ -107,30 +104,32 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname) @@ -107,30 +104,32 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
#endif
}
int
_serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
{
struct string_elist *iter, *tmp;
const char*s, *p;
const char *dev, *colon;
bool inhibitauto = false;
char found = 0;
size_t dnamel = strlen(dname);
size_t namel = strlen(api->name);
size_t dnamel = strlen(api->dname);
list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
s = iter->string;
if ((p = strchr(s, ':')) && p[1] != '\0') {
size_t plen = p - s;
if (plen != dnamel || strncasecmp(s, dname, plen))
dev = iter->string;
if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
size_t idlen = colon - dev;
// allow either name:device or dname:device
if ((idlen != namel || strncasecmp(dev, api->name, idlen))
&& (idlen != dnamel || strncasecmp(dev, api->dname, idlen)))
continue;
s = p + 1;
dev = colon + 1;
}
if (!strcmp(s, "auto"))
if (!strcmp(dev, "auto"))
forceauto = true;
else
if (!strcmp(s, "noauto"))
else if (!strcmp(dev, "noauto"))
inhibitauto = true;
else
if (detectone(s)) {
else if (detectone(dev)) {
string_elist_del(iter);
inhibitauto = true;
++found;
@ -311,8 +310,7 @@ void termios_debug(const char *devpath, struct termios *my_termios, const char * @@ -311,8 +310,7 @@ void termios_debug(const char *devpath, struct termios *my_termios, const char *
#endif
#endif
int
serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge)
int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge)
{
#ifdef WIN32
HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
@ -429,8 +427,7 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p @@ -429,8 +427,7 @@ serial_open(const char*devpath, unsigned long baud, signed short timeout, bool p
#endif
}
ssize_t
_serial_read(int fd, char *buf, size_t bufsiz, char *eol)
ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
{
ssize_t len, tlen = 0;
while (bufsiz) {
@ -446,8 +443,7 @@ _serial_read(int fd, char *buf, size_t bufsiz, char *eol) @@ -446,8 +443,7 @@ _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
return tlen;
}
static FILE*
_open_bitstream(const char*path, const char*subdir, const char*filename)
static FILE *_open_bitstream(const char *path, const char *subdir, const char *filename)
{
char fullpath[PATH_MAX];
strcpy(fullpath, path);
@ -471,8 +467,7 @@ _open_bitstream(const char*path, const char*subdir, const char*filename) @@ -471,8 +467,7 @@ _open_bitstream(const char*path, const char*subdir, const char*filename)
_open_bitstream(path, NULL); \
} while(0)
FILE*
open_bitstream(const char*dname, const char*filename)
FILE *open_bitstream(const char *dname, const char *filename)
{
FILE *f;

26
fpgautils.h

@ -16,24 +16,24 @@ @@ -16,24 +16,24 @@
typedef bool(*detectone_func_t)(const char*);
typedef int(*autoscan_func_t)();
extern int _serial_detect(const char*dname, detectone_func_t, autoscan_func_t, bool force_autoscan);
#define serial_detect_fauto(dname, detectone, autoscan) \
_serial_detect(dname, detectone, autoscan, true)
#define serial_detect_auto(dname, detectone, autoscan) \
_serial_detect(dname, detectone, autoscan, false)
#define serial_detect(dname, detectone) \
_serial_detect(dname, detectone, NULL, false)
extern int serial_autodetect_devserial(detectone_func_t, const char*prodname);
extern int serial_autodetect_udev (detectone_func_t, const char*prodname);
extern int _serial_detect(struct device_api *api, detectone_func_t, autoscan_func_t, bool force_autoscan);
#define serial_detect_fauto(api, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, true)
#define serial_detect_auto(api, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, false)
#define serial_detect(api, detectone) \
_serial_detect(api, detectone, NULL, false)
extern int serial_autodetect_devserial(detectone_func_t, const char *prodname);
extern int serial_autodetect_udev(detectone_func_t, const char *prodname);
extern int serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge);
extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char*eol);
extern int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge);
extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
#define serial_read(fd, buf, count) \
_serial_read(fd, (char*)(buf), count, NULL)
#define serial_read_line(fd, buf, bufsiz, eol) \
_serial_read(fd, buf, count, &eol)
_serial_read(fd, buf, bufsiz, &eol)
#define serial_close(fd) close(fd)
extern FILE*open_bitstream(const char*dname, const char*filename);
extern FILE *open_bitstream(const char *dname, const char *filename);
#endif

2
logging.h

@ -20,6 +20,8 @@ enum { @@ -20,6 +20,8 @@ enum {
/* original / legacy debug flags */
extern bool opt_debug;
extern bool opt_log_output;
extern bool opt_realquiet;
extern bool want_per_device_stats;
/* global log_level, messages with lower or equal prio are logged */
extern int opt_log_level;

42
miner.h

@ -239,6 +239,7 @@ struct device_api { @@ -239,6 +239,7 @@ struct device_api {
void (*get_statline)(char*, struct cgpu_info*);
struct api_data *(*get_api_stats)(struct cgpu_info*);
bool (*get_stats)(struct cgpu_info*);
void (*identify_device)(struct cgpu_info*); // e.g. to flash a led
// Thread-specific functions
bool (*thread_prepare)(struct thr_info*);
@ -276,6 +277,7 @@ enum dev_reason { @@ -276,6 +277,7 @@ enum dev_reason {
REASON_DEV_OVER_HEAT,
REASON_DEV_THERMAL_CUTOFF,
REASON_DEV_COMMS_ERROR,
REASON_DEV_THROTTLE,
};
#define REASON_NONE "None"
@ -288,6 +290,7 @@ enum dev_reason { @@ -288,6 +290,7 @@ enum dev_reason {
#define REASON_DEV_OVER_HEAT_STR "Device over heated"
#define REASON_DEV_THERMAL_CUTOFF_STR "Device reached thermal cutoff"
#define REASON_DEV_COMMS_ERROR_STR "Device comms error"
#define REASON_DEV_THROTTLE_STR "Device throttle"
#define REASON_UNKNOWN_STR "Unknown reason - code bug"
#define MIN_SEC_UNSET 99999999
@ -335,6 +338,7 @@ struct cgpu_info { @@ -335,6 +338,7 @@ struct cgpu_info {
uint32_t nonces;
bool nonce_range;
bool polling;
bool flash_led;
#endif
pthread_mutex_t device_mutex;
@ -395,8 +399,12 @@ struct cgpu_info { @@ -395,8 +399,12 @@ struct cgpu_info {
int gpu_powertune;
float gpu_vddc;
#endif
int diff1;
double diff_accepted;
double diff_rejected;
int last_share_pool;
time_t last_share_pool_time;
double last_share_diff;
time_t device_last_well;
time_t device_last_not_well;
@ -410,6 +418,7 @@ struct cgpu_info { @@ -410,6 +418,7 @@ struct cgpu_info {
int dev_over_heat_count; // It's a warning but worth knowing
int dev_thermal_cutoff_count;
int dev_comms_error_count;
int dev_throttle_count;
struct cgminer_stats cgminer_stats;
};
@ -449,6 +458,7 @@ extern void thr_info_cancel(struct thr_info *thr); @@ -449,6 +458,7 @@ extern void thr_info_cancel(struct thr_info *thr);
extern void thr_info_freeze(struct thr_info *thr);
extern void nmsleep(unsigned int msecs);
extern double us_tdiff(struct timeval *end, struct timeval *start);
extern double tdiff(struct timeval *end, struct timeval *start);
struct string_elist {
char *string;
@ -575,6 +585,7 @@ extern bool opt_delaynet; @@ -575,6 +585,7 @@ extern bool opt_delaynet;
extern bool opt_restart;
extern char *opt_icarus_options;
extern char *opt_icarus_timing;
extern bool opt_worktime;
#ifdef USE_BITFORCE
extern bool opt_bfl_noncerange;
#endif
@ -585,6 +596,8 @@ extern const uint32_t sha256_init_state[]; @@ -585,6 +596,8 @@ extern const uint32_t sha256_init_state[];
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, bool, bool, int *,
struct pool *pool, bool);
extern const char *proxytype(curl_proxytype proxytype);
extern char *get_proxy(char *url, struct pool *pool);
extern char *bin2hex(const unsigned char *p, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@ -598,7 +611,9 @@ typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate, @@ -598,7 +611,9 @@ typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate,
extern bool fulltest(const unsigned char *hash, const unsigned char *target);
extern int opt_queue;
extern int opt_scantime;
extern int opt_expiry;
extern pthread_mutex_t console_lock;
extern pthread_mutex_t ch_lock;
@ -671,6 +686,7 @@ extern unsigned int new_blocks; @@ -671,6 +686,7 @@ extern unsigned int new_blocks;
extern unsigned int found_blocks;
extern int total_accepted, total_rejected, total_diff1;;
extern int total_getworks, total_stale, total_discarded;
extern double total_diff_accepted, total_diff_rejected, total_diff_stale;
extern unsigned int local_work;
extern unsigned int total_go, total_ro;
extern const int opt_cutofftemp;
@ -735,6 +751,10 @@ struct pool { @@ -735,6 +751,10 @@ struct pool {
int solved;
int diff1;
double diff_accepted;
double diff_rejected;
double diff_stale;
int queued;
int staged;
@ -763,6 +783,8 @@ struct pool { @@ -763,6 +783,8 @@ struct pool {
char *rpc_url;
char *rpc_userpass;
char *rpc_user, *rpc_pass;
curl_proxytype rpc_proxytype;
char *rpc_proxy;
pthread_mutex_t pool_lock;
@ -778,11 +800,17 @@ struct pool { @@ -778,11 +800,17 @@ struct pool {
struct list_head curlring;
time_t last_share_time;
double last_share_diff;
struct cgminer_stats cgminer_stats;
struct cgminer_pool_stats cgminer_pool_stats;
};
#define GETWORK_MODE_TESTPOOL 'T'
#define GETWORK_MODE_POOL 'P'
#define GETWORK_MODE_LP 'L'
#define GETWORK_MODE_BENCHMARK 'B'
struct work {
unsigned char data[128];
unsigned char hash1[64];
@ -815,7 +843,14 @@ struct work { @@ -815,7 +843,14 @@ struct work {
int id;
UT_hash_handle hh;
time_t share_found_time;
double work_difficulty;
struct timeval tv_getwork;
struct timeval tv_getwork_reply;
struct timeval tv_cloned;
struct timeval tv_work_start;
struct timeval tv_work_found;
char getwork_mode;
};
#ifdef USE_MODMINER
@ -837,7 +872,6 @@ struct modminer_fpga_state { @@ -837,7 +872,6 @@ struct modminer_fpga_state {
#endif
extern void get_datestamp(char *, struct timeval *);
extern bool test_nonce(struct work *work, uint32_t nonce);
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern void tailsprintf(char *f, const char *fmt, ...);
extern void wlogprint(const char *f, ...);
@ -880,7 +914,8 @@ enum api_data_type { @@ -880,7 +914,8 @@ enum api_data_type {
API_UTILITY,
API_FREQ,
API_VOLTS,
API_HS
API_HS,
API_DIFF
};
struct api_data {
@ -911,5 +946,6 @@ extern struct api_data *api_add_utility(struct api_data *root, char *name, doubl @@ -911,5 +946,6 @@ extern struct api_data *api_add_utility(struct api_data *root, char *name, doubl
extern struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data);
extern struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data);
extern struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data);
extern struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data);
#endif /* __MINER_H__ */

79
miner.php

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
session_start();
#
global $title, $miner, $port, $readonly, $notify, $rigs;
global $rigtotals, $forcerigtotals;
global $rigipsecurity, $rigtotals, $forcerigtotals;
global $socksndtimeoutsec, $sockrcvtimeoutsec;
global $checklastshare, $poolinputs, $hidefields;
global $ignorerefresh, $changerefresh, $autorefresh;
@ -40,6 +40,10 @@ $poolinputs = false; @@ -40,6 +40,10 @@ $poolinputs = false;
# format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name'
$rigs = array('127.0.0.1:4028');
#
# Set $rigipsecurity to false to show the IP/Port of the rig
# in the socket error messages and also show the full socket message
$rigipsecurity = true;
#
# Set $rigtotals to true to display totals on the single rig page
# 'false' means no totals (and ignores $forcerigtotals)
# You can force it to always show rig totals when there is only
@ -226,7 +230,7 @@ function htmlhead($checkapi, $rig, $pg = null) @@ -226,7 +230,7 @@ function htmlhead($checkapi, $rig, $pg = null)
if ($readonly === false && $checkapi === true)
{
$error = null;
$access = api('privileged');
$access = api($rig, 'privileged');
if ($error != null
|| !isset($access['STATUS']['STATUS'])
|| $access['STATUS']['STATUS'] != 'S')
@ -275,8 +279,9 @@ global $haderror, $error; @@ -275,8 +279,9 @@ global $haderror, $error;
$haderror = false;
$error = null;
#
function getsock($addr, $port)
function getsock($rig, $addr, $port)
{
global $rigipsecurity;
global $haderror, $error, $socksndtimeoutsec, $sockrcvtimeoutsec;
$error = null;
@ -285,9 +290,15 @@ function getsock($addr, $port) @@ -285,9 +290,15 @@ function getsock($addr, $port)
if ($socket === false || $socket === null)
{
$haderror = true;
if ($rigipsecurity === false)
{
$error = socket_strerror(socket_last_error());
$msg = "socket create(TCP) failed";
$error = "ERR: $msg '$error'\n";
}
else
$error = "ERR: socket create(TCP) failed\n";
return null;
}
@ -301,9 +312,15 @@ function getsock($addr, $port) @@ -301,9 +312,15 @@ function getsock($addr, $port)
if ($res === false)
{
$haderror = true;
if ($rigipsecurity === false)
{
$error = socket_strerror(socket_last_error());
$msg = "socket connect($addr,$port) failed";
$error = "ERR: $msg '$error'\n";
}
else
$error = "ERR: socket connect($rig) failed\n";
socket_close($socket);
return null;
}
@ -365,12 +382,12 @@ function revert($str) @@ -365,12 +382,12 @@ function revert($str)
return str_replace(array("\1", "\2", "\3", "\4"), array("|", "\\", "=", ","), $str);
}
#
function api($cmd)
function api($rig, $cmd)
{
global $haderror, $error;
global $miner, $port, $hidefields;
$socket = getsock($miner, $port);
$socket = getsock($rig, $miner, $port);
if ($socket != null)
{
socket_write($socket, $cmd, strlen($cmd));
@ -506,7 +523,15 @@ function classlastshare($when, $alldata, $warnclass, $errorclass) @@ -506,7 +523,15 @@ function classlastshare($when, $alldata, $warnclass, $errorclass)
if (!isset($alldata['Last Share Time']))
return '';
if (!isset($alldata['Last Share Difficulty']))
return '';
$expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6));
// If the share difficulty changes while waiting on a share,
// this calculation will of course be incorrect
$expected *= $alldata['Last Share Difficulty'];
$howlong = $when - $alldata['Last Share Time'];
if ($howlong < 1)
$howlong = 1;
@ -641,11 +666,20 @@ function fmt($section, $name, $value, $when, $alldata) @@ -641,11 +666,20 @@ function fmt($section, $name, $value, $when, $alldata)
if ($value == 0)
$class = $errorclass;
else
if (isset($alldata['MHS av']))
if (isset($alldata['Difficulty Accepted'])
&& isset($alldata['Accepted'])
&& isset($alldata['MHS av'])
&& ($alldata['Difficulty Accepted'] > 0)
&& ($alldata['Accepted'] > 0))
{
$expected = 60 * $alldata['MHS av'] * (pow(10, 6) / pow(2, 32));
if ($expected == 0)
$expected = 0.000001; // 1 H/s
$da = $alldata['Difficulty Accepted'];
$a = $alldata['Accepted'];
$expected /= ($da / $a);
$ratio = $value / $expected;
if ($ratio < 0.9)
$class = $loclass;
@ -713,16 +747,26 @@ function fmt($section, $name, $value, $when, $alldata) @@ -713,16 +747,26 @@ function fmt($section, $name, $value, $when, $alldata)
$dec = '';
else
$dec = '.'.$parts[1];
$ret = number_format($parts[0]).$dec;
$ret = number_format((float)$parts[0]).$dec;
if ($value == 0)
$class = $errorclass;
else
if (isset($alldata['Utility']))
if (isset($alldata['Difficulty Accepted'])
&& isset($alldata['Accepted'])
&& isset($alldata['Utility'])
&& ($alldata['Difficulty Accepted'] > 0)
&& ($alldata['Accepted'] > 0))
{
$expected = 60 * $value * (pow(10, 6) / pow(2, 32));
$utility = $alldata['Utility'];
$ratio = $utility / $expected;
if ($expected == 0)
$expected = 0.000001; // 1 H/s
$da = $alldata['Difficulty Accepted'];
$a = $alldata['Accepted'];
$expected /= ($da / $a);
$ratio = $alldata['Utility'] / $expected;
if ($ratio < 0.9)
$class = $hiclass;
else
@ -757,12 +801,15 @@ function fmt($section, $name, $value, $when, $alldata) @@ -757,12 +801,15 @@ function fmt($section, $name, $value, $when, $alldata)
case 'total.Discarded':
case 'POOL.Diff1 Shares':
case 'total.Diff1 Shares':
case 'GPU.Diff1 Work':
case 'PGA.Diff1 Work':
case 'total.Diff1 Work':
$parts = explode('.', $value, 2);
if (count($parts) == 1)
$dec = '';
else
$dec = '.'.$parts[1];
$ret = number_format($parts[0]).$dec;
$ret = number_format((float)$parts[0]).$dec;
break;
case 'GPU.Status':
case 'PGA.Status':
@ -1067,7 +1114,7 @@ function processgpus($rig) @@ -1067,7 +1114,7 @@ function processgpus($rig)
global $error;
global $warnfont, $warnoff;
$gpus = api('gpucount');
$gpus = api($rig, 'gpucount');
if ($error != null)
otherrow("<td>Error getting GPU count: $warnfont$error$warnoff</td>");
@ -1136,7 +1183,7 @@ function process($cmds, $rig) @@ -1136,7 +1183,7 @@ function process($cmds, $rig)
$count = count($cmds);
foreach ($cmds as $cmd => $des)
{
$process = api($cmd);
$process = api($rig, $cmd);
if ($error != null)
{
@ -1251,7 +1298,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime) @@ -1251,7 +1298,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
else
$name = $num;
$ans = api($cmd);
$ans = api($name, $cmd);
if ($error != null)
{
@ -1763,7 +1810,7 @@ function processcustompage($pagename, $sections, $sum, $namemap) @@ -1763,7 +1810,7 @@ function processcustompage($pagename, $sections, $sum, $namemap)
foreach ($cmds as $cmd => $one)
{
$process = api($cmd);
$process = api($name, $cmd);
if ($error != null)
{
@ -2052,7 +2099,7 @@ function display() @@ -2052,7 +2099,7 @@ function display()
newtable();
doforeach('version', 'rig summary', array(), array(), true);
$sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH', 'Work Utility', 'Diff1 Shares');
$sum = array('MHS av', 'Getworks', 'Found Blocks', 'Accepted', 'Rejected', 'Discarded', 'Stale', 'Utility', 'Local Work', 'Total MH', 'Work Utility', 'Diff1 Shares', 'Diff1 Work');
doforeach('summary', 'summary information', $sum, array(), false);
endtable();
otherrow('<td><br><br></td>');

73
util.c

@ -305,7 +305,10 @@ json_t *json_rpc_call(CURL *curl, const char *url, @@ -305,7 +305,10 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, resp_hdr_cb);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &hi);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
if (opt_socks_proxy) {
if (pool->rpc_proxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, pool->rpc_proxy);
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, pool->rpc_proxytype);
} else if (opt_socks_proxy) {
curl_easy_setopt(curl, CURLOPT_PROXY, opt_socks_proxy);
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
}
@ -460,6 +463,68 @@ err_out: @@ -460,6 +463,68 @@ err_out:
return NULL;
}
#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
static struct {
const char *name;
curl_proxytype proxytype;
} proxynames[] = {
{ "http:", CURLPROXY_HTTP },
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 19) || (LIBCURL_VERSION_MINOR == 19 && LIBCURL_VERSION_PATCH >= 4)
{ "http0:", CURLPROXY_HTTP_1_0 },
#endif
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 15) || (LIBCURL_VERSION_MINOR == 15 && LIBCURL_VERSION_PATCH >= 2)
{ "socks4:", CURLPROXY_SOCKS4 },
#endif
{ "socks5:", CURLPROXY_SOCKS5 },
#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR >= 18)
{ "socks4a:", CURLPROXY_SOCKS4A },
{ "socks5h:", CURLPROXY_SOCKS5_HOSTNAME },
#endif
};
#endif
const char *proxytype(curl_proxytype proxytype)
{
int i;
for (i = 0; proxynames[i].name; i++)
if (proxynames[i].proxytype == proxytype)
return proxynames[i].name;
return "invalid";
}
char *get_proxy(char *url, struct pool *pool)
{
pool->rpc_proxy = NULL;
#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
char *split;
int plen, len, i;
for (i = 0; proxynames[i].name; i++) {
plen = strlen(proxynames[i].name);
if (strncmp(url, proxynames[i].name, plen) == 0) {
if (!(split = strchr(url, '|')))
return url;
*split = '\0';
len = split - url;
pool->rpc_proxy = malloc(1 + len - plen);
if (!(pool->rpc_proxy))
quit(1, "Failed to malloc rpc_proxy");
strcpy(pool->rpc_proxy, url + plen);
pool->rpc_proxytype = proxynames[i].proxytype;
url = split + 1;
break;
}
}
#endif
return url;
}
char *bin2hex(const unsigned char *p, size_t len)
{
char *s = malloc((len * 2) + 1);
@ -722,3 +787,9 @@ double us_tdiff(struct timeval *end, struct timeval *start) @@ -722,3 +787,9 @@ double us_tdiff(struct timeval *end, struct timeval *start)
{
return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
}
/* Returns the seconds difference between end and start times as a double */
double tdiff(struct timeval *end, struct timeval *start)
{
return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0;
}

Loading…
Cancel
Save