diff --git a/src/3rdparty/clib-net/CHANGELOGS b/src/3rdparty/clib-net/CHANGELOGS new file mode 100644 index 00000000..602a3244 --- /dev/null +++ b/src/3rdparty/clib-net/CHANGELOGS @@ -0,0 +1,16 @@ + +# Change Logs + +2014-4-13(v0.1.1): + +* add a fake function: tls_get_peer_cert + +* tls_handle_bio_error and tls_handle_ssl_error added for a common usage + +* fix a high cpu bug in uv lines + +* make SSL_MODE_RELEASE_BUFFERS be gracefully imported + +* correct onConnect and onRead for ssl + +* fix a memory leak in ssl part \ No newline at end of file diff --git a/src/3rdparty/clib-net/Makefile b/src/3rdparty/clib-net/Makefile new file mode 100644 index 00000000..5c19c896 --- /dev/null +++ b/src/3rdparty/clib-net/Makefile @@ -0,0 +1,17 @@ + +CC ?= gcc +SRC = $(wildcard src/*.c) tests/simple.c +DEPS = $(wildcard deps/*/*.c) +CFLAGS = -std=c++11\ + -Iinclude\ + -Isrc\ + -Ideps\ + -Ideps/libuv/include\ + -Ldeps/libuv/build/Release\ + -Wall -Wno-unused-function +LDFLAGS = -lcrypto -lssl -luv + +test: $(SRC) + $(CC) $(CFLAGS) -o $@ $(SRC) $(DEPS) $(LDFLAGS) + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/History.md b/src/3rdparty/clib-net/deps/buffer/History.md new file mode 100644 index 00000000..86de93b4 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/History.md @@ -0,0 +1,40 @@ + +0.4.0 / 2015-01-05 +================== + + * refactor + * buffer: Remove printf() statement + * Add `buffer_appendf()` (#10, marcomorain) + +0.3.0 / 2014-12-24 +================== + + * travis: Fail the build if any memory is leaked + * test: Fix memory leaks + * travis: setup + * Add `buffer_append_n(buffer_t *, const char *, size_t)` + +0.2.1 / 2014-12-23 +================== + + * fix header guard + * fix compilation on linux + * Add missing null terminator after realloc (buffer resize) + * Make it safe to always use `data` as a character string + +0.2.0 / 2013-01-05 +================== + + * add print_buffer() + * add buffer_compact() + +0.1.0 / 2012-12-26 +================== + + * add trim functions + * add buffer_clear(buffer_t *self) + * add buffer_fill(buffer_t *self, int c) + * add buffer_new_with_string_length(char *str, size_t len) + * add buffer_new_with_copy(char *str) + * add buffer_indexof() + diff --git a/src/3rdparty/clib-net/deps/buffer/Makefile b/src/3rdparty/clib-net/deps/buffer/Makefile new file mode 100644 index 00000000..e2f516c8 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Makefile @@ -0,0 +1,6 @@ + +test: buffer.c test.c + @$(CC) $^ -std=c99 -o $@ + @./test + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/Readme.md b/src/3rdparty/clib-net/deps/buffer/Readme.md new file mode 100644 index 00000000..c620ea0d --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Readme.md @@ -0,0 +1,82 @@ + +# buffer + + Tiny C string manipulation library. + +## Installation + + Install with [clib](https://github.com/clibs/clib): + +``` +$ clib install clibs/buffer +``` + +## API + +```c +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, char *str); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) +``` + +## License + + MIT diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.c b/src/3rdparty/clib-net/deps/buffer/buffer.c new file mode 100644 index 00000000..c11b67fd --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.c @@ -0,0 +1,353 @@ +// +// buffer.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include +#include +#include +#include "buffer.h" + +// TODO: shared with reference counting +// TODO: linked list for append/prepend etc + +/* + * Compute the nearest multiple of `a` from `b`. + */ + +#define nearest_multiple_of(a, b) \ + (((b) + ((a) - 1)) & ~((a) - 1)) + +/* + * Allocate a new buffer with BUFFER_DEFAULT_SIZE. + */ + +buffer_t * +buffer_new() { + return buffer_new_with_size(BUFFER_DEFAULT_SIZE); +} + +/* + * Allocate a new buffer with `n` bytes. + */ + +buffer_t * +buffer_new_with_size(size_t n) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = n; + self->data = self->alloc = calloc(n + 1, 1); + return self; +} + +/* + * Allocate a new buffer with `str`. + */ + +buffer_t * +buffer_new_with_string(char *str) { + return buffer_new_with_string_length(str, strlen(str)); +} + +/* + * Allocate a new buffer with `str` and `len`. + */ + +buffer_t * +buffer_new_with_string_length(char *str, size_t len) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = len; + self->data = self->alloc = str; + return self; +} + +/* + * Allocate a new buffer with a copy of `str`. + */ + +buffer_t * +buffer_new_with_copy(char *str) { + size_t len = strlen(str); + buffer_t *self = buffer_new_with_size(len); + if (!self) return NULL; + memcpy(self->alloc, str, len); + self->data = self->alloc; + return self; +} + +/* + * Deallocate excess memory, the number + * of bytes removed or -1. + */ + +ssize_t +buffer_compact(buffer_t *self) { + size_t len = buffer_length(self); + size_t rem = self->len - len; + char *buf = calloc(len + 1, 1); + if (!buf) return -1; + memcpy(buf, self->data, len); + free(self->alloc); + self->len = len; + self->data = self->alloc = buf; + return rem; +} + +/* + * Free the buffer. + */ + +void +buffer_free(buffer_t *self) { + free(self->alloc); + free(self); +} + +/* + * Return buffer size. + */ + +size_t +buffer_size(buffer_t *self) { + return self->len; +} + +/* + * Return string length. + */ + +size_t +buffer_length(buffer_t *self) { + return strlen(self->data); +} + +/* + * Resize to hold `n` bytes. + */ + +int +buffer_resize(buffer_t *self, size_t n) { + n = nearest_multiple_of(1024, n); + self->len = n; + self->alloc = self->data = realloc(self->alloc, n + 1); + if (!self->alloc) return -1; + self->alloc[n] = '\0'; + return 0; +} + +/* + * Append a printf-style formatted string to the buffer. + */ + +int buffer_appendf(buffer_t *self, const char *format, ...) { + va_list ap; + va_list tmpa; + char *dst = NULL; + int length = 0; + int required = 0; + int bytes = 0; + + va_start(ap, format); + + length = buffer_length(self); + + // First, we compute how many bytes are needed + // for the formatted string and allocate that + // much more space in the buffer. + va_copy(tmpa, ap); + required = vsnprintf(NULL, 0, format, tmpa); + va_end(tmpa); + if (-1 == buffer_resize(self, length + required)) { + va_end(ap); + return -1; + } + + // Next format the string into the space that we + // have made room for. + dst = self->data + length; + bytes = vsnprintf(dst, 1 + required, format, ap); + va_end(ap); + + return bytes < 0 + ? -1 + : 0; +} + +/* + * Append `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_append(buffer_t *self, const char *str) { + return buffer_append_n(self, str, strlen(str)); +} + +/* + * Append the first `len` bytes from `str` to `self` and + * return 0 on success, -1 on failure. + */ +int +buffer_append_n(buffer_t *self, const char *str, size_t len) { + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) { + strncat(self->data, str, len); + return 0; + } + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + strncat(self->data, str, len); + + return 0; +} + +/* + * Prepend `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_prepend(buffer_t *self, char *str) { + size_t len = strlen(str); + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) goto move; + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + + // move + move: + memmove(self->data + len, self->data, len + 1); + memcpy(self->data, str, len); + + return 0; +} + +/* + * Return a new buffer based on the `from..to` slice of `buf`, + * or NULL on error. + */ + +buffer_t * +buffer_slice(buffer_t *buf, size_t from, ssize_t to) { + size_t len = strlen(buf->data); + + // bad range + if (to < from) return NULL; + + // relative to end + if (to < 0) to = len - ~to; + + // cap end + if (to > len) to = len; + + size_t n = to - from; + buffer_t *self = buffer_new_with_size(n); + memcpy(self->data, buf->data + from, n); + return self; +} + +/* + * Return 1 if the buffers contain equivalent data. + */ + +int +buffer_equals(buffer_t *self, buffer_t *other) { + return 0 == strcmp(self->data, other->data); +} + +/* + * Return the index of the substring `str`, or -1 on failure. + */ + +ssize_t +buffer_indexof(buffer_t *self, char *str) { + char *sub = strstr(self->data, str); + if (!sub) return -1; + return sub - self->data; +} + +/* + * Trim leading whitespace. + */ + +void +buffer_trim_left(buffer_t *self) { + int c; + while ((c = *self->data) && isspace(c)) { + ++self->data; + } +} + +/* + * Trim trailing whitespace. + */ + +void +buffer_trim_right(buffer_t *self) { + int c; + size_t i = buffer_length(self) - 1; + while ((c = self->data[i]) && isspace(c)) { + self->data[i--] = 0; + } +} + +/* + * Trim trailing and leading whitespace. + */ + +void +buffer_trim(buffer_t *self) { + buffer_trim_left(self); + buffer_trim_right(self); +} + +/* + * Fill the buffer with `c`. + */ + +void +buffer_fill(buffer_t *self, int c) { + memset(self->data, c, self->len); +} + +/* + * Fill the buffer with 0. + */ + +void +buffer_clear(buffer_t *self) { + buffer_fill(self, 0); +} + +/* + * Print a hex dump of the buffer. + */ + +void +buffer_print(buffer_t *self) { + int i; + size_t len = self->len; + + printf("\n "); + + // hex + for (i = 0; i < len; ++i) { + printf(" %02x", self->alloc[i]); + if ((i + 1) % 8 == 0) printf("\n "); + } + + printf("\n"); +} diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.h b/src/3rdparty/clib-net/deps/buffer/buffer.h new file mode 100644 index 00000000..5cecbb0d --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.h @@ -0,0 +1,101 @@ + +// +// buffer.h +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#ifndef BUFFER_H +#define BUFFER_H 1 + +#include + +/* + * Default buffer size. + */ + +#ifndef BUFFER_DEFAULT_SIZE +#define BUFFER_DEFAULT_SIZE 64 +#endif + +/* + * Buffer struct. + */ + +typedef struct { + size_t len; + char *alloc; + char *data; +} buffer_t; + +// prototypes + +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, const char *str); + +int +buffer_appendf(buffer_t *self, const char *format, ...); + +int +buffer_append_n(buffer_t *self, const char *str, size_t len); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) + +#endif diff --git a/src/3rdparty/clib-net/include/net.h b/src/3rdparty/clib-net/include/net.h new file mode 100644 index 00000000..674a7bc3 --- /dev/null +++ b/src/3rdparty/clib-net/include/net.h @@ -0,0 +1,177 @@ + +/* + * Copyright 2014 + */ + +#ifndef __NET_H__ +#define __NET_H__ + +#include +#include + +#ifndef XMRIG_NO_SSL_TLS +#include "tls.h" +#endif + +#define NOT_SSL 0x00 +#define USE_SSL 0x01 + +#define NET_OK 0 +#define NET_VERSION_MAJOR 0 +#define NET_VERSION_MINOR 1 +#define NET_VERSION_PATCH 2 +#define NET_VERSION_IS_RELEASE 0 + +typedef struct net_s net_t; +typedef struct addrinfo net_ai; +typedef struct sockaddr_in socketPair_t; + +#define NET_FIELDS \ + NET_CONNECTION_FIELDS \ + NET_UV_FIELDS \ + NET_TLS_FIELDS \ + +#define NET_CONNECTION_FIELDS \ + char *hostname; \ + int port; \ + int connected; \ + + +#define NET_UV_FIELDS \ + uv_getaddrinfo_t *resolver; \ + uv_loop_t *loop; \ + uv_tcp_t *handle; \ + uv_connect_t *conn; \ + +#ifndef XMRIG_NO_SSL_TLS + #define NET_TLS_FIELDS \ + int use_ssl; \ + int tls_established; \ + tls_t *tls; +#else + #define NET_TLS_FIELDS \ + int use_ssl; \ + int tls_established; +#endif + + +struct net_s { + NET_FIELDS; + void *data; + void (*conn_cb)(net_t*); + void (*read_cb)(net_t*, size_t, char*); + void (*error_cb)(net_t*, int, char*); + void (*close_cb)(uv_handle_t*); +}; + +/* + * Create an new network. + */ +net_t * +net_new(char * hostname, int port); + + +#ifndef XMRIG_NO_SSL_TLS +/* + * Set SSL's Context + */ +int +net_set_tls(net_t * net, tls_ctx * ctx); +#endif +/* + * Do connect to new + */ +int +net_connect(net_t * net); + +/* + * Just close the holding connection + */ +int +net_close(net_t * net, void (*cb)(uv_handle_t*)); + +/* + * free connection + */ +int +net_free(net_t * net); + +/* + * real free function + */ +void +net_free_cb(uv_handle_t * handle); + +/* + * DNS resolve + */ +int +net_resolve(net_t * net); + +/* + * DNS -> IP done, and call `net_resolve_cb` + */ +void +net_resolve_cb(uv_getaddrinfo_t *rv, int stat, net_ai * ai); + +/* + * connect created, and call `net_connect_cb` + */ +void +net_connect_cb(uv_connect_t *conn, int stat); + +/* + * realloc buffer before you read + */ +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); + +/* + * read buffer + */ +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf); + +/* + * write buffer + */ +int +net_write(net_t * net, char * buf); + +/* + * write buffer with length specified + */ +int +net_write2(net_t * net, char * buf, unsigned int len); + +/* + * return use_ssl + */ +int +net_use_ssl(net_t * net); + +/* + * continue to read after on data + */ +int +net_resume(net_t * net); + +/* + * pause read + */ +int +net_pause(net_t * net); + +/* + * set error_cb + */ +int +net_set_error_cb(net_t * net, void * cb); + +/* + * write buffer, and call `net_write_cb`. + */ +void +net_write_cb(uv_write_t *writer, int stat); + +#endif /* __NET_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/include/tls.h b/src/3rdparty/clib-net/include/tls.h new file mode 100644 index 00000000..76ca8fd0 --- /dev/null +++ b/src/3rdparty/clib-net/include/tls.h @@ -0,0 +1,133 @@ + +/* + * Copyright 2014 + */ + +#ifndef __TLS_H__ +#define __TLS_H__ + +#include +#include +#include +#include +#include + +#define SSL_CHUNK_SIZE 512 + +typedef SSL_CTX tls_ctx; +typedef struct tls_s { + SSL_CTX * ctx; + SSL * ssl; + BIO * bio_in; + BIO * bio_out; + buffer_t * buffer; + int connected; + char * data; + char buf[SSL_CHUNK_SIZE]; /* internal usage */ +} tls_t; + +static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL + | ASN1_STRFLGS_ESC_MSB + | XN_FLAG_SEP_MULTILINE + | XN_FLAG_FN_SN; + +/* + * initialize the ssl + */ +void +ssl_init(); + +/* + * destroy the ssl settings and internal tables + */ +void +ssl_destroy(); + +/* + * create a context for ssl + */ +tls_ctx * +tls_ctx_new(); + +/* + * create a tls instance + */ +tls_t * +tls_create(tls_ctx * ctx); + +/* + * shutdown tls + */ +int +tls_shutdown(tls_t * tls); + +/* + * destroy a tls instance + */ +int +tls_free(tls_t * tls); + +/* + * get peer certification info + */ +int +tls_get_peer_cert(tls_t * tls); + +/* + * do connect to tls + */ +int +tls_connect(tls_t * tls); + +/* + * handle error in bio + */ +int +tls_handle_bio_error(tls_t * tls, int err); + +/* + * handle error in ssl + */ +int +tls_handle_ssl_error(tls_t *tls, int err); + +/* + * a port in tls for `bio_read` + */ +int +tls_bio_read(tls_t * tls, int len); + +/* + * a port in tls for `bio_write` + */ +int +tls_bio_write(tls_t * tls, char * written, int len); + +/* + * read + */ +int +tls_read(tls_t * tls); + +/* + * write + */ +int +tls_write(tls_t * tls, char * written, int len); + +/* + * write a tls packet + */ +#define REQUEST_TLS_WRITE(name, cmd, read, req) do { \ + tls_write(req->tls, cmd); \ + do { \ + read = tls_bio_read(req->tls, 0); \ + if (read > 0) { \ + REQUEST_WRITE(req, req->tls->buf, read, name); \ + } \ + } while (read > 0); \ +} \ +while (0) + + +#endif /* __TLS_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/readme.md b/src/3rdparty/clib-net/readme.md new file mode 100644 index 00000000..b034d353 --- /dev/null +++ b/src/3rdparty/clib-net/readme.md @@ -0,0 +1,53 @@ + +# net-client + +Simple network client + +### Requirement + +* libuv 0.10.x + +* buffer 0.2.0 + +### Installation + +```sh +$ clib install clibs/net +$ git clone https://github.com/joyent/libuv.git deps/libuv +$ checkout v0.10.25 +``` + +### Run tests + +```sh +make test +./test +``` + +### Example + +```c +static void +imap_parser(net_t * net, size_t read, char * buf) { + printf("%s\n", buf); + printf("%zu\n", read); +} + +int +main(int argc, char *argv[]) { + ssl_init(); + tls_ctx * ctx = tls_ctx_new(); + net_t * net = net_new("imap.gmail.com", 993); + net->onRead = imap_parser; + + // convert this socket to ssl + net_set_tls(net, ctx); + net_connect(net); + + uv_run(net->loop, UV_RUN_DEFAULT); +} +``` + +### License + +MIT diff --git a/src/3rdparty/clib-net/src/net.c b/src/3rdparty/clib-net/src/net.c new file mode 100644 index 00000000..cde76073 --- /dev/null +++ b/src/3rdparty/clib-net/src/net.c @@ -0,0 +1,390 @@ + +#include +#include +#include "net.h" + +net_t * +net_new(char * hostname, int port) { + net_t * net = (net_t*) malloc(sizeof(net_t)); + net->loop = uv_default_loop(); + net->hostname = hostname; + net->port = port; + net->connected = 0; + net->tls_established = 0; + net->use_ssl = 0; + net->conn_cb = NULL; + net->read_cb = NULL; + net->error_cb = NULL; + net->close_cb = NULL; + net->handle = (uv_tcp_t *) malloc(sizeof(uv_tcp_t)); + net->conn = (uv_connect_t *) malloc(sizeof(uv_connect_t)); + net->handle->data + = net->conn->data + = (void *) net; + + return net; +} + +#ifndef XMRIG_NO_SSL_TLS +int +net_set_tls(net_t * net, tls_ctx * ctx) { + net->use_ssl = USE_SSL; + net->tls = tls_create(ctx); + return NET_OK; +} +#endif + +int +net_connect(net_t * net) { + net_resolve(net); + return NET_OK; +} + +int +net_close(net_t * net, void (*cb)(uv_handle_t*)) { + int r = net->connected; + if (r == 1) { + net->connected = 0; + net->tls_established = 0; + +#ifndef XMRIG_NO_SSL_TLS + if (net->use_ssl) { + tls_shutdown(net->tls); + } +#endif + + uv_close((uv_handle_t*)net->handle, cb); + +#ifndef XMRIG_NO_SSL_TLS + if (net->use_ssl) { + tls_free(net->tls); + } +#endif + } + + return r; +} + +int +net_free(net_t * net) { + net_close(net, NULL); + free(net->resolver); + free(net); + return NET_OK; +} + +void +net_free_cb(uv_handle_t * handle) { + net_t * net = (net_t *) handle->data; + if (net->handle != NULL) { + free(net->handle); + net->handle = NULL; + } + if (net->conn != NULL) { + free(net->conn); + net->conn = NULL; + } + if (net->resolver != NULL) { + free(net->resolver); + net->resolver = NULL; + } + if (net != NULL) { + free(net); + net = NULL; + } +} + +int +net_resolve(net_t * net) { + net_ai hints; + int ret; + char buf[6]; + + snprintf(buf, sizeof(buf), "%d", net->port); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + net->resolver = malloc(sizeof(uv_getaddrinfo_t)); + if (!net->resolver) { + /* + * TODO(Yorkie): depent parital handles + */ + return -1; + } + + net->resolver->data = (void *) net; + ret = uv_getaddrinfo(net->loop, net->resolver, + net_resolve_cb, net->hostname, NULL, &hints); + + return ret; +} + +void +net_resolve_cb(uv_getaddrinfo_t *rv, int err, net_ai * ai) { + net_t * net = (net_t*) rv->data; + char addr[INET6_ADDRSTRLEN]; + int ret; + struct sockaddr_in dest; + + if (err != 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + uv_ip4_name((socketPair_t *) ai->ai_addr, addr, INET6_ADDRSTRLEN); + ret = uv_ip4_addr(addr, net->port, &dest); + + if (ret != 0) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * create tcp instance. + */ + uv_tcp_init(net->loop, net->handle); + ret = uv_tcp_connect(net->conn, net->handle, (const struct sockaddr*) &dest, net_connect_cb); + if (ret != NET_OK) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * free + */ + uv_freeaddrinfo(ai); +} + +void +net_connect_cb(uv_connect_t *conn, int err) { + net_t * net = (net_t *) conn->data; + int read; + + if (err < 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * change the `connected` state + */ + net->connected = 1; + + /* + * read buffers via uv + */ + uv_read_start((uv_stream_t *) net->handle, net_alloc, net_read); + + /* + * call `onConnect`, the tcp connection has been + * established in user-land. + */ + if (net->use_ssl == NOT_SSL && net->conn_cb != NULL) { + net->conn_cb(net); + } + +#ifndef XMRIG_NO_SSL_TLS + /* + * Handle TLS Partial + */ + if (net->use_ssl == USE_SSL && tls_connect(net->tls) == NET_OK) { + read = 0; + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char buf[read]; + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf, 0, read); + memcpy(buf, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + } + } while (read > 0); + } +#endif +} + +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = (char *) calloc(size, 1); + buf->len = size; +} + +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + net_t * net = (net_t *) handle->data; + + if (nread < 0) { + if (net->error_cb) { + net->error_cb(net, nread, (char *) uv_strerror(nread)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(nread)); + net_free(net); + } + return; + } + +#ifndef XMRIG_NO_SSL_TLS + /* + * BIO Return rule: + * All these functions return either the amount of data successfully + * read or written (if the return value is positive) or that no data + * was successfully read or written if the result is 0 or -1. If the + * return value is -2 then the operation is not implemented in the specific BIO type. + */ + if (net->use_ssl) { + tls_bio_write(net->tls, buf->base, nread); + free(buf->base); + + int read = 0; + int stat = tls_read(net->tls); + if (stat == 1) { + /* + * continue: Say hello + */ + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char buf2[read]; + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf2, 0, read); + memcpy(buf2, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf2, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + } + } while (read > 0); + + } else { + /* + * SSL Connection is created + * Here need to call user-land callback + */ + if (!net->tls_established) { + net->tls_established = 1; + if (net->conn_cb != NULL) { + net->conn_cb(net); + } + } + + /* + * read buffer + */ + if (stat == 0) { + if (buffer_string(net->tls->buffer) > 0) + // uv_read_stop((uv_stream_t*)net->handle); + + if (net->read_cb != NULL && net->connected && net->tls_established) { + net->read_cb(net, buffer_length(net->tls->buffer), + buffer_string(net->tls->buffer)); + } + } + } + return; + } +#endif + + /* + * TCP Part, no SSL, just proxy of uv. + */ + uv_read_stop(handle); + buf->base[nread] = 0; + if (net->read_cb != NULL) { + net->read_cb(net, nread, buf->base); + free(buf->base); + } +} + +int +net_write(net_t * net, char * buf) { + return net_write2(net, buf, strlen(buf)); +} + +int +net_write2(net_t * net, char * buf, unsigned int len) { + uv_write_t * req; + uv_buf_t uvbuf; + int read = 0; + + switch (net->use_ssl) { + case USE_SSL: +#ifndef XMRIG_NO_SSL_TLS + tls_write(net->tls, buf, (int)len); + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(net->tls->buf, read); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + } + } while (read > 0); + break; +#endif + case NOT_SSL: + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(buf, len); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + break; + } + + return NET_OK; +} + +int +net_use_ssl(net_t * net) { + return net->use_ssl == USE_SSL; +} + +int +net_resume(net_t * net) { + uv_read_start((uv_stream_t *)net->handle, net_alloc, net_read); + return NET_OK; +} + +int +net_pause(net_t * net) { + uv_read_stop((uv_stream_t *)net->handle); + return NET_OK; +} + +int +net_set_error_cb(net_t * net, void * cb) { + net->error_cb = cb; + return NET_OK; +} + +void +net_write_cb(uv_write_t *req, int stat) { + net_resume((net_t*)req->data); + free(req); +} diff --git a/src/3rdparty/clib-net/src/tls.c b/src/3rdparty/clib-net/src/tls.c new file mode 100644 index 00000000..26d2e1b4 --- /dev/null +++ b/src/3rdparty/clib-net/src/tls.c @@ -0,0 +1,221 @@ + +/* + * Copyright 2014 + */ + +#include +#include "tls.h" + +void +ssl_init() { + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); +} + +void +ssl_destroy() { + EVP_cleanup(); + ERR_free_strings(); +} + +tls_ctx * +tls_ctx_new() { + tls_ctx *ctx = SSL_CTX_new(SSLv23_method()); +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); +#endif + + return ctx; +} + +tls_t * +tls_create(tls_ctx *ctx) { + tls_t * tls = (tls_t *) malloc(sizeof(tls_t)+1); + if (tls == NULL) + fprintf(stderr, "tls> %s", "Out of Memory"); + + tls->ctx = ctx; + tls->ssl = SSL_new(tls->ctx); + tls->bio_in = BIO_new(BIO_s_mem()); + tls->bio_out = BIO_new(BIO_s_mem()); + tls->connected = -1; + tls->buffer = buffer_new(); + +#ifdef SSL_MODE_RELEASE_BUFFERS + long mode = SSL_get_mode(tls->ssl); + SSL_set_mode(tls->ssl, mode | SSL_MODE_RELEASE_BUFFERS); +#endif + + if (tls->ssl == NULL) + printf("tls> %s", "Out of Memory"); + + SSL_set_connect_state(tls->ssl); + SSL_set_bio(tls->ssl, tls->bio_in, tls->bio_out); + return tls; +} + +int +tls_shutdown(tls_t * tls) { + assert(tls != NULL); + if (SSL_shutdown(tls->ssl) == 0) { + SSL_shutdown(tls->ssl); + } + return 0; +} + +int +tls_free(tls_t * tls) { + if (tls->ssl) { + SSL_free(tls->ssl); + SSL_CTX_free(tls->ctx); + tls->ssl = NULL; + } + + buffer_free(tls->buffer); + free(tls); + return 0; +} + +int +tls_get_peer_cert(tls_t *tls) { + X509* peer_cert = SSL_get_peer_certificate(tls->ssl); + if (peer_cert != NULL) { + /* + * TODO(Yorkie): This function is used just for debug + */ + X509_free(peer_cert); + } + return 0; +} + +int +tls_connect(tls_t *tls) { + int rv; + int er; + + rv = SSL_do_handshake(tls->ssl); + if (rv == 1) { + /* + * `SSL_do_handshake()` could not return 1, + * that caused no message could be returned in `SSL_get_error()`. + * TODO(Yorkie): handle error, exit? + */ + return -1; + } + + if (!SSL_is_init_finished(tls->ssl)) + er = SSL_connect(tls->ssl); + else + return -1; + + if (er < 0 && SSL_get_error(tls->ssl, er) == SSL_ERROR_WANT_READ) + return 0; + else + return -1; +} + +int +tls_handle_bio_error(tls_t *tls, int err) { + int rv; + int retry = BIO_should_retry(tls->bio_out); + if (BIO_should_write(tls->bio_out)) + rv = -retry; + else if (BIO_should_read(tls->bio_out)) + rv = -retry; + else { + char ssl_error_buf[512]; + ERR_error_string_n(err, ssl_error_buf, sizeof(ssl_error_buf)); + fprintf(stderr, "[%p] BIO: read failed: (%d) %s\n", tls->ssl, err, ssl_error_buf); + return err; + } + return err; +} + +int +tls_handle_ssl_error(tls_t *tls, int err) { + int ret; + int rv = SSL_get_error(tls->ssl, err); + switch (rv) { + case SSL_ERROR_WANT_READ: + ret = 1; + break; + default: + ret = -2; + break; + } + return ret; +} + +int +tls_bio_read(tls_t *tls, int buf_len) { + if (buf_len == 0) { + buf_len = sizeof(tls->buf); + } + memset(tls->buf, 0, buf_len); + + int ret = BIO_read(tls->bio_out, tls->buf, buf_len); + if (ret >= 0) { + tls->buf[ret] = 0; + return ret; + } else { + return tls_handle_bio_error(tls, ret); + } +} + +int +tls_bio_write(tls_t *tls, char *buf, int len) { + int ret = BIO_write(tls->bio_in, buf, len); + if (ret >= 0) + return ret; + else + return tls_handle_bio_error(tls, ret); +} + +int +tls_read(tls_t *tls) { + int err; + int ret; + int read; + + int done = SSL_is_init_finished(tls->ssl); + if (!done) { + err = SSL_connect(tls->ssl); + if (err <= 0) { + return tls_handle_ssl_error(tls, err); + } + + /* + * TODO(Yorkie): returns not 1 nor < 0 + */ + assert(err == 1); + } + + /* finished */ + buffer_clear(tls->buffer); + + ret = -1; + do { + read = SSL_read(tls->ssl, tls->buf, SSL_CHUNK_SIZE); + if (read > 0) { + ret = 0; + tls->buf[read] = 0; + buffer_append(tls->buffer, tls->buf); + } else { + tls_handle_ssl_error(tls, read); + } + } while (read > 0); + + if (tls->connected == -1) { + tls->connected = 1; + } else { + ret = 0; + } + return ret; +} + +int +tls_write(tls_t *tls, char *buf_w, int len) { + return SSL_write(tls->ssl, buf_w, len); +} \ No newline at end of file