-
Notifications
You must be signed in to change notification settings - Fork 53
macOS Support & Page Refresh #157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
4540602
e7060e1
b89733e
3eecfb6
c0bbf8d
c3a8b0c
967f7bb
eae901c
50c5417
a295bec
a9b7180
a077ff7
ba5718e
c450a32
741c819
32d9d43
4f61ce3
d922697
95d4ba9
f065e70
104ba04
54d9770
d3f2af9
1a035bb
b6f0d04
196db32
f50d021
ea90064
dd1551d
45fab7a
4088c8d
b0abf0d
c21cd9c
fe2c9ad
f111000
fc9b0ea
c114726
91b2de6
7e96b53
c2d975b
dc5aa74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -139,6 +139,12 @@ void datum_api_var_DATUM_MINER_TAG(char *buffer, size_t buffer_size, const T_DAT | |
| buffer[i+1] = '"'; | ||
| buffer[i+2] = 0; | ||
| } | ||
| void datum_api_var_PAGE_REFRESH_TIMED_OUT(char *buffer, size_t buffer_size, const T_DATUM_API_DASH_VARS *vardata) { | ||
| if (datum_config.datum_page_refresh_seconds != 0) | ||
| { | ||
| snprintf(buffer, buffer_size, "%d", datum_config.datum_page_refresh_seconds); | ||
| } | ||
| } | ||
| void datum_api_var_DATUM_POOL_DIFF(char *buffer, size_t buffer_size, const T_DATUM_API_DASH_VARS *vardata) { | ||
| snprintf(buffer, buffer_size, "%llu", (unsigned long long)datum_config.override_vardiff_min); | ||
| } | ||
|
|
@@ -256,7 +262,9 @@ DATUM_API_VarEntry var_entries[] = { | |
| {"STRATUM_JOB_WEIGHT", datum_api_var_STRATUM_JOB_WEIGHT}, | ||
| {"STRATUM_JOB_SIGOPS", datum_api_var_STRATUM_JOB_SIGOPS}, | ||
| {"STRATUM_JOB_TXNCOUNT", datum_api_var_STRATUM_JOB_TXNCOUNT}, | ||
|
|
||
|
|
||
| {"PAGE_REFRESH_TIMED_OUT", datum_api_var_PAGE_REFRESH_TIMED_OUT}, | ||
|
|
||
| {NULL, NULL} // Mark the end of the array | ||
| }; | ||
|
|
||
|
|
@@ -955,7 +963,10 @@ size_t datum_api_fill_config_var(const char *var_start, const size_t var_name_le | |
| const size_t var_name_len_2 = var_end - var_start_2; | ||
| const char * const underscore_pos = memchr(var_start_2, '_', var_name_len_2); | ||
| int val; | ||
| if (var_name_len_2 == 3 && 0 == strncmp(var_start_2, "*ro", 3)) { | ||
| if (var_name_len_2 == 16 && 0 == strncmp(var_start_2, "time_out_in_secs", 16)) | ||
| { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing else-if chaining could cause unnecessary string comparisons. |
||
| val = datum_config.datum_page_refresh_seconds; | ||
| } else if (var_name_len_2 == 3 && 0 == strncmp(var_start_2, "*ro", 3)) { | ||
| val = !(datum_config.api_modify_conf && datum_config.api_admin_password_len); | ||
| if (!colon_pos) { | ||
| var_start = "readonly:"; | ||
|
|
@@ -1147,7 +1158,17 @@ struct datum_api_config_set_status { | |
| // If anything fails (including validation), errors is appended and false is returned | ||
| bool datum_api_config_set(const char * const key, const char * const val, struct datum_api_config_set_status * const status) { | ||
| json_t * const errors = status->errors; | ||
| if (0 == strcmp(key, "mining_pool_address")) { | ||
| if (0 == strcmp(key, "time_out_in_secs")) { | ||
| const int val_int = datum_atoi_strict(val, strlen(val)); | ||
| if (val_int == datum_config.datum_page_refresh_seconds) return true; | ||
| if (val_int < 0) { | ||
| json_t * const j = json_pack("{s:i}", key, val_int); | ||
| json_array_append_new(errors, j); | ||
| return false; | ||
| } | ||
| datum_config.datum_page_refresh_seconds = val_int; | ||
| datum_api_json_modify_new("page_refresh", key, json_integer(val_int)); | ||
| } else if (0 == strcmp(key, "mining_pool_address")) { | ||
| if (0 == strcmp(val, datum_config.mining_pool_address)) return true; | ||
| unsigned char dummy[64]; | ||
| if (!addr_2_output_script(val, &dummy[0], 64)) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| /* datum_cross_platform_io.h - Cross-platform I/O abstraction */ | ||
|
|
||
| #ifndef DATUM_CROSS_PLATFORM_IO_H | ||
| #define DATUM_CROSS_PLATFORM_IO_H | ||
|
|
||
| #if defined(__APPLE__) || defined(__BSD__) | ||
| #include <sys/event.h> | ||
| #include <sys/time.h> | ||
| #include <unistd.h> | ||
| #include <errno.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <stdio.h> | ||
| #include <pthread.h> | ||
| #define IO_HANDLE int | ||
| #define IO_EVENT_READ EVFILT_READ | ||
| #define IO_EVENT_ERROR EVFILT_EXCEPT | ||
| #define IO_MAX_EVENTS 32 | ||
|
|
||
| static inline int datum_io_create() { | ||
| return kqueue(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing a return value check for |
||
| } | ||
|
|
||
| static inline int datum_io_add(IO_HANDLE kq, uintptr_t fd, struct kevent *evSet) { | ||
| evSet->ident = fd; | ||
| EV_SET(evSet, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); | ||
| return kevent(kq, evSet, 1, NULL, 0, NULL); | ||
| } | ||
|
|
||
| static inline int datum_io_delete(IO_HANDLE kq, uintptr_t fd, struct kevent *evSet) | ||
| { | ||
| if (evSet) { | ||
| evSet->ident = fd; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For |
||
| } | ||
| EV_SET(evSet, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); | ||
| return kevent(kq, evSet, 1, NULL, 0, NULL); | ||
| } | ||
|
|
||
| static inline int datum_io_modify(IO_HANDLE kq, uintptr_t fd, struct kevent *evSet) | ||
| { | ||
| if (evSet) { | ||
| evSet->ident = fd; | ||
| } | ||
| EV_SET(evSet, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); | ||
| return kevent(kq, evSet, 1, NULL, 0, NULL); | ||
| } | ||
|
|
||
| static inline int datum_io_wait(IO_HANDLE kq, struct kevent* events, int max_events, int timeout_ms) { | ||
| struct timespec ts = { | ||
| .tv_sec = timeout_ms / 1000, | ||
| .tv_nsec = (timeout_ms % 1000) * 1000000 | ||
| }; | ||
| return kevent(kq, NULL, 0, events, max_events, &ts); | ||
| } | ||
|
|
||
| static inline int portable_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) { | ||
| while (nanosleep(timeout, NULL) == -1 && errno == EINTR) continue; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this use of |
||
| return pthread_mutex_trylock(mutex); | ||
| } | ||
|
|
||
| #elif defined(__linux__) | ||
| #include <sys/epoll.h> | ||
| #include <unistd.h> | ||
| #include <errno.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <stdio.h> | ||
| #include <pthread.h> | ||
| #define IO_HANDLE int | ||
| #define IO_EVENT_READ EPOLLIN | ||
| #define IO_EVENT_ERROR (EPOLLERR | EPOLLHUP) | ||
| #define IO_MAX_EVENTS 32 | ||
|
|
||
| static inline int datum_io_create(int flags) { | ||
| return epoll_create1(flags); | ||
| } | ||
|
|
||
| static inline int datum_io_add(IO_HANDLE epfd, uintptr_t fd, struct epoll_event *ev) { | ||
| if (ev) { | ||
| ev->events = EPOLLIN | EPOLLERR | EPOLLHUP; | ||
| ev->data.fd = fd; | ||
| } | ||
| return epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev); | ||
| } | ||
|
|
||
| static inline int datum_io_delete(IO_HANDLE epfd, uintptr_t fd, struct epoll_event *ev) { | ||
| return epoll_ctl(epfd, EPOLL_CTL_DEL, fd, ev); | ||
| } | ||
|
|
||
| static inline int datum_io_modify(IO_HANDLE epfd, uintptr_t fd, struct epoll_event *ev) { | ||
| return epoll_ctl(epfd, EPOLL_CTL_MOD, fd, ev); | ||
| } | ||
|
|
||
| static inline int datum_io_wait(IO_HANDLE epfd, struct epoll_event* events, int max_events, int timeout_ms) { | ||
| return epoll_wait(epfd, events, max_events, timeout_ms); | ||
| } | ||
|
|
||
| static inline int portable_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *timeout) { | ||
| return pthread_mutex_timedlock(mutex, timeout); | ||
| } | ||
|
|
||
| #else | ||
| #error Platform not supported | ||
| #endif | ||
|
|
||
| #endif // DATUM_CROSS_PLATFORM_IO_H | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,17 +34,17 @@ | |
| */ | ||
|
|
||
| // DATUM Client protocol implementation | ||
| // Encrypted and on the wire has 7.999 bits of entropy per byte in testing. completely uncompressable. | ||
| // Encrypted and on the wire has 7.999 bits of entropy per byte in testing. completely uncompressed. | ||
|
|
||
| // TODO: Clean this up and break up various functions | ||
| // TODO: Generalize encryption related operations vs repeated code | ||
| // TODO: Implement versioning on the protocol for feature lists | ||
| // TODO: Add pool-side assistance with startup to ensure that the client's node is fully sync'd with the network | ||
| // TODO: Add pool-side assistance with startup to ensure that the client's node is fully synced with the network | ||
| // TODO: Optionally allow pool to suggest node peers | ||
| // TODO: Implement graceful negotiation of chain forks | ||
| // TODO: Implement preciousblock for pool blocks not found by the client | ||
| // TODO: Implement precious block for pool blocks not found by the client | ||
| // TODO: Handle network failures that aren't immediately obvious more gracefully (like not receiving responses to server commands) | ||
| // TODO: Implement resuiming of work without allowing one client to cause duplicate work for another | ||
| // TODO: Implement resuming of work without allowing one client to cause duplicate work for another | ||
|
|
||
| #include <sodium.h> | ||
| #include <stdatomic.h> | ||
|
|
@@ -58,7 +58,13 @@ | |
| #include <netdb.h> | ||
| #include <arpa/inet.h> | ||
| #include <fcntl.h> | ||
| #include <sys/epoll.h> | ||
| #include "datum_cross_platform_io.h" | ||
| #if defined(__APPLE__) || defined(__BSD__) | ||
| #include <sys/event.h> // macOS uses kqueue instead of epoll | ||
| #include <mach/mach_time.h> | ||
| #else | ||
| #include <sys/epoll.h> // Linux-specific | ||
| #endif | ||
| #include <time.h> | ||
| #include <sys/time.h> | ||
| #include <pthread.h> | ||
|
|
@@ -294,7 +300,7 @@ int datum_protocol_coinbaser_fetch_response(int len, unsigned char *data) { | |
| return 0; | ||
| } | ||
|
|
||
| rc = pthread_mutex_timedlock(&datum_protocol_coinbaser_fetch_mutex, &ts); | ||
| rc = portable_mutex_timedlock(&datum_protocol_coinbaser_fetch_mutex, &ts); | ||
| if (rc != 0) { | ||
| DLOG_DEBUG("Could not get a lock on the coinbaser reception mutex after 5 seconds... bug?"); | ||
| return 0; | ||
|
|
@@ -1467,7 +1473,12 @@ void *datum_protocol_client(void *args) { | |
| int sockfd = -1; | ||
| int epollfd, nfds; | ||
| int flag = 1; | ||
| #ifdef __linux__ | ||
| struct epoll_event ev, events[MAX_DATUM_CLIENT_EVENTS]; | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| struct kevent ev, events[MAX_DATUM_CLIENT_EVENTS]; | ||
| #endif | ||
|
|
||
| struct timeval start, now; | ||
| int ret,i,n; | ||
| datum_protocol_client_active = 1; | ||
|
|
@@ -1580,23 +1591,26 @@ void *datum_protocol_client(void *args) { | |
| } | ||
|
|
||
| // Set up epoll | ||
| if ((epollfd = epoll_create1(0)) == -1) { | ||
| #ifdef __linux__ | ||
| if ((epollfd = datum_io_create(0)) == -1) { | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| if ((epollfd = datum_io_create()) == -1) { | ||
| #endif | ||
|
|
||
| DLOG_FATAL("epoll_create1(...) error: %s",strerror(errno)); | ||
| close(sockfd); | ||
| datum_protocol_client_active = 0; | ||
| return NULL; | ||
| } | ||
|
|
||
| ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; | ||
| ev.data.fd = sockfd; | ||
|
|
||
| if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) { | ||
|
|
||
| if (datum_io_add(epollfd, sockfd, &ev) == -1) { | ||
| DLOG_FATAL("epoll_ctl(...) error: %s",strerror(errno)); | ||
| close(sockfd); | ||
| close(epollfd); | ||
| datum_protocol_client_active = 0; | ||
| return NULL; | ||
| } | ||
|
|
||
| i = 0; | ||
| datum_last_accepted_share_tsms = 0; | ||
| datum_last_accepted_share_local_tsms = 0; | ||
|
|
@@ -1687,9 +1701,14 @@ void *datum_protocol_client(void *args) { | |
| } | ||
|
|
||
| if (break_again) break; | ||
|
|
||
| nfds = epoll_wait(epollfd, events, MAX_DATUM_CLIENT_EVENTS, 5); // Wait for 5ms | ||
|
|
||
|
|
||
| #ifdef __linux__ | ||
| int wait_ms = 5; | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| int wait_ms = 5000; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is there a massive difference between Linux and Apple/BSD behavior for |
||
| #endif | ||
| nfds = datum_io_wait(epollfd, events, MAX_DATUM_CLIENT_EVENTS, wait_ms); // Wait for 5ms | ||
|
|
||
| if (nfds == -1 && errno != EINTR) { | ||
| DLOG_FATAL("epoll_wait(...) error: %s",strerror(errno)); | ||
| break; | ||
|
|
@@ -1698,12 +1717,20 @@ void *datum_protocol_client(void *args) { | |
| if (nfds <= 0) { | ||
| continue; // Timeout, nothing happened | ||
| } | ||
| #ifdef __linux__ | ||
| if (events[0].events & (EPOLLERR | EPOLLHUP)) { | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| if (events[0].flags & EVFILT_EXCEPT) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be using |
||
| #endif | ||
|
|
||
| int err = 0; | ||
| socklen_t errlen = sizeof(err); | ||
|
|
||
| if (getsockopt(events[0].data.fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == 0) { | ||
| #ifdef __linux__ | ||
| int fd = events[0].data.fd; | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| int fd = events[0].ident; | ||
| #endif | ||
| if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == 0) { | ||
| if (err != 0) { | ||
| DLOG_ERROR("Socket error: %s", strerror(err)); | ||
| } else { | ||
|
|
@@ -1714,8 +1741,12 @@ void *datum_protocol_client(void *args) { | |
| } | ||
| break; | ||
| } | ||
|
|
||
|
|
||
| #ifdef __linux__ | ||
| if (events[0].events & EPOLLIN) { | ||
| #elif defined(__APPLE__) || defined(__BSD__) | ||
| if (events[0].flags & EV_ADD) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be using |
||
| #endif | ||
| // data to receive | ||
| break_again = false; | ||
| // Receive the header, followed by any data specified by the header | ||
|
|
@@ -1958,4 +1989,4 @@ int datum_encrypt_generate_keys(DATUM_ENC_KEYS *keys) { | |
| keys->is_remote = false; | ||
|
|
||
| return 0; | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing newline at EOF? |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't CMake already provide platform detection without you having to define them here explicitly?