iodine 0.7.41 → 0.7.45

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