mirror of
https://github.com/xmrig/xmrig.git
synced 2024-11-16 15:57:38 +00:00
Remove obsolete source files.
This commit is contained in:
parent
827e611911
commit
2d08f59184
10 changed files with 0 additions and 2338 deletions
47
compat.h
47
compat.h
|
@ -1,47 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __COMPAT_H__
|
||||
#define __COMPAT_H__
|
||||
|
||||
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
|
||||
#define likely(expr) (__builtin_expect(!!(expr), 1))
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define sleep(secs) Sleep((secs) * 1000)
|
||||
|
||||
enum {
|
||||
PRIO_PROCESS = 0,
|
||||
};
|
||||
|
||||
static inline int setpriority(int which, int who, int prio)
|
||||
{
|
||||
return -!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#endif /* __COMPAT_H__ */
|
274
elist.h
274
elist.h
|
@ -1,274 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = (void *) 0;
|
||||
entry->prev = (void *) 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void __list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head);
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); \
|
||||
pos = pos->next)
|
||||
/**
|
||||
* list_for_each_prev - iterate over a list backwards
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_prev(pos, head) \
|
||||
for (pos = (head)->prev; pos != (head); \
|
||||
pos = pos->prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - iterate over list of given type
|
||||
* continuing after existing point
|
||||
* @pos: the type * to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
prefetch(pos->member.next))
|
||||
|
||||
#endif
|
137
stats.c
137
stats.c
|
@ -1,137 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "stats.h"
|
||||
#include "options.h"
|
||||
#include "utils/applog.h"
|
||||
#include "persistent_memory.h"
|
||||
|
||||
|
||||
static unsigned long accepted_count = 0L;
|
||||
static unsigned long rejected_count = 0L;
|
||||
static double *thr_hashrates;
|
||||
static double *thr_times;
|
||||
static uint32_t target = 0;
|
||||
|
||||
pthread_mutex_t stats_lock;
|
||||
|
||||
|
||||
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
|
||||
|
||||
|
||||
/**
|
||||
* @brief stats_init
|
||||
*/
|
||||
void stats_init() {
|
||||
pthread_mutex_init(&stats_lock, NULL);
|
||||
|
||||
thr_hashrates = (double *) persistent_calloc(opt_n_threads, sizeof(double));
|
||||
thr_times = (double *) persistent_calloc(opt_n_threads, sizeof(double));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief stats_set_target
|
||||
* @param target
|
||||
*/
|
||||
void stats_set_target(uint32_t new_target)
|
||||
{
|
||||
target = new_target;
|
||||
|
||||
applog(LOG_DEBUG, "Pool set diff to %g", ((double) 0xffffffff) / target);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stats_share_result
|
||||
* @param result
|
||||
*/
|
||||
void stats_share_result(bool success)
|
||||
{
|
||||
double hashrate = 0.0;
|
||||
|
||||
pthread_mutex_lock(&stats_lock);
|
||||
|
||||
for (int i = 0; i < opt_n_threads; i++) {
|
||||
if (thr_times[i] > 0) {
|
||||
hashrate += thr_hashrates[i] / thr_times[i];
|
||||
}
|
||||
}
|
||||
|
||||
success ? accepted_count++ : rejected_count++;
|
||||
pthread_mutex_unlock(&stats_lock);
|
||||
|
||||
applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %.2f H/s at diff %g",
|
||||
accepted_count, accepted_count + rejected_count,
|
||||
100. * accepted_count / (accepted_count + rejected_count), hashrate,
|
||||
(((double) 0xffffffff) / target));
|
||||
}
|
||||
|
||||
|
||||
void stats_add_hashes(int thr_id, struct timeval *tv_start, unsigned long hashes_done)
|
||||
{
|
||||
struct timeval tv_end, diff;
|
||||
|
||||
/* record scanhash elapsed time */
|
||||
gettimeofday(&tv_end, NULL);
|
||||
timeval_subtract(&diff, &tv_end, tv_start);
|
||||
|
||||
if (diff.tv_usec || diff.tv_sec) {
|
||||
pthread_mutex_lock(&stats_lock);
|
||||
thr_hashrates[thr_id] = hashes_done;
|
||||
thr_times[thr_id] = (diff.tv_sec + 1e-6 * diff.tv_usec);
|
||||
pthread_mutex_unlock(&stats_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Subtract the `struct timeval' values X and Y,
|
||||
storing the result in RESULT.
|
||||
Return 1 if the difference is negative, otherwise 0. */
|
||||
static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
|
||||
{
|
||||
/* Perform the carry for the later subtraction by updating Y. */
|
||||
if (x->tv_usec < y->tv_usec) {
|
||||
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
||||
y->tv_usec -= 1000000 * nsec;
|
||||
y->tv_sec += nsec;
|
||||
}
|
||||
if (x->tv_usec - y->tv_usec > 1000000) {
|
||||
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
|
||||
y->tv_usec += 1000000 * nsec;
|
||||
y->tv_sec -= nsec;
|
||||
}
|
||||
|
||||
/* Compute the time remaining to wait.
|
||||
* `tv_usec' is certainly positive. */
|
||||
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||
result->tv_usec = x->tv_usec - y->tv_usec;
|
||||
|
||||
/* Return 1 if result is negative. */
|
||||
return x->tv_sec < y->tv_sec;
|
||||
}
|
37
stats.h
37
stats.h
|
@ -1,37 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STATS_H__
|
||||
#define __STATS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
void stats_init();
|
||||
void stats_set_target(uint32_t new_target);
|
||||
void stats_share_result(bool success);
|
||||
void stats_add_hashes(int thr_id, struct timeval *tv_start, unsigned long hashes_done);
|
||||
|
||||
|
||||
#endif /* __STATS_H__ */
|
718
stratum.c
718
stratum.c
|
@ -1,718 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <jansson.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
# include <winsock2.h>
|
||||
# include <mstcpip.h>
|
||||
#else
|
||||
# include <errno.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE_CC__
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "stratum.h"
|
||||
#include "version.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
#include "utils/applog.h"
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
# define socket_blocks() (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||
# define poll(fdarray, nfds, timeout) WSAPoll(fdarray, nfds, timeout)
|
||||
# define SHUT_RDWR SD_BOTH
|
||||
#else
|
||||
# define socket_blocks() (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
# define closesocket(x) close((x))
|
||||
#endif
|
||||
|
||||
#define RBUFSIZE 2048
|
||||
#define RECVSIZE (RBUFSIZE - 4)
|
||||
|
||||
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
|
||||
|
||||
|
||||
static struct work work;
|
||||
|
||||
|
||||
static bool send_line(curl_socket_t sock, char *s);
|
||||
static bool socket_full(curl_socket_t sock, int timeout);
|
||||
static void buffer_append(struct stratum_ctx *sctx, const char *s);
|
||||
static bool job(struct stratum_ctx *sctx, json_t *params);
|
||||
static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, curlsocktype purpose);
|
||||
static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose, struct curl_sockaddr *addr);
|
||||
static int closesocket_cb(void *clientp, curl_socket_t item);
|
||||
static bool login_decode(struct stratum_ctx *sctx, const json_t *val);
|
||||
static bool job_decode(const json_t *job);
|
||||
static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen);
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_socket_full
|
||||
* @param sctx
|
||||
* @param timeout
|
||||
* @return
|
||||
*/
|
||||
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout)
|
||||
{
|
||||
return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_send_line
|
||||
* @param sctx
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
bool stratum_send_line(struct stratum_ctx *sctx, char *s)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
pthread_mutex_lock(&sctx->sock_lock);
|
||||
ret = send_line(sctx->sock, s);
|
||||
pthread_mutex_unlock(&sctx->sock_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_recv_line
|
||||
* @param sctx
|
||||
* @return
|
||||
*/
|
||||
char *stratum_recv_line(struct stratum_ctx *sctx)
|
||||
{
|
||||
if (!strstr(sctx->sockbuf, "\n")) {
|
||||
bool ret = true;
|
||||
time_t rstart;
|
||||
|
||||
time(&rstart);
|
||||
|
||||
if (!socket_full(sctx->sock, 60)) {
|
||||
applog(LOG_ERR, "stratum_recv_line timed out");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
char s[RBUFSIZE];
|
||||
ssize_t n;
|
||||
|
||||
memset(s, 0, RBUFSIZE);
|
||||
n = recv(sctx->sock, s, RECVSIZE, 0);
|
||||
if (!n) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
if (!socket_blocks() || !socket_full(sctx->sock, 1)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
buffer_append(sctx, s);
|
||||
}
|
||||
} while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n"));
|
||||
|
||||
if (!ret) {
|
||||
applog(LOG_ERR, "stratum_recv_line failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t buflen = strlen(sctx->sockbuf);
|
||||
char *tok = strtok(sctx->sockbuf, "\n");
|
||||
|
||||
if (!tok) {
|
||||
applog(LOG_ERR, "stratum_recv_line failed to parse a newline-terminated string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *sret = strdup(tok);
|
||||
ssize_t len = strlen(sret);
|
||||
|
||||
if (buflen > len + 1) {
|
||||
memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1);
|
||||
}
|
||||
else {
|
||||
sctx->sockbuf[0] = '\0';
|
||||
}
|
||||
|
||||
return sret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_disconnect
|
||||
* @param sctx
|
||||
*/
|
||||
void stratum_disconnect(struct stratum_ctx *sctx)
|
||||
{
|
||||
pthread_mutex_lock(&sctx->sock_lock);
|
||||
|
||||
sctx->ready = false;
|
||||
|
||||
if (sctx->curl) {
|
||||
curl_easy_cleanup(sctx->curl);
|
||||
sctx->curl = NULL;
|
||||
sctx->sockbuf[0] = '\0';
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&sctx->sock_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_handle_method
|
||||
* @param sctx
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
bool stratum_handle_method(struct stratum_ctx *sctx, const char *s)
|
||||
{
|
||||
bool ret = false;
|
||||
const char *method;
|
||||
json_t *val = json_decode(s);
|
||||
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (method = json_string_value(json_object_get(val, "method"))) {
|
||||
if (!strcasecmp(method, "job")) {
|
||||
ret = job(sctx, json_object_get(val, "params"));
|
||||
}
|
||||
else {
|
||||
applog(LOG_WARNING, "Unknown method: \"%s\"", method);
|
||||
}
|
||||
}
|
||||
|
||||
json_decref(val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_handle_response
|
||||
* @param buf
|
||||
* @return
|
||||
*/
|
||||
bool stratum_handle_response(char *buf) {
|
||||
bool valid = false;
|
||||
|
||||
json_t *val = json_decode(buf);
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t *res_val = json_object_get(val, "result");
|
||||
json_t *err_val = json_object_get(val, "error");
|
||||
json_t *id_val = json_object_get(val, "id");
|
||||
|
||||
if (!id_val || json_is_null(id_val) || !res_val) {
|
||||
const char* message;
|
||||
|
||||
if (json_is_object(err_val) && (message = json_string_value(json_object_get(err_val, "message")))) {
|
||||
applog(LOG_ERR, "error: \"%s\"", message);
|
||||
}
|
||||
|
||||
json_decref(val);
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t *status = json_object_get(res_val, "status");
|
||||
|
||||
if (status && !strcmp(json_string_value(status), "KEEPALIVED") ) {
|
||||
applog(LOG_DEBUG, "Keepalived receveid");
|
||||
json_decref(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
valid = !strcmp(json_string_value(status), "OK") && json_is_null(err_val);
|
||||
} else {
|
||||
valid = json_is_null(err_val);
|
||||
}
|
||||
|
||||
stats_share_result(valid);
|
||||
json_decref(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_keepalived
|
||||
* @param sctx
|
||||
* @return
|
||||
*/
|
||||
bool stratum_keepalived(struct stratum_ctx *sctx)
|
||||
{
|
||||
char *s = malloc(128);
|
||||
snprintf(s, 128, "{\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"},\"id\":1}", sctx->id);
|
||||
bool ret = stratum_send_line(sctx, s);
|
||||
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_authorize
|
||||
* @param sctx
|
||||
* @param user
|
||||
* @param pass
|
||||
* @return
|
||||
*/
|
||||
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass)
|
||||
{
|
||||
char *sret;
|
||||
|
||||
char *req = malloc(128 + strlen(user) + strlen(pass));
|
||||
sprintf(req, "{\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s/%s\"},\"id\":1}", user, pass, APP_NAME, APP_VERSION);
|
||||
|
||||
if (!stratum_send_line(sctx, req)) {
|
||||
free(req);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(req);
|
||||
|
||||
while (1) {
|
||||
sret = stratum_recv_line(sctx);
|
||||
if (!sret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stratum_handle_method(sctx, sret)) {
|
||||
break;
|
||||
}
|
||||
|
||||
free(sret);
|
||||
}
|
||||
|
||||
json_t *val = json_decode(sret);
|
||||
free(sret);
|
||||
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
|
||||
json_t *result = json_object_get(val, "result");
|
||||
json_t *error = json_object_get(val, "error");
|
||||
|
||||
if (!result || json_is_false(result) || (error && !json_is_null(error))) {
|
||||
const char* message;
|
||||
|
||||
if (json_is_object(error) && (message = json_string_value(json_object_get(error, "message")))) {
|
||||
applog(LOG_ERR, "Stratum authentication failed: \"%s\"", message);
|
||||
}
|
||||
else {
|
||||
applog(LOG_ERR, "Stratum authentication failed");
|
||||
}
|
||||
|
||||
json_decref(val);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (login_decode(sctx, val) && job(sctx, json_object_get(result, "job"))) {
|
||||
pthread_mutex_lock(&sctx->sock_lock);
|
||||
sctx->ready = true;
|
||||
pthread_mutex_unlock(&sctx->sock_lock);
|
||||
}
|
||||
|
||||
json_decref(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_connect
|
||||
* @param sctx
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
bool stratum_connect(struct stratum_ctx *sctx, const char *url)
|
||||
{
|
||||
CURL *curl;
|
||||
|
||||
pthread_mutex_lock(&sctx->sock_lock);
|
||||
sctx->ready = false;
|
||||
|
||||
if (sctx->curl) {
|
||||
curl_easy_cleanup(sctx->curl);
|
||||
}
|
||||
|
||||
sctx->curl = curl_easy_init();
|
||||
if (!sctx->curl) {
|
||||
applog(LOG_ERR, "CURL initialization failed");
|
||||
pthread_mutex_unlock(&sctx->sock_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
curl = sctx->curl;
|
||||
if (!sctx->sockbuf) {
|
||||
sctx->sockbuf = calloc(RBUFSIZE, 1);
|
||||
sctx->sockbuf_size = RBUFSIZE;
|
||||
}
|
||||
|
||||
sctx->sockbuf[0] = '\0';
|
||||
pthread_mutex_unlock(&sctx->sock_lock);
|
||||
|
||||
if (url != sctx->url) {
|
||||
free(sctx->url);
|
||||
sctx->url = strdup(url);
|
||||
}
|
||||
|
||||
free(sctx->curl_url);
|
||||
sctx->curl_url = malloc(strlen(url));
|
||||
sprintf(sctx->curl_url, "http%s/", strstr(url, "://"));
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
|
||||
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_grab_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sctx->sock);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
|
||||
int rc = curl_easy_perform(curl);
|
||||
if (rc) {
|
||||
applog(LOG_ERR, "Stratum connection failed: code: %d, text: %s", rc, sctx->curl_err_str);
|
||||
curl_easy_cleanup(curl);
|
||||
sctx->curl = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief send_line
|
||||
* @param sock
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
static bool send_line(curl_socket_t sock, char *s)
|
||||
{
|
||||
ssize_t len, sent = 0;
|
||||
|
||||
len = strlen(s);
|
||||
s[len++] = '\n';
|
||||
|
||||
while (len > 0) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = sock;
|
||||
pfd.events = POLLOUT;
|
||||
|
||||
if (poll(&pfd, 1, 0) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t n = send(sock, s + sent, len, 0);
|
||||
if (n < 0) {
|
||||
if (!socket_blocks()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
}
|
||||
|
||||
sent += n;
|
||||
len -= n;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief socket_full
|
||||
* @param sock
|
||||
* @param timeout
|
||||
* @return
|
||||
*/
|
||||
static bool socket_full(curl_socket_t sock, int timeout)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
pfd.fd = sock;
|
||||
pfd.events = POLLIN;
|
||||
|
||||
return poll(&pfd, 1, timeout * 1000) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief buffer_append
|
||||
* @param sctx
|
||||
* @param s
|
||||
*/
|
||||
static void buffer_append(struct stratum_ctx *sctx, const char *s)
|
||||
{
|
||||
size_t old, new;
|
||||
|
||||
old = strlen(sctx->sockbuf);
|
||||
new = old + strlen(s) + 1;
|
||||
|
||||
if (new >= sctx->sockbuf_size) {
|
||||
sctx->sockbuf_size = new + (RBUFSIZE - (new % RBUFSIZE));
|
||||
sctx->sockbuf = realloc(sctx->sockbuf, sctx->sockbuf_size);
|
||||
}
|
||||
|
||||
strcpy(sctx->sockbuf + old, s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief job
|
||||
* @param sctx
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
static bool job(struct stratum_ctx *sctx, json_t *params)
|
||||
{
|
||||
if (!job_decode(params)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&sctx->work_lock);
|
||||
|
||||
if (sctx->work.target != work.target) {
|
||||
stats_set_target(work.target);
|
||||
}
|
||||
|
||||
memcpy(&sctx->work, &work, sizeof(struct work));
|
||||
pthread_mutex_unlock(&sctx->work_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief sockopt_keepalive_cb
|
||||
* @param userdata
|
||||
* @param fd
|
||||
* @param purpose
|
||||
* @return
|
||||
*/
|
||||
static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, curlsocktype purpose)
|
||||
{
|
||||
int keepalive = 1;
|
||||
int tcp_keepcnt = 3;
|
||||
int tcp_keepidle = 50;
|
||||
int tcp_keepintvl = 50;
|
||||
|
||||
#ifndef WIN32
|
||||
if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
# ifdef __linux
|
||||
if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_keepcnt, sizeof(tcp_keepcnt)))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)))) {
|
||||
return 1;
|
||||
}
|
||||
# endif /* __linux */
|
||||
|
||||
# ifdef __APPLE_CC__
|
||||
if (unlikely(setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl)))) {
|
||||
return 1;
|
||||
}
|
||||
# endif /* __APPLE_CC__ */
|
||||
#else /* WIN32 */
|
||||
struct tcp_keepalive vals;
|
||||
vals.onoff = 1;
|
||||
vals.keepalivetime = tcp_keepidle * 1000;
|
||||
vals.keepaliveinterval = tcp_keepintvl * 1000;
|
||||
DWORD outputBytes;
|
||||
|
||||
if (unlikely(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outputBytes, NULL, NULL))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int closesocket_cb(void *clientp, curl_socket_t item) {
|
||||
shutdown(item, SHUT_RDWR);
|
||||
return closesocket(item);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief opensocket_grab_cb
|
||||
* @param clientp
|
||||
* @param purpose
|
||||
* @param addr
|
||||
* @return
|
||||
*/
|
||||
static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose, struct curl_sockaddr *addr)
|
||||
{
|
||||
curl_socket_t *sock = clientp;
|
||||
*sock = socket(addr->family, addr->socktype, addr->protocol);
|
||||
return *sock;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief login_decode
|
||||
* @param sctx
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
static bool login_decode(struct stratum_ctx *sctx, const json_t *val) {
|
||||
json_t *res = json_object_get(val, "result");
|
||||
if (!res) {
|
||||
applog(LOG_ERR, "JSON invalid result");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *id = json_string_value(json_object_get(res, "id"));
|
||||
if (!id || strlen(id) >= (sizeof(sctx->id))) {
|
||||
applog(LOG_ERR, "JSON invalid id");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&sctx->id, 0, sizeof(sctx->id));
|
||||
memcpy(&sctx->id, id, strlen(id));
|
||||
|
||||
const char *s = json_string_value(json_object_get(res, "status"));
|
||||
if (!s) {
|
||||
applog(LOG_ERR, "JSON invalid status");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(s, "OK")) {
|
||||
applog(LOG_ERR, "JSON returned status \"%s\"", s);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief job_decode
|
||||
* @param sctx
|
||||
* @param job
|
||||
* @param work
|
||||
* @return
|
||||
*/
|
||||
static bool job_decode(const json_t *job) {
|
||||
const char *job_id = json_string_value(json_object_get(job, "job_id"));
|
||||
if (!job_id || strlen(job_id) >= sizeof(work.job_id)) {
|
||||
applog(LOG_ERR, "JSON invalid job id");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *blob = json_string_value(json_object_get(job, "blob"));
|
||||
if (!blob) {
|
||||
applog(LOG_ERR, "JSON invalid blob");
|
||||
return false;
|
||||
}
|
||||
|
||||
work.blob_size = strlen(blob);
|
||||
if (work.blob_size % 2 != 0) {
|
||||
applog(LOG_ERR, "JSON invalid blob length");
|
||||
return false;
|
||||
}
|
||||
|
||||
work.blob_size /= 2;
|
||||
if (work.blob_size < 76 || work.blob_size > (sizeof(work.blob))) {
|
||||
applog(LOG_ERR, "JSON invalid blob length");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hex2bin((unsigned char *) work.blob, blob, work.blob_size)) {
|
||||
applog(LOG_ERR, "JSON invalid blob");
|
||||
return false;
|
||||
}
|
||||
|
||||
jobj_binary(job, "target", &work.target, 4);
|
||||
|
||||
memset(work.job_id, 0, sizeof(work.job_id));
|
||||
memcpy(work.job_id, job_id, strlen(job_id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief jobj_binary
|
||||
* @param obj
|
||||
* @param key
|
||||
* @param buf
|
||||
* @param buflen
|
||||
* @return
|
||||
*/
|
||||
static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen) {
|
||||
const char *hexstr;
|
||||
json_t *tmp;
|
||||
|
||||
tmp = json_object_get(obj, key);
|
||||
if (unlikely(!tmp)) {
|
||||
applog(LOG_ERR, "JSON key '%s' not found", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
hexstr = json_string_value(tmp);
|
||||
if (unlikely(!hexstr)) {
|
||||
applog(LOG_ERR, "JSON key '%s' is not a string", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!hex2bin(buf, hexstr, buflen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
78
stratum.h
78
stratum.h
|
@ -1,78 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __STRATUM_H__
|
||||
#define __STRATUM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
/**
|
||||
* 128tx exploit.
|
||||
*
|
||||
* Max blob size is 84 (75 fixed + 9 variable), aligned to 96.
|
||||
* https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk.
|
||||
*/
|
||||
struct work {
|
||||
uint32_t blob[21] __attribute__((aligned(16)));
|
||||
size_t blob_size __attribute__((aligned(16)));
|
||||
uint32_t target __attribute__((aligned(16)));
|
||||
uint32_t hash[8] __attribute__((aligned(16)));
|
||||
char job_id[64] __attribute__((aligned(16)));
|
||||
};
|
||||
|
||||
|
||||
struct stratum_ctx {
|
||||
char *url;
|
||||
|
||||
CURL *curl;
|
||||
char *curl_url;
|
||||
char curl_err_str[CURL_ERROR_SIZE];
|
||||
curl_socket_t sock;
|
||||
size_t sockbuf_size;
|
||||
char *sockbuf;
|
||||
pthread_mutex_t sock_lock;
|
||||
bool ready;
|
||||
|
||||
char id[64];
|
||||
|
||||
struct work work;
|
||||
struct work g_work;
|
||||
time_t g_work_time;
|
||||
pthread_mutex_t work_lock;
|
||||
};
|
||||
|
||||
|
||||
bool stratum_send_line(struct stratum_ctx *sctx, char *s);
|
||||
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout);
|
||||
char *stratum_recv_line(struct stratum_ctx *sctx);
|
||||
bool stratum_connect(struct stratum_ctx *sctx, const char *url);
|
||||
void stratum_disconnect(struct stratum_ctx *sctx);
|
||||
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass);
|
||||
bool stratum_handle_method(struct stratum_ctx *sctx, const char *s);
|
||||
bool stratum_handle_response(char *buf);
|
||||
bool stratum_keepalived(struct stratum_ctx *sctx);
|
||||
|
||||
#endif /* __STRATUM_H__ */
|
270
util.c
270
util.c
|
@ -1,270 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "elist.h"
|
||||
#include "utils/applog.h"
|
||||
|
||||
|
||||
struct tq_ent {
|
||||
void *data;
|
||||
struct list_head q_node;
|
||||
};
|
||||
|
||||
|
||||
struct thread_q {
|
||||
struct list_head q;
|
||||
bool frozen;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
|
||||
json_t *json_decode(const char *s)
|
||||
{
|
||||
json_error_t err;
|
||||
json_t *val = json_loads(s, 0, &err);
|
||||
|
||||
if (!val) {
|
||||
applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief bin2hex
|
||||
* @param p
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
char *bin2hex(const unsigned char *p, size_t len)
|
||||
{
|
||||
char *s = malloc((len * 2) + 1);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
sprintf(s + (i * 2), "%02x", (unsigned int) p[i]);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief hex2bin
|
||||
* @param p
|
||||
* @param hexstr
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
|
||||
{
|
||||
char hex_byte[3];
|
||||
char *ep;
|
||||
|
||||
hex_byte[2] = '\0';
|
||||
|
||||
while (*hexstr && len) {
|
||||
if (!hexstr[1]) {
|
||||
applog(LOG_ERR, "hex2bin str truncated");
|
||||
return false;
|
||||
}
|
||||
|
||||
hex_byte[0] = hexstr[0];
|
||||
hex_byte[1] = hexstr[1];
|
||||
*p = (unsigned char) strtol(hex_byte, &ep, 16);
|
||||
if (*ep) {
|
||||
applog(LOG_ERR, "hex2bin failed on '%s'", hex_byte);
|
||||
return false;
|
||||
}
|
||||
|
||||
p++;
|
||||
hexstr += 2;
|
||||
len--;
|
||||
}
|
||||
|
||||
return (len == 0 && *hexstr == 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_new
|
||||
* @return
|
||||
*/
|
||||
struct thread_q *tq_new(void)
|
||||
{
|
||||
struct thread_q *tq;
|
||||
|
||||
tq = calloc(1, sizeof(*tq));
|
||||
if (!tq)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&tq->q);
|
||||
pthread_mutex_init(&tq->mutex, NULL);
|
||||
pthread_cond_init(&tq->cond, NULL);
|
||||
|
||||
return tq;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_free
|
||||
* @param tq
|
||||
*/
|
||||
void tq_free(struct thread_q *tq)
|
||||
{
|
||||
struct tq_ent *ent, *iter;
|
||||
|
||||
if (!tq)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(ent, iter, &tq->q, q_node) {
|
||||
list_del(&ent->q_node);
|
||||
free(ent);
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&tq->cond);
|
||||
pthread_mutex_destroy(&tq->mutex);
|
||||
|
||||
memset(tq, 0, sizeof(*tq)); /* poison */
|
||||
free(tq);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_freezethaw
|
||||
* @param tq
|
||||
* @param frozen
|
||||
*/
|
||||
static void tq_freezethaw(struct thread_q *tq, bool frozen)
|
||||
{
|
||||
pthread_mutex_lock(&tq->mutex);
|
||||
|
||||
tq->frozen = frozen;
|
||||
|
||||
pthread_cond_signal(&tq->cond);
|
||||
pthread_mutex_unlock(&tq->mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_freeze
|
||||
* @param tq
|
||||
*/
|
||||
void tq_freeze(struct thread_q *tq)
|
||||
{
|
||||
tq_freezethaw(tq, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_thaw
|
||||
* @param tq
|
||||
*/
|
||||
void tq_thaw(struct thread_q *tq)
|
||||
{
|
||||
tq_freezethaw(tq, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_push
|
||||
* @param tq
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
bool tq_push(struct thread_q *tq, void *data)
|
||||
{
|
||||
struct tq_ent *ent;
|
||||
bool rc = true;
|
||||
|
||||
ent = calloc(1, sizeof(*ent));
|
||||
if (!ent)
|
||||
return false;
|
||||
|
||||
ent->data = data;
|
||||
INIT_LIST_HEAD(&ent->q_node);
|
||||
|
||||
pthread_mutex_lock(&tq->mutex);
|
||||
|
||||
if (!tq->frozen) {
|
||||
list_add_tail(&ent->q_node, &tq->q);
|
||||
} else {
|
||||
free(ent);
|
||||
rc = false;
|
||||
}
|
||||
|
||||
pthread_cond_signal(&tq->cond);
|
||||
pthread_mutex_unlock(&tq->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief tq_pop
|
||||
* @param tq
|
||||
* @param abstime
|
||||
* @return
|
||||
*/
|
||||
void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
|
||||
{
|
||||
struct tq_ent *ent;
|
||||
void *rval = NULL;
|
||||
int rc;
|
||||
|
||||
pthread_mutex_lock(&tq->mutex);
|
||||
|
||||
if (!list_empty(&tq->q))
|
||||
goto pop;
|
||||
|
||||
if (abstime)
|
||||
rc = pthread_cond_timedwait(&tq->cond, &tq->mutex, abstime);
|
||||
else
|
||||
rc = pthread_cond_wait(&tq->cond, &tq->mutex);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (list_empty(&tq->q))
|
||||
goto out;
|
||||
|
||||
pop:
|
||||
ent = list_entry(tq->q.next, struct tq_ent, q_node);
|
||||
rval = ent->data;
|
||||
|
||||
list_del(&ent->q_node);
|
||||
free(ent);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&tq->mutex);
|
||||
return rval;
|
||||
}
|
43
util.h
43
util.h
|
@ -1,43 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __UTIL_H__
|
||||
#define __UTIL_H__
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
json_t *json_decode(const char *s);
|
||||
|
||||
char *bin2hex(const unsigned char *p, size_t len);
|
||||
bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
|
||||
|
||||
struct thread_q *tq_new(void);
|
||||
void tq_free(struct thread_q *tq);
|
||||
bool tq_push(struct thread_q *tq, void *data);
|
||||
void *tq_pop(struct thread_q *tq, const struct timespec *abstime);
|
||||
void tq_freeze(struct thread_q *tq);
|
||||
void tq_thaw(struct thread_q *tq);
|
||||
|
||||
|
||||
#endif /* __UTIL_H__ */
|
677
xmrig.c
677
xmrig.c
|
@ -1,677 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <jansson.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <jansson.h>
|
||||
#include <curl/curl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "xmrig.h"
|
||||
#include "algo/cryptonight/cryptonight.h"
|
||||
#include "options.h"
|
||||
#include "cpu.h"
|
||||
#include "persistent_memory.h"
|
||||
#include "stratum.h"
|
||||
#include "stats.h"
|
||||
#include "util.h"
|
||||
#include "utils/summary.h"
|
||||
#include "utils/applog.h"
|
||||
|
||||
#define LP_SCANTIME 60
|
||||
#define JSON_BUF_LEN 345
|
||||
|
||||
|
||||
struct workio_cmd {
|
||||
struct thr_info *thr;
|
||||
struct work *work;
|
||||
};
|
||||
|
||||
|
||||
struct thr_info *thr_info;
|
||||
static int work_thr_id = -1;
|
||||
static int timer_thr_id = -1;
|
||||
static int stratum_thr_id = -1;
|
||||
struct work_restart *work_restart = NULL;
|
||||
static struct stratum_ctx *stratum_ctx = NULL;
|
||||
static bool backup_active = false;
|
||||
static bool g_want_donate = false;
|
||||
|
||||
|
||||
static void workio_cmd_free(struct workio_cmd *wc);
|
||||
|
||||
|
||||
/**
|
||||
* @brief work_copy
|
||||
* @param dest
|
||||
* @param src
|
||||
*/
|
||||
static inline void work_copy(struct work *dest, const struct work *src) {
|
||||
memcpy(dest, src, sizeof(struct work));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief restart_threads
|
||||
*/
|
||||
static inline void restart_threads(void) {
|
||||
for (int i = 0; i < opt_n_threads; i++) {
|
||||
work_restart[i].restart = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief gen_workify
|
||||
* @param sctx
|
||||
* @param work
|
||||
*/
|
||||
static inline void gen_workify(struct stratum_ctx *sctx) {
|
||||
pthread_mutex_lock(&stratum_ctx->work_lock);
|
||||
|
||||
if (stratum_ctx->work.job_id && (!stratum_ctx->g_work_time || strcmp(stratum_ctx->work.job_id, stratum_ctx->g_work.job_id))) {
|
||||
memcpy(&sctx->g_work, &sctx->work, sizeof(struct work));
|
||||
time(&stratum_ctx->g_work_time);
|
||||
|
||||
pthread_mutex_unlock(&stratum_ctx->work_lock);
|
||||
|
||||
applog(LOG_DEBUG, "Stratum detected new block");
|
||||
restart_threads();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stratum_ctx->work_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief submit_upstream_work
|
||||
* @param work
|
||||
* @return
|
||||
*/
|
||||
static bool submit_upstream_work(struct work *work) {
|
||||
char s[JSON_BUF_LEN];
|
||||
|
||||
/* pass if the previous hash is not the current previous hash */
|
||||
if (memcmp(work->blob + 1, stratum_ctx->g_work.blob + 1, 32)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char *noncestr = bin2hex(((const unsigned char*) work->blob) + 39, 4);
|
||||
char *hashhex = bin2hex((const unsigned char *) work->hash, 32);
|
||||
|
||||
snprintf(s, JSON_BUF_LEN,
|
||||
"{\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"},\"id\":1}",
|
||||
stratum_ctx->id, work->job_id, noncestr, hashhex);
|
||||
|
||||
free(hashhex);
|
||||
free(noncestr);
|
||||
|
||||
if (unlikely(!stratum_send_line(stratum_ctx, s))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief workio_cmd_free
|
||||
* @param wc
|
||||
*/
|
||||
static void workio_cmd_free(struct workio_cmd *wc) {
|
||||
if (!wc) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(wc->work);
|
||||
|
||||
memset(wc, 0, sizeof(*wc)); /* poison */
|
||||
free(wc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief workio_submit_work
|
||||
* @param wc
|
||||
* @param curl
|
||||
* @return
|
||||
*/
|
||||
static bool workio_submit_work(struct workio_cmd *wc) {
|
||||
while (!submit_upstream_work(wc->work)) {
|
||||
sleep(opt_retry_pause);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief workio_thread
|
||||
* @param userdata
|
||||
* @return
|
||||
*/
|
||||
static void *workio_thread(void *userdata) {
|
||||
struct thr_info *mythr = userdata;
|
||||
bool ok = true;
|
||||
|
||||
while (ok) {
|
||||
struct workio_cmd *wc;
|
||||
|
||||
/* wait for workio_cmd sent to us, on our queue */
|
||||
wc = tq_pop(mythr->q, NULL );
|
||||
if (!wc) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
workio_submit_work(wc);
|
||||
workio_cmd_free(wc);
|
||||
}
|
||||
|
||||
tq_freeze(mythr->q);
|
||||
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief submit_work
|
||||
* @param thr
|
||||
* @param work_in
|
||||
* @return
|
||||
*/
|
||||
static bool submit_work(struct thr_info *thr, const struct work *work_in) {
|
||||
struct workio_cmd *wc;
|
||||
|
||||
/* fill out work request message */
|
||||
wc = calloc(1, sizeof(*wc));
|
||||
wc->work = malloc(sizeof(*work_in));
|
||||
|
||||
if (likely(wc->work)) {
|
||||
wc->thr = thr;
|
||||
work_copy(wc->work, work_in);
|
||||
|
||||
if (likely(tq_push(thr_info[work_thr_id].q, wc))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
workio_cmd_free(wc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool should_pause(int thr_id) {
|
||||
bool ret = false;
|
||||
|
||||
pthread_mutex_lock(&stratum_ctx->sock_lock);
|
||||
|
||||
if (!stratum_ctx->ready) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stratum_ctx->sock_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief miner_thread
|
||||
* @param userdata
|
||||
* @return
|
||||
*/
|
||||
static void *miner_thread(void *userdata) {
|
||||
struct thr_info *mythr = userdata;
|
||||
const int thr_id = mythr->id;
|
||||
struct work work = { { 0 } };
|
||||
uint32_t max_nonce;
|
||||
uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20;
|
||||
|
||||
struct cryptonight_ctx *persistentctx = (struct cryptonight_ctx *) create_persistent_ctx(thr_id);
|
||||
|
||||
if (cpu_info.total_logical_cpus > 1 && opt_affinity != -1L) {
|
||||
affine_to_cpu_mask(thr_id, (unsigned long) opt_affinity);
|
||||
}
|
||||
|
||||
uint32_t *nonceptr = NULL;
|
||||
uint32_t hash[8] __attribute__((aligned(32)));
|
||||
|
||||
while (1) {
|
||||
if (should_pause(thr_id)) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&stratum_ctx->work_lock);
|
||||
|
||||
if (memcmp(work.job_id, stratum_ctx->g_work.job_id, 64)) {
|
||||
work_copy(&work, &stratum_ctx->g_work);
|
||||
nonceptr = (uint32_t*) (((char*) work.blob) + 39);
|
||||
|
||||
if (opt_nicehash) {
|
||||
end_nonce = (*nonceptr & 0xff000000U) + (0xffffffU / opt_n_threads * (thr_id + 1) - 0x20);
|
||||
*nonceptr = (*nonceptr & 0xff000000U) + (0xffffffU / opt_n_threads * thr_id);
|
||||
}
|
||||
else {
|
||||
*nonceptr = 0xffffffffU / opt_n_threads * thr_id;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stratum_ctx->work_lock);
|
||||
|
||||
work_restart[thr_id].restart = 0;
|
||||
|
||||
if (*nonceptr + LP_SCANTIME > end_nonce) {
|
||||
max_nonce = end_nonce;
|
||||
} else {
|
||||
max_nonce = *nonceptr + LP_SCANTIME;
|
||||
}
|
||||
|
||||
unsigned long hashes_done = 0;
|
||||
|
||||
struct timeval tv_start;
|
||||
gettimeofday(&tv_start, NULL);
|
||||
|
||||
/* scan nonces for a proof-of-work hash */
|
||||
const int rc = scanhash_cryptonight(thr_id, hash, work.blob, work.blob_size, work.target, max_nonce, &hashes_done, persistentctx);
|
||||
stats_add_hashes(thr_id, &tv_start, hashes_done);
|
||||
|
||||
if (!rc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(work.hash, hash, 32);
|
||||
submit_work(mythr, &work);
|
||||
++(*nonceptr);
|
||||
}
|
||||
|
||||
tq_freeze(mythr->q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief miner_thread_double
|
||||
* @param userdata
|
||||
* @return
|
||||
*/
|
||||
static void *miner_thread_double(void *userdata) {
|
||||
struct thr_info *mythr = userdata;
|
||||
const int thr_id = mythr->id;
|
||||
struct work work = { { 0 } };
|
||||
uint32_t max_nonce;
|
||||
uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20;
|
||||
|
||||
struct cryptonight_ctx *persistentctx = (struct cryptonight_ctx *) create_persistent_ctx(thr_id);
|
||||
|
||||
if (cpu_info.total_logical_cpus > 1 && opt_affinity != -1L) {
|
||||
affine_to_cpu_mask(thr_id, (unsigned long) opt_affinity);
|
||||
}
|
||||
|
||||
uint32_t *nonceptr0 = NULL;
|
||||
uint32_t *nonceptr1 = NULL;
|
||||
uint8_t double_hash[64];
|
||||
uint8_t double_blob[sizeof(work.blob) * 2];
|
||||
|
||||
while (1) {
|
||||
if (should_pause(thr_id)) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&stratum_ctx->work_lock);
|
||||
|
||||
if (memcmp(work.job_id, stratum_ctx->g_work.job_id, 64)) {
|
||||
work_copy(&work, &stratum_ctx->g_work);
|
||||
|
||||
memcpy(double_blob, work.blob, work.blob_size);
|
||||
memcpy(double_blob + work.blob_size, work.blob, work.blob_size);
|
||||
|
||||
nonceptr0 = (uint32_t*) (((char*) double_blob) + 39);
|
||||
nonceptr1 = (uint32_t*) (((char*) double_blob) + 39 + work.blob_size);
|
||||
|
||||
if (opt_nicehash) {
|
||||
end_nonce = (*nonceptr0 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * (thr_id + 1) - 0x20);
|
||||
*nonceptr0 = (*nonceptr0 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * thr_id);
|
||||
*nonceptr1 = (*nonceptr1 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * (thr_id + opt_n_threads));
|
||||
}
|
||||
else {
|
||||
*nonceptr0 = 0xffffffffU / (opt_n_threads * 2) * thr_id;
|
||||
*nonceptr1 = 0xffffffffU / (opt_n_threads * 2) * (thr_id + opt_n_threads);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&stratum_ctx->work_lock);
|
||||
|
||||
work_restart[thr_id].restart = 0;
|
||||
|
||||
if (*nonceptr0 + (LP_SCANTIME / 2) > end_nonce) {
|
||||
max_nonce = end_nonce;
|
||||
} else {
|
||||
max_nonce = *nonceptr0 + (LP_SCANTIME / 2);
|
||||
}
|
||||
|
||||
unsigned long hashes_done = 0;
|
||||
|
||||
struct timeval tv_start;
|
||||
gettimeofday(&tv_start, NULL);
|
||||
|
||||
/* scan nonces for a proof-of-work hash */
|
||||
const int rc = scanhash_cryptonight_double(thr_id, (uint32_t *) double_hash, double_blob, work.blob_size, work.target, max_nonce, &hashes_done, persistentctx);
|
||||
stats_add_hashes(thr_id, &tv_start, hashes_done);
|
||||
|
||||
if (!rc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc & 1) {
|
||||
memcpy(work.hash, double_hash, 32);
|
||||
memcpy(work.blob, double_blob, work.blob_size);
|
||||
submit_work(mythr, &work);
|
||||
}
|
||||
|
||||
if (rc & 2) {
|
||||
memcpy(work.hash, double_hash + 32, 32);
|
||||
memcpy(work.blob, double_blob + work.blob_size, work.blob_size);
|
||||
submit_work(mythr, &work);
|
||||
}
|
||||
|
||||
++(*nonceptr0);
|
||||
++(*nonceptr1);
|
||||
}
|
||||
|
||||
tq_freeze(mythr->q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_thread
|
||||
* @param userdata
|
||||
* @return
|
||||
*/
|
||||
static void *timer_thread(void *userdata) {
|
||||
const int max_user_time = 100 - opt_donate_level;
|
||||
int user_time_remaning = max_user_time;
|
||||
int donate_time_remaning = 0;
|
||||
|
||||
|
||||
while (1) {
|
||||
sleep(60);
|
||||
|
||||
if (user_time_remaning > 0) {
|
||||
if (--user_time_remaning == 0) {
|
||||
g_want_donate = true;
|
||||
|
||||
donate_time_remaning = opt_donate_level;
|
||||
stratum_disconnect(stratum_ctx);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (donate_time_remaning > 0) {
|
||||
if (--donate_time_remaning == 0) {
|
||||
g_want_donate = false;
|
||||
|
||||
user_time_remaning = max_user_time;
|
||||
stratum_disconnect(stratum_ctx);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void switch_stratum() {
|
||||
static bool want_donate = false;
|
||||
|
||||
if (g_want_donate && !want_donate) {
|
||||
stratum_ctx->url = opt_algo == ALGO_CRYPTONIGHT ? "stratum+tcp://donate.xmrig.com:443" : "stratum+tcp://donate.xmrig.com:3333";
|
||||
applog(LOG_NOTICE, "Switching to dev pool");
|
||||
want_donate = true;
|
||||
}
|
||||
|
||||
if (!g_want_donate && want_donate) {
|
||||
stratum_ctx->url = backup_active ? opt_backup_url : opt_url;
|
||||
applog(LOG_NOTICE, "Switching to user pool: \"%s\"", stratum_ctx->url);
|
||||
want_donate = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief stratum_thread
|
||||
* @param userdata
|
||||
* @return
|
||||
*/
|
||||
static void *stratum_thread(void *userdata) {
|
||||
char *s;
|
||||
|
||||
stratum_ctx->url = opt_url;
|
||||
stratum_ctx->ready = false;
|
||||
|
||||
while (1) {
|
||||
int failures = 0;
|
||||
switch_stratum();
|
||||
|
||||
while (!stratum_ctx->curl) {
|
||||
pthread_mutex_lock(&stratum_ctx->work_lock);
|
||||
stratum_ctx->g_work_time = 0;
|
||||
pthread_mutex_unlock(&stratum_ctx->work_lock);
|
||||
|
||||
restart_threads();
|
||||
switch_stratum();
|
||||
|
||||
if (!stratum_connect(stratum_ctx, stratum_ctx->url) || !stratum_authorize(stratum_ctx, opt_user, opt_pass)) {
|
||||
stratum_disconnect(stratum_ctx);
|
||||
failures++;
|
||||
|
||||
if (failures > opt_retries && opt_backup_url) {
|
||||
failures = 0;
|
||||
|
||||
backup_active = !backup_active;
|
||||
stratum_ctx->url = backup_active ? opt_backup_url : opt_url;
|
||||
sleep(opt_retry_pause);
|
||||
|
||||
applog(LOG_WARNING, "Switch to: \"%s\"", stratum_ctx->url);
|
||||
continue;
|
||||
}
|
||||
|
||||
applog(LOG_ERR, "...retry after %d seconds", opt_retry_pause);
|
||||
sleep(opt_retry_pause);
|
||||
}
|
||||
}
|
||||
|
||||
gen_workify(stratum_ctx);
|
||||
|
||||
if (opt_keepalive && !stratum_socket_full(stratum_ctx, 90)) {
|
||||
stratum_keepalived(stratum_ctx);
|
||||
}
|
||||
|
||||
if (!stratum_socket_full(stratum_ctx, 300)) {
|
||||
applog(LOG_ERR, "Stratum connection timed out");
|
||||
s = NULL;
|
||||
} else {
|
||||
s = stratum_recv_line(stratum_ctx);
|
||||
}
|
||||
|
||||
if (!s) {
|
||||
stratum_disconnect(stratum_ctx);
|
||||
applog(LOG_ERR, "Stratum connection interrupted");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!stratum_handle_method(stratum_ctx, s)) {
|
||||
stratum_handle_response(s);
|
||||
}
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief start work I/O thread
|
||||
* @return
|
||||
*/
|
||||
static bool start_workio() {
|
||||
work_thr_id = opt_n_threads;
|
||||
|
||||
struct thr_info *thr = &thr_info[work_thr_id];
|
||||
thr->id = work_thr_id;
|
||||
thr->q = tq_new();
|
||||
|
||||
if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, workio_thread, thr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief start_stratum
|
||||
* @return
|
||||
*/
|
||||
static bool start_stratum() {
|
||||
stratum_thr_id = opt_n_threads + 1;
|
||||
|
||||
stratum_ctx = persistent_calloc(1, sizeof(struct stratum_ctx));
|
||||
pthread_mutex_init(&stratum_ctx->work_lock, NULL);
|
||||
pthread_mutex_init(&stratum_ctx->sock_lock, NULL);
|
||||
|
||||
struct thr_info *thr = &thr_info[stratum_thr_id];
|
||||
thr->id = stratum_thr_id;
|
||||
thr->q = tq_new();
|
||||
|
||||
if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, stratum_thread, thr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tq_push(thr_info[stratum_thr_id].q, strdup(opt_url));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief start_timer
|
||||
* @return
|
||||
*/
|
||||
static bool start_timer() {
|
||||
timer_thr_id = opt_n_threads + 2;
|
||||
|
||||
if (opt_donate_level < 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct thr_info *thr = &thr_info[timer_thr_id];
|
||||
thr->id = timer_thr_id;
|
||||
thr->q = tq_new();
|
||||
|
||||
if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, timer_thread, thr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief start_mining
|
||||
* @return
|
||||
*/
|
||||
static bool start_mining() {
|
||||
for (int i = 0; i < opt_n_threads; i++) {
|
||||
struct thr_info *thr = &thr_info[i];
|
||||
|
||||
thr->id = i;
|
||||
thr->q = tq_new();
|
||||
|
||||
if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, opt_double_hash ? miner_thread_double : miner_thread, thr))) {
|
||||
applog(LOG_ERR, "thread %d create failed", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief main
|
||||
* @param argc
|
||||
* @param argv
|
||||
* @return
|
||||
*/
|
||||
int main(int argc, char *argv[]) {
|
||||
applog_init();
|
||||
cpu_init();
|
||||
parse_cmdline(argc, argv);
|
||||
persistent_memory_allocate();
|
||||
print_summary();
|
||||
|
||||
stats_init();
|
||||
os_specific_init();
|
||||
|
||||
work_restart = persistent_calloc(opt_n_threads, sizeof(*work_restart));
|
||||
thr_info = persistent_calloc(opt_n_threads + 3, sizeof(struct thr_info));
|
||||
|
||||
if (!start_workio()) {
|
||||
applog(LOG_ERR, "workio thread create failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!start_stratum()) {
|
||||
applog(LOG_ERR, "stratum thread create failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
start_timer();
|
||||
|
||||
if (!start_mining()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pthread_join(thr_info[work_thr_id].pth, NULL);
|
||||
applog(LOG_INFO, "workio thread dead, exiting.");
|
||||
persistent_memory_free();
|
||||
return 0;
|
||||
}
|
||||
|
57
xmrig.h
57
xmrig.h
|
@ -1,57 +0,0 @@
|
|||
/* XMRig
|
||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright 2016-2017 XMRig <support@xmrig.com>
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __XMRIG_H__
|
||||
#define __XMRIG_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <jansson.h>
|
||||
#include <curl/curl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
|
||||
#define likely(expr) (__builtin_expect(!!(expr), 1))
|
||||
|
||||
|
||||
struct thr_info {
|
||||
int id;
|
||||
pthread_t pth;
|
||||
struct thread_q *q;
|
||||
};
|
||||
|
||||
|
||||
struct work_restart {
|
||||
volatile unsigned long restart;
|
||||
char padding[128 - sizeof(unsigned long)];
|
||||
};
|
||||
|
||||
|
||||
struct work;
|
||||
|
||||
|
||||
extern struct thr_info *thr_info;
|
||||
extern struct work_restart *work_restart;
|
||||
extern void os_specific_init();
|
||||
|
||||
#endif /* __XMRIG_H__ */
|
Loading…
Reference in a new issue