mirror of
https://github.com/GOSTSec/sgminer
synced 2025-01-11 23:37:54 +00:00
Merge branch 'master' of git://github.com/ckolivas/cgminer.git
This commit is contained in:
commit
c5696629d7
@ -383,7 +383,7 @@ miner.php - an example web page to access the API
|
||||
Feature Changelog for external applications using the API:
|
||||
|
||||
|
||||
API V1.19
|
||||
API V1.19 (cgminer v2.7.6)
|
||||
|
||||
Added API commands:
|
||||
'debug'
|
||||
|
@ -32,7 +32,7 @@ cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@
|
||||
cgminer_SOURCES := cgminer.c
|
||||
|
||||
cgminer_SOURCES += elist.h miner.h compat.h bench_block.h \
|
||||
util.c uthash.h logging.h \
|
||||
util.c util.h uthash.h logging.h \
|
||||
sha2.c sha2.h api.c
|
||||
|
||||
cgminer_SOURCES += logging.c
|
||||
|
225
NEWS
225
NEWS
@ -1,5 +1,230 @@
|
||||
Version 2.8.3 - October 12, 2012
|
||||
|
||||
- Left align values that are suffix_string generated.
|
||||
- Share_diff should not be converting the work data to hex.
|
||||
- Off by one error.
|
||||
- Prevent overflows of the port char array in extract_sockaddr.
|
||||
- Disable stratum detection with scrypt.
|
||||
- Use the suffix string function when displaying device hashrates.
|
||||
- Be consistent with the get_statline function.
|
||||
- Use the suffix string function for displaying hashrate with 4 significant
|
||||
digits.
|
||||
- Display the actual share diff next to the pool required diff, using a suffix
|
||||
creation function to prevent values of >1000 being shown in their entirety.
|
||||
- Fix 4 * 0 being 0 that would break dynamic intensity mode.
|
||||
- Fix wrong byteswap macro being used on mingw32 which was breaking target
|
||||
generation on stratum.
|
||||
|
||||
|
||||
Version 2.8.2 - October 11, 2012
|
||||
|
||||
- Reinstate the history on dynamic intensity mode to damp fluctuations in
|
||||
intensity but use an upper limit on how much the value can increase at any time
|
||||
to cope with rare overflows.
|
||||
- Create a fix-protocol option which prevents cgminer from switching to stratum
|
||||
if it's detected.
|
||||
- Simplify target generation code.
|
||||
- Add support for client.get_version for stratum.
|
||||
- Use a 64 bit unsigned integer on the diff target to generate the hex target.
|
||||
- Update reconnect message to show whole address including port.
|
||||
- Look for null values and parse correct separate array entries for url and port
|
||||
with client reconnect commands for stratum.
|
||||
- The command for stratum is client.reconnect, not mining.reconnect.
|
||||
- Only copy the stratum url to the rpc url if an rpc url does not exist.
|
||||
- Implement rudimentary mining.reconnect support for stratum.
|
||||
- Ignore the value of stratum_active on calling initiate_stratum and assume
|
||||
we're always trying to reinitiate it, and set the active flag to false in that
|
||||
function.
|
||||
- stratum auth can be unset if we fail to authorise on subsequent calls to
|
||||
auth_stratum which undoes the requirement of setting it in one place so set it
|
||||
in pool_active.
|
||||
|
||||
|
||||
Version 2.8.1 - October 8, 2012
|
||||
|
||||
- Use the stratum url as the rpc url advertised if we switch to it.
|
||||
- Count an invalid nonce count as a hardware error on opencl.
|
||||
- Count each stratum work item as local work.
|
||||
- Cope with one stratum pool being the only active pool when it dies by sleeping
|
||||
for 5 seconds before retrying to get work from it instead of getting work
|
||||
indefinitely.
|
||||
- Detect stratum outage based on either select timing out or receiving an empty
|
||||
buffer and properly re-establish connection by disabling the stratum_active
|
||||
flag, coping with empty buffers in parse_stratum.
|
||||
|
||||
|
||||
Version 2.8.0 - October 7, 2012
|
||||
|
||||
- Major upgrade - support for the stratum mining protocol.
|
||||
- Fix various modminer warnings on mingw.
|
||||
- Fix sign warning on windows build for bitforce.
|
||||
- Cast socketfail to integer since SOCKET is an unsigned int on windows.
|
||||
- Use strtod not strtol for bitforce temp backup.
|
||||
- Cope with broken drivers returning nonsense values for bitforce temperatures.
|
||||
- Minor warning fixes.
|
||||
- Use the stratum thread to detect when a stratum pool has died based on no
|
||||
message for 2 minutes.
|
||||
- Only set the stratum auth flag once and once the stratum thread is started,
|
||||
use that to set/unset the stratum active flag.
|
||||
- Only hand off to stratum from getwork if we succeed in initiating the
|
||||
protocol.
|
||||
- Target should only be 32 bytes copied.
|
||||
- Use a static array for work submission data instead of stack memory.
|
||||
- Clear the buffer data before sprinting to it.
|
||||
- Clear work stratum strings before setting them and add them to debug output.
|
||||
- Drop stratum connect failed message to verbose level only since it's a regular
|
||||
probing message.
|
||||
- TCP Keepalive in curl is only in very recent versions and not required with
|
||||
regular messages on stratum anyway.
|
||||
- Move stratum sockets to curl infrastructure with locking around send+recv to
|
||||
begin support for proxies and ssl.
|
||||
- Make detect stratum fail if a proxy has been set up.
|
||||
- Stratum does not currently have any proxy support so do not try to switch to
|
||||
stratum if a proxy has been specified.
|
||||
- Windows doesn't work with MSG_PEEK on recv so move to a continuously updating
|
||||
buffer for incoming messages.
|
||||
- Alloca is unreliable on windows so use static arrays in util.c stratum code.
|
||||
- Begin support for mingw stratum build.
|
||||
- Add space to reject reason.
|
||||
- Parse the reject reason where possible from stratum share submission.
|
||||
- Pass json error value to share result function to be able to parse reject
|
||||
reason in stratum.
|
||||
- Don't try to parse unneeded parameters in response to mining.subscribe.
|
||||
- Remove the sshare hash entry if we failed to send it.
|
||||
- Change notify message to info level to avoid spamming repeatedly when a pool
|
||||
is down.
|
||||
- Check the stratum pool difference has not changed compared to the work diff
|
||||
when testing whether a share meets the target or not and retarget if necessary.
|
||||
- Bit error in target calculation for stratum.
|
||||
- Set work_block in gen_stratum_work for when work is reused to avoid thinking
|
||||
it's all stale.
|
||||
- Offset the current block detection to the prev block hash.
|
||||
- We should be testing for id_val, not id in parse stratum response.
|
||||
- Make target on stratum scale to any size by clearing sequential bits according
|
||||
to diff.
|
||||
- Correct target calculation in gen_stratum_work.
|
||||
- If a share result has an error code but still has an id, it is likely a
|
||||
reject, not an error.
|
||||
- Initiate stratum the first time in pool_active only, allowing us to switch to
|
||||
it on getting a failed getwork and detecting the presence of stratum on the url
|
||||
at that time.
|
||||
- Use 5 second timeout on sock full for now as a temporary workaround.
|
||||
- If no stratum url is set by the end of the detect stratum routine, copy the
|
||||
sockaddr url.
|
||||
- Make all buffers slightly larger to prevent overflow.
|
||||
- Make the stratum recv buffer larger than the recvsize.
|
||||
- Userpass needs to be copied to user and pass earlier to allow stratum
|
||||
authorisation to work with it.
|
||||
- Store a sockaddr url of the stripped url used in determining sockaddr to not
|
||||
confuse it with the stratum url and fix build warnings.
|
||||
- Decrease the queued count with stratum work once it's staged as well.
|
||||
- Allow the stratum retry to initiate and auth stratum in pool_alive to make
|
||||
sure the stratum thread is started.
|
||||
- Avoid duplicating pool->rpc_url and setting pool->stratum_url twice to itself.
|
||||
- Detect if a getwork based pool has the X-Stratum header on startup, and if so,
|
||||
switch to the stratum based pool.
|
||||
- Comment update.
|
||||
- Minor message change.
|
||||
- Create a work item from a "clean" request from stratum allowing the new block
|
||||
to be detected and the appropriate block change message to be given.
|
||||
- Use statically allocated stratum strings in struct work to cope with the
|
||||
inability to safely deallocate dynamically allocated ram.
|
||||
- Use the current pool when deciding whether to reuse work from a stratum source
|
||||
rather than the work's previous pool.
|
||||
- Copy the stratum url to the rpc url to avoid none being set.
|
||||
- Provide locking around stratum send operations to avoid races.
|
||||
- Submit shares from stratum through the abstracted submit share function
|
||||
detecting what message they belong to and showing the data from the associated
|
||||
work, and then deleting it from the hash.
|
||||
- Use a more robust mechanism to obtain a \n terminated string over a socket.
|
||||
- Abstract out share submit as a function to be useable by stratum.
|
||||
- Rename parse_stratum to parse_method as it is only for stratum messages that
|
||||
contain methods.
|
||||
- Display stratum as mechanism in status line when current pool is running it.
|
||||
- Count each stratum notify as a getwork equivalent.
|
||||
- Correct nonce submitted with share.
|
||||
- Extranonce2 should be added before coinbase2.
|
||||
- We should be hashing the binary coinbase, not the hex one.
|
||||
- Fix endianness of nonce submitted for stratum.
|
||||
- Check that stratum is already active in initiate_stratum to avoid
|
||||
de-authorising ourselves by subscribing again.
|
||||
- Begin implementing a hash database of submissions and attempt sending results.
|
||||
- Copy parameters from stratum work required for share submission.
|
||||
- Set lagging flag on first adding a pool to prevent pool slow warning at
|
||||
startup.
|
||||
- Fix work->target being a 32 byte binary in gen_stratum_work.
|
||||
- Store and display stripped url in its own variable.
|
||||
- Create machinery to divert work requests to stratum.
|
||||
- Generate the work target in gen_stratum_work, setting default diff to 1 in
|
||||
case it is not yet set.
|
||||
- Generate work data, midstate and hash1 in gen_stratum_work.
|
||||
- Generate header created from stratum structures in gen_stratum_work.
|
||||
- Generate merkle root hash in gen_stratum_work.
|
||||
- Generate the coinbase for generation of stratum based work.
|
||||
- The number of transactions is variable so make merkle a variable length
|
||||
dynamically allocated array and track how many there are for stratum.
|
||||
- Rename nonce2 to n2size reflecting that it's a size variable and not the
|
||||
actual nonce.
|
||||
- Provide rudimentary support for stratum clean work command in the stratum
|
||||
thread.
|
||||
- Cope with pools being removed in the stratum thread.
|
||||
- Use the pool sock value directly in the stratum thread in case it changes
|
||||
after reconnecting.
|
||||
- Create a stratum thread per pool that has stratum that monitors the socket and
|
||||
serves received data.
|
||||
- Check return value of stratum_parse.
|
||||
- Complete authorisation in stratum.
|
||||
- Implement stratum parsing of notify parameters and storing them in the pool
|
||||
stratum work structure.
|
||||
- Create helper functions for duplicating json strings to avoid keeping json
|
||||
references in use.
|
||||
- Append \n in the sock_send function instead of adding it when constructing
|
||||
json in stratum.
|
||||
- Don't keep any json references around with stratum structures.
|
||||
- Create parse_stratum function that hands off stratum parameters to other
|
||||
functions to manage pool stratum work struct variables. Implement mining
|
||||
difficulty setting.
|
||||
- Create helper functions for checking when a socket is ready to read on and
|
||||
receive a single line at a time. Begin stratum authorisation process.
|
||||
- Provide a helper function for reading a single \n terminated string from a
|
||||
socket.
|
||||
- Create a stratum work structure to store current work variables.
|
||||
- Test specifically for stratum being active in pool_active.
|
||||
- Detect stratum in common place when adding urls, and use a bool to tell us
|
||||
when it's active.
|
||||
- Fix warnings.
|
||||
- Extract and store various parameters on stratum init confirming successful
|
||||
mining notify.
|
||||
- Use existing socket macros and close the socket on failure in init stratum.
|
||||
- Initiate stratum and grab first json result.
|
||||
- Get detailed addressinfo from the parsed URL for future raw socket usage when
|
||||
possible. IPV4 only for now.
|
||||
- Prepare for getaddrinfo call.
|
||||
- Add data structures to pool struct for socket communications.
|
||||
- Put all socket definitions in util.h to allow reusing by added socket
|
||||
functions to be used in util.c.
|
||||
|
||||
|
||||
Version 2.7.7 - October 7, 2012
|
||||
|
||||
- Fix unused warnings on ming build.
|
||||
- Fix sign warning in ocl.c
|
||||
- fds need to be zeroed before set in modminer.
|
||||
- Put scrypt warning on separate line to avoid 0 being shown on windows as
|
||||
bufsize.
|
||||
- Display correct pool number when block is found.
|
||||
- Prevent corrupt values returned from the opencl code from trying to read
|
||||
beyond the end of the buffer by masking the value to a max of 15.
|
||||
- Icarus USB write failure is also a comms error
|
||||
- api.c DEBUG message has no paramter
|
||||
- Icarus catch more USB errors and close/reopen the port
|
||||
- API-README update cgminer verison number
|
||||
- hashmeter fix stats kh/s on 32bit windows
|
||||
|
||||
|
||||
Version 2.7.6 - September 24, 2012
|
||||
|
||||
- Reorder libztex header include order to fix missing struct definition.
|
||||
- Display share difficulty on log with a shortened hash display on submission.
|
||||
- API stats add some pool getwork difficulty stats
|
||||
- Ignore any pings pushed to the worker threads if the thread is still paused to
|
||||
|
30
README
30
README
@ -146,6 +146,7 @@ Options for both config file and command line:
|
||||
--debug|-D Enable debug output
|
||||
--expiry|-E <arg> Upper bound on how many seconds after getting work we consider a share from it stale (default: 120)
|
||||
--failover-only Don't leak work to backup pools when primary pool is lagging
|
||||
--fix-protocol Do not redirect to a different getwork protocol (eg. stratum)
|
||||
--kernel-path|-K <arg> Specify a path to where bitstream and kernel files are (default: "/usr/local/bin")
|
||||
--load-balance Change multipool strategy from failover to efficiency based balance
|
||||
--log|-l <arg> Interval in seconds between log output (default: 5)
|
||||
@ -304,6 +305,10 @@ Single pool with a socks5 proxy, regular desktop:
|
||||
|
||||
cgminer -o "socks5:proxy:port|http://pool:port" -u username -p password
|
||||
|
||||
Single pool with stratum protocol support:
|
||||
|
||||
cgminer -o stratum+tcp://pool:port -u username -p password
|
||||
|
||||
The list of proxy types are:
|
||||
http: standard http 1.1 proxy
|
||||
http0: http 1.0 proxy
|
||||
@ -377,6 +382,17 @@ Thread 1: 60.2 Mh/s Enabled ALIVE
|
||||
Or press any other key to continue
|
||||
|
||||
|
||||
The running log shows output like this:
|
||||
|
||||
[2012-10-12 18:02:20] Accepted f0c05469 Diff 1/1 GPU 0 pool 1
|
||||
[2012-10-12 18:02:22] Accepted 218ac982 Diff 7/1 GPU 1 pool 1
|
||||
[2012-10-12 18:02:23] Accepted d8300795 Diff 1/1 GPU 3 pool 1
|
||||
[2012-10-12 18:02:24] Accepted 122c1ff1 Diff 14/1 GPU 1 pool 1
|
||||
|
||||
The 8 byte hex value are the 2nd 8 bytes of the share being submitted to the
|
||||
pool. The 2 diff values are the actual difficulty target that share reached
|
||||
followed by the difficulty target the pool is currently asking for.
|
||||
|
||||
---
|
||||
Also many issues and FAQs are covered in the forum thread
|
||||
dedicated to this program,
|
||||
@ -908,6 +924,20 @@ To permanently give your account the 'dialout' group:
|
||||
sudo usermod -G dialout -a `whoami`
|
||||
Then logout and back in again
|
||||
|
||||
Q: What is stratum and how do I use it?
|
||||
A: Stratum is a protocol designed for pooled mining in such a way as to
|
||||
minimise the amount of network communications, yet scale to hardware of any
|
||||
speed. With versions of cgminer 2.8.0+, if a pool has stratum support, cgminer
|
||||
will automatically detect it and switch to the support as advertised if it can.
|
||||
Stratum uses direct TCP connections to the pool and thus it will NOT currently
|
||||
work through a http proxy but will work via a socks proxy if you need to use
|
||||
one. If you input the stratum port directly into your configuration, or use the
|
||||
special prefix "stratum+tcp://" instead of "http://", cgminer will ONLY try to
|
||||
use stratum protocol mining. The advantages of stratum to the miner are no
|
||||
delays in getting more work for the miner, less rejects across block changes,
|
||||
and far less network communications for the same amount of mining hashrate. If
|
||||
you do NOT wish cgminer to automatically switch to stratum protocol even if it
|
||||
is detected, add the --fix-protocol option.
|
||||
|
||||
---
|
||||
|
||||
|
192
api.c
192
api.c
@ -25,122 +25,13 @@
|
||||
|
||||
#include "compat.h"
|
||||
#include "miner.h"
|
||||
#include "util.h"
|
||||
#include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
|
||||
|
||||
#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_ZTEX) || defined(USE_MODMINER)
|
||||
#define HAVE_AN_FPGA 1
|
||||
#endif
|
||||
|
||||
#if defined(unix) || defined(__APPLE__)
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define SOCKETTYPE int
|
||||
#define SOCKETFAIL(a) ((a) < 0)
|
||||
#define INVSOCK -1
|
||||
#define INVINETADDR -1
|
||||
#define CLOSESOCKET close
|
||||
|
||||
#define SOCKERRMSG strerror(errno)
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#define SOCKETTYPE SOCKET
|
||||
#define SOCKETFAIL(a) ((a) == SOCKET_ERROR)
|
||||
#define INVSOCK INVALID_SOCKET
|
||||
#define INVINETADDR INADDR_NONE
|
||||
#define CLOSESOCKET closesocket
|
||||
|
||||
static char WSAbuf[1024];
|
||||
|
||||
struct WSAERRORS {
|
||||
int id;
|
||||
char *code;
|
||||
} WSAErrors[] = {
|
||||
{ 0, "No error" },
|
||||
{ WSAEINTR, "Interrupted system call" },
|
||||
{ WSAEBADF, "Bad file number" },
|
||||
{ WSAEACCES, "Permission denied" },
|
||||
{ WSAEFAULT, "Bad address" },
|
||||
{ WSAEINVAL, "Invalid argument" },
|
||||
{ WSAEMFILE, "Too many open sockets" },
|
||||
{ WSAEWOULDBLOCK, "Operation would block" },
|
||||
{ WSAEINPROGRESS, "Operation now in progress" },
|
||||
{ WSAEALREADY, "Operation already in progress" },
|
||||
{ WSAENOTSOCK, "Socket operation on non-socket" },
|
||||
{ WSAEDESTADDRREQ, "Destination address required" },
|
||||
{ WSAEMSGSIZE, "Message too long" },
|
||||
{ WSAEPROTOTYPE, "Protocol wrong type for socket" },
|
||||
{ WSAENOPROTOOPT, "Bad protocol option" },
|
||||
{ WSAEPROTONOSUPPORT, "Protocol not supported" },
|
||||
{ WSAESOCKTNOSUPPORT, "Socket type not supported" },
|
||||
{ WSAEOPNOTSUPP, "Operation not supported on socket" },
|
||||
{ WSAEPFNOSUPPORT, "Protocol family not supported" },
|
||||
{ WSAEAFNOSUPPORT, "Address family not supported" },
|
||||
{ WSAEADDRINUSE, "Address already in use" },
|
||||
{ WSAEADDRNOTAVAIL, "Can't assign requested address" },
|
||||
{ WSAENETDOWN, "Network is down" },
|
||||
{ WSAENETUNREACH, "Network is unreachable" },
|
||||
{ WSAENETRESET, "Net connection reset" },
|
||||
{ WSAECONNABORTED, "Software caused connection abort" },
|
||||
{ WSAECONNRESET, "Connection reset by peer" },
|
||||
{ WSAENOBUFS, "No buffer space available" },
|
||||
{ WSAEISCONN, "Socket is already connected" },
|
||||
{ WSAENOTCONN, "Socket is not connected" },
|
||||
{ WSAESHUTDOWN, "Can't send after socket shutdown" },
|
||||
{ WSAETOOMANYREFS, "Too many references, can't splice" },
|
||||
{ WSAETIMEDOUT, "Connection timed out" },
|
||||
{ WSAECONNREFUSED, "Connection refused" },
|
||||
{ WSAELOOP, "Too many levels of symbolic links" },
|
||||
{ WSAENAMETOOLONG, "File name too long" },
|
||||
{ WSAEHOSTDOWN, "Host is down" },
|
||||
{ WSAEHOSTUNREACH, "No route to host" },
|
||||
{ WSAENOTEMPTY, "Directory not empty" },
|
||||
{ WSAEPROCLIM, "Too many processes" },
|
||||
{ WSAEUSERS, "Too many users" },
|
||||
{ WSAEDQUOT, "Disc quota exceeded" },
|
||||
{ WSAESTALE, "Stale NFS file handle" },
|
||||
{ WSAEREMOTE, "Too many levels of remote in path" },
|
||||
{ WSASYSNOTREADY, "Network system is unavailable" },
|
||||
{ WSAVERNOTSUPPORTED, "Winsock version out of range" },
|
||||
{ WSANOTINITIALISED, "WSAStartup not yet called" },
|
||||
{ WSAEDISCON, "Graceful shutdown in progress" },
|
||||
{ WSAHOST_NOT_FOUND, "Host not found" },
|
||||
{ WSANO_DATA, "No host data of that type was found" },
|
||||
{ -1, "Unknown error code" }
|
||||
};
|
||||
|
||||
static char *WSAErrorMsg()
|
||||
{
|
||||
int i;
|
||||
int id = WSAGetLastError();
|
||||
|
||||
/* Assume none of them are actually -1 */
|
||||
for (i = 0; WSAErrors[i].id != -1; i++)
|
||||
if (WSAErrors[i].id == id)
|
||||
break;
|
||||
|
||||
sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code);
|
||||
|
||||
return &(WSAbuf[0]);
|
||||
}
|
||||
|
||||
#define SOCKERRMSG WSAErrorMsg()
|
||||
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#endif
|
||||
|
||||
#ifndef in_addr_t
|
||||
#define in_addr_t uint32_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Big enough for largest API request
|
||||
// though a PC with 100s of PGAs/CPUs may exceed the size ...
|
||||
// Current code assumes it can socket send this size also
|
||||
@ -153,6 +44,80 @@
|
||||
// However lots of PGA's may mean more
|
||||
#define QUEUE 100
|
||||
|
||||
#if defined WIN32
|
||||
static char WSAbuf[1024];
|
||||
|
||||
struct WSAERRORS {
|
||||
int id;
|
||||
char *code;
|
||||
} WSAErrors[] = {
|
||||
{ 0, "No error" },
|
||||
{ WSAEINTR, "Interrupted system call" },
|
||||
{ WSAEBADF, "Bad file number" },
|
||||
{ WSAEACCES, "Permission denied" },
|
||||
{ WSAEFAULT, "Bad address" },
|
||||
{ WSAEINVAL, "Invalid argument" },
|
||||
{ WSAEMFILE, "Too many open sockets" },
|
||||
{ WSAEWOULDBLOCK, "Operation would block" },
|
||||
{ WSAEINPROGRESS, "Operation now in progress" },
|
||||
{ WSAEALREADY, "Operation already in progress" },
|
||||
{ WSAENOTSOCK, "Socket operation on non-socket" },
|
||||
{ WSAEDESTADDRREQ, "Destination address required" },
|
||||
{ WSAEMSGSIZE, "Message too long" },
|
||||
{ WSAEPROTOTYPE, "Protocol wrong type for socket" },
|
||||
{ WSAENOPROTOOPT, "Bad protocol option" },
|
||||
{ WSAEPROTONOSUPPORT, "Protocol not supported" },
|
||||
{ WSAESOCKTNOSUPPORT, "Socket type not supported" },
|
||||
{ WSAEOPNOTSUPP, "Operation not supported on socket" },
|
||||
{ WSAEPFNOSUPPORT, "Protocol family not supported" },
|
||||
{ WSAEAFNOSUPPORT, "Address family not supported" },
|
||||
{ WSAEADDRINUSE, "Address already in use" },
|
||||
{ WSAEADDRNOTAVAIL, "Can't assign requested address" },
|
||||
{ WSAENETDOWN, "Network is down" },
|
||||
{ WSAENETUNREACH, "Network is unreachable" },
|
||||
{ WSAENETRESET, "Net connection reset" },
|
||||
{ WSAECONNABORTED, "Software caused connection abort" },
|
||||
{ WSAECONNRESET, "Connection reset by peer" },
|
||||
{ WSAENOBUFS, "No buffer space available" },
|
||||
{ WSAEISCONN, "Socket is already connected" },
|
||||
{ WSAENOTCONN, "Socket is not connected" },
|
||||
{ WSAESHUTDOWN, "Can't send after socket shutdown" },
|
||||
{ WSAETOOMANYREFS, "Too many references, can't splice" },
|
||||
{ WSAETIMEDOUT, "Connection timed out" },
|
||||
{ WSAECONNREFUSED, "Connection refused" },
|
||||
{ WSAELOOP, "Too many levels of symbolic links" },
|
||||
{ WSAENAMETOOLONG, "File name too long" },
|
||||
{ WSAEHOSTDOWN, "Host is down" },
|
||||
{ WSAEHOSTUNREACH, "No route to host" },
|
||||
{ WSAENOTEMPTY, "Directory not empty" },
|
||||
{ WSAEPROCLIM, "Too many processes" },
|
||||
{ WSAEUSERS, "Too many users" },
|
||||
{ WSAEDQUOT, "Disc quota exceeded" },
|
||||
{ WSAESTALE, "Stale NFS file handle" },
|
||||
{ WSAEREMOTE, "Too many levels of remote in path" },
|
||||
{ WSASYSNOTREADY, "Network system is unavailable" },
|
||||
{ WSAVERNOTSUPPORTED, "Winsock version out of range" },
|
||||
{ WSANOTINITIALISED, "WSAStartup not yet called" },
|
||||
{ WSAEDISCON, "Graceful shutdown in progress" },
|
||||
{ WSAHOST_NOT_FOUND, "Host not found" },
|
||||
{ WSANO_DATA, "No host data of that type was found" },
|
||||
{ -1, "Unknown error code" }
|
||||
};
|
||||
|
||||
char *WSAErrorMsg(void) {
|
||||
int i;
|
||||
int id = WSAGetLastError();
|
||||
|
||||
/* Assume none of them are actually -1 */
|
||||
for (i = 0; WSAErrors[i].id != -1; i++)
|
||||
if (WSAErrors[i].id == id)
|
||||
break;
|
||||
|
||||
sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code);
|
||||
|
||||
return &(WSAbuf[0]);
|
||||
}
|
||||
#endif
|
||||
static char *io_buffer = NULL;
|
||||
static char *msg_buffer = NULL;
|
||||
static SOCKETTYPE sock = INVSOCK;
|
||||
@ -558,7 +523,7 @@ 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" },
|
||||
{ SEVERITY_SUCC, MSG_DEBUGSET,PARAM_NONE, "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" },
|
||||
@ -2210,6 +2175,7 @@ exitsama:
|
||||
static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
|
||||
{
|
||||
char *url, *user, *pass;
|
||||
struct pool *pool;
|
||||
char *ptr;
|
||||
|
||||
if (param == NULL || *param == '\0') {
|
||||
@ -2226,7 +2192,9 @@ static void addpool(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __may
|
||||
return;
|
||||
}
|
||||
|
||||
add_pool_details(true, url, user, pass);
|
||||
pool = add_pool();
|
||||
detect_stratum(pool, url);
|
||||
add_pool_details(pool, true, url, user, pass);
|
||||
|
||||
ptr = escape_string(url, isjson);
|
||||
strcpy(io_buffer, message(MSG_ADDPOOL, 0, ptr, isjson));
|
||||
|
@ -1,8 +1,8 @@
|
||||
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
||||
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
||||
m4_define([v_maj], [2])
|
||||
m4_define([v_min], [7])
|
||||
m4_define([v_mic], [6])
|
||||
m4_define([v_min], [8])
|
||||
m4_define([v_mic], [3])
|
||||
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
|
||||
m4_define([v_ver], [v_maj.v_min.v_mic])
|
||||
m4_define([lt_rev], m4_eval(v_maj + v_min))
|
||||
@ -92,6 +92,7 @@ case $target in
|
||||
PTHREAD_FLAGS=""
|
||||
DLOPEN_FLAGS=""
|
||||
WS2_LIBS="-lws2_32"
|
||||
AC_DEFINE([_WIN32_WINNT], [0x0501], "WinNT version for XP+ support")
|
||||
;;
|
||||
powerpc-*-darwin*)
|
||||
CFLAGS="$CFLAGS -faltivec"
|
||||
@ -351,8 +352,7 @@ fi
|
||||
|
||||
PKG_PROG_PKG_CONFIG()
|
||||
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.15.6], [AC_DEFINE([CURL_HAS_SOCKOPT], [1], [Defined if version of curl supports sockopts.])],
|
||||
[PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.10.1], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.10.1])])])
|
||||
PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])
|
||||
AC_SUBST(LIBCURL_LIBS)
|
||||
|
||||
dnl CCAN wants to know a lot of vars.
|
||||
|
@ -154,7 +154,7 @@ static int bitforce_autodetect_ftdi(void)
|
||||
char **bufptrs;
|
||||
char *buf;
|
||||
int found = 0;
|
||||
int i;
|
||||
DWORD i;
|
||||
|
||||
FT_STATUS ftStatus;
|
||||
DWORD numDevs;
|
||||
@ -410,6 +410,11 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
|
||||
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) {
|
||||
float temp = strtof(s + 1, NULL);
|
||||
|
||||
/* Cope with older software that breaks and reads nonsense
|
||||
* values */
|
||||
if (temp > 100)
|
||||
temp = strtod(s + 1, NULL);
|
||||
|
||||
if (temp > 0) {
|
||||
bitforce->temp = temp;
|
||||
if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) {
|
||||
|
@ -29,6 +29,8 @@
|
||||
* nonce range is completely calculated.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
@ -223,6 +225,11 @@ static void rev(unsigned char *s, size_t l)
|
||||
#define icarus_open2(devpath, baud, purge) serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
|
||||
#define icarus_open(devpath, baud) icarus_open2(devpath, baud, false)
|
||||
|
||||
#define ICA_GETS_ERROR -1
|
||||
#define ICA_GETS_OK 0
|
||||
#define ICA_GETS_RESTART 1
|
||||
#define ICA_GETS_TIMEOUT 2
|
||||
|
||||
static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
@ -233,12 +240,14 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st
|
||||
// Read reply 1 byte at a time to get earliest tv_finish
|
||||
while (true) {
|
||||
ret = read(fd, buf, 1);
|
||||
if (ret < 0)
|
||||
return ICA_GETS_ERROR;
|
||||
|
||||
if (first)
|
||||
gettimeofday(tv_finish, NULL);
|
||||
|
||||
if (ret >= read_amount)
|
||||
return 0;
|
||||
return ICA_GETS_OK;
|
||||
|
||||
if (ret > 0) {
|
||||
buf += ret;
|
||||
@ -254,16 +263,16 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, st
|
||||
"Icarus Read: No data in %.2f seconds",
|
||||
(float)rc/(float)TIME_FACTOR);
|
||||
}
|
||||
return 1;
|
||||
return ICA_GETS_TIMEOUT;
|
||||
}
|
||||
|
||||
if (thr->work_restart) {
|
||||
if (thr && thr->work_restart) {
|
||||
if (opt_debug) {
|
||||
applog(LOG_DEBUG,
|
||||
"Icarus Read: Work restart at %.2f seconds",
|
||||
(float)(rc)/(float)TIME_FACTOR);
|
||||
}
|
||||
return 1;
|
||||
return ICA_GETS_RESTART;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -281,6 +290,13 @@ static int icarus_write(int fd, const void *buf, size_t bufLen)
|
||||
|
||||
#define icarus_close(fd) close(fd)
|
||||
|
||||
static void do_icarus_close(struct thr_info *thr)
|
||||
{
|
||||
struct cgpu_info *icarus = thr->cgpu;
|
||||
icarus_close(icarus->device_fd);
|
||||
icarus->device_fd = -1;
|
||||
}
|
||||
|
||||
static const char *timing_mode_str(enum timing_mode timing_mode)
|
||||
{
|
||||
switch(timing_mode) {
|
||||
@ -533,10 +549,7 @@ static bool icarus_detect_one(const char *devpath)
|
||||
gettimeofday(&tv_start, NULL);
|
||||
|
||||
memset(nonce_bin, 0, sizeof(nonce_bin));
|
||||
struct thr_info dummy = {
|
||||
.work_restart = false,
|
||||
};
|
||||
icarus_gets(nonce_bin, fd, &tv_finish, &dummy, 1);
|
||||
icarus_gets(nonce_bin, fd, &tv_finish, NULL, 1);
|
||||
|
||||
icarus_close(fd);
|
||||
|
||||
@ -563,6 +576,7 @@ static bool icarus_detect_one(const char *devpath)
|
||||
icarus = calloc(1, sizeof(struct cgpu_info));
|
||||
icarus->api = &icarus_api;
|
||||
icarus->device_path = strdup(devpath);
|
||||
icarus->device_fd = -1;
|
||||
icarus->threads = 1;
|
||||
add_cgpu(icarus);
|
||||
icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1));
|
||||
@ -607,6 +621,8 @@ static bool icarus_prepare(struct thr_info *thr)
|
||||
|
||||
struct timeval now;
|
||||
|
||||
icarus->device_fd = -1;
|
||||
|
||||
int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud);
|
||||
if (unlikely(-1 == fd)) {
|
||||
applog(LOG_ERR, "Failed to open Icarus on %s",
|
||||
@ -653,6 +669,17 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||
elapsed.tv_sec = elapsed.tv_usec = 0;
|
||||
|
||||
icarus = thr->cgpu;
|
||||
if (icarus->device_fd == -1)
|
||||
if (!icarus_prepare(thr)) {
|
||||
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id);
|
||||
icarus->device_last_not_well = time(NULL);
|
||||
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR;
|
||||
icarus->dev_comms_error_count++;
|
||||
|
||||
// fail the device if the reopen attempt fails
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = icarus->device_fd;
|
||||
|
||||
memset(ob_bin, 0, sizeof(ob_bin));
|
||||
@ -664,8 +691,14 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||
tcflush(fd, TCOFLUSH);
|
||||
#endif
|
||||
ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
|
||||
if (ret)
|
||||
return -1; /* This should never happen */
|
||||
if (ret) {
|
||||
do_icarus_close(thr);
|
||||
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id);
|
||||
icarus->device_last_not_well = time(NULL);
|
||||
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR;
|
||||
icarus->dev_comms_error_count++;
|
||||
return 0; /* This should never happen */
|
||||
}
|
||||
|
||||
gettimeofday(&tv_start, NULL);
|
||||
|
||||
@ -682,12 +715,19 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||
memset(nonce_bin, 0, sizeof(nonce_bin));
|
||||
info = icarus_info[icarus->device_id];
|
||||
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count);
|
||||
if (ret == ICA_GETS_ERROR) {
|
||||
do_icarus_close(thr);
|
||||
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id);
|
||||
icarus->device_last_not_well = time(NULL);
|
||||
icarus->device_not_well_reason = REASON_DEV_COMMS_ERROR;
|
||||
icarus->dev_comms_error_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
work->blk.nonce = 0xffffffff;
|
||||
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
|
||||
|
||||
// aborted before becoming idle, get new work
|
||||
if (nonce == 0 && ret) {
|
||||
if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) {
|
||||
timersub(&tv_finish, &tv_start, &elapsed);
|
||||
|
||||
// ONLY up to just when it aborted
|
||||
@ -709,6 +749,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||
return estimate_hashes;
|
||||
}
|
||||
|
||||
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
|
||||
|
||||
#if !defined (__BIG_ENDIAN__) && !defined(MIPSEB)
|
||||
nonce = swab32(nonce);
|
||||
#endif
|
||||
@ -717,6 +759,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
|
||||
submit_nonce(thr, work, nonce);
|
||||
was_hw_error = (curr_hw_errors > icarus->hw_errors);
|
||||
|
||||
// Force a USB close/reopen on any hw error
|
||||
if (was_hw_error)
|
||||
do_icarus_close(thr);
|
||||
|
||||
hash_count = (nonce & info->nonce_mask);
|
||||
hash_count++;
|
||||
hash_count *= info->fpga_count;
|
||||
@ -862,8 +908,7 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
|
||||
|
||||
static void icarus_shutdown(struct thr_info *thr)
|
||||
{
|
||||
struct cgpu_info *icarus = thr->cgpu;
|
||||
icarus_close(icarus->device_fd);
|
||||
do_icarus_close(thr);
|
||||
}
|
||||
|
||||
struct device_api icarus_api = {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "logging.h"
|
||||
#include "miner.h"
|
||||
#include "fpgautils.h"
|
||||
#include "util.h"
|
||||
|
||||
#define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd"
|
||||
#define BISTREAM_USER_ID "\2\4$B"
|
||||
@ -48,7 +49,7 @@ modminer_detect_one(const char *devpath)
|
||||
bailout(LOG_DEBUG, "ModMiner detect: failed to open %s", devpath);
|
||||
|
||||
char buf[0x100];
|
||||
size_t len;
|
||||
ssize_t len;
|
||||
|
||||
// Sending 45 noops, just in case the device was left in "start job" reading
|
||||
(void)(write(fd, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 45) ?:0);
|
||||
@ -128,6 +129,7 @@ modminer_detect()
|
||||
} while(0)
|
||||
|
||||
#define status_read(eng) do { \
|
||||
FD_ZERO(&fds); \
|
||||
FD_SET(fd, &fds); \
|
||||
select(fd+1, &fds, NULL, NULL, NULL); \
|
||||
if (1 != read(fd, buf, 1)) \
|
||||
@ -139,7 +141,7 @@ select(fd+1, &fds, NULL, NULL, NULL); \
|
||||
static bool
|
||||
modminer_fpga_upload_bitstream(struct cgpu_info*modminer)
|
||||
{
|
||||
fd_set fds;
|
||||
fd_set fds;
|
||||
char buf[0x100];
|
||||
unsigned char *ubuf = (unsigned char*)buf;
|
||||
unsigned long len;
|
||||
@ -185,7 +187,7 @@ fd_set fds;
|
||||
len = ((unsigned long)ubuf[0] << 24) | ((unsigned long)ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3];
|
||||
applog(LOG_DEBUG, " Bitstream size: %lu", len);
|
||||
|
||||
int fd = modminer->device_fd;
|
||||
SOCKETTYPE fd = modminer->device_fd;
|
||||
|
||||
applog(LOG_WARNING, "%s %u: Programming %s... DO NOT EXIT CGMINER UNTIL COMPLETE", modminer->api->name, modminer->device_id, modminer->device_path);
|
||||
buf[0] = '\x05'; // Program Bitstream
|
||||
@ -375,7 +377,7 @@ fd_set fds;
|
||||
struct cgpu_info*modminer = thr->cgpu;
|
||||
struct modminer_fpga_state *state = thr->cgpu_data;
|
||||
char fpgaid = thr->device_thread;
|
||||
int fd = modminer->device_fd;
|
||||
SOCKETTYPE fd = modminer->device_fd;
|
||||
|
||||
char buf[1];
|
||||
|
||||
|
@ -1585,14 +1585,19 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
|
||||
gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpumid);
|
||||
if (gpu_us > 0 && ++gpu->hit > 4) {
|
||||
gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals;
|
||||
/* Very rarely we may get an overflow so put an upper
|
||||
* limit on the detected time */
|
||||
if (unlikely(gpu->gpu_us_average > 0 && gpu_us > gpu->gpu_us_average * 4))
|
||||
gpu_us = gpu->gpu_us_average * 4;
|
||||
gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63;
|
||||
|
||||
/* Try to not let the GPU be out for longer than
|
||||
* opt_dynamic_interval in ms, but increase
|
||||
* intensity when the system is idle in dynamic mode */
|
||||
if (gpu_us > dynamic_us) {
|
||||
if (gpu->gpu_us_average > dynamic_us) {
|
||||
if (gpu->intensity > MIN_INTENSITY)
|
||||
--gpu->intensity;
|
||||
} else if (gpu_us < dynamic_us / 2) {
|
||||
} else if (gpu->gpu_us_average < dynamic_us / 2) {
|
||||
if (gpu->intensity < MAX_INTENSITY)
|
||||
++gpu->intensity;
|
||||
}
|
||||
|
10
findnonce.c
10
findnonce.c
@ -252,6 +252,16 @@ static void *postcalc_hash(void *userdata)
|
||||
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
/* To prevent corrupt values in FOUND from trying to read beyond the
|
||||
* end of the res[] array */
|
||||
if (unlikely(pcd->res[FOUND] & ~FOUND)) {
|
||||
applog(LOG_WARNING, "%s%d: invalid nonce count - HW error",
|
||||
thr->cgpu->api->name, thr->cgpu->device_id);
|
||||
hw_errors++;
|
||||
thr->cgpu->hw_errors++;
|
||||
pcd->res[FOUND] &= FOUND;
|
||||
}
|
||||
|
||||
for (entry = 0; entry < pcd->res[FOUND]; entry++) {
|
||||
uint32_t nonce = pcd->res[entry];
|
||||
|
||||
|
@ -74,7 +74,7 @@ int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_un
|
||||
}
|
||||
#endif
|
||||
|
||||
int serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
|
||||
int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname)
|
||||
{
|
||||
#ifndef WIN32
|
||||
DIR *D;
|
||||
|
@ -7,6 +7,8 @@
|
||||
* any later version. See COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logging.h"
|
||||
|
91
miner.h
91
miner.h
@ -12,6 +12,7 @@
|
||||
#include "elist.h"
|
||||
#include "uthash.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
#ifdef __APPLE_CC__
|
||||
@ -51,6 +52,19 @@ void *alloca (size_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
static inline int fsync (int fd)
|
||||
{
|
||||
return (FlushFileBuffers ((HANDLE) _get_osfhandle (fd))) ? 0 : -1;
|
||||
}
|
||||
|
||||
#ifndef MSG_DONTWAIT
|
||||
# define MSG_DONTWAIT 0x1000000
|
||||
#endif
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
#if defined (__linux)
|
||||
#ifndef LINUX
|
||||
#define LINUX
|
||||
@ -125,14 +139,19 @@ void *alloca (size_t);
|
||||
#endif
|
||||
#endif /* !defined(__GLXBYTEORDER_H__) */
|
||||
|
||||
/* This assumes htobe32 is a macro in endian.h */
|
||||
/* This assumes htobe32 is a macro in endian.h, and if it doesn't exist, then
|
||||
* htobe64 also won't exist */
|
||||
#ifndef htobe32
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define be32toh(x) bswap_32(x)
|
||||
# define be64toh(x) bswap_64(x)
|
||||
# define htobe32(x) bswap_32(x)
|
||||
# define htobe64(x) bswap_64(x)
|
||||
# elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define be32toh(x) (x)
|
||||
# define be64toh(x) (x)
|
||||
# define htobe32(x) (x)
|
||||
# define htobe64(x) (x)
|
||||
#else
|
||||
#error UNKNOWN BYTE ORDER
|
||||
#endif
|
||||
@ -378,11 +397,12 @@ struct cgpu_info {
|
||||
|
||||
#ifdef USE_SCRYPT
|
||||
int opt_lg, lookup_gap;
|
||||
int opt_tc, thread_concurrency;
|
||||
int shaders;
|
||||
size_t opt_tc, thread_concurrency;
|
||||
size_t shaders;
|
||||
#endif
|
||||
struct timeval tv_gpustart;
|
||||
struct timeval tv_gpumid;
|
||||
double gpu_us_average;
|
||||
int intervals, hit;
|
||||
#endif
|
||||
|
||||
@ -510,6 +530,21 @@ static inline void swap256(void *dest_p, const void *src_p)
|
||||
dest[7] = src[0];
|
||||
}
|
||||
|
||||
static inline void swab256(void *dest_p, const void *src_p)
|
||||
{
|
||||
uint32_t *dest = dest_p;
|
||||
const uint32_t *src = src_p;
|
||||
|
||||
dest[0] = swab32(src[7]);
|
||||
dest[1] = swab32(src[6]);
|
||||
dest[2] = swab32(src[5]);
|
||||
dest[3] = swab32(src[4]);
|
||||
dest[4] = swab32(src[3]);
|
||||
dest[5] = swab32(src[2]);
|
||||
dest[6] = swab32(src[1]);
|
||||
dest[7] = swab32(src[0]);
|
||||
}
|
||||
|
||||
extern void quit(int status, const char *format, ...);
|
||||
|
||||
static inline void mutex_lock(pthread_mutex_t *lock)
|
||||
@ -594,6 +629,7 @@ extern bool opt_worktime;
|
||||
#ifdef USE_BITFORCE
|
||||
extern bool opt_bfl_noncerange;
|
||||
#endif
|
||||
extern int swork_id;
|
||||
|
||||
extern pthread_rwlock_t netacc_lock;
|
||||
|
||||
@ -645,7 +681,9 @@ extern void api(int thr_id);
|
||||
|
||||
extern struct pool *current_pool(void);
|
||||
extern int enabled_pools;
|
||||
extern void add_pool_details(bool live, char *url, char *user, char *pass);
|
||||
extern bool detect_stratum(struct pool *pool, char *url);
|
||||
extern struct pool *add_pool(void);
|
||||
extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
|
||||
|
||||
#define MAX_GPUDEVICES 16
|
||||
|
||||
@ -748,6 +786,24 @@ enum pool_enable {
|
||||
POOL_REJECTING,
|
||||
};
|
||||
|
||||
struct stratum_work {
|
||||
char *job_id;
|
||||
char *prev_hash;
|
||||
char *coinbase1;
|
||||
char *coinbase2;
|
||||
char **merkle;
|
||||
char *bbversion;
|
||||
char *nbit;
|
||||
char *ntime;
|
||||
bool clean;
|
||||
|
||||
int merkles;
|
||||
int diff;
|
||||
};
|
||||
|
||||
#define RECVSIZE 8191
|
||||
#define RBUFSIZE (RECVSIZE + 1)
|
||||
|
||||
struct pool {
|
||||
int pool_no;
|
||||
int prio;
|
||||
@ -810,12 +866,31 @@ struct pool {
|
||||
|
||||
struct cgminer_stats cgminer_stats;
|
||||
struct cgminer_pool_stats cgminer_pool_stats;
|
||||
|
||||
/* Stratum variables */
|
||||
char *stratum_url;
|
||||
char *stratum_port;
|
||||
CURL *stratum_curl;
|
||||
SOCKETTYPE sock;
|
||||
char sockbuf[RBUFSIZE];
|
||||
struct sockaddr_in *server, client;
|
||||
char *sockaddr_url; /* stripped url used for sockaddr */
|
||||
char *nonce1;
|
||||
uint32_t nonce2;
|
||||
int n2size;
|
||||
bool has_stratum;
|
||||
bool stratum_active;
|
||||
bool stratum_auth;
|
||||
struct stratum_work swork;
|
||||
pthread_t stratum_thread;
|
||||
pthread_mutex_t stratum_lock;
|
||||
};
|
||||
|
||||
#define GETWORK_MODE_TESTPOOL 'T'
|
||||
#define GETWORK_MODE_POOL 'P'
|
||||
#define GETWORK_MODE_LP 'L'
|
||||
#define GETWORK_MODE_BENCHMARK 'B'
|
||||
#define GETWORK_MODE_STRATUM 'S'
|
||||
|
||||
struct work {
|
||||
unsigned char data[128];
|
||||
@ -845,6 +920,14 @@ struct work {
|
||||
bool block;
|
||||
bool queued;
|
||||
|
||||
bool stratum;
|
||||
/* These are arbitrary lengths as it is too hard to keep track of
|
||||
* dynamically allocated ram in work structs */
|
||||
char job_id[64];
|
||||
char nonce2[64];
|
||||
char ntime[16];
|
||||
int sdiff;
|
||||
|
||||
unsigned int work_block;
|
||||
int id;
|
||||
UT_hash_handle hh;
|
||||
|
8
ocl.c
8
ocl.c
@ -541,7 +541,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
|
||||
strcat(binaryfilename, "g");
|
||||
if (opt_scrypt) {
|
||||
#ifdef USE_SCRYPT
|
||||
sprintf(numbuf, "lg%dtc%d", cgpu->lookup_gap, cgpu->thread_concurrency);
|
||||
sprintf(numbuf, "lg%utc%u", cgpu->lookup_gap, (unsigned int)cgpu->thread_concurrency);
|
||||
strcat(binaryfilename, numbuf);
|
||||
#endif
|
||||
} else {
|
||||
@ -614,7 +614,7 @@ build:
|
||||
#ifdef USE_SCRYPT
|
||||
if (opt_scrypt)
|
||||
sprintf(CompilerOptions, "-D LOOKUP_GAP=%d -D CONCURRENT_THREADS=%d -D WORKSIZE=%d",
|
||||
cgpu->lookup_gap, cgpu->thread_concurrency, (int)clState->wsize);
|
||||
cgpu->lookup_gap, (unsigned int)cgpu->thread_concurrency, (int)clState->wsize);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
@ -810,8 +810,8 @@ built:
|
||||
/* Use the max alloc value which has been rounded to a power of
|
||||
* 2 greater >= required amount earlier */
|
||||
if (bufsize > cgpu->max_alloc) {
|
||||
applog(LOG_WARNING, "Maximum buffer memory device %d supports says %u, your scrypt settings come to %u",
|
||||
gpu, cgpu->max_alloc, bufsize);
|
||||
applog(LOG_WARNING, "Maximum buffer memory device %d supports says %u", gpu, cgpu->max_alloc);
|
||||
applog(LOG_WARNING, "Your scrypt settings come to %u", bufsize);
|
||||
} else
|
||||
bufsize = cgpu->max_alloc;
|
||||
applog(LOG_DEBUG, "Creating scrypt buffer sized %d", bufsize);
|
||||
|
612
util.c
612
util.c
@ -26,20 +26,17 @@
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <netdb.h>
|
||||
#else
|
||||
# include <winsock2.h>
|
||||
# include <mstcpip.h>
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#include "miner.h"
|
||||
#include "elist.h"
|
||||
#include "compat.h"
|
||||
|
||||
#if JANSSON_MAJOR_VERSION >= 2
|
||||
#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr))
|
||||
#else
|
||||
#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr))
|
||||
#endif
|
||||
#include "util.h"
|
||||
|
||||
bool successful_connect = false;
|
||||
struct timeval nettime;
|
||||
@ -58,6 +55,7 @@ struct header_info {
|
||||
char *lp_path;
|
||||
int rolltime;
|
||||
char *reason;
|
||||
char *stratum_url;
|
||||
bool hadrolltime;
|
||||
bool canroll;
|
||||
bool hadexpire;
|
||||
@ -187,13 +185,17 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data)
|
||||
val = NULL;
|
||||
}
|
||||
|
||||
if (!strcasecmp("X-Stratum", key)) {
|
||||
hi->stratum_url = val;
|
||||
val = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
free(key);
|
||||
free(val);
|
||||
return ptrlen;
|
||||
}
|
||||
|
||||
#ifdef CURL_HAS_SOCKOPT
|
||||
int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
|
||||
curlsocktype __maybe_unused purpose)
|
||||
{
|
||||
@ -241,7 +243,6 @@ int json_rpc_call_sockopt_cb(void __maybe_unused *userdata, curl_socket_t fd,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void last_nettime(struct timeval *last)
|
||||
{
|
||||
@ -265,7 +266,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
|
||||
{
|
||||
long timeout = longpoll ? (60 * 60) : 60;
|
||||
struct data_buffer all_data = {NULL, 0};
|
||||
struct header_info hi = {NULL, 0, NULL, false, false, false};
|
||||
struct header_info hi = {NULL, 0, NULL, NULL, false, false, false};
|
||||
char len_hdr[64], user_agent_hdr[128];
|
||||
char curl_err_str[CURL_ERROR_SIZE];
|
||||
struct curl_slist *headers = NULL;
|
||||
@ -316,10 +317,8 @@ json_t *json_rpc_call(CURL *curl, const char *url,
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
}
|
||||
#ifdef CURL_HAS_SOCKOPT
|
||||
if (longpoll)
|
||||
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, json_rpc_call_sockopt_cb);
|
||||
#endif
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
|
||||
if (opt_protocol)
|
||||
@ -392,9 +391,19 @@ json_t *json_rpc_call(CURL *curl, const char *url,
|
||||
pool->hdr_path = hi.lp_path;
|
||||
} else
|
||||
pool->hdr_path = NULL;
|
||||
} else if (hi.lp_path) {
|
||||
free(hi.lp_path);
|
||||
hi.lp_path = NULL;
|
||||
if (hi.stratum_url) {
|
||||
pool->stratum_url = hi.stratum_url;
|
||||
hi.stratum_url = NULL;
|
||||
}
|
||||
} else {
|
||||
if (hi.lp_path) {
|
||||
free(hi.lp_path);
|
||||
hi.lp_path = NULL;
|
||||
}
|
||||
if (hi.stratum_url) {
|
||||
free(hi.stratum_url);
|
||||
hi.stratum_url = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*rolltime = hi.rolltime;
|
||||
@ -794,3 +803,578 @@ double tdiff(struct timeval *end, struct timeval *start)
|
||||
{
|
||||
return end->tv_sec - start->tv_sec + (end->tv_usec - start->tv_usec) / 1000000.0;
|
||||
}
|
||||
|
||||
bool extract_sockaddr(struct pool *pool, char *url)
|
||||
{
|
||||
char *url_begin, *url_end, *port_start = NULL;
|
||||
char url_address[256], port[6];
|
||||
struct addrinfo hints, *res;
|
||||
int url_len, port_len = 0;
|
||||
|
||||
url_begin = strstr(url, "//");
|
||||
if (!url_begin)
|
||||
url_begin = url;
|
||||
else
|
||||
url_begin += 2;
|
||||
url_end = strstr(url_begin, ":");
|
||||
if (url_end) {
|
||||
url_len = url_end - url_begin;
|
||||
port_len = strlen(url_begin) - url_len - 1;
|
||||
if (port_len < 1)
|
||||
return false;
|
||||
port_start = url_end + 1;
|
||||
} else
|
||||
url_len = strlen(url_begin);
|
||||
|
||||
if (url_len < 1)
|
||||
return false;
|
||||
|
||||
sprintf(url_address, "%.*s", url_len, url_begin);
|
||||
|
||||
if (port_len)
|
||||
snprintf(port, 6, "%.*s", port_len, port_start);
|
||||
else
|
||||
strcpy(port, "80");
|
||||
|
||||
pool->stratum_port = strdup(port);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if (getaddrinfo(url_address, port, &hints, &res)) {
|
||||
applog(LOG_DEBUG, "Failed to extract sock addr");
|
||||
return false;
|
||||
}
|
||||
|
||||
pool->server = (struct sockaddr_in *)res->ai_addr;
|
||||
pool->sockaddr_url = strdup(url_address);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Send a single command across a socket, appending \n to it */
|
||||
bool stratum_send(struct pool *pool, char *s, ssize_t len)
|
||||
{
|
||||
ssize_t ssent = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (opt_protocol)
|
||||
applog(LOG_DEBUG, "SEND: %s", s);
|
||||
|
||||
strcat(s, "\n");
|
||||
len++;
|
||||
|
||||
mutex_lock(&pool->stratum_lock);
|
||||
while (len > 0 ) {
|
||||
size_t sent = 0;
|
||||
|
||||
if (curl_easy_send(pool->stratum_curl, s + ssent, len, &sent) != CURLE_OK) {
|
||||
applog(LOG_DEBUG, "Failed to curl_easy_send in stratum_send");
|
||||
ret = false;
|
||||
goto out_unlock;
|
||||
}
|
||||
ssent += sent;
|
||||
len -= ssent;
|
||||
}
|
||||
ret = true;
|
||||
out_unlock:
|
||||
mutex_unlock(&pool->stratum_lock);
|
||||
return ret;;
|
||||
}
|
||||
|
||||
#define RECVSIZE 8191
|
||||
#define RBUFSIZE (RECVSIZE + 1)
|
||||
|
||||
static void clear_sock(struct pool *pool)
|
||||
{
|
||||
SOCKETTYPE sock = pool->sock;
|
||||
|
||||
recv(sock, pool->sockbuf, RECVSIZE, MSG_DONTWAIT);
|
||||
strcpy(pool->sockbuf, "");
|
||||
}
|
||||
|
||||
/* Check to see if Santa's been good to you */
|
||||
static bool sock_full(struct pool *pool, bool wait)
|
||||
{
|
||||
SOCKETTYPE sock = pool->sock;
|
||||
struct timeval timeout;
|
||||
fd_set rd;
|
||||
|
||||
if (strlen(pool->sockbuf))
|
||||
return true;
|
||||
|
||||
FD_ZERO(&rd);
|
||||
FD_SET(sock, &rd);
|
||||
timeout.tv_usec = 0;
|
||||
if (wait)
|
||||
timeout.tv_sec = 60;
|
||||
else
|
||||
timeout.tv_sec = 0;
|
||||
if (select(sock + 1, &rd, NULL, NULL, &timeout) > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Peeks at a socket to find the first end of line and then reads just that
|
||||
* from the socket and returns that as a malloced char */
|
||||
char *recv_line(struct pool *pool)
|
||||
{
|
||||
ssize_t len, buflen;
|
||||
char *tok, *sret = NULL;
|
||||
size_t n;
|
||||
|
||||
if (!strstr(pool->sockbuf, "\n")) {
|
||||
char s[RBUFSIZE];
|
||||
CURLcode rc;
|
||||
|
||||
if (!sock_full(pool, true)) {
|
||||
applog(LOG_DEBUG, "Timed out waiting for data on sock_full");
|
||||
goto out;
|
||||
}
|
||||
memset(s, 0, RBUFSIZE);
|
||||
|
||||
mutex_lock(&pool->stratum_lock);
|
||||
rc = curl_easy_recv(pool->stratum_curl, s, RECVSIZE, &n);
|
||||
mutex_unlock(&pool->stratum_lock);
|
||||
|
||||
if (rc != CURLE_OK) {
|
||||
applog(LOG_DEBUG, "Failed to recv sock in recv_line");
|
||||
goto out;
|
||||
}
|
||||
strcat(pool->sockbuf, s);
|
||||
}
|
||||
|
||||
buflen = strlen(pool->sockbuf);
|
||||
tok = strtok(pool->sockbuf, "\n");
|
||||
if (!tok) {
|
||||
applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line");
|
||||
goto out;
|
||||
}
|
||||
sret = strdup(tok);
|
||||
len = strlen(sret);
|
||||
|
||||
/* Copy what's left in the buffer after the \n, including the
|
||||
* terminating \0 */
|
||||
if (buflen > len + 1)
|
||||
memmove(pool->sockbuf, pool->sockbuf + len + 1, buflen - len + 1);
|
||||
else
|
||||
strcpy(pool->sockbuf, "");
|
||||
out:
|
||||
if (!sret)
|
||||
clear_sock(pool);
|
||||
else if (opt_protocol)
|
||||
applog(LOG_DEBUG, "RECVD: %s", sret);
|
||||
return sret;
|
||||
}
|
||||
|
||||
/* Extracts a string value from a json array with error checking. To be used
|
||||
* when the value of the string returned is only examined and not to be stored.
|
||||
* See json_array_string below */
|
||||
static char *__json_array_string(json_t *val, unsigned int entry)
|
||||
{
|
||||
json_t *arr_entry;
|
||||
|
||||
if (json_is_null(val))
|
||||
return NULL;
|
||||
if (!json_is_array(val))
|
||||
return NULL;
|
||||
if (entry > json_array_size(val))
|
||||
return NULL;
|
||||
arr_entry = json_array_get(val, entry);
|
||||
if (!json_is_string(arr_entry))
|
||||
return NULL;
|
||||
|
||||
return (char *)json_string_value(arr_entry);
|
||||
}
|
||||
|
||||
/* Creates a freshly malloced dup of __json_array_string */
|
||||
static char *json_array_string(json_t *val, unsigned int entry)
|
||||
{
|
||||
char *buf = __json_array_string(val, entry);
|
||||
|
||||
if (buf)
|
||||
return strdup(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool parse_notify(struct pool *pool, json_t *val)
|
||||
{
|
||||
char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime;
|
||||
int merkles, i;
|
||||
json_t *arr;
|
||||
bool clean;
|
||||
|
||||
arr = json_array_get(val, 4);
|
||||
if (!arr || !json_is_array(arr))
|
||||
return false;
|
||||
|
||||
merkles = json_array_size(arr);
|
||||
|
||||
job_id = json_array_string(val, 0);
|
||||
prev_hash = json_array_string(val, 1);
|
||||
coinbase1 = json_array_string(val, 2);
|
||||
coinbase2 = json_array_string(val, 3);
|
||||
bbversion = json_array_string(val, 5);
|
||||
nbit = json_array_string(val, 6);
|
||||
ntime = json_array_string(val, 7);
|
||||
clean = json_is_true(json_array_get(val, 8));
|
||||
|
||||
if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime) {
|
||||
/* Annoying but we must not leak memory */
|
||||
if (job_id)
|
||||
free(job_id);
|
||||
if (prev_hash)
|
||||
free(prev_hash);
|
||||
if (coinbase1)
|
||||
free(coinbase1);
|
||||
if (coinbase2)
|
||||
free(coinbase2);
|
||||
if (bbversion)
|
||||
free(bbversion);
|
||||
if (nbit)
|
||||
free(nbit);
|
||||
if (ntime)
|
||||
free(ntime);
|
||||
return false;
|
||||
}
|
||||
|
||||
mutex_lock(&pool->pool_lock);
|
||||
pool->swork.job_id = job_id;
|
||||
pool->swork.prev_hash = prev_hash;
|
||||
pool->swork.coinbase1 = coinbase1;
|
||||
pool->swork.coinbase2 = coinbase2;
|
||||
pool->swork.bbversion = bbversion;
|
||||
pool->swork.nbit = nbit;
|
||||
pool->swork.ntime = ntime;
|
||||
pool->swork.clean = clean;
|
||||
for (i = 0; i < pool->swork.merkles; i++)
|
||||
free(pool->swork.merkle[i]);
|
||||
if (merkles) {
|
||||
pool->swork.merkle = realloc(pool->swork.merkle, sizeof(char *) * merkles + 1);
|
||||
for (i = 0; i < merkles; i++)
|
||||
pool->swork.merkle[i] = json_array_string(arr, i);
|
||||
}
|
||||
pool->swork.merkles = merkles;
|
||||
if (clean)
|
||||
pool->nonce2 = 0;
|
||||
mutex_unlock(&pool->pool_lock);
|
||||
|
||||
if (opt_protocol) {
|
||||
applog(LOG_DEBUG, "job_id: %s", job_id);
|
||||
applog(LOG_DEBUG, "prev_hash: %s", prev_hash);
|
||||
applog(LOG_DEBUG, "coinbase1: %s", coinbase1);
|
||||
applog(LOG_DEBUG, "coinbase2: %s", coinbase2);
|
||||
for (i = 0; i < merkles; i++)
|
||||
applog(LOG_DEBUG, "merkle%d: %s", i, pool->swork.merkle[i]);
|
||||
applog(LOG_DEBUG, "bbversion: %s", bbversion);
|
||||
applog(LOG_DEBUG, "nbit: %s", nbit);
|
||||
applog(LOG_DEBUG, "ntime: %s", ntime);
|
||||
applog(LOG_DEBUG, "clean: %s", clean ? "yes" : "no");
|
||||
}
|
||||
|
||||
/* A notify message is the closest stratum gets to a getwork */
|
||||
pool->getwork_requested++;
|
||||
total_getworks++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_diff(struct pool *pool, json_t *val)
|
||||
{
|
||||
int diff;
|
||||
|
||||
diff = json_integer_value(json_array_get(val, 0));
|
||||
if (diff < 1)
|
||||
return false;
|
||||
|
||||
mutex_lock(&pool->pool_lock);
|
||||
pool->swork.diff = diff;
|
||||
mutex_unlock(&pool->pool_lock);
|
||||
|
||||
applog(LOG_DEBUG, "Pool %d difficulty set to %d", pool->pool_no, diff);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_reconnect(struct pool *pool, json_t *val)
|
||||
{
|
||||
char *url, *port, address[256];
|
||||
|
||||
memset(address, 0, 255);
|
||||
url = (char *)json_string_value(json_array_get(val, 0));
|
||||
if (!url)
|
||||
url = pool->sockaddr_url;
|
||||
|
||||
port = (char *)json_string_value(json_array_get(val, 1));
|
||||
if (!port)
|
||||
port = pool->stratum_port;
|
||||
|
||||
sprintf(address, "%s:%s", url, port);
|
||||
|
||||
if (!extract_sockaddr(pool, address))
|
||||
return false;
|
||||
|
||||
pool->stratum_url = pool->sockaddr_url;
|
||||
|
||||
applog(LOG_NOTICE, "Reconnect requested from pool %d to %s", pool->pool_no, address);
|
||||
|
||||
if (!initiate_stratum(pool) || !auth_stratum(pool))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool send_version(struct pool *pool, json_t *val)
|
||||
{
|
||||
char s[RBUFSIZE];
|
||||
int id = json_integer_value(json_object_get(val, "id"));
|
||||
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
sprintf(s, "{\"id\": %d, \"result\": \""PACKAGE"/"VERSION"\", \"error\": null}", id);
|
||||
if (!stratum_send(pool, s, strlen(s)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_method(struct pool *pool, char *s)
|
||||
{
|
||||
json_t *val = NULL, *method, *err_val, *params;
|
||||
json_error_t err;
|
||||
bool ret = false;
|
||||
char *buf;
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
val = JSON_LOADS(s, &err);
|
||||
if (!val) {
|
||||
applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text);
|
||||
goto out;
|
||||
}
|
||||
|
||||
method = json_object_get(val, "method");
|
||||
if (!method)
|
||||
goto out;
|
||||
err_val = json_object_get(val, "error");
|
||||
params = json_object_get(val, "params");
|
||||
|
||||
if (err_val && !json_is_null(err_val)) {
|
||||
char *ss;
|
||||
|
||||
if (err_val)
|
||||
ss = json_dumps(err_val, JSON_INDENT(3));
|
||||
else
|
||||
ss = strdup("(unknown reason)");
|
||||
|
||||
applog(LOG_INFO, "JSON-RPC method decode failed: %s", ss);
|
||||
|
||||
free(ss);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = (char *)json_string_value(method);
|
||||
if (!buf)
|
||||
goto out;
|
||||
|
||||
if (!strncasecmp(buf, "mining.notify", 13) && parse_notify(pool, params)) {
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strncasecmp(buf, "mining.set_difficulty", 21) && parse_diff(pool, params)) {
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strncasecmp(buf, "client.reconnect", 16) && parse_reconnect(pool, params)) {
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strncasecmp(buf, "client.get_version", 18) && send_version(pool, val)) {
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (val)
|
||||
json_decref(val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool auth_stratum(struct pool *pool)
|
||||
{
|
||||
json_t *val = NULL, *res_val, *err_val;
|
||||
char s[RBUFSIZE], *sret = NULL;
|
||||
json_error_t err;
|
||||
bool ret = false;
|
||||
|
||||
sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}",
|
||||
swork_id++, pool->rpc_user, pool->rpc_pass);
|
||||
|
||||
/* Parse all data prior sending auth request */
|
||||
while (sock_full(pool, false)) {
|
||||
sret = recv_line(pool);
|
||||
if (!parse_method(pool, sret)) {
|
||||
clear_sock(pool);
|
||||
applog(LOG_INFO, "Failed to parse stratum buffer");
|
||||
free(sret);
|
||||
return ret;
|
||||
}
|
||||
free(sret);
|
||||
}
|
||||
|
||||
if (!stratum_send(pool, s, strlen(s)))
|
||||
goto out;
|
||||
|
||||
sret = recv_line(pool);
|
||||
if (!sret)
|
||||
goto out;
|
||||
val = JSON_LOADS(sret, &err);
|
||||
free(sret);
|
||||
res_val = json_object_get(val, "result");
|
||||
err_val = json_object_get(val, "error");
|
||||
|
||||
if (!res_val || json_is_false(res_val) || (err_val && !json_is_null(err_val))) {
|
||||
char *ss;
|
||||
|
||||
if (err_val)
|
||||
ss = json_dumps(err_val, JSON_INDENT(3));
|
||||
else
|
||||
ss = strdup("(unknown reason)");
|
||||
applog(LOG_WARNING, "JSON stratum auth failed: %s", ss);
|
||||
free(ss);
|
||||
|
||||
goto out;
|
||||
}
|
||||
ret = true;
|
||||
applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no);
|
||||
out:
|
||||
if (val)
|
||||
json_decref(val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool initiate_stratum(struct pool *pool)
|
||||
{
|
||||
json_t *val = NULL, *res_val, *err_val;
|
||||
char curl_err_str[CURL_ERROR_SIZE];
|
||||
char s[RBUFSIZE], *sret = NULL;
|
||||
CURL *curl = NULL;
|
||||
json_error_t err;
|
||||
bool ret = false;
|
||||
|
||||
if (!pool->stratum_curl) {
|
||||
pool->stratum_curl = curl_easy_init();
|
||||
if (unlikely(!pool->stratum_curl))
|
||||
quit(1, "Failed to curl_easy_init in initiate_stratum");
|
||||
}
|
||||
curl = pool->stratum_curl;
|
||||
|
||||
/* Create a http url for use with curl */
|
||||
memset(s, 0, RBUFSIZE);
|
||||
sprintf(s, "http://%s:%s", pool->sockaddr_url, pool->stratum_port);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, s);
|
||||
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
|
||||
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);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
|
||||
if (curl_easy_perform(curl)) {
|
||||
applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str);
|
||||
goto out;
|
||||
}
|
||||
curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, (long *)&pool->sock);
|
||||
|
||||
sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": []}", swork_id++);
|
||||
|
||||
if (!stratum_send(pool, s, strlen(s))) {
|
||||
applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!sock_full(pool, true)) {
|
||||
applog(LOG_DEBUG, "Timed out waiting for response in initiate_stratum");
|
||||
goto out;
|
||||
}
|
||||
|
||||
sret = recv_line(pool);
|
||||
if (!sret)
|
||||
goto out;
|
||||
|
||||
val = JSON_LOADS(sret, &err);
|
||||
free(sret);
|
||||
if (!val) {
|
||||
applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text);
|
||||
goto out;
|
||||
}
|
||||
|
||||
res_val = json_object_get(val, "result");
|
||||
err_val = json_object_get(val, "error");
|
||||
|
||||
if (!res_val || json_is_null(res_val) ||
|
||||
(err_val && !json_is_null(err_val))) {
|
||||
char *ss;
|
||||
|
||||
if (err_val)
|
||||
ss = json_dumps(err_val, JSON_INDENT(3));
|
||||
else
|
||||
ss = strdup("(unknown reason)");
|
||||
|
||||
applog(LOG_INFO, "JSON-RPC decode failed: %s", ss);
|
||||
|
||||
free(ss);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
pool->nonce1 = json_array_string(res_val, 1);
|
||||
if (!pool->nonce1) {
|
||||
applog(LOG_INFO, "Failed to get nonce1 in initiate_stratum");
|
||||
goto out;
|
||||
}
|
||||
pool->n2size = json_integer_value(json_array_get(res_val, 2));
|
||||
if (!pool->n2size) {
|
||||
applog(LOG_INFO, "Failed to get n2size in initiate_stratum");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
out:
|
||||
if (val)
|
||||
json_decref(val);
|
||||
|
||||
if (ret) {
|
||||
if (!pool->stratum_url)
|
||||
pool->stratum_url = pool->sockaddr_url;
|
||||
pool->stratum_active = true;
|
||||
pool->swork.diff = 1;
|
||||
if (opt_protocol) {
|
||||
applog(LOG_DEBUG, "Pool %d confirmed mining.subscribe with extranonce1 %s extran2size %d",
|
||||
pool->pool_no, pool->nonce1, pool->n2size);
|
||||
}
|
||||
} else {
|
||||
pool->stratum_active = false;
|
||||
if (curl) {
|
||||
curl_easy_cleanup(curl);
|
||||
pool->stratum_curl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
53
util.h
Normal file
53
util.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __UTIL_H__
|
||||
#define __UTIL_H__
|
||||
|
||||
#if defined(unix) || defined(__APPLE__)
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define SOCKETTYPE long
|
||||
#define SOCKETFAIL(a) ((a) < 0)
|
||||
#define INVSOCK -1
|
||||
#define INVINETADDR -1
|
||||
#define CLOSESOCKET close
|
||||
|
||||
#define SOCKERRMSG strerror(errno)
|
||||
#elif defined WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
#define SOCKETTYPE SOCKET
|
||||
#define SOCKETFAIL(a) ((int)(a) == SOCKET_ERROR)
|
||||
#define INVSOCK INVALID_SOCKET
|
||||
#define INVINETADDR INADDR_NONE
|
||||
#define CLOSESOCKET closesocket
|
||||
|
||||
extern char *WSAErrorMsg(void);
|
||||
#define SOCKERRMSG WSAErrorMsg()
|
||||
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#endif
|
||||
|
||||
#ifndef in_addr_t
|
||||
#define in_addr_t uint32_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if JANSSON_MAJOR_VERSION >= 2
|
||||
#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr))
|
||||
#else
|
||||
#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr))
|
||||
#endif
|
||||
|
||||
struct pool;
|
||||
bool stratum_send(struct pool *pool, char *s, ssize_t len);
|
||||
char *recv_line(struct pool *pool);
|
||||
bool parse_method(struct pool *pool, char *s);
|
||||
bool extract_sockaddr(struct pool *pool, char *url);
|
||||
bool auth_stratum(struct pool *pool);
|
||||
bool initiate_stratum(struct pool *pool);
|
||||
|
||||
#endif /* __UTIL_H__ */
|
Loading…
Reference in New Issue
Block a user