uringmachine 0.4 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -1
- data/CHANGELOG.md +16 -0
- data/README.md +44 -1
- data/TODO.md +12 -3
- data/examples/bm_snooze.rb +89 -0
- data/examples/bm_sqlite.rb +89 -0
- data/examples/bm_write.rb +56 -0
- data/examples/dns_client.rb +12 -0
- data/examples/http_server.rb +42 -43
- data/examples/pg.rb +85 -0
- data/examples/server_client.rb +64 -0
- data/examples/snooze.rb +44 -0
- data/examples/stream.rb +85 -0
- data/examples/write_dev_null.rb +16 -0
- data/ext/um/extconf.rb +81 -14
- data/ext/um/um.c +468 -414
- data/ext/um/um.h +149 -40
- data/ext/um/um_async_op.c +40 -0
- data/ext/um/um_async_op_class.c +136 -0
- data/ext/um/um_buffer.c +49 -0
- data/ext/um/um_class.c +176 -44
- data/ext/um/um_const.c +174 -9
- data/ext/um/um_ext.c +8 -0
- data/ext/um/um_mutex_class.c +47 -0
- data/ext/um/um_op.c +89 -111
- data/ext/um/um_queue_class.c +58 -0
- data/ext/um/um_ssl.c +850 -0
- data/ext/um/um_ssl.h +22 -0
- data/ext/um/um_ssl_class.c +138 -0
- data/ext/um/um_sync.c +273 -0
- data/ext/um/um_utils.c +1 -1
- data/lib/uringmachine/dns_resolver.rb +84 -0
- data/lib/uringmachine/ssl/context_builder.rb +96 -0
- data/lib/uringmachine/ssl.rb +394 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +27 -3
- data/supressions/ruby.supp +71 -0
- data/test/helper.rb +6 -0
- data/test/test_async_op.rb +119 -0
- data/test/test_ssl.rb +155 -0
- data/test/test_um.rb +464 -47
- data/uringmachine.gemspec +3 -2
- data/vendor/liburing/.gitignore +5 -0
- data/vendor/liburing/CHANGELOG +1 -0
- data/vendor/liburing/configure +32 -0
- data/vendor/liburing/examples/Makefile +1 -0
- data/vendor/liburing/examples/reg-wait.c +159 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
- data/vendor/liburing/src/include/liburing.h +28 -2
- data/vendor/liburing/src/int_flags.h +10 -3
- data/vendor/liburing/src/liburing-ffi.map +13 -2
- data/vendor/liburing/src/liburing.map +9 -0
- data/vendor/liburing/src/queue.c +25 -16
- data/vendor/liburing/src/register.c +73 -4
- data/vendor/liburing/src/setup.c +46 -18
- data/vendor/liburing/src/setup.h +6 -0
- data/vendor/liburing/test/Makefile +7 -0
- data/vendor/liburing/test/cmd-discard.c +427 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
- data/vendor/liburing/test/file-exit-unreg.c +48 -0
- data/vendor/liburing/test/io_uring_passthrough.c +2 -0
- data/vendor/liburing/test/io_uring_register.c +13 -2
- data/vendor/liburing/test/napi-test.c +1 -1
- data/vendor/liburing/test/no-mmap-inval.c +1 -1
- data/vendor/liburing/test/read-mshot-empty.c +2 -0
- data/vendor/liburing/test/read-mshot-stdin.c +121 -0
- data/vendor/liburing/test/read-mshot.c +6 -0
- data/vendor/liburing/test/recvsend_bundle.c +2 -2
- data/vendor/liburing/test/reg-fd-only.c +1 -1
- data/vendor/liburing/test/reg-wait.c +251 -0
- data/vendor/liburing/test/regbuf-clone.c +458 -0
- data/vendor/liburing/test/resize-rings.c +643 -0
- data/vendor/liburing/test/rsrc_tags.c +1 -1
- data/vendor/liburing/test/sqpoll-sleep.c +39 -8
- data/vendor/liburing/test/sqwait.c +136 -0
- data/vendor/liburing/test/sync-cancel.c +8 -1
- data/vendor/liburing/test/timeout.c +13 -8
- metadata +52 -8
- data/examples/http_server_multishot.rb +0 -57
- data/examples/http_server_simpler.rb +0 -34
data/ext/um/um_ssl.h
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#ifndef UM_SSL_H
|
2
|
+
#define UM_SSL_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
// #include <openssl/bio.h>
|
6
|
+
#include <openssl/ssl.h>
|
7
|
+
// #include <openssl/dh.h>
|
8
|
+
// #include <openssl/err.h>
|
9
|
+
// #include <openssl/x509.h>
|
10
|
+
|
11
|
+
enum ssl_role {
|
12
|
+
ROLE_SERVER,
|
13
|
+
ROLE_CLIENT
|
14
|
+
};
|
15
|
+
|
16
|
+
struct um_ssl_connection {
|
17
|
+
VALUE self;
|
18
|
+
|
19
|
+
enum ssl_role role;
|
20
|
+
};
|
21
|
+
|
22
|
+
#endif // UM_SSL_H
|
@@ -0,0 +1,138 @@
|
|
1
|
+
/*
|
2
|
+
Adopted from:
|
3
|
+
https://github.com/puma/puma/blob/master/ext/puma_http11/mini_ssl.c
|
4
|
+
|
5
|
+
License (BSD-3):
|
6
|
+
https://github.com/puma/puma/blob/master/LICENSE
|
7
|
+
*/
|
8
|
+
|
9
|
+
#include "um.h"
|
10
|
+
#include "um_ssl.h"
|
11
|
+
// #include <openssl/bio.h>
|
12
|
+
#include <openssl/ssl.h>
|
13
|
+
// #include <openssl/dh.h>
|
14
|
+
// #include <openssl/err.h>
|
15
|
+
// #include <openssl/x509.h>
|
16
|
+
|
17
|
+
VALUE eSSLError;
|
18
|
+
VALUE cSSLConnection;
|
19
|
+
|
20
|
+
static void UM_SSL_Connection_mark(void *ptr) {
|
21
|
+
// struct um_ssl_connection *connection = ptr;
|
22
|
+
// rb_gc_mark_movable(connection->self);
|
23
|
+
|
24
|
+
// um_op_list_mark(machine, machine->transient_head);
|
25
|
+
// um_op_list_mark(machine, machine->runqueue_head);
|
26
|
+
}
|
27
|
+
|
28
|
+
static void UM_SSL_Connection_compact(void *ptr) {
|
29
|
+
// struct um_ssl_connection *connection = ptr;
|
30
|
+
// machine->self = rb_gc_location(machine->self);
|
31
|
+
// machine->poll_fiber = rb_gc_location(machine->poll_fiber);
|
32
|
+
|
33
|
+
// um_op_list_compact(machine, machine->transient_head);
|
34
|
+
// um_op_list_compact(machine, machine->runqueue_head);
|
35
|
+
}
|
36
|
+
|
37
|
+
static void UM_SSL_Connection_free(void *ptr) {
|
38
|
+
// um_ssl_connection_teardown((struct um_ssl_connection *)ptr);
|
39
|
+
free(ptr);
|
40
|
+
}
|
41
|
+
|
42
|
+
static size_t UM_SSL_Connection_size(const void *ptr) {
|
43
|
+
return sizeof(struct um_ssl_connection);
|
44
|
+
}
|
45
|
+
|
46
|
+
static const rb_data_type_t UM_SSL_Connection_type = {
|
47
|
+
"UringMachine::SSL::Connection",
|
48
|
+
{UM_SSL_Connection_mark, UM_SSL_Connection_free, UM_SSL_Connection_size, UM_SSL_Connection_compact},
|
49
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
50
|
+
};
|
51
|
+
|
52
|
+
static VALUE UM_SSL_Connection_allocate(VALUE klass) {
|
53
|
+
struct um_ssl_connection *connection = ALLOC(struct um_ssl_connection);
|
54
|
+
return TypedData_Wrap_Struct(klass, &UM_SSL_Connection_type, connection);
|
55
|
+
}
|
56
|
+
|
57
|
+
VALUE UM_SSL_Connection_initialize(VALUE self, VALUE machine, VALUE fd, VALUE ctx) {
|
58
|
+
// struct um_ssl_connection *connection = RTYPEDDATA_DATA(self);
|
59
|
+
|
60
|
+
return self;
|
61
|
+
}
|
62
|
+
|
63
|
+
VALUE UM_SSL_check(VALUE self) {
|
64
|
+
return Qnil;
|
65
|
+
}
|
66
|
+
|
67
|
+
void Init_SSL(void) {
|
68
|
+
VALUE cUM = rb_define_class("UringMachine", rb_cObject);
|
69
|
+
VALUE cSSL = rb_define_module_under(cUM, "SSL");
|
70
|
+
|
71
|
+
cSSLConnection = rb_define_class_under(cSSL, "Connection", rb_cObject);
|
72
|
+
rb_define_alloc_func(cUM, UM_SSL_Connection_allocate);
|
73
|
+
|
74
|
+
rb_define_method(cSSLConnection, "initialize", UM_SSL_Connection_initialize, 3);
|
75
|
+
|
76
|
+
// cCtx = rb_define_class_under(cSSL, "SSLContext", rb_cObject);
|
77
|
+
// rb_define_alloc_func(cCtx, sslctx_alloc);
|
78
|
+
// rb_define_method(cCtx, "initialize", sslctx_initialize, 1);
|
79
|
+
// rb_undef_method(cCtx, "initialize_copy");
|
80
|
+
|
81
|
+
// OpenSSL Build / Runtime/Load versions
|
82
|
+
|
83
|
+
/* Version of OpenSSL that UringMachine was compiled with */
|
84
|
+
rb_define_const(cSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
|
85
|
+
|
86
|
+
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
|
87
|
+
/* Version of OpenSSL that UringMachine loaded with */
|
88
|
+
rb_define_const(cSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
|
89
|
+
#else
|
90
|
+
rb_define_const(cSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
|
91
|
+
#endif
|
92
|
+
|
93
|
+
#if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
|
94
|
+
/* True if SSL3 is not available */
|
95
|
+
rb_define_const(cSSL, "OPENSSL_NO_SSL3", Qtrue);
|
96
|
+
#else
|
97
|
+
rb_define_const(cSSL, "OPENSSL_NO_SSL3", Qfalse);
|
98
|
+
#endif
|
99
|
+
|
100
|
+
#if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
|
101
|
+
/* True if TLS1 is not available */
|
102
|
+
rb_define_const(cSSL, "OPENSSL_NO_TLS1", Qtrue);
|
103
|
+
#else
|
104
|
+
rb_define_const(cSSL, "OPENSSL_NO_TLS1", Qfalse);
|
105
|
+
#endif
|
106
|
+
|
107
|
+
#if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
|
108
|
+
/* True if TLS1_1 is not available */
|
109
|
+
rb_define_const(cSSL, "OPENSSL_NO_TLS1_1", Qtrue);
|
110
|
+
#else
|
111
|
+
rb_define_const(cSSL, "OPENSSL_NO_TLS1_1", Qfalse);
|
112
|
+
#endif
|
113
|
+
|
114
|
+
rb_define_singleton_method(cSSL, "check", UM_SSL_check, 0);
|
115
|
+
|
116
|
+
eSSLError = rb_define_class_under(cSSL, "SSLError", rb_eStandardError);
|
117
|
+
|
118
|
+
// rb_define_singleton_method(cSSLConnection, "server", engine_init_server, 1);
|
119
|
+
// rb_define_singleton_method(cSSLConnection, "client", engine_init_client, 0);
|
120
|
+
|
121
|
+
// rb_define_method(cSSLConnection, "inject", engine_inject, 1);
|
122
|
+
// rb_define_method(cSSLConnection, "read", engine_read, 0);
|
123
|
+
|
124
|
+
// rb_define_method(cSSLConnection, "write", engine_write, 1);
|
125
|
+
// rb_define_method(cSSLConnection, "extract", engine_extract, 0);
|
126
|
+
|
127
|
+
// rb_define_method(cSSLConnection, "shutdown", engine_shutdown, 0);
|
128
|
+
|
129
|
+
// rb_define_method(cSSLConnection, "init?", engine_init, 0);
|
130
|
+
|
131
|
+
/* @!attribute [r] peercert
|
132
|
+
* Returns `nil` when `MiniSSL::Context#verify_mode` is set to `VERIFY_NONE`.
|
133
|
+
* @return [String, nil] DER encoded cert
|
134
|
+
*/
|
135
|
+
// rb_define_method(cSSLConnection, "peercert", engine_peercert, 0);
|
136
|
+
|
137
|
+
// rb_define_method(cSSLConnection, "ssl_vers_st", engine_ssl_vers_st, 0);
|
138
|
+
}
|
data/ext/um/um_sync.c
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdatomic.h>
|
3
|
+
#include <linux/futex.h>
|
4
|
+
|
5
|
+
#define FUTEX2_SIZE_U32 0x02
|
6
|
+
|
7
|
+
void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
8
|
+
struct um_op op;
|
9
|
+
um_prep_op(machine, &op, OP_FUTEX_WAIT);
|
10
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
11
|
+
io_uring_prep_futex_wait(
|
12
|
+
sqe, (uint32_t *)futex, expect, FUTEX_BITSET_MATCH_ANY,
|
13
|
+
FUTEX2_SIZE_U32, 0
|
14
|
+
);
|
15
|
+
|
16
|
+
VALUE ret = um_fiber_switch(machine);
|
17
|
+
if (!um_op_completed_p(&op))
|
18
|
+
um_cancel_and_wait(machine, &op);
|
19
|
+
else {
|
20
|
+
if (op.result.res != -EAGAIN)
|
21
|
+
um_raise_on_error_result(op.result.res);
|
22
|
+
}
|
23
|
+
|
24
|
+
RB_GC_GUARD(ret);
|
25
|
+
raise_if_exception(ret);
|
26
|
+
}
|
27
|
+
|
28
|
+
void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
29
|
+
struct um_op op;
|
30
|
+
um_prep_op(machine, &op, OP_FUTEX_WAKE);
|
31
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
32
|
+
// submit futex_wait
|
33
|
+
io_uring_prep_futex_wake(
|
34
|
+
sqe, (uint32_t *)futex, num_waiters, FUTEX_BITSET_MATCH_ANY,
|
35
|
+
FUTEX2_SIZE_U32, 0
|
36
|
+
);
|
37
|
+
|
38
|
+
VALUE ret = um_fiber_switch(machine);
|
39
|
+
um_check_completion(machine, &op);
|
40
|
+
|
41
|
+
RB_GC_GUARD(ret);
|
42
|
+
raise_if_exception(ret);
|
43
|
+
}
|
44
|
+
|
45
|
+
void um_futex_wake_transient(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
46
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
|
47
|
+
io_uring_prep_futex_wake(
|
48
|
+
sqe, (uint32_t *)futex, num_waiters, FUTEX_BITSET_MATCH_ANY,
|
49
|
+
FUTEX2_SIZE_U32, 0
|
50
|
+
);
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
#define MUTEX_LOCKED 1
|
55
|
+
#define MUTEX_UNLOCKED 0
|
56
|
+
|
57
|
+
void um_mutex_init(struct um_mutex *mutex) {
|
58
|
+
mutex->state = MUTEX_UNLOCKED;
|
59
|
+
}
|
60
|
+
|
61
|
+
inline void um_mutex_lock(struct um *machine, uint32_t *state) {
|
62
|
+
while (*state == MUTEX_LOCKED) {
|
63
|
+
um_futex_wait(machine, state, MUTEX_LOCKED);
|
64
|
+
}
|
65
|
+
*state = MUTEX_LOCKED;
|
66
|
+
}
|
67
|
+
|
68
|
+
inline void um_mutex_unlock(struct um *machine, uint32_t *state) {
|
69
|
+
*state = MUTEX_UNLOCKED;
|
70
|
+
// Wake up 1 waiting fiber
|
71
|
+
um_futex_wake(machine, state, 1);
|
72
|
+
}
|
73
|
+
|
74
|
+
struct sync_ctx {
|
75
|
+
struct um *machine;
|
76
|
+
uint32_t *state;
|
77
|
+
};
|
78
|
+
|
79
|
+
VALUE synchronize_begin(VALUE arg) {
|
80
|
+
struct sync_ctx *ctx = (struct sync_ctx *)arg;
|
81
|
+
um_mutex_lock(ctx->machine, ctx->state);
|
82
|
+
return rb_yield(Qnil);
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE synchronize_ensure(VALUE arg) {
|
86
|
+
struct sync_ctx *ctx = (struct sync_ctx *)arg;
|
87
|
+
um_mutex_unlock(ctx->machine, ctx->state);
|
88
|
+
return Qnil;
|
89
|
+
}
|
90
|
+
|
91
|
+
inline VALUE um_mutex_synchronize(struct um *machine, uint32_t *state) {
|
92
|
+
struct sync_ctx ctx = { .machine = machine, .state = state };
|
93
|
+
return rb_ensure(synchronize_begin, (VALUE)&ctx, synchronize_ensure, (VALUE)&ctx);
|
94
|
+
}
|
95
|
+
|
96
|
+
#define QUEUE_EMPTY 0
|
97
|
+
#define QUEUE_READY 1
|
98
|
+
|
99
|
+
inline void um_queue_init(struct um_queue *queue) {
|
100
|
+
queue->head = queue->tail = queue->free_head = NULL;
|
101
|
+
queue->state = QUEUE_EMPTY;
|
102
|
+
queue->count = 0;
|
103
|
+
}
|
104
|
+
|
105
|
+
inline void um_queue_free(struct um_queue *queue) {
|
106
|
+
struct um_queue_entry *entry = queue->head;
|
107
|
+
while (entry) {
|
108
|
+
struct um_queue_entry *next = entry->next;
|
109
|
+
free(entry);
|
110
|
+
entry = next;
|
111
|
+
}
|
112
|
+
|
113
|
+
entry = queue->free_head;
|
114
|
+
while (entry) {
|
115
|
+
struct um_queue_entry *next = entry->next;
|
116
|
+
free(entry);
|
117
|
+
entry = next;
|
118
|
+
}
|
119
|
+
|
120
|
+
free(queue);
|
121
|
+
}
|
122
|
+
|
123
|
+
inline void um_queue_mark(struct um_queue *queue) {
|
124
|
+
rb_gc_mark_movable(queue->self);
|
125
|
+
struct um_queue_entry *entry = queue->head;
|
126
|
+
while (entry) {
|
127
|
+
rb_gc_mark_movable(entry->value);
|
128
|
+
entry = entry->next;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
inline void um_queue_compact(struct um_queue *queue) {
|
133
|
+
queue->self = rb_gc_location(queue->self);
|
134
|
+
struct um_queue_entry *entry = queue->head;
|
135
|
+
while (entry) {
|
136
|
+
entry->value = rb_gc_location(entry->value);
|
137
|
+
entry = entry->next;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
inline struct um_queue_entry *um_queue_entry_checkout(struct um_queue *queue) {
|
142
|
+
struct um_queue_entry *entry = queue->free_head;
|
143
|
+
if (entry) {
|
144
|
+
queue->free_head = entry->next;
|
145
|
+
}
|
146
|
+
else
|
147
|
+
entry = malloc(sizeof(struct um_queue_entry));
|
148
|
+
return entry;
|
149
|
+
}
|
150
|
+
|
151
|
+
inline void um_queue_entry_checkin(struct um_queue *queue, struct um_queue_entry *entry) {
|
152
|
+
entry->next = queue->free_head;
|
153
|
+
queue->free_head = entry;
|
154
|
+
}
|
155
|
+
|
156
|
+
static inline void queue_add_head(struct um_queue *queue, VALUE value) {
|
157
|
+
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
158
|
+
|
159
|
+
entry->next = queue->head;
|
160
|
+
if (queue->head) {
|
161
|
+
queue->head->prev = entry;
|
162
|
+
queue->head = entry;
|
163
|
+
}
|
164
|
+
else
|
165
|
+
queue->head = queue->tail = entry;
|
166
|
+
entry->prev = NULL;
|
167
|
+
RB_OBJ_WRITE(queue->self, &entry->value, value);
|
168
|
+
}
|
169
|
+
|
170
|
+
static inline void queue_add_tail(struct um_queue *queue, VALUE value) {
|
171
|
+
struct um_queue_entry *entry = um_queue_entry_checkout(queue);
|
172
|
+
|
173
|
+
entry->prev = queue->tail;
|
174
|
+
if (queue->tail) {
|
175
|
+
queue->tail->next = entry;
|
176
|
+
queue->tail = entry;
|
177
|
+
}
|
178
|
+
else
|
179
|
+
queue->head = queue->tail = entry;
|
180
|
+
entry->next = NULL;
|
181
|
+
RB_OBJ_WRITE(queue->self, &entry->value, value);
|
182
|
+
}
|
183
|
+
|
184
|
+
VALUE queue_remove_head(struct um_queue *queue) {
|
185
|
+
struct um_queue_entry *entry = queue->head;
|
186
|
+
queue->head = entry->next;
|
187
|
+
if (!queue->head) queue->tail = NULL;
|
188
|
+
|
189
|
+
VALUE v = entry->value;
|
190
|
+
um_queue_entry_checkin(queue, entry);
|
191
|
+
return v;
|
192
|
+
|
193
|
+
}
|
194
|
+
|
195
|
+
VALUE queue_remove_tail(struct um_queue *queue) {
|
196
|
+
struct um_queue_entry *entry = queue->tail;
|
197
|
+
queue->tail = entry->prev;
|
198
|
+
if (!queue->tail) queue->head = NULL;
|
199
|
+
|
200
|
+
VALUE v = entry->value;
|
201
|
+
um_queue_entry_checkin(queue, entry);
|
202
|
+
return v;
|
203
|
+
}
|
204
|
+
|
205
|
+
static inline VALUE um_queue_add(struct um *machine, struct um_queue *queue, VALUE value, int add_head) {
|
206
|
+
if (add_head) queue_add_head(queue, value);
|
207
|
+
else queue_add_tail(queue, value);
|
208
|
+
|
209
|
+
queue->count++;
|
210
|
+
|
211
|
+
queue->state = QUEUE_READY;
|
212
|
+
if (queue->num_waiters)
|
213
|
+
um_futex_wake_transient(machine, &queue->state, 1);
|
214
|
+
return queue->self;
|
215
|
+
}
|
216
|
+
|
217
|
+
VALUE um_queue_push(struct um *machine, struct um_queue *queue, VALUE value) {
|
218
|
+
return um_queue_add(machine, queue, value, false);
|
219
|
+
}
|
220
|
+
|
221
|
+
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value) {
|
222
|
+
return um_queue_add(machine, queue, value, true);
|
223
|
+
}
|
224
|
+
|
225
|
+
enum queue_op { QUEUE_POP, QUEUE_SHIFT };
|
226
|
+
|
227
|
+
struct queue_wait_ctx {
|
228
|
+
struct um *machine;
|
229
|
+
struct um_queue *queue;
|
230
|
+
enum queue_op op;
|
231
|
+
};
|
232
|
+
|
233
|
+
VALUE um_queue_remove_begin(VALUE arg) {
|
234
|
+
struct queue_wait_ctx *ctx = (struct queue_wait_ctx *)arg;
|
235
|
+
|
236
|
+
ctx->queue->num_waiters++;
|
237
|
+
while (ctx->queue->state == QUEUE_EMPTY) {
|
238
|
+
um_futex_wait(ctx->machine, &ctx->queue->state, QUEUE_EMPTY);
|
239
|
+
}
|
240
|
+
|
241
|
+
if (ctx->queue->state != QUEUE_READY)
|
242
|
+
rb_raise(rb_eRuntimeError, "Internal error: queue should be in ready state!");
|
243
|
+
if (!ctx->queue->tail)
|
244
|
+
rb_raise(rb_eRuntimeError, "Internal error: queue should be in ready state!");
|
245
|
+
|
246
|
+
ctx->queue->count--;
|
247
|
+
return (ctx->op == QUEUE_POP ? queue_remove_tail : queue_remove_head)(ctx->queue);
|
248
|
+
}
|
249
|
+
|
250
|
+
VALUE um_queue_remove_ensure(VALUE arg) {
|
251
|
+
struct queue_wait_ctx *ctx = (struct queue_wait_ctx *)arg;
|
252
|
+
|
253
|
+
ctx->queue->num_waiters--;
|
254
|
+
|
255
|
+
if (ctx->queue->num_waiters && ctx->queue->tail) {
|
256
|
+
um_futex_wake_transient(ctx->machine, &ctx->queue->state, 1);
|
257
|
+
}
|
258
|
+
else if (!ctx->queue->tail) {
|
259
|
+
ctx->queue->state = QUEUE_EMPTY;
|
260
|
+
}
|
261
|
+
|
262
|
+
return Qnil;
|
263
|
+
}
|
264
|
+
|
265
|
+
VALUE um_queue_pop(struct um *machine, struct um_queue *queue) {
|
266
|
+
struct queue_wait_ctx ctx = { .machine = machine, .queue = queue, .op = QUEUE_POP };
|
267
|
+
return rb_ensure(um_queue_remove_begin, (VALUE)&ctx, um_queue_remove_ensure, (VALUE)&ctx);
|
268
|
+
}
|
269
|
+
|
270
|
+
VALUE um_queue_shift(struct um *machine, struct um_queue *queue) {
|
271
|
+
struct queue_wait_ctx ctx = { .machine = machine, .queue = queue, .op = QUEUE_SHIFT };
|
272
|
+
return rb_ensure(um_queue_remove_begin, (VALUE)&ctx, um_queue_remove_ensure, (VALUE)&ctx);
|
273
|
+
}
|
data/ext/um/um_utils.c
CHANGED
@@ -24,7 +24,7 @@ inline VALUE um_raise_exception(VALUE e) {
|
|
24
24
|
return rb_funcall(rb_mKernel, ID_raise, 1, e);
|
25
25
|
}
|
26
26
|
|
27
|
-
inline void
|
27
|
+
inline void um_raise_on_error_result(int result) {
|
28
28
|
if (unlikely(result < 0)) rb_syserr_fail(-result, strerror(-result));
|
29
29
|
}
|
30
30
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'resolv'
|
4
|
+
|
5
|
+
class UringMachine
|
6
|
+
class DNSResolver
|
7
|
+
def initialize(machine)
|
8
|
+
@machine = machine
|
9
|
+
@requests = UM::Queue.new
|
10
|
+
@nameservers = get_nameservers
|
11
|
+
@fiber = @machine.spin { handle_requests_loop }
|
12
|
+
@last_id = 0
|
13
|
+
@cache = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def resolve(hostname, type)
|
17
|
+
@machine.push(@requests, [hostname, type, Fiber.current])
|
18
|
+
@machine.yield
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_requests_loop
|
22
|
+
while true
|
23
|
+
hostname, type, fiber = @machine.shift(@requests)
|
24
|
+
res = do_resolve(hostname, type)
|
25
|
+
@machine.schedule(fiber, res)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_nameservers
|
30
|
+
nameservers = []
|
31
|
+
IO.readlines('/etc/resolv.conf').each do |line|
|
32
|
+
if line =~ /^nameserver (.+)$/
|
33
|
+
nameservers << $1.split(/\s+/).first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
nameservers
|
37
|
+
end
|
38
|
+
|
39
|
+
def socket_fd
|
40
|
+
@socket_fd ||= prepare_socket
|
41
|
+
end
|
42
|
+
|
43
|
+
def prepare_socket
|
44
|
+
fd = @machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
|
45
|
+
@machine.bind(fd, '0.0.0.0', 0)
|
46
|
+
@machine.connect(fd, @nameservers.sample, 53)
|
47
|
+
fd
|
48
|
+
end
|
49
|
+
|
50
|
+
def do_resolve(hostname, type, try_count = 0)
|
51
|
+
fd = socket_fd
|
52
|
+
req = prepare_request_packet(hostname, type)
|
53
|
+
msg = req.encode
|
54
|
+
@machine.send(fd, msg, msg.bytesize, 0)
|
55
|
+
|
56
|
+
buf = +''
|
57
|
+
@machine.recv(fd, buf, 16384, 0)
|
58
|
+
|
59
|
+
msg = Resolv::DNS::Message.decode buf
|
60
|
+
addrs = []
|
61
|
+
msg.each_answer do |name, ttl, data|
|
62
|
+
p [name, ttl, data]
|
63
|
+
if data.kind_of?(Resolv::DNS::Resource::IN::A) ||
|
64
|
+
data.kind_of?(Resolv::DNS::Resource::IN::AAAA)
|
65
|
+
addrs << data.address.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
addrs
|
69
|
+
end
|
70
|
+
|
71
|
+
def prepare_request_packet(hostname, type)
|
72
|
+
msg = Resolv::DNS::Message.new
|
73
|
+
msg.id = (@last_id += 1)
|
74
|
+
msg.rd = 1
|
75
|
+
msg.add_question hostname, msg_type(type)
|
76
|
+
msg
|
77
|
+
end
|
78
|
+
|
79
|
+
def msg_type(type)
|
80
|
+
# TODO: add support for other types
|
81
|
+
Resolv::DNS::Resource::IN::A
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module UringMachine
|
2
|
+
module SSL
|
3
|
+
class ContextBuilder
|
4
|
+
def initialize(params, log_writer)
|
5
|
+
@params = params
|
6
|
+
@log_writer = log_writer
|
7
|
+
end
|
8
|
+
|
9
|
+
def context
|
10
|
+
ctx = SSL::Context.new
|
11
|
+
|
12
|
+
if defined?(JRUBY_VERSION)
|
13
|
+
unless params['keystore']
|
14
|
+
log_writer.error "Please specify the Java keystore via 'keystore='"
|
15
|
+
end
|
16
|
+
|
17
|
+
ctx.keystore = params['keystore']
|
18
|
+
|
19
|
+
unless params['keystore-pass']
|
20
|
+
log_writer.error "Please specify the Java keystore password via 'keystore-pass='"
|
21
|
+
end
|
22
|
+
|
23
|
+
ctx.keystore_pass = params['keystore-pass']
|
24
|
+
ctx.keystore_type = params['keystore-type']
|
25
|
+
|
26
|
+
if truststore = params['truststore']
|
27
|
+
ctx.truststore = truststore.eql?('default') ? :default : truststore
|
28
|
+
ctx.truststore_pass = params['truststore-pass']
|
29
|
+
ctx.truststore_type = params['truststore-type']
|
30
|
+
end
|
31
|
+
|
32
|
+
ctx.cipher_suites = params['cipher_suites'] || params['ssl_cipher_list']
|
33
|
+
ctx.protocols = params['protocols'] if params['protocols']
|
34
|
+
else
|
35
|
+
if params['key'].nil? && params['key_pem'].nil?
|
36
|
+
log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
|
37
|
+
end
|
38
|
+
|
39
|
+
ctx.key = params['key'] if params['key']
|
40
|
+
ctx.key_pem = params['key_pem'] if params['key_pem']
|
41
|
+
ctx.key_password_command = params['key_password_command'] if params['key_password_command']
|
42
|
+
|
43
|
+
if params['cert'].nil? && params['cert_pem'].nil?
|
44
|
+
log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
|
45
|
+
end
|
46
|
+
|
47
|
+
ctx.cert = params['cert'] if params['cert']
|
48
|
+
ctx.cert_pem = params['cert_pem'] if params['cert_pem']
|
49
|
+
|
50
|
+
if ['peer', 'force_peer'].include?(params['verify_mode'])
|
51
|
+
unless params['ca']
|
52
|
+
log_writer.error "Please specify the SSL ca via 'ca='"
|
53
|
+
end
|
54
|
+
# needed for UM::SSL::Socket#peercert, env['puma.peercert']
|
55
|
+
require 'openssl'
|
56
|
+
end
|
57
|
+
|
58
|
+
ctx.ca = params['ca'] if params['ca']
|
59
|
+
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
|
60
|
+
ctx.ssl_ciphersuites = params['ssl_ciphersuites'] if params['ssl_ciphersuites'] && HAS_TLS1_3
|
61
|
+
|
62
|
+
ctx.reuse = params['reuse'] if params['reuse']
|
63
|
+
end
|
64
|
+
|
65
|
+
ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
|
66
|
+
ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
|
67
|
+
|
68
|
+
if params['verify_mode']
|
69
|
+
ctx.verify_mode = case params['verify_mode']
|
70
|
+
when "peer"
|
71
|
+
SSL::VERIFY_PEER
|
72
|
+
when "force_peer"
|
73
|
+
SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
74
|
+
when "none"
|
75
|
+
SSL::VERIFY_NONE
|
76
|
+
else
|
77
|
+
log_writer.error "Please specify a valid verify_mode="
|
78
|
+
SSL::VERIFY_NONE
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if params['verification_flags']
|
83
|
+
ctx.verification_flags = params['verification_flags'].split(',').
|
84
|
+
map { |flag| SSL::VERIFICATION_FLAGS.fetch(flag) }.
|
85
|
+
inject { |sum, flag| sum ? sum | flag : flag }
|
86
|
+
end
|
87
|
+
|
88
|
+
ctx
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
attr_reader :params, :log_writer
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|