iodine 0.7.41 → 0.7.45

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +24 -0
  5. data/README.md +2 -2
  6. data/SPEC-PubSub-Draft.md +89 -47
  7. data/SPEC-WebSocket-Draft.md +92 -55
  8. data/examples/async_task.ru +92 -0
  9. data/ext/iodine/extconf.rb +21 -16
  10. data/ext/iodine/fio.c +1108 -162
  11. data/ext/iodine/fio.h +49 -13
  12. data/ext/iodine/fio_cli.c +1 -1
  13. data/ext/iodine/fio_tls_missing.c +8 -0
  14. data/ext/iodine/fio_tls_openssl.c +8 -0
  15. data/ext/iodine/fio_tmpfile.h +13 -1
  16. data/ext/iodine/fiobj_data.c +6 -4
  17. data/ext/iodine/fiobj_data.h +2 -1
  18. data/ext/iodine/fiobj_hash.c +32 -6
  19. data/ext/iodine/fiobj_mustache.c +9 -0
  20. data/ext/iodine/fiobj_numbers.c +86 -8
  21. data/ext/iodine/fiobj_str.c +24 -11
  22. data/ext/iodine/fiobject.c +1 -1
  23. data/ext/iodine/fiobject.h +5 -3
  24. data/ext/iodine/http.c +66 -10
  25. data/ext/iodine/http1.c +2 -1
  26. data/ext/iodine/http1_parser.h +1065 -103
  27. data/ext/iodine/http_internal.c +1 -0
  28. data/ext/iodine/http_internal.h +4 -2
  29. data/ext/iodine/iodine.c +66 -1
  30. data/ext/iodine/iodine.h +3 -0
  31. data/ext/iodine/iodine_caller.c +48 -8
  32. data/ext/iodine/iodine_connection.c +24 -8
  33. data/ext/iodine/iodine_http.c +32 -8
  34. data/ext/iodine/iodine_mustache.c +2 -4
  35. data/ext/iodine/iodine_rack_io.c +21 -0
  36. data/ext/iodine/iodine_tcp.c +14 -0
  37. data/ext/iodine/iodine_tls.c +8 -0
  38. data/ext/iodine/mustache_parser.h +4 -0
  39. data/ext/iodine/redis_engine.c +14 -11
  40. data/ext/iodine/websockets.c +7 -3
  41. data/iodine.gemspec +5 -4
  42. data/lib/iodine/version.rb +1 -1
  43. data/lib/rack/handler/iodine.rb +6 -0
  44. metadata +15 -13
@@ -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);
@@ -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
- .private_data.vtbl = h->private_data.vtbl,
125
- .private_data.flag = h->private_data.flag,
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
@@ -33,6 +33,7 @@ VALUE IodineBaseModule;
33
33
  VALUE iodine_default_args;
34
34
 
35
35
  ID iodine_call_id;
36
+ ID iodine_to_s_id;
36
37
 
37
38
  static VALUE address_sym;
38
39
  static VALUE app_sym;
