Skip to content

Commit

Permalink
Support custom memory allocators
Browse files Browse the repository at this point in the history
This makes it possible to use custom allocators, for example GC_malloc()
when used in a garbage collected project.

The code is an adaptation from libuv itself, which supports custom
allocators.
  • Loading branch information
plajjan committed Feb 11, 2024
1 parent de411b0 commit ba00cee
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 152 deletions.
19 changes: 10 additions & 9 deletions src/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#else
#include <sys/param.h>
#endif
#include "common.h"
#include "bio.h"

struct msg {
Expand All @@ -30,7 +31,7 @@ struct msg {
};

tlsuv_BIO *tlsuv_BIO_new(void) {
tlsuv_BIO * bio = calloc(1, sizeof(tlsuv_BIO));
tlsuv_BIO * bio = tlsuv_calloc(1, sizeof(tlsuv_BIO));
bio->available = 0;
bio->headoffset = 0;
bio->qlen = 0;
Expand All @@ -43,26 +44,26 @@ void tlsuv_BIO_free(tlsuv_BIO *bio) {
while(!STAILQ_EMPTY(&bio->message_q)) {
struct msg *m = STAILQ_FIRST(&bio->message_q);
STAILQ_REMOVE_HEAD(&bio->message_q, next);
free(m->buf);
free(m);
tlsuv_free(m->buf);
tlsuv_free(m);
}

free(bio);
tlsuv_free(bio);
}

size_t tlsuv_BIO_available(tlsuv_BIO *bio) {
return bio->available;
}

int tlsuv_BIO_put(tlsuv_BIO *bio, const uint8_t *buf, size_t len) {
struct msg *m = malloc(sizeof(struct msg));
struct msg *m = tlsuv_malloc(sizeof(struct msg));
if (m == NULL) {
return -1;
}

m->buf = malloc(len);
m->buf = tlsuv_malloc(len);
if (m->buf == NULL) {
free(m);
tlsuv_free(m);
return -1;
}
memcpy(m->buf, buf, len);
Expand Down Expand Up @@ -94,8 +95,8 @@ int tlsuv_BIO_read(tlsuv_BIO *bio, uint8_t *buf, size_t len) {
bio->headoffset = 0;
bio->qlen -= 1;

free(m->buf);
free(m);
tlsuv_free(m->buf);
tlsuv_free(m);
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <uv.h>
#include "common.h"

typedef struct {
tlsuv_malloc_func malloc;
tlsuv_realloc_func realloc;
tlsuv_calloc_func calloc;
tlsuv_free_func free;
} tlsuv__allocator_t;

static tlsuv__allocator_t tlsuv__allocator = {
malloc,
realloc,
calloc,
free,
};

int tlsuv_replace_allocator(tlsuv_malloc_func malloc_func,
tlsuv_realloc_func realloc_func,
tlsuv_calloc_func calloc_func,
tlsuv_free_func free_func) {
if (malloc_func == NULL || realloc_func == NULL ||
calloc_func == NULL || free_func == NULL) {
return UV_EINVAL;
}

tlsuv__allocator.malloc = malloc_func;
tlsuv__allocator.realloc = realloc_func;
tlsuv__allocator.calloc = calloc_func;
tlsuv__allocator.free = free_func;

return 0;
}

void* tlsuv_malloc(size_t size) {
if (size > 0)
return tlsuv__allocator.malloc(size);
return NULL;
}

void* tlsuv_realloc(void* ptr, size_t size) {
if (size > 0)
return tlsuv__allocator.realloc(ptr, size);
tlsuv_free(ptr);
return NULL;
}


void* tlsuv_calloc(size_t count, size_t size) {
return tlsuv__allocator.calloc(count, size);
}

void tlsuv_free(void* ptr) {
int saved_errno;

/* The system allocator the assumption that errno is not modified but custom
* allocators may not be so careful.
*/
saved_errno = errno;
tlsuv__allocator.free(ptr);
errno = saved_errno;
}
18 changes: 18 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <stdlib.h>

typedef void* (*tlsuv_malloc_func)(size_t size);
typedef void* (*tlsuv_malloc_func)(size_t size);
typedef void* (*tlsuv_realloc_func)(void* ptr, size_t size);
typedef void* (*tlsuv_calloc_func)(size_t count, size_t size);
typedef void (*tlsuv_free_func)(void* ptr);

int tlsuv_replace_allocator(tlsuv_malloc_func malloc_func,
tlsuv_realloc_func realloc_func,
tlsuv_calloc_func calloc_func,
tlsuv_free_func free_func);

void *tlsuv_malloc(size_t size);
void *tlsuv_realloc(void* ptr, size_t size);
void *tlsuv_calloc(size_t count, size_t size);
void tlsuv_free(void* ptr);
55 changes: 28 additions & 27 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <stdlib.h>
#include <string.h>

#include "common.h"
#include "um_debug.h"
#include "win32_compat.h"
#include "http_req.h"
Expand Down Expand Up @@ -81,7 +82,7 @@ static void http_read_cb(uv_link_t *link, ssize_t nread, const uv_buf_t *buf) {
close_connection(c);
uv_async_send(&c->proc);
if (buf && buf->base) {
free(buf->base);
tlsuv_free(buf->base);
}
return;
}
Expand All @@ -93,7 +94,7 @@ static void http_read_cb(uv_link_t *link, ssize_t nread, const uv_buf_t *buf) {
UM_LOG(WARN, "failed to parse HTTP response");
fail_active_request(c, UV_EINVAL, "failed to parse HTTP response");
close_connection(c);
free(buf->base);
tlsuv_free(buf->base);
return;
}
}
Expand All @@ -115,7 +116,7 @@ static void http_read_cb(uv_link_t *link, ssize_t nread, const uv_buf_t *buf) {
}

http_req_free(hr);
free(hr);
tlsuv_free(hr);

if (!keep_alive) {
close_connection(c);
Expand All @@ -128,7 +129,7 @@ static void http_read_cb(uv_link_t *link, ssize_t nread, const uv_buf_t *buf) {
}

if (buf && buf->base) {
free(buf->base);
tlsuv_free(buf->base);
}
}

Expand All @@ -139,7 +140,7 @@ static void clear_req_body(tlsuv_http_req_t *req, int code) {
if (chunk->cb) {
chunk->cb(req, chunk->chunk, code);
}
free(chunk);
tlsuv_free(chunk);

chunk = next;
}
Expand All @@ -153,7 +154,7 @@ static void fail_active_request(tlsuv_http_t *c, int code, const char *msg) {
c->active->resp_cb(&c->active->resp, c->active->data);
clear_req_body(c->active, code);
http_req_free(c->active);
free(c->active);
tlsuv_free(c->active);
c->active = NULL;
}
}
Expand All @@ -173,7 +174,7 @@ static void fail_all_requests(tlsuv_http_t *c, int code, const char *msg) {
}
clear_req_body(r, code);
http_req_free(r);
free(r);
tlsuv_free(r);
}
}

