iodine 0.7.43 → 0.7.46
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/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +18 -0
- data/examples/etag.ru +16 -0
- data/ext/iodine/extconf.rb +21 -16
- data/ext/iodine/fio.c +1108 -162
- data/ext/iodine/fio.h +49 -13
- data/ext/iodine/fio_cli.c +1 -1
- data/ext/iodine/fio_tls_missing.c +8 -0
- data/ext/iodine/fio_tls_openssl.c +8 -0
- data/ext/iodine/fio_tmpfile.h +13 -1
- data/ext/iodine/fiobj_data.c +6 -4
- data/ext/iodine/fiobj_data.h +2 -1
- data/ext/iodine/fiobj_hash.c +32 -6
- data/ext/iodine/fiobj_mustache.c +9 -0
- data/ext/iodine/fiobj_numbers.c +86 -8
- data/ext/iodine/fiobj_str.c +24 -11
- data/ext/iodine/fiobject.c +1 -1
- data/ext/iodine/fiobject.h +5 -3
- data/ext/iodine/http.c +75 -32
- data/ext/iodine/http1.c +2 -1
- data/ext/iodine/http1_parser.h +1065 -103
- data/ext/iodine/http_internal.c +1 -0
- data/ext/iodine/http_internal.h +4 -2
- data/ext/iodine/iodine.c +64 -1
- data/ext/iodine/iodine.h +2 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +4 -0
- data/ext/iodine/iodine_http.c +28 -2
- data/ext/iodine/iodine_rack_io.c +15 -2
- data/ext/iodine/iodine_tcp.c +14 -0
- data/ext/iodine/iodine_tls.c +8 -0
- data/ext/iodine/mustache_parser.h +4 -0
- data/ext/iodine/redis_engine.c +14 -11
- data/ext/iodine/websockets.c +7 -3
- data/iodine.gemspec +5 -4
- data/lib/iodine/version.rb +1 -1
- metadata +15 -13
data/ext/iodine/http_internal.c
CHANGED
@@ -98,6 +98,7 @@ int http_send_error2(size_t error, intptr_t uuid, http_settings_s *settings) {
|
|
98
98
|
return -1;
|
99
99
|
fio_protocol_s *pr = http1_new(uuid, settings, NULL, 0);
|
100
100
|
http_s *r = fio_malloc(sizeof(*r));
|
101
|
+
FIO_ASSERT_ALLOC(r);
|
101
102
|
FIO_ASSERT(pr, "Couldn't allocate response object for error report.")
|
102
103
|
http_s_new(r, (http_fio_protocol_s *)pr, http1_vtable());
|
103
104
|
int ret = http_send_error(r, error);
|
data/ext/iodine/http_internal.h
CHANGED
@@ -15,7 +15,9 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
15
15
|
|
16
16
|
#include <http.h>
|
17
17
|
|
18
|
+
#ifndef __MINGW32__
|
18
19
|
#include <arpa/inet.h>
|
20
|
+
#endif
|
19
21
|
#include <errno.h>
|
20
22
|
|
21
23
|
/* *****************************************************************************
|
@@ -121,8 +123,8 @@ static inline void http_s_destroy(http_s *h, uint8_t log) {
|
|
121
123
|
fiobj_free(h->params);
|
122
124
|
|
123
125
|
*h = (http_s){
|
124
|
-
|
125
|
-
|
126
|
+
.private_data.vtbl = h->private_data.vtbl,
|
127
|
+
.private_data.flag = h->private_data.flag,
|
126
128
|
};
|
127
129
|
}
|
128
130
|
|
data/ext/iodine/iodine.c
CHANGED
@@ -413,7 +413,7 @@ static VALUE iodine_cli_parse(VALUE self) {
|
|
413
413
|
FIO_CLI_PRINT_HEADER("WebSocket Settings:"),
|
414
414
|
FIO_CLI_INT("-max-msg -maxms incoming WebSocket message limit in Kb. "
|
415
415
|
"Default: 250Kb"),
|
416
|
-
FIO_CLI_INT("-ping websocket ping interval (
|
416
|
+
FIO_CLI_INT("-ping websocket ping interval (1..255). Default: 40s"),
|
417
417
|
FIO_CLI_PRINT_HEADER("SSL/TLS:"),
|
418
418
|
FIO_CLI_BOOL("-tls enable SSL/TLS using a self-signed certificate."),
|
419
419
|
FIO_CLI_STRING(
|
@@ -519,6 +519,7 @@ static VALUE iodine_cli_parse(VALUE self) {
|
|
519
519
|
rb_hash_aset(defaults, max_headers_sym,
|
520
520
|
INT2NUM((fio_cli_get_i("-maxhd") /* * 1024 */)));
|
521
521
|
}
|
522
|
+
#ifndef __MINGW32__
|
522
523
|
if (fio_cli_get_bool("-tls") || fio_cli_get("-key") || fio_cli_get("-cert")) {
|
523
524
|
VALUE rbtls = IodineCaller.call(IodineTLSClass, rb_intern2("new", 3));
|
524
525
|
if (rbtls == Qnil) {
|
@@ -543,6 +544,7 @@ static VALUE iodine_cli_parse(VALUE self) {
|
|
543
544
|
}
|
544
545
|
rb_hash_aset(defaults, tls_sym, rbtls);
|
545
546
|
}
|
547
|
+
#endif
|
546
548
|
if (fio_cli_unnamed_count()) {
|
547
549
|
rb_hash_aset(defaults, ID2SYM(rb_intern("filename_")),
|
548
550
|
rb_str_new_cstr(fio_cli_unnamed(0)));
|
@@ -634,8 +636,10 @@ FIO_FUNC void iodine_connect_args_cleanup(iodine_connection_args_s *s) {
|
|
634
636
|
fio_free(s->port.data);
|
635
637
|
if (s->address.capa)
|
636
638
|
fio_free(s->address.data);
|
639
|
+
#ifndef __MINGW32__
|
637
640
|
if (s->tls)
|
638
641
|
fio_tls_destroy(s->tls);
|
642
|
+
#endif
|
639
643
|
}
|
640
644
|
|
641
645
|
/*
|
@@ -686,7 +690,9 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
686
690
|
VALUE r_public = rb_hash_aref(s, public_sym);
|
687
691
|
VALUE service = rb_hash_aref(s, service_sym);
|
688
692
|
VALUE timeout = rb_hash_aref(s, timeout_sym);
|
693
|
+
#ifndef __MINGW32__
|
689
694
|
VALUE tls = rb_hash_aref(s, tls_sym);
|
695
|
+
#endif
|
690
696
|
VALUE r_url = rb_hash_aref(s, url_sym);
|
691
697
|
fio_str_info_s service_str = {.data = NULL};
|
692
698
|
|
@@ -726,8 +732,10 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
726
732
|
// service = rb_hash_aref(iodine_default_args, service_sym);
|
727
733
|
if (timeout == Qnil)
|
728
734
|
timeout = rb_hash_aref(iodine_default_args, timeout_sym);
|
735
|
+
#ifndef __MINGW32__
|
729
736
|
if (tls == Qnil)
|
730
737
|
tls = rb_hash_aref(iodine_default_args, tls_sym);
|
738
|
+
#endif
|
731
739
|
|
732
740
|
/* TODO: deprecation */
|
733
741
|
if (handler == Qnil) {
|
@@ -824,11 +832,13 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
824
832
|
else
|
825
833
|
r.timeout = FIX2ULONG(timeout);
|
826
834
|
}
|
835
|
+
#ifndef __MINGW32__
|
827
836
|
if (tls != Qnil) {
|
828
837
|
r.tls = iodine_tls2c(tls);
|
829
838
|
if (r.tls)
|
830
839
|
fio_tls_dup(r.tls);
|
831
840
|
}
|
841
|
+
#endif
|
832
842
|
/* URL parsing */
|
833
843
|
if (r_url != Qnil && RB_TYPE_P(r_url, T_STRING)) {
|
834
844
|
r.url = IODINE_RSTRINFO(r_url);
|
@@ -888,6 +898,56 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
888
898
|
/* test/set service type */
|
889
899
|
r.service = IODINE_SERVICE_RAW;
|
890
900
|
if (service_str.data) {
|
901
|
+
#ifdef __MINGW32__
|
902
|
+
switch (service_str.data[0]) {
|
903
|
+
case 't': /* overflow */
|
904
|
+
/* tcp or tls */
|
905
|
+
if (service_str.data[1] == 'l') {
|
906
|
+
char *local = NULL;
|
907
|
+
char buf[1024];
|
908
|
+
buf[1023] = 0;
|
909
|
+
if (is_srv) {
|
910
|
+
local = buf;
|
911
|
+
if (fio_local_addr(buf, 1023) >= 1022)
|
912
|
+
local = NULL;
|
913
|
+
}
|
914
|
+
}
|
915
|
+
/* overflow */
|
916
|
+
case 'u': /* overflow */
|
917
|
+
/* unix */
|
918
|
+
case 'r':
|
919
|
+
/* raw */
|
920
|
+
r.service = IODINE_SERVICE_RAW;
|
921
|
+
break;
|
922
|
+
case 'h':
|
923
|
+
/* http(s) */
|
924
|
+
r.service = IODINE_SERVICE_HTTP;
|
925
|
+
if (service_str.len == 5) {
|
926
|
+
char *local = NULL;
|
927
|
+
char buf[1024];
|
928
|
+
buf[1023] = 0;
|
929
|
+
if (is_srv) {
|
930
|
+
local = buf;
|
931
|
+
if (fio_local_addr(buf, 1023) >= 1022)
|
932
|
+
local = NULL;
|
933
|
+
}
|
934
|
+
}
|
935
|
+
case 'w':
|
936
|
+
/* ws(s) */
|
937
|
+
r.service = IODINE_SERVICE_WS;
|
938
|
+
if (service_str.len == 3) {
|
939
|
+
char *local = NULL;
|
940
|
+
char buf[1024];
|
941
|
+
buf[1023] = 0;
|
942
|
+
if (is_srv) {
|
943
|
+
local = buf;
|
944
|
+
if (fio_local_addr(buf, 1023) >= 1022)
|
945
|
+
local = NULL;
|
946
|
+
}
|
947
|
+
}
|
948
|
+
break;
|
949
|
+
}
|
950
|
+
#else
|
891
951
|
switch (service_str.data[0]) {
|
892
952
|
case 't': /* overflow */
|
893
953
|
/* tcp or tls */
|
@@ -939,6 +999,7 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
|
|
939
999
|
}
|
940
1000
|
break;
|
941
1001
|
}
|
1002
|
+
#endif
|
942
1003
|
}
|
943
1004
|
return r;
|
944
1005
|
}
|
@@ -1349,8 +1410,10 @@ void Init_iodine(void) {
|
|
1349
1410
|
// initialize the HTTP module
|
1350
1411
|
iodine_init_http();
|
1351
1412
|
|
1413
|
+
#ifndef __MINGW32__
|
1352
1414
|
// initialize SSL/TLS support module
|
1353
1415
|
iodine_init_tls();
|
1416
|
+
#endif
|
1354
1417
|
|
1355
1418
|
// initialize JSON helpers
|
1356
1419
|
iodine_init_json();
|
data/ext/iodine/iodine.h
CHANGED
data/ext/iodine/iodine_caller.c
CHANGED
@@ -5,7 +5,19 @@
|
|
5
5
|
|
6
6
|
#include <fio.h>
|
7
7
|
|
8
|
-
|
8
|
+
#include <pthread.h>
|
9
|
+
|
10
|
+
static pthread_key_t iodine_GVL_state_key;
|
11
|
+
static pthread_once_t iodine_GVL_state_once = PTHREAD_ONCE_INIT;
|
12
|
+
static void init_iodine_GVL_state_key(void) {
|
13
|
+
pthread_key_create(&iodine_GVL_state_key, NULL);
|
14
|
+
}
|
15
|
+
static void init_iodine_GVL_state_init(void) {
|
16
|
+
uint8_t *gvl = malloc(sizeof(uint8_t));
|
17
|
+
FIO_ASSERT_ALLOC(gvl);
|
18
|
+
*gvl = 1;
|
19
|
+
pthread_setspecific(iodine_GVL_state_key, gvl);
|
20
|
+
}
|
9
21
|
|
10
22
|
/* *****************************************************************************
|
11
23
|
Calling protected Ruby methods
|
@@ -84,25 +96,37 @@ API
|
|
84
96
|
|
85
97
|
/** Calls a C function within the GVL. */
|
86
98
|
static void *iodine_enterGVL(void *(*func)(void *), void *arg) {
|
87
|
-
|
99
|
+
pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
|
100
|
+
uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
101
|
+
if (!iodine_GVL_state) {
|
102
|
+
init_iodine_GVL_state_init();
|
103
|
+
iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
104
|
+
}
|
105
|
+
if (*iodine_GVL_state) {
|
88
106
|
return func(arg);
|
89
107
|
}
|
90
108
|
void *rv = NULL;
|
91
|
-
iodine_GVL_state = 1;
|
109
|
+
*iodine_GVL_state = 1;
|
92
110
|
rv = rb_thread_call_with_gvl(func, arg);
|
93
|
-
iodine_GVL_state = 0;
|
111
|
+
*iodine_GVL_state = 0;
|
94
112
|
return rv;
|
95
113
|
}
|
96
114
|
|
97
115
|
/** Calls a C function outside the GVL. */
|
98
116
|
static void *iodine_leaveGVL(void *(*func)(void *), void *arg) {
|
117
|
+
pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
|
118
|
+
uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
99
119
|
if (!iodine_GVL_state) {
|
120
|
+
init_iodine_GVL_state_init();
|
121
|
+
iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
122
|
+
}
|
123
|
+
if (!*iodine_GVL_state) {
|
100
124
|
return func(arg);
|
101
125
|
}
|
102
126
|
void *rv = NULL;
|
103
|
-
iodine_GVL_state = 0;
|
127
|
+
*iodine_GVL_state = 0;
|
104
128
|
rv = rb_thread_call_without_gvl(func, arg, NULL, NULL);
|
105
|
-
iodine_GVL_state = 1;
|
129
|
+
*iodine_GVL_state = 1;
|
106
130
|
return rv;
|
107
131
|
}
|
108
132
|
|
@@ -151,10 +175,26 @@ static VALUE iodine_call_block(VALUE obj, ID method, int argc, VALUE *argv,
|
|
151
175
|
}
|
152
176
|
|
153
177
|
/** Returns the GVL state flag. */
|
154
|
-
static uint8_t iodine_in_GVL(void) {
|
178
|
+
static uint8_t iodine_in_GVL(void) {
|
179
|
+
pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
|
180
|
+
uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
181
|
+
if (!iodine_GVL_state) {
|
182
|
+
init_iodine_GVL_state_init();
|
183
|
+
iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
184
|
+
}
|
185
|
+
return *iodine_GVL_state;
|
186
|
+
}
|
155
187
|
|
156
188
|
/** Forces the GVL state flag. */
|
157
|
-
static void iodine_set_GVL(uint8_t state) {
|
189
|
+
static void iodine_set_GVL(uint8_t state) {
|
190
|
+
pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
|
191
|
+
uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
192
|
+
if (!iodine_GVL_state) {
|
193
|
+
init_iodine_GVL_state_init();
|
194
|
+
iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
|
195
|
+
}
|
196
|
+
*iodine_GVL_state = state;
|
197
|
+
}
|
158
198
|
|
159
199
|
/* *****************************************************************************
|
160
200
|
Caller Initialization
|
@@ -403,8 +403,12 @@ static void *iodine_on_pubsub_call_block(void *msg_) {
|
|
403
403
|
fio_msg_s *msg = msg_;
|
404
404
|
VALUE args[2];
|
405
405
|
args[0] = rb_str_new(msg->channel.data, msg->channel.len);
|
406
|
+
IodineStore.add(args[0]);
|
406
407
|
args[1] = rb_str_new(msg->msg.data, msg->msg.len);
|
408
|
+
IodineStore.add(args[1]);
|
407
409
|
IodineCaller.call2((VALUE)msg->udata2, call_id, 2, args);
|
410
|
+
IodineStore.remove(args[1]);
|
411
|
+
IodineStore.remove(args[0]);
|
408
412
|
return NULL;
|
409
413
|
}
|
410
414
|
|
data/ext/iodine/iodine_http.c
CHANGED
@@ -12,11 +12,15 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
12
12
|
#include <ruby/io.h>
|
13
13
|
// #include "iodine_websockets.h"
|
14
14
|
|
15
|
+
#ifndef __MINGW32__
|
15
16
|
#include <arpa/inet.h>
|
17
|
+
#endif
|
16
18
|
#include <ctype.h>
|
17
19
|
#include <stdlib.h>
|
18
20
|
#include <string.h>
|
21
|
+
#ifndef __MINGW32__
|
19
22
|
#include <sys/socket.h>
|
23
|
+
#endif
|
20
24
|
|
21
25
|
/* *****************************************************************************
|
22
26
|
Available Globals
|
@@ -555,9 +559,11 @@ static inline int ruby2c_response_send(iodine_http_request_handle_s *handle,
|
|
555
559
|
|
556
560
|
if (TYPE(body) == T_STRING) {
|
557
561
|
// fprintf(stderr, "Review body as String\n");
|
558
|
-
|
562
|
+
handle->type = IODINE_HTTP_NONE;
|
563
|
+
if (RSTRING_LEN(body)) {
|
559
564
|
handle->body = fiobj_str_new(RSTRING_PTR(body), RSTRING_LEN(body));
|
560
|
-
|
565
|
+
handle->type = IODINE_HTTP_SENDBODY;
|
566
|
+
}
|
561
567
|
return 0;
|
562
568
|
} else if (rb_respond_to(body, each_method_id)) {
|
563
569
|
// fprintf(stderr, "Review body as for-each ...\n");
|
@@ -936,6 +942,15 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
|
|
936
942
|
support_xsendfile = 1;
|
937
943
|
}
|
938
944
|
IodineStore.add(args.handler);
|
945
|
+
#ifdef __MINGW32__
|
946
|
+
intptr_t uuid = http_listen(
|
947
|
+
args.port.data, args.address.data, .on_request = on_rack_request,
|
948
|
+
.on_upgrade = on_rack_upgrade, .udata = (void *)args.handler,
|
949
|
+
.timeout = args.timeout, .ws_timeout = args.ping,
|
950
|
+
.ws_max_msg_size = args.max_msg, .max_header_size = args.max_headers,
|
951
|
+
.on_finish = free_iodine_http, .log = args.log,
|
952
|
+
.max_body_size = args.max_body, .public_folder = args.public.data);
|
953
|
+
#else
|
939
954
|
intptr_t uuid = http_listen(
|
940
955
|
args.port.data, args.address.data, .on_request = on_rack_request,
|
941
956
|
.on_upgrade = on_rack_upgrade, .udata = (void *)args.handler,
|
@@ -943,6 +958,7 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
|
|
943
958
|
.ws_max_msg_size = args.max_msg, .max_header_size = args.max_headers,
|
944
959
|
.on_finish = free_iodine_http, .log = args.log,
|
945
960
|
.max_body_size = args.max_body, .public_folder = args.public.data);
|
961
|
+
#endif
|
946
962
|
if (uuid == -1)
|
947
963
|
return uuid;
|
948
964
|
|
@@ -1052,9 +1068,11 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
|
|
1052
1068
|
FIOBJ url_tmp = FIOBJ_INVALID;
|
1053
1069
|
if (!args.url.data) {
|
1054
1070
|
url_tmp = fiobj_str_buf(64);
|
1071
|
+
#ifndef __MINGW32__
|
1055
1072
|
if (args.tls)
|
1056
1073
|
fiobj_str_write(url_tmp, "wss://", 6);
|
1057
1074
|
else
|
1075
|
+
#endif
|
1058
1076
|
fiobj_str_write(url_tmp, "ws://", 5);
|
1059
1077
|
if (!is_unix_socket) {
|
1060
1078
|
fiobj_str_write(url_tmp, args.address.data, args.address.len);
|
@@ -1070,11 +1088,19 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
|
|
1070
1088
|
args.url = fiobj_obj2cstr(url_tmp);
|
1071
1089
|
}
|
1072
1090
|
|
1091
|
+
#ifdef __MINGW32__
|
1092
|
+
intptr_t uuid = http_connect(
|
1093
|
+
args.url.data, (is_unix_socket ? args.address.data : NULL),
|
1094
|
+
.udata = request_data_create(&args),
|
1095
|
+
.on_response = ws_client_http_connected,
|
1096
|
+
.on_finish = ws_client_http_connection_finished);
|
1097
|
+
#else
|
1073
1098
|
intptr_t uuid = http_connect(
|
1074
1099
|
args.url.data, (is_unix_socket ? args.address.data : NULL),
|
1075
1100
|
.udata = request_data_create(&args),
|
1076
1101
|
.on_response = ws_client_http_connected,
|
1077
1102
|
.on_finish = ws_client_http_connection_finished, .tls = args.tls);
|
1103
|
+
#endif
|
1078
1104
|
fiobj_free(url_tmp);
|
1079
1105
|
return uuid;
|
1080
1106
|
}
|
data/ext/iodine/iodine_rack_io.c
CHANGED
@@ -61,6 +61,9 @@ static VALUE TCPSOCKET_CLASS;
|
|
61
61
|
static ID for_fd_id;
|
62
62
|
static ID iodine_fd_var_id;
|
63
63
|
static ID iodine_new_func_id;
|
64
|
+
#ifdef __MINGW32__
|
65
|
+
static ID iodine_osffd_id;
|
66
|
+
#endif
|
64
67
|
static rb_encoding *IodineUTF8Encoding;
|
65
68
|
static rb_encoding *IodineBinaryEncoding;
|
66
69
|
|
@@ -69,7 +72,7 @@ static rb_encoding *IodineBinaryEncoding;
|
|
69
72
|
|
70
73
|
inline static http_s *get_handle(VALUE obj) {
|
71
74
|
VALUE i = rb_ivar_get(obj, iodine_fd_var_id);
|
72
|
-
return (http_s *)
|
75
|
+
return (http_s *)NUM2ULL(i);
|
73
76
|
}
|
74
77
|
|
75
78
|
/* *****************************************************************************
|
@@ -78,7 +81,7 @@ IO API
|
|
78
81
|
|
79
82
|
static inline FIOBJ get_data(VALUE self) {
|
80
83
|
VALUE i = rb_ivar_get(self, io_id);
|
81
|
-
return (FIOBJ)
|
84
|
+
return (FIOBJ)NUM2ULL(i);
|
82
85
|
}
|
83
86
|
|
84
87
|
static VALUE rio_rewind(VALUE self) {
|
@@ -196,7 +199,14 @@ static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
|
|
196
199
|
set_handle(self, NULL);
|
197
200
|
// hijack the IO object
|
198
201
|
intptr_t uuid = http_hijack(h, NULL);
|
202
|
+
#ifdef __MINGW32__
|
203
|
+
int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
|
204
|
+
if (osffd == -1)
|
205
|
+
return Qfalse;
|
206
|
+
VALUE fd = INT2FIX(osffd);
|
207
|
+
#else
|
199
208
|
VALUE fd = INT2FIX(fio_uuid2fd(uuid));
|
209
|
+
#endif
|
200
210
|
// VALUE new_io = how the fuck do we create a new IO from the fd?
|
201
211
|
VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
|
202
212
|
&fd); // TCPSocket.for_fd(fd) ... cool...
|
@@ -238,6 +248,9 @@ static void init_rack_io(void) {
|
|
238
248
|
for_fd_id = rb_intern("for_fd");
|
239
249
|
iodine_fd_var_id = rb_intern("fd");
|
240
250
|
iodine_new_func_id = rb_intern("new");
|
251
|
+
#ifdef __MINGW32__
|
252
|
+
iodine_osffd_id = rb_intern("osffd");
|
253
|
+
#endif
|
241
254
|
hijack_func_sym = ID2SYM(rb_intern("_hijack"));
|
242
255
|
|
243
256
|
TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
data/ext/iodine/iodine_tcp.c
CHANGED
@@ -209,10 +209,17 @@ Returns the handler object used.
|
|
209
209
|
intptr_t iodine_tcp_listen(iodine_connection_args_s args) {
|
210
210
|
// clang-format on
|
211
211
|
IodineStore.add(args.handler);
|
212
|
+
#ifdef __MINGW32__
|
213
|
+
return fio_listen(.port = args.port.data, .address = args.address.data,
|
214
|
+
.on_open = iodine_tcp_on_open,
|
215
|
+
.on_finish = iodine_tcp_on_finish,
|
216
|
+
.udata = (void *)args.handler);
|
217
|
+
#else
|
212
218
|
return fio_listen(.port = args.port.data, .address = args.address.data,
|
213
219
|
.on_open = iodine_tcp_on_open,
|
214
220
|
.on_finish = iodine_tcp_on_finish, .tls = args.tls,
|
215
221
|
.udata = (void *)args.handler);
|
222
|
+
#endif
|
216
223
|
}
|
217
224
|
|
218
225
|
// clang-format off
|
@@ -238,10 +245,17 @@ Returns the handler object used.
|
|
238
245
|
intptr_t iodine_tcp_connect(iodine_connection_args_s args){
|
239
246
|
// clang-format on
|
240
247
|
IodineStore.add(args.handler);
|
248
|
+
#ifdef __MINGW32__
|
249
|
+
return fio_connect(.port = args.port.data, .address = args.address.data,
|
250
|
+
.on_connect = iodine_tcp_on_connect,
|
251
|
+
.on_fail = iodine_tcp_on_fail, .timeout = args.ping,
|
252
|
+
.udata = (void *)args.handler);
|
253
|
+
#else
|
241
254
|
return fio_connect(.port = args.port.data, .address = args.address.data,
|
242
255
|
.on_connect = iodine_tcp_on_connect, .tls = args.tls,
|
243
256
|
.on_fail = iodine_tcp_on_fail, .timeout = args.ping,
|
244
257
|
.udata = (void *)args.handler);
|
258
|
+
#endif
|
245
259
|
}
|
246
260
|
|
247
261
|
// clang-format off
|
data/ext/iodine/iodine_tls.c
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
#ifdef __MINGW32__
|
2
|
+
// make pedantic compiler happy
|
3
|
+
typedef struct {
|
4
|
+
int bogus;
|
5
|
+
} bogus_s;
|
6
|
+
|
7
|
+
#else
|
1
8
|
#include <ruby.h>
|
2
9
|
|
3
10
|
#include <fio.h>
|
@@ -251,3 +258,4 @@ void iodine_init_tls(void) {
|
|
251
258
|
#endif
|
252
259
|
}
|
253
260
|
#undef IODINE_MAKE_SYM
|
261
|
+
#endif
|
@@ -28,6 +28,10 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
28
28
|
#include <sys/stat.h>
|
29
29
|
#include <sys/types.h>
|
30
30
|
|
31
|
+
#ifdef __MINGW32__
|
32
|
+
ssize_t pread(int, void*, size_t, off_t);
|
33
|
+
#endif
|
34
|
+
|
31
35
|
#if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
|
32
36
|
#define __attribute__(...)
|
33
37
|
#define __has_include(...) 0
|
data/ext/iodine/redis_engine.c
CHANGED
@@ -493,6 +493,7 @@ static void redis_pub_ping(intptr_t uuid, fio_protocol_s *pr) {
|
|
493
493
|
return;
|
494
494
|
}
|
495
495
|
redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + 15);
|
496
|
+
FIO_ASSERT_ALLOC(cmd);
|
496
497
|
*cmd = (redis_commands_s){.cmd_len = 14};
|
497
498
|
memcpy(cmd->cmd, "*1\r\n$4\r\nPING\r\n\0", 15);
|
498
499
|
redis_attach_cmd(r, cmd);
|
@@ -534,6 +535,7 @@ static void redis_on_connect(intptr_t uuid, void *i_) {
|
|
534
535
|
r = pub2redis(i);
|
535
536
|
if (r->auth_len) {
|
536
537
|
redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + r->auth_len);
|
538
|
+
FIO_ASSERT_ALLOC(cmd);
|
537
539
|
*cmd =
|
538
540
|
(redis_commands_s){.cmd_len = r->auth_len, .callback = redis_on_auth};
|
539
541
|
memcpy(cmd->cmd, r->auth, r->auth_len);
|
@@ -638,6 +640,7 @@ static void redis_on_publish_root(const fio_pubsub_engine_s *eng,
|
|
638
640
|
uint8_t is_json) {
|
639
641
|
redis_engine_s *r = (redis_engine_s *)eng;
|
640
642
|
redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + channel.len + msg.len + 96);
|
643
|
+
FIO_ASSERT_ALLOC(cmd);
|
641
644
|
*cmd = (redis_commands_s){.cmd_len = 0};
|
642
645
|
memcpy(cmd->cmd, "*3\r\n$7\r\nPUBLISH\r\n$", 18);
|
643
646
|
char *buf = (char *)cmd->cmd + 18;
|
@@ -684,7 +687,7 @@ static void redis_on_publish_child(const fio_pubsub_engine_s *eng,
|
|
684
687
|
fio_str_s tmp = FIO_STR_INIT;
|
685
688
|
/* by using fio_str_s, short names are allocated on the stack */
|
686
689
|
fio_str_info_s tmp_info = fio_str_resize(&tmp, channel.len + 8);
|
687
|
-
fio_u2str64(tmp_info.data, (
|
690
|
+
fio_u2str64(tmp_info.data, (uintptr_t)eng);
|
688
691
|
memcpy(tmp_info.data + 8, channel.data, channel.len);
|
689
692
|
/* forward publication request to Root */
|
690
693
|
fio_publish(.filter = -1, .channel = tmp_info, .message = msg,
|
@@ -701,7 +704,7 @@ Root Publication Handler
|
|
701
704
|
static void redis_on_internal_publish(fio_msg_s *msg) {
|
702
705
|
if (msg->channel.len < 8)
|
703
706
|
return; /* internal error, unexpected data */
|
704
|
-
void *en = (void *)fio_str2u64(msg->channel.data);
|
707
|
+
void *en = (void *)(uintptr_t)fio_str2u64(msg->channel.data);
|
705
708
|
if (en != msg->udata1)
|
706
709
|
return; /* should be delivered by a different engine */
|
707
710
|
/* step after the engine data */
|
@@ -721,8 +724,8 @@ Sending commands using the Root connection
|
|
721
724
|
static void redis_forward_reply(fio_pubsub_engine_s *e, FIOBJ reply,
|
722
725
|
void *udata) {
|
723
726
|
uint8_t *data = udata;
|
724
|
-
fio_pubsub_engine_s *engine = (fio_pubsub_engine_s *)fio_str2u64(data + 0);
|
725
|
-
void *callback = (void *)fio_str2u64(data + 8);
|
727
|
+
fio_pubsub_engine_s *engine = (fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(data + 0);
|
728
|
+
void *callback = (void *)(uintptr_t)fio_str2u64(data + 8);
|
726
729
|
if (engine != e || !callback) {
|
727
730
|
FIO_LOG_DEBUG("Redis reply not forwarded (callback: %p)", callback);
|
728
731
|
return;
|
@@ -738,7 +741,7 @@ static void redis_forward_reply(fio_pubsub_engine_s *e, FIOBJ reply,
|
|
738
741
|
static void redis_on_internal_cmd(fio_msg_s *msg) {
|
739
742
|
// void*(void *)fio_str2u64(msg->msg.data);
|
740
743
|
fio_pubsub_engine_s *engine =
|
741
|
-
(fio_pubsub_engine_s *)fio_str2u64(msg->channel.data + 0);
|
744
|
+
(fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(msg->channel.data + 0);
|
742
745
|
if (engine != msg->udata1) {
|
743
746
|
return;
|
744
747
|
}
|
@@ -756,7 +759,7 @@ static void redis_on_internal_cmd(fio_msg_s *msg) {
|
|
756
759
|
/* Listens on filter `-10 -getpid()` for incoming reply data */
|
757
760
|
static void redis_on_internal_reply(fio_msg_s *msg) {
|
758
761
|
fio_pubsub_engine_s *engine =
|
759
|
-
(fio_pubsub_engine_s *)fio_str2u64(msg->channel.data + 0);
|
762
|
+
(fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(msg->channel.data + 0);
|
760
763
|
if (engine != msg->udata1) {
|
761
764
|
FIO_LOG_DEBUG("Redis reply not forwarded (engine mismatch: %p != %p)",
|
762
765
|
(void *)engine, msg->udata1);
|
@@ -765,8 +768,8 @@ static void redis_on_internal_reply(fio_msg_s *msg) {
|
|
765
768
|
FIOBJ reply;
|
766
769
|
fiobj_json2obj(&reply, msg->msg.data, msg->msg.len);
|
767
770
|
void (*callback)(fio_pubsub_engine_s *, FIOBJ, void *) = (void (*)(
|
768
|
-
fio_pubsub_engine_s *, FIOBJ, void *))fio_str2u64(msg->channel.data + 8);
|
769
|
-
void *udata = (void *)fio_str2u64(msg->channel.data + 16);
|
771
|
+
fio_pubsub_engine_s *, FIOBJ, void *))(uintptr_t)fio_str2u64(msg->channel.data + 8);
|
772
|
+
void *udata = (void *)(uintptr_t)fio_str2u64(msg->channel.data + 16);
|
770
773
|
callback(engine, reply, udata);
|
771
774
|
fiobj_free(reply);
|
772
775
|
}
|
@@ -788,9 +791,9 @@ intptr_t redis_engine_send(fio_pubsub_engine_s *engine, FIOBJ command,
|
|
788
791
|
fio_str_s tmp = FIO_STR_INIT;
|
789
792
|
fio_str_info_s ti = fio_str_resize(&tmp, 28);
|
790
793
|
/* combine metadata */
|
791
|
-
fio_u2str64(ti.data + 0, (
|
792
|
-
fio_u2str64(ti.data + 8, (
|
793
|
-
fio_u2str64(ti.data + 16, (
|
794
|
+
fio_u2str64(ti.data + 0, (uintptr_t)engine);
|
795
|
+
fio_u2str64(ti.data + 8, (uintptr_t)callback);
|
796
|
+
fio_u2str64(ti.data + 16, (uintptr_t)udata);
|
794
797
|
fio_u2str32(ti.data + 24, (uint32_t)getpid());
|
795
798
|
FIOBJ cmd = fiobj2resp_tmp(command);
|
796
799
|
fio_publish(.filter = -2, .channel = ti, .message = fiobj_obj2cstr(cmd),
|
data/ext/iodine/websockets.c
CHANGED
@@ -17,7 +17,9 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
17
17
|
#include <http.h>
|
18
18
|
#include <http_internal.h>
|
19
19
|
|
20
|
+
#ifndef __MINGW32__
|
20
21
|
#include <arpa/inet.h>
|
22
|
+
#endif
|
21
23
|
#include <errno.h>
|
22
24
|
#include <stdio.h>
|
23
25
|
#include <stdlib.h>
|
@@ -26,7 +28,7 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
26
28
|
|
27
29
|
#include <websocket_parser.h>
|
28
30
|
|
29
|
-
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
|
31
|
+
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && !defined(__MINGW32__)
|
30
32
|
#include <endian.h>
|
31
33
|
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
|
32
34
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
@@ -71,6 +73,7 @@ struct buffer_s create_ws_buffer(ws_s *owner) {
|
|
71
73
|
struct buffer_s buff;
|
72
74
|
buff.size = WS_INITIAL_BUFFER_SIZE;
|
73
75
|
buff.data = malloc(buff.size);
|
76
|
+
FIO_ASSERT_ALLOC(buff.data);
|
74
77
|
return buff;
|
75
78
|
}
|
76
79
|
|
@@ -79,7 +82,6 @@ struct buffer_s resize_ws_buffer(ws_s *owner, struct buffer_s buff) {
|
|
79
82
|
void *tmp = realloc(buff.data, buff.size);
|
80
83
|
if (!tmp) {
|
81
84
|
free_ws_buffer(owner, buff);
|
82
|
-
buff.data = NULL;
|
83
85
|
buff.size = 0;
|
84
86
|
}
|
85
87
|
buff.data = tmp;
|
@@ -174,6 +176,7 @@ static void websocket_on_protocol_ping(void *ws_p, void *msg_, uint64_t len) {
|
|
174
176
|
ws_s *ws = ws_p;
|
175
177
|
if (msg_) {
|
176
178
|
void *buff = malloc(len + 16);
|
179
|
+
FIO_ASSERT_ALLOC(buff);
|
177
180
|
len = (((ws_s *)ws)->is_client
|
178
181
|
? websocket_client_wrap(buff, msg_, len, 10, 1, 1, 0)
|
179
182
|
: websocket_server_wrap(buff, msg_, len, 10, 1, 1, 0));
|
@@ -305,6 +308,7 @@ Create/Destroy the websocket object
|
|
305
308
|
static ws_s *new_websocket(intptr_t uuid) {
|
306
309
|
// allocate the protocol object
|
307
310
|
ws_s *ws = malloc(sizeof(*ws));
|
311
|
+
FIO_ASSERT_ALLOC(ws);
|
308
312
|
*ws = (ws_s){
|
309
313
|
.protocol.ping = ws_ping,
|
310
314
|
.protocol.on_data = on_data_first,
|
@@ -330,7 +334,6 @@ static void destroy_ws(ws_s *ws) {
|
|
330
334
|
void websocket_attach(intptr_t uuid, http_settings_s *http_settings,
|
331
335
|
websocket_settings_s *args, void *data, size_t length) {
|
332
336
|
ws_s *ws = new_websocket(uuid);
|
333
|
-
FIO_ASSERT_ALLOC(ws);
|
334
337
|
// we have an active websocket connection - prep the connection buffer
|
335
338
|
ws->buffer = create_ws_buffer(ws);
|
336
339
|
// Setup ws callbacks
|
@@ -383,6 +386,7 @@ static void websocket_write_impl(intptr_t fd, void *data, size_t len, char text,
|
|
383
386
|
char first, char last, char client) {
|
384
387
|
if (len <= WS_MAX_FRAME_SIZE) {
|
385
388
|
void *buff = fio_malloc(len + 16);
|
389
|
+
FIO_ASSERT_ALLOC(buff);
|
386
390
|
len = (client ? websocket_client_wrap(buff, data, len, (text ? 1 : 2),
|
387
391
|
first, last, 0)
|
388
392
|
: websocket_server_wrap(buff, data, len, (text ? 1 : 2),
|
data/iodine.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Boaz Segev']
|
10
10
|
spec.email = ['bo@plezi.io']
|
11
11
|
|
12
|
-
spec.summary = 'iodine - a fast HTTP / Websocket Server with Pub/Sub support, optimized for Ruby MRI on Linux / BSD'
|
13
|
-
spec.description = 'A fast HTTP / Websocket Server with built-in Pub/Sub support (with or without Redis), static file support and many other features, optimized for Ruby MRI on Linux / BSD / macOS'
|
12
|
+
spec.summary = 'iodine - a fast HTTP / Websocket Server with Pub/Sub support, optimized for Ruby MRI on Linux / BSD / Windows'
|
13
|
+
spec.description = 'A fast HTTP / Websocket Server with built-in Pub/Sub support (with or without Redis), static file support and many other features, optimized for Ruby MRI on Linux / BSD / macOS / Windows'
|
14
14
|
spec.homepage = 'https://github.com/boazsegev/iodine'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
@@ -35,10 +35,11 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.requirements << 'An updated C compiler.'
|
36
36
|
spec.requirements << 'Ruby >= 2.3.8 (Ruby EOL).'
|
37
37
|
spec.requirements << 'Ruby >= 2.5.0 recommended.'
|
38
|
-
spec.requirements << 'TLS requires OpenSSL >= 1.1.0'
|
38
|
+
spec.requirements << 'TLS requires OpenSSL >= 1.1.0.'
|
39
|
+
spec.requirements << 'Or Windows with Ruby >= 3.0.0 build with MingW and MingW as compiler.'
|
39
40
|
|
40
41
|
# spec.add_development_dependency 'bundler', '>= 1.10', '< 2.0'
|
41
|
-
spec.add_development_dependency 'rake', '
|
42
|
+
spec.add_development_dependency 'rake', '>= 12.0', '< 14.0'
|
42
43
|
spec.add_development_dependency 'minitest', '>=5', '< 6.0'
|
43
44
|
spec.add_development_dependency 'rspec', '>=3.9.0', '< 4.0'
|
44
45
|
spec.add_development_dependency 'spec', '>=5.3.0', '< 6.0'
|
data/lib/iodine/version.rb
CHANGED