@@ -412,7 +413,7 @@ static VALUE iodine_cli_parse(VALUE self) {
412
413
  FIO_CLI_PRINT_HEADER("WebSocket Settings:"),
413
414
  FIO_CLI_INT("-max-msg -maxms incoming WebSocket message limit in Kb. "
414
415
  "Default: 250Kb"),
415
- FIO_CLI_INT("-ping websocket ping interval (0..255). Default: 40s"),
416
+ FIO_CLI_INT("-ping websocket ping interval (1..255). Default: 40s"),
416
417
  FIO_CLI_PRINT_HEADER("SSL/TLS:"),
417
418
  FIO_CLI_BOOL("-tls enable SSL/TLS using a self-signed certificate."),
418
419
  FIO_CLI_STRING(
@@ -518,6 +519,7 @@ static VALUE iodine_cli_parse(VALUE self) {
518
519
  rb_hash_aset(defaults, max_headers_sym,
519
520
  INT2NUM((fio_cli_get_i("-maxhd") /* * 1024 */)));
520
521
  }
522
+ #ifndef __MINGW32__
521
523
  if (fio_cli_get_bool("-tls") || fio_cli_get("-key") || fio_cli_get("-cert")) {
522
524
  VALUE rbtls = IodineCaller.call(IodineTLSClass, rb_intern2("new", 3));
523
525
  if (rbtls == Qnil) {
@@ -542,6 +544,7 @@ static VALUE iodine_cli_parse(VALUE self) {
542
544
  }
543
545
  rb_hash_aset(defaults, tls_sym, rbtls);
544
546
  }
547
+ #endif
545
548
  if (fio_cli_unnamed_count()) {
546
549
  rb_hash_aset(defaults, ID2SYM(rb_intern("filename_")),
547
550
  rb_str_new_cstr(fio_cli_unnamed(0)));
@@ -633,8 +636,10 @@ FIO_FUNC void iodine_connect_args_cleanup(iodine_connection_args_s *s) {
633
636
  fio_free(s->port.data);
634
637
  if (s->address.capa)
635
638
  fio_free(s->address.data);
639
+ #ifndef __MINGW32__
636
640
  if (s->tls)
637
641
  fio_tls_destroy(s->tls);
642
+ #endif
638
643
  }
639
644
 
640
645
  /*
@@ -685,7 +690,9 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
685
690
  VALUE r_public = rb_hash_aref(s, public_sym);
686
691
  VALUE service = rb_hash_aref(s, service_sym);
687
692
  VALUE timeout = rb_hash_aref(s, timeout_sym);
693
+ #ifndef __MINGW32__
688
694
  VALUE tls = rb_hash_aref(s, tls_sym);
695
+ #endif
689
696
  VALUE r_url = rb_hash_aref(s, url_sym);
690
697
  fio_str_info_s service_str = {.data = NULL};
691
698
 
@@ -725,8 +732,10 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
725
732
  // service = rb_hash_aref(iodine_default_args, service_sym);
726
733
  if (timeout == Qnil)
727
734
  timeout = rb_hash_aref(iodine_default_args, timeout_sym);
735
+ #ifndef __MINGW32__
728
736
  if (tls == Qnil)
729
737
  tls = rb_hash_aref(iodine_default_args, tls_sym);
738
+ #endif
730
739
 
731
740
  /* TODO: deprecation */
732
741
  if (handler == Qnil) {
@@ -823,11 +832,13 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
823
832
  else
824
833
  r.timeout = FIX2ULONG(timeout);
825
834
  }
835
+ #ifndef __MINGW32__
826
836
  if (tls != Qnil) {
827
837
  r.tls = iodine_tls2c(tls);
828
838
  if (r.tls)
829
839
  fio_tls_dup(r.tls);
830
840
  }
841
+ #endif
831
842
  /* URL parsing */
832
843
  if (r_url != Qnil && RB_TYPE_P(r_url, T_STRING)) {
833
844
  r.url = IODINE_RSTRINFO(r_url);
@@ -887,6 +898,56 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
887
898
  /* test/set service type */
888
899
  r.service = IODINE_SERVICE_RAW;
889
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
890
951
  switch (service_str.data[0]) {
891
952
  case 't': /* overflow */
892
953
  /* tcp or tls */
@@ -938,6 +999,7 @@ FIO_FUNC iodine_connection_args_s iodine_connect_args(VALUE s, uint8_t is_srv) {
938
999
  }
939
1000
  break;
940
1001
  }
1002
+ #endif
941
1003
  }
942
1004
  return r;
943
1005
  }
@@ -1302,6 +1364,7 @@ void Init_iodine(void) {
1302
1364
  IodineBaseModule = rb_define_module_under(IodineModule, "Base");
1303
1365
  VALUE IodineCLIModule = rb_define_module_under(IodineBaseModule, "CLI");
1304
1366
  iodine_call_id = rb_intern2("call", 4);
1367
+ iodine_to_s_id = rb_intern("to_s");
1305
1368
 
1306
1369
  // register core methods
1307
1370
  rb_define_module_function(IodineModule, "threads", iodine_threads_get, 0);
@@ -1347,8 +1410,10 @@ void Init_iodine(void) {
1347
1410
  // initialize the HTTP module
1348
1411
  iodine_init_http();
1349
1412
 
1413
+ #ifndef __MINGW32__
1350
1414
  // initialize SSL/TLS support module
1351
1415
  iodine_init_tls();
1416
+ #endif
1352
1417
 
1353
1418
  // initialize JSON helpers
1354
1419
  iodine_init_json();
data/ext/iodine/iodine.h CHANGED
@@ -15,7 +15,9 @@ typedef struct {
15
15
  fio_str_info_s body;
16
16
  fio_str_info_s public;
17
17
  fio_str_info_s url;
18
+ #ifndef __MINGW32__
18
19
  fio_tls_s *tls;
20
+ #endif
19
21
  VALUE handler;
20
22
  FIOBJ headers;
21
23
  FIOBJ cookies;
@@ -53,6 +55,7 @@ extern VALUE IodineModule;
53
55
  extern VALUE IodineBaseModule;
54
56
  extern VALUE iodine_default_args;
55
57
  extern ID iodine_call_id;
58
+ extern ID iodine_to_s_id;
56
59
 
57
60
  #define IODINE_RSTRINFO(rstr) \
58
61
  ((fio_str_info_s){.len = RSTRING_LEN(rstr), .data = RSTRING_PTR(rstr)})
@@ -5,7 +5,19 @@
5
5
 
6
6
  #include <fio.h>
7
7
 
8
- static __thread volatile uint8_t iodine_GVL_state;
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
- if (iodine_GVL_state) {
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) { return iodine_GVL_state; }
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) { iodine_GVL_state = 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
@@ -159,7 +159,7 @@ Ruby Connection Methods - write, close open? pending
159
159
  ***************************************************************************** */
160
160
 
161
161
  /**
162
- * Writes data to the connection asynchronously.
162
+ * Writes data to the connection asynchronously. `data` MUST be a String.
163
163
  *
164
164
  * In effect, the `write` call does nothing, it only schedules the data to be
165
165
  * sent and marks the data as pending.
@@ -174,6 +174,16 @@ static VALUE iodine_connection_write(VALUE self, VALUE data) {
174
174
  return Qnil;
175
175
  // rb_raise(rb_eIOError, "Connection closed or invalid.");
176
176
  }
177
+ if (!RB_TYPE_P(data, T_STRING)) {
178
+ VALUE tmp = data;
179
+ data = IodineCaller.call(data, iodine_to_s_id);
180
+ if (!RB_TYPE_P(data, T_STRING))
181
+ Check_Type(tmp, T_STRING);
182
+ rb_backtrace();
183
+ FIO_LOG_WARNING(
184
+ "`Iodine::Connection#write` was called with a non-String object.");
185
+ }
186
+
177
187
  switch (c->info.type) {
178
188
  case IODINE_CONNECTION_WEBSOCKET:
179
189
  /* WebSockets*/
@@ -234,6 +244,14 @@ static VALUE iodine_connection_is_open(VALUE self) {
234
244
  }
235
245
  return Qfalse;
236
246
  }
247
+
248
+ /**
249
+ * Always returns true, since Iodine connections support the pub/sub extension.
250
+ */
251
+ static VALUE iodine_connection_is_pubsub(VALUE self) {
252
+ return INT2NUM(0);
253
+ (void)self;
254
+ }
237
255
  /**
238
256
  * Returns the number of pending `write` operations that need to complete
239
257
  * before the next `on_drained` callback is called.
@@ -385,8 +403,12 @@ static void *iodine_on_pubsub_call_block(void *msg_) {
385
403
  fio_msg_s *msg = msg_;
386
404
  VALUE args[2];
387
405
  args[0] = rb_str_new(msg->channel.data, msg->channel.len);
406
+ IodineStore.add(args[0]);
388
407
  args[1] = rb_str_new(msg->msg.data, msg->msg.len);
408
+ IodineStore.add(args[1]);
389
409
  IodineCaller.call2((VALUE)msg->udata2, call_id, 2, args);
410
+ IodineStore.remove(args[1]);
411
+ IodineStore.remove(args[0]);
390
412
  return NULL;
391
413
  }
392
414
 
@@ -675,13 +697,6 @@ The method accepts an optional `engine` argument:
675
697
 
676
698
  publish(to, message, my_pubsub_engine)
677
699
 
678
-
679
- Alternatively, accepts the following named arguments:
680
-
681
- - `:to` - The channel to publish to (required).
682
- - `:message` - The message to be published (required).
683
- - `:engine` - If provided, the engine to use for pub/sub. Otherwise the default engine is used.
684
-
685
700
  */
686
701
  static VALUE iodine_pubsub_publish(int argc, VALUE *argv, VALUE self) {
687
702
  // clang-format on
@@ -903,6 +918,7 @@ void iodine_connection_init(void) {
903
918
  0);
904
919
  rb_define_method(ConnectionKlass, "handler=", iodine_connection_handler_set,
905
920
  1);
921
+ rb_define_method(ConnectionKlass, "pubsub?", iodine_connection_is_pubsub, 0);
906
922
  rb_define_method(ConnectionKlass, "subscribe", iodine_pubsub_subscribe, -1);
907
923
  rb_define_method(ConnectionKlass, "unsubscribe", iodine_pubsub_unsubscribe,
908
924
  1);
@@ -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
@@ -51,7 +55,6 @@ static VALUE hijack_func_sym;
51
55
  static ID close_method_id;
52
56
  static ID each_method_id;
53
57
  static ID attach_method_id;
54
- static ID iodine_to_s_method_id;
55
58
  static ID iodine_call_proc_id;
56
59
 
57
60
  static VALUE env_template_no_upgrade;
@@ -294,9 +297,9 @@ static int iodine_copy2env_task(FIOBJ o, void *env_) {
294
297
 
295
298
  } else {
296
299
  /* it's an array */
297
- VALUE ary = rb_ary_new();
298
- rb_hash_aset(env, hname, ary);
299
300
  size_t count = fiobj_ary_count(o);
301
+ VALUE ary = rb_ary_new2(count);
302
+ rb_hash_aset(env, hname, ary);
300
303
  for (size_t i = 0; i < count; ++i) {
301
304
  tmp = fiobj_obj2cstr(fiobj_ary_index(o, i));
302
305
  rb_ary_push(ary, rb_enc_str_new(tmp.data, tmp.len, IodineBinaryEncoding));
@@ -476,11 +479,11 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
476
479
  http_s *h = (http_s *)h_;
477
480
  // fprintf(stderr, "For_each - headers\n");
478
481
  if (TYPE(key) != T_STRING)
479
- key = IodineCaller.call(key, iodine_to_s_method_id);
482
+ key = IodineCaller.call(key, iodine_to_s_id);
480
483
  if (TYPE(key) != T_STRING)
481
484
  return ST_CONTINUE;
482
485
  if (TYPE(val) != T_STRING) {
483
- val = IodineCaller.call(val, iodine_to_s_method_id);
486
+ val = IodineCaller.call(val, iodine_to_s_id);
484
487
  if (TYPE(val) != T_STRING)
485
488
  return ST_STOP;
486
489
  }
@@ -556,9 +559,11 @@ static inline int ruby2c_response_send(iodine_http_request_handle_s *handle,
556
559
 
557
560
  if (TYPE(body) == T_STRING) {
558
561
  // fprintf(stderr, "Review body as String\n");
559
- if (RSTRING_LEN(body))
562
+ handle->type = IODINE_HTTP_NONE;
563
+ if (RSTRING_LEN(body)) {
560
564
  handle->body = fiobj_str_new(RSTRING_PTR(body), RSTRING_LEN(body));
561
- handle->type = IODINE_HTTP_SENDBODY;
565
+ handle->type = IODINE_HTTP_SENDBODY;
566
+ }
562
567
  return 0;
563
568
  } else if (rb_respond_to(body, each_method_id)) {
564
569
  // fprintf(stderr, "Review body as for-each ...\n");
@@ -937,6 +942,15 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
937
942
  support_xsendfile = 1;
938
943
  }
939
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
940
954
  intptr_t uuid = http_listen(
941
955
  args.port.data, args.address.data, .on_request = on_rack_request,
942
956
  .on_upgrade = on_rack_upgrade, .udata = (void *)args.handler,
@@ -944,6 +958,7 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
944
958
  .ws_max_msg_size = args.max_msg, .max_header_size = args.max_headers,
945
959
  .on_finish = free_iodine_http, .log = args.log,
946
960
  .max_body_size = args.max_body, .public_folder = args.public.data);
961
+ #endif
947
962
  if (uuid == -1)
948
963
  return uuid;
949
964
 
@@ -1053,9 +1068,11 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
1053
1068
  FIOBJ url_tmp = FIOBJ_INVALID;
1054
1069
  if (!args.url.data) {
1055
1070
  url_tmp = fiobj_str_buf(64);
1071
+ #ifndef __MINGW32__
1056
1072
  if (args.tls)
1057
1073
  fiobj_str_write(url_tmp, "wss://", 6);
1058
1074
  else
1075
+ #endif
1059
1076
  fiobj_str_write(url_tmp, "ws://", 5);
1060
1077
  if (!is_unix_socket) {
1061
1078
  fiobj_str_write(url_tmp, args.address.data, args.address.len);
@@ -1071,11 +1088,19 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
1071
1088
  args.url = fiobj_obj2cstr(url_tmp);
1072
1089
  }
1073
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
1074
1098
  intptr_t uuid = http_connect(
1075
1099
  args.url.data, (is_unix_socket ? args.address.data : NULL),
1076
1100
  .udata = request_data_create(&args),
1077
1101
  .on_response = ws_client_http_connected,
1078
1102
  .on_finish = ws_client_http_connection_finished, .tls = args.tls);
1103
+ #endif
1079
1104
  fiobj_free(url_tmp);
1080
1105
  return uuid;
1081
1106
  }
@@ -1130,7 +1155,6 @@ void iodine_init_http(void) {
1130
1155
  close_method_id = rb_intern("close");
1131
1156
  each_method_id = rb_intern("each");
1132
1157
  attach_method_id = rb_intern("attach_fd");
1133
- iodine_to_s_method_id = rb_intern("to_s");
1134
1158
  iodine_call_proc_id = rb_intern("call");
1135
1159
 
1136
1160
  IodineUTF8Encoding = rb_enc_find("UTF-8");
@@ -8,7 +8,6 @@
8
8
  #include <fio.h>
9
9
 
10
10
  static ID call_func_id;
11
- static ID to_s_func_id;
12
11
  static VALUE filename_id;
13
12
  static VALUE data_id;
14
13
  static VALUE template_id;
@@ -169,7 +168,7 @@ static int mustache_on_arg(mustache_section_s *section, const char *name,
169
168
  if (rb_respond_to(o, call_func_id))
170
169
  o = IodineCaller.call(o, call_func_id);
171
170
  if (!RB_TYPE_P(o, T_STRING))
172
- o = IodineCaller.call(o, to_s_func_id);
171
+ o = IodineCaller.call(o, iodine_to_s_id);
173
172
  }
174
173
  if (!RB_TYPE_P(o, T_STRING) || !RSTRING_LEN(o))
175
174
  return 0;
@@ -220,7 +219,7 @@ static int32_t mustache_on_section_test(mustache_section_s *section,
220
219
  }
221
220
  o = IodineCaller.call2(o, call_func_id, 1, &str);
222
221
  if (!RB_TYPE_P(o, T_STRING))
223
- o = rb_funcall2(o, to_s_func_id, 0, NULL);
222
+ o = rb_funcall2(o, iodine_to_s_id, 0, NULL);
224
223
  if (RB_TYPE_P(o, T_STRING) && RSTRING_LEN(o))
225
224
  mustache_write_text(section, RSTRING_PTR(o), RSTRING_LEN(o), 0);
226
225
  return 0;
@@ -553,7 +552,6 @@ Initialize Iodine::Mustache
553
552
 
554
553
  void iodine_init_mustache(void) {
555
554
  call_func_id = rb_intern2("call", 4);
556
- to_s_func_id = rb_intern2("to_s", 4);
557
555
  filename_id = rb_id2sym(rb_intern2("filename", 8));
558
556
  data_id = rb_id2sym(rb_intern2("data", 4));
559
557
  template_id = rb_id2sym(rb_intern2("template", 8));
@@ -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,11 @@ 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);
75
+ #ifdef __MINGW32__
76
+ return (http_s *)NUM2ULL(i);
77
+ #else
72
78
  return (http_s *)FIX2ULONG(i);
79
+ #endif
73
80
  }
74
81
 
75
82
  /* *****************************************************************************
@@ -78,7 +85,11 @@ IO API
78
85
 
79
86
  static inline FIOBJ get_data(VALUE self) {
80
87
  VALUE i = rb_ivar_get(self, io_id);
88
+ #ifdef __MINGW32__
89
+ return (FIOBJ)NUM2ULL(i);
90
+ #else
81
91
  return (FIOBJ)FIX2ULONG(i);
92
+ #endif
82
93
  }
83
94
 
84
95
  static VALUE rio_rewind(VALUE self) {
@@ -196,7 +207,14 @@ static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
196
207
  set_handle(self, NULL);
197
208
  // hijack the IO object
198
209
  intptr_t uuid = http_hijack(h, NULL);
210
+ #ifdef __MINGW32__
211
+ int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
212
+ if (osffd == -1)
213
+ return Qfalse;
214
+ VALUE fd = INT2FIX(osffd);
215
+ #else
199
216
  VALUE fd = INT2FIX(fio_uuid2fd(uuid));
217
+ #endif
200
218
  // VALUE new_io = how the fuck do we create a new IO from the fd?
201
219
  VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
202
220
  &fd); // TCPSocket.for_fd(fd) ... cool...
@@ -238,6 +256,9 @@ static void init_rack_io(void) {
238
256
  for_fd_id = rb_intern("for_fd");
239
257
  iodine_fd_var_id = rb_intern("fd");
240
258
  iodine_new_func_id = rb_intern("new");
259
+ #ifdef __MINGW32__
260
+ iodine_osffd_id = rb_intern("osffd");
261
+ #endif
241
262
  hijack_func_sym = ID2SYM(rb_intern("_hijack"));
242
263
 
243
264
  TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
@@ -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
@@ -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