Expand Down Expand Up @@ -290,7 +291,7 @@ static void src_connect_timeout(uv_timer_t *t) {

static void req_write_cb(uv_link_t *source, int status, void *arg) {
UM_LOG(VERB, "request write completed: %d", status);
free(arg);
tlsuv_free(arg);
}

static void req_write_body_cb(uv_link_t *source, int status, void *arg) {
Expand All @@ -299,12 +300,12 @@ static void req_write_body_cb(uv_link_t *source, int status, void *arg) {
if (chunk->cb) {
chunk->cb(chunk->req, chunk->chunk, status);
}
free(chunk);
tlsuv_free(chunk);
}

static void chunk_hdr_wcb(uv_link_t *l, int status, void *arg) {
if (arg != NULL) {
free(arg);
tlsuv_free(arg);
}
}

Expand All @@ -323,7 +324,7 @@ static void send_body(tlsuv_http_req_t *req) {

if (req->req_chunked) {
if (b->len > 0) {
buf.base = malloc(10);
buf.base = tlsuv_malloc(10);
buf.len = snprintf(buf.base, 10, "%zx\r\n", b->len);
uv_link_write((uv_link_t *) &clt->http_link, &buf, 1, NULL, chunk_hdr_wcb, buf.base);

Expand All @@ -338,7 +339,7 @@ static void send_body(tlsuv_http_req_t *req) {
buf.base = "0\r\n\r\n";
buf.len = 5;
uv_link_write((uv_link_t *) &clt->http_link, &buf, 1, NULL, chunk_hdr_wcb, NULL);
free(b);
tlsuv_free(b);
req->state = body_sent;
}
}
Expand Down Expand Up @@ -408,10 +409,10 @@ static void process_requests(uv_async_t *ar) {
if (c->active->state < headers_sent) {
UM_LOG(VERB, "sending request[%s] headers", c->active->path);
uv_buf_t req;
req.base = malloc(8196);
req.base = tlsuv_malloc(8196);
ssize_t header_len = http_req_write(c->active, req.base, 8196);
if (header_len == UV_ENOMEM) {
free(req.base);
tlsuv_free(req.base);
fail_active_request(c, (int)header_len, "request header too big");
uv_async_send(&c->proc);
return;
Expand Down Expand Up @@ -458,12 +459,12 @@ int tlsuv_http_close(tlsuv_http_t *clt, tlsuv_http_close_cb close_cb) {

static void http_set_prefix(tlsuv_http_t *clt, const char *pfx, size_t pfx_len) {
if (clt->prefix) {
free(clt->prefix);
tlsuv_free(clt->prefix);
clt->prefix = NULL;
}

if (pfx) {
clt->prefix = calloc(1, pfx_len + 1);
clt->prefix = tlsuv_calloc(1, pfx_len + 1);
strncpy(clt->prefix, pfx, pfx_len);
}
}
Expand Down Expand Up @@ -499,7 +500,7 @@ int tlsuv_http_set_url(tlsuv_http_t *clt, const char *url) {

if (clt->host) {
clt->host_change = true;
free(clt->host);
tlsuv_free(clt->host);
}
set_http_header(&clt->headers, "Host", NULL);

Expand Down Expand Up @@ -541,7 +542,7 @@ int tlsuv_http_init_with_src(uv_loop_t *l, tlsuv_http_t *clt, const char *url, t

clt->connect_timeout = 0;
clt->idle_time = DEFAULT_IDLE_TIMEOUT;
clt->conn_timer = calloc(1, sizeof(uv_timer_t));
clt->conn_timer = tlsuv_calloc(1, sizeof(uv_timer_t));
uv_timer_init(l, clt->conn_timer);
uv_unref((uv_handle_t *) clt->conn_timer);
clt->conn_timer->data = clt;
Expand All @@ -563,7 +564,7 @@ void tlsuv_http_set_path_prefix(tlsuv_http_t *clt, const char *prefix) {
}

int tlsuv_http_init(uv_loop_t *l, tlsuv_http_t *clt, const char *url) {
tcp_src_t *src = calloc(1, sizeof(tcp_src_t));
tcp_src_t *src = tlsuv_calloc(1, sizeof(tcp_src_t));
tcp_src_init(l, src);
tcp_src_nodelay(src, 1);
tcp_src_keepalive(src, 1, 3);
Expand All @@ -588,7 +589,7 @@ void tlsuv_http_set_ssl(tlsuv_http_t *clt, tls_context *tls) {
}

tlsuv_http_req_t *tlsuv_http_req(tlsuv_http_t *clt, const char *method, const char *path, tlsuv_http_resp_cb resp_cb, void *ctx) {
tlsuv_http_req_t *r = calloc(1, sizeof(tlsuv_http_req_t));
tlsuv_http_req_t *r = tlsuv_calloc(1, sizeof(tlsuv_http_req_t));
http_req_init(r, method, path);

r->client = clt;
Expand Down Expand Up @@ -647,7 +648,7 @@ int http_req_cancel_err(tlsuv_http_t *clt, tlsuv_http_req_t *req, int error, con
}

http_req_free(req);
free(req);
tlsuv_free(req);
return 0;
} else {
return UV_EINVAL;
Expand Down Expand Up @@ -686,7 +687,7 @@ int tlsuv_http_req_header(tlsuv_http_req_t *req, const char *name, const char *v

void tlsuv_http_req_end(tlsuv_http_req_t *req) {
if (req->req_chunked) {
struct body_chunk_s *chunk = calloc(1, sizeof(struct body_chunk_s));
struct body_chunk_s *chunk = tlsuv_calloc(1, sizeof(struct body_chunk_s));

chunk->len = 0;
chunk->next = NULL;
Expand Down Expand Up @@ -717,7 +718,7 @@ int tlsuv_http_req_data(tlsuv_http_req_t *req, const char *body, size_t bodylen,
return UV_EINVAL;
}

struct body_chunk_s *chunk = calloc(1, sizeof(struct body_chunk_s));
struct body_chunk_s *chunk = tlsuv_calloc(1, sizeof(struct body_chunk_s));
chunk->chunk = (char*)body;
chunk->len = bodylen;
chunk->cb = cb;
Expand All @@ -742,26 +743,26 @@ int tlsuv_http_req_data(tlsuv_http_req_t *req, const char *body, size_t bodylen,

static void free_http(tlsuv_http_t *clt) {
free_hdr_list(&clt->headers);
free(clt->host);
tlsuv_free(clt->host);
if (clt->prefix) free(clt->prefix);

if (clt->active) {
http_req_free(clt->active);
free(clt->active);
tlsuv_free(clt->active);
clt->active = NULL;
}

while (!STAILQ_EMPTY(&clt->requests)) {
tlsuv_http_req_t *req = STAILQ_FIRST(&clt->requests);
STAILQ_REMOVE_HEAD(&clt->requests, _next);
http_req_free(req);
free(req);
tlsuv_free(req);
}

if (clt->own_src && clt->src) {
clt->src->release(clt->src);
tcp_src_free((tcp_src_t *) clt->src);
free(clt->src);
tlsuv_free(clt->src);
clt->src = NULL;
}
tlsuv_tls_link_free(&clt->tls_link);
Expand Down
Loading

0 comments on commit ba00cee

Please sign in to comment.