Remove obsolete source files.

This commit is contained in:
XMRig 2017-06-13 11:51:49 +03:00
parent 827e611911
commit 2d08f59184
10 changed files with 0 additions and 2338 deletions

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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;
}

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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__ */