iodine 0.7.43 → 0.7.46
Sign up to get free protection for your applications and to get access to all the features.
- 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