iodine 0.7.23 → 0.7.24

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f79c66c0601bd9b530d826440476bb2c670c641b0d249ecef01b68d50cf3bee
4
- data.tar.gz: 63e8eda390f1e86a2d585e8173c1681dee333b68a5efb09cda2b00e81ecda75f
3
+ metadata.gz: 14bd75ae5e5c3c0c2fa768fa147a4dfdeb27feb66b7db6896478814cd06c8452
4
+ data.tar.gz: 84b5ee6178d1bc91945a43d79d4180d08a90f4975d74ef62f7ec0c9e7cea9b66
5
5
  SHA512:
6
- metadata.gz: e00867e6c5cf0efa7925af1cd9ee5d16869df7563b7cc9ce2c52551db679689fbfaf7b2991561ce0098bc959dacdd2e1499f26657a7d01be5e4bf056256deb38
7
- data.tar.gz: 18c9c99f0b8d5a191f691e0945aea15244e23f49d69a182bed501655dc263e3d2c8162f994049e9ac66e3e1c8373b53540a28b68c5aebe0d4a0d0ac88383a2c2
6
+ metadata.gz: 39c5fcb1bd65f16a20854493d900f39bcdd8dcf705828af5dabec5842290ac879c5dd3e2fd8c7eaa491cf90b3ef81a68636f34744a85bd23483c7545c2acf518
7
+ data.tar.gz: 1743ce505418cc271f1607632dddbadaddf88aa6ba8c22fa1b459df8a8a70b19007bc14dba93860971bebb0e7a84b643812dea4e66af0ea95b48cc2415122161
@@ -6,6 +6,16 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.7.24
10
+
11
+ **Fix**: (`fio`) fixed server shutdown on pub/sub stress, where internal pub/sub stress was mistakingly identified as a Slowloris attack. Credit to @moxgeek (Marouane Elmidaoui) for exposing this issue (plezi#32).
12
+
13
+ **Fix**: (`fio`): fixed Slowloris detection for buffer attack variation.
14
+
15
+ **Fix**: (`fio`): fixed `pending` result, where packet count wouldn't decrement until queue was drained.
16
+
17
+ **Updates**: (`fio`) facil.io updates, including pub/sub memory improvements for cluster mode.
18
+
9
19
  #### Change log v.0.7.23
10
20
 
11
21
  **Fix**: (`fio`): fixed logging message for overflowing log messages. Credit to @weskerfoot (Wesley Kerfoot) and @adam12 (Adam Daniels) for exposing the issue (issue #56).
data/README.md CHANGED
@@ -64,7 +64,28 @@ Then start your application from the command-line / terminal using iodine:
64
64
  bundler exec iodine
65
65
  ```
66
66
 
67
- **KNOWN ISSUE:** the installation script tests for OpenSSL 1.1.0 and above. However, this testing approach sometimes provides false positives. If TLS isn't required, install with `NO_SSL=1`. i.e.:
67
+ #### Installing with SSL/TLS
68
+
69
+ Make sure to update OpenSSL to the latest version **before installing Ruby** (`rbenv` should do this automatically).
70
+
71
+ To avoid name resolution conflicts, iodine will bind to the same OpenSSL version Ruby is bound to. To use SSL/TLS this should be OpenSSL >= 1.1.0 or LibreSSL >= 2.7.4.
72
+
73
+ Verbose installation should provide a confirmation message, such as:
74
+
75
+ ```bash
76
+ $ gem install iodine -f -V
77
+ ...
78
+ checking for -lcrypto... yes
79
+ checking for -lssl... yes
80
+ Detected OpenSSL library, testing for version.
81
+ Confirmed OpenSSL to be version 1.1.0 or above (OpenSSL 1.1.0j 20 Nov 2018)...
82
+ * Compiling with HAVE_OPENSSL.
83
+ ...
84
+ ```
85
+
86
+ **KNOWN ISSUE:**
87
+
88
+ The installation script tests for OpenSSL 1.1.0 and above. However, this testing approach sometimes provides false positives. If TLS isn't required, install with `NO_SSL=1`. i.e.:
68
89
 
69
90
  ```bash
70
91
  NO_SSL=1 bundler exec iodine
@@ -29,17 +29,34 @@ else
29
29
  puts 'using an unknown (old?) compiler... who knows if this will work out... we hope.'
30
30
  end
31
31
 
32
-
33
32
  # Test for OpenSSL version equal to 1.0.0 or greater.
34
- unless ENV['NO_SSL']
33
+ unless ENV['NO_SSL'] || ENV['NO_TLS'] || ENV["DISABLE_SSL"]
34
+ OPENSSL_TEST_CODE = <<EOS
35
+ \#include <openssl/bio.h>
36
+ \#include <openssl/err.h>
37
+ \#include <openssl/ssl.h>
38
+ \#if OPENSSL_VERSION_NUMBER < 0x10100000L
39
+ \#error "OpenSSL version too small"
40
+ \#endif
41
+ int main(void) {
42
+ SSL_library_init();
43
+ SSL_CTX *ctx = SSL_CTX_new(TLS_method());
44
+ SSL *ssl = SSL_new(ctx);
45
+ BIO *bio = BIO_new_socket(3, 0);
46
+ BIO_up_ref(bio);
47
+ SSL_set0_rbio(ssl, bio);
48
+ SSL_set0_wbio(ssl, bio);
49
+ }
50
+ EOS
51
+
52
+ dir_config("openssl")
35
53
  begin
36
54
  require 'openssl'
37
55
  rescue LoadError
38
56
  else
39
57
  if have_library('crypto') && have_library('ssl')
40
- puts "Detected OpenSSL library, testing for version."
41
- if try_compile("\#include <openssl/ssl.h>\r\#if OPENSSL_VERSION_NUMBER < 0x10100000L\r\#error \"OpenSSL version too small\"\r\#endif\rint main(void) { SSL_library_init(); }")
42
- # if ((OpenSSL::OPENSSL_VERSION_NUMBER >> 24) > 16) || (((OpenSSL::OPENSSL_VERSION_NUMBER >> 24) == 16) && (((OpenSSL::OPENSSL_VERSION_NUMBER >> 16) & 255) >= 16))
58
+ puts "Detected OpenSSL library, testing for version and required functions."
59
+ if try_compile(OPENSSL_TEST_CODE)
43
60
  $defs << "-DHAVE_OPENSSL"
44
61
  puts "Confirmed OpenSSL to be version 1.1.0 or above (#{OpenSSL::OPENSSL_LIBRARY_VERSION})...\n* Compiling with HAVE_OPENSSL."
45
62
  else
@@ -54,6 +71,4 @@ RbConfig::MAKEFILE_CONFIG['CFLAGS'] = $CFLAGS = "-std=c11 -DFIO_PRINT_STATE=0 #{
54
71
  RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
55
72
  RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
56
73
 
57
- # abort "Missing OpenSSL." unless have_library("ssl")
58
-
59
74
  create_makefile 'iodine/iodine'
@@ -2138,15 +2138,18 @@ postpone:
2138
2138
 
2139
2139
  static void deferred_on_ready(void *arg, void *arg2) {
2140
2140
  errno = 0;
2141
- if (fio_flush((intptr_t)arg) > 0 || errno == EWOULDBLOCK) {
2142
- fio_poll_add_write(fio_uuid2fd(arg));
2141
+ if (fio_flush((intptr_t)arg) > 0 || errno == EWOULDBLOCK || errno == EAGAIN) {
2142
+ if (arg2)
2143
+ fio_defer_push_urgent(deferred_on_ready, arg, NULL);
2144
+ else
2145
+ fio_poll_add_write(fio_uuid2fd(arg));
2143
2146
  return;
2144
2147
  }
2145
2148
  if (!uuid_data(arg).protocol) {
2146
2149
  return;
2147
2150
  }
2151
+
2148
2152
  fio_defer_push_task(deferred_on_ready_usr, arg, NULL);
2149
- (void)arg2;
2150
2153
  }
2151
2154
 
2152
2155
  static void deferred_on_data(void *uuid, void *arg2) {
@@ -2571,12 +2574,12 @@ static void fio_sock_perform_close_fd(intptr_t fd) { close(fd); }
2571
2574
  static inline void fio_sock_packet_rotate_unsafe(uintptr_t fd) {
2572
2575
  fio_packet_s *packet = fd_data(fd).packet;
2573
2576
  fd_data(fd).packet = packet->next;
2577
+ fio_atomic_sub(&fd_data(fd).packet_count, 1);
2574
2578
  if (!packet->next) {
2575
2579
  fd_data(fd).packet_last = &fd_data(fd).packet;
2576
2580
  fd_data(fd).packet_count = 0;
2577
2581
  } else if (&packet->next == fd_data(fd).packet_last) {
2578
2582
  fd_data(fd).packet_last = &fd_data(fd).packet;
2579
- fio_atomic_sub(&fd_data(fd).packet_count, 1);
2580
2583
  }
2581
2584
  fio_packet_free(packet);
2582
2585
  }
@@ -2797,7 +2800,7 @@ ssize_t fio_write2_fn(intptr_t uuid, fio_write_args_s options) {
2797
2800
 
2798
2801
  if (was_empty) {
2799
2802
  touchfd(fio_uuid2fd(uuid));
2800
- fio_defer_push_urgent(deferred_on_ready, (void *)uuid, NULL);
2803
+ deferred_on_ready((void *)uuid, (void *)1);
2801
2804
  }
2802
2805
  return 0;
2803
2806
  locked_error:
@@ -2860,7 +2863,7 @@ void fio_force_close(intptr_t uuid) {
2860
2863
  if (!uuid_data(uuid).close)
2861
2864
  uuid_data(uuid).close = 1;
2862
2865
  /* clear away any packets in case we want to cut the connection short. */
2863
- fio_packet_s *packet;
2866
+ fio_packet_s *packet = NULL;
2864
2867
  fio_lock(&uuid_data(uuid).sock_lock);
2865
2868
  packet = uuid_data(uuid).packet;
2866
2869
  uuid_data(uuid).packet = NULL;
@@ -2913,7 +2916,7 @@ ssize_t fio_flush(intptr_t uuid) {
2913
2916
  if (!uuid_data(uuid).packet)
2914
2917
  goto flush_rw_hook;
2915
2918
 
2916
- const size_t old_count = uuid_data(uuid).packet_count;
2919
+ const fio_packet_s *old_packet = uuid_data(uuid).packet;
2917
2920
  const size_t old_sent = uuid_data(uuid).sent;
2918
2921
 
2919
2922
  tmp = uuid_data(uuid).packet->write_func(fio_uuid2fd(uuid),
@@ -2922,7 +2925,8 @@ ssize_t fio_flush(intptr_t uuid) {
2922
2925
  goto test_errno;
2923
2926
  }
2924
2927
 
2925
- if (old_count >= 1024 && uuid_data(uuid).packet_count == old_count &&
2928
+ if (uuid_data(uuid).packet_count >= 1024 &&
2929
+ uuid_data(uuid).packet == old_packet &&
2926
2930
  uuid_data(uuid).sent >= old_sent &&
2927
2931
  (uuid_data(uuid).sent - old_sent) < 32768) {
2928
2932
  /* Slowloris attack assumed */
@@ -2965,11 +2969,16 @@ test_errno:
2965
2969
  #if EWOULDBLOCK != EAGAIN
2966
2970
  case EAGAIN: /* ovreflow */
2967
2971
  #endif
2968
- case ENOTCONN: /* ovreflow */
2969
- case EINPROGRESS: /* ovreflow */
2970
- case ENOSPC: /* ovreflow */
2972
+ case ENOTCONN: /* ovreflow */
2973
+ case EINPROGRESS: /* ovreflow */
2974
+ case ENOSPC: /* ovreflow */
2975
+ case EADDRNOTAVAIL: /* ovreflow */
2971
2976
  case EINTR:
2972
2977
  return 1;
2978
+ case EFAULT:
2979
+ FIO_LOG_ERROR("fio_flush EFAULT - possible memory address error sent to "
2980
+ "Unix socket.");
2981
+ /* ovreflow */
2973
2982
  case EPIPE: /* ovreflow */
2974
2983
  case EIO: /* ovreflow */
2975
2984
  case EINVAL: /* ovreflow */
@@ -2978,6 +2987,8 @@ test_errno:
2978
2987
  fio_force_close(uuid);
2979
2988
  return -1;
2980
2989
  }
2990
+ fprintf(stderr, "UUID error: %p (%d)\n", (void *)uuid, errno);
2991
+ perror("No errno handler");
2981
2992
  return 0;
2982
2993
 
2983
2994
  invalid:
@@ -3447,14 +3458,13 @@ static void fio_pubsub_on_fork(void);
3447
3458
 
3448
3459
  /* Called within a child process after it starts. */
3449
3460
  static void fio_on_fork(void) {
3461
+ fio_timer_lock = FIO_LOCK_INIT;
3450
3462
  fio_data->lock = FIO_LOCK_INIT;
3451
3463
  fio_defer_on_fork();
3452
3464
  fio_malloc_after_fork();
3453
3465
  fio_poll_init();
3454
3466
  fio_state_callback_on_fork();
3455
- fio_pubsub_on_fork();
3456
- fio_timer_lock = FIO_LOCK_INIT;
3457
- fio_max_fd_shrink();
3467
+
3458
3468
  const size_t limit = fio_data->capa;
3459
3469
  for (size_t i = 0; i < limit; ++i) {
3460
3470
  fd_data(i).sock_lock = FIO_LOCK_INIT;
@@ -3464,6 +3474,9 @@ static void fio_on_fork(void) {
3464
3474
  fio_force_close(fd2uuid(i));
3465
3475
  }
3466
3476
  }
3477
+
3478
+ fio_pubsub_on_fork();
3479
+ fio_max_fd_shrink();
3467
3480
  uint16_t old_active = fio_data->active;
3468
3481
  fio_data->active = 0;
3469
3482
  fio_defer_perform();
@@ -5180,8 +5193,6 @@ fio_pubsub_engine_s *FIO_PUBSUB_DEFAULT = FIO_PUBSUB_CLUSTER;
5180
5193
  Internal message object creation
5181
5194
  ***************************************************************************** */
5182
5195
 
5183
- #if 1 /* Copy Meta-Data Array vs. lock and unlock per callback */
5184
-
5185
5196
  /** returns a temporary fio_meta_ary_s with a copy of the metadata array */
5186
5197
  static fio_meta_ary_s fio_postoffice_meta_copy_new(void) {
5187
5198
  fio_meta_ary_s t = FIO_ARY_INIT;
@@ -5189,56 +5200,17 @@ static fio_meta_ary_s fio_postoffice_meta_copy_new(void) {
5189
5200
  return t;
5190
5201
  }
5191
5202
  fio_lock(&fio_postoffice.meta.lock);
5192
- size_t len = fio_meta_ary_count(&fio_postoffice.meta.ary);
5193
- if (len) {
5194
- t.end = t.capa = len;
5195
- t.arry = fio_malloc(sizeof(*t.arry) * len);
5196
- FIO_ASSERT_ALLOC(t.arry);
5197
- memcpy(t.arry, fio_meta_ary_to_a(&fio_postoffice.meta.ary),
5198
- sizeof(*t.arry) * len);
5199
- }
5203
+ fio_meta_ary_concat(&t, &fio_postoffice.meta.ary);
5200
5204
  fio_unlock(&fio_postoffice.meta.lock);
5201
5205
  return t;
5202
5206
  }
5203
5207
 
5204
5208
  /** frees a temporary copy created by postoffice_meta_copy_new */
5205
- static void fio_postoffice_meta_copy_free(fio_meta_ary_s cpy) {
5206
- fio_free(cpy.arry);
5207
- }
5208
-
5209
- static fio_msg_internal_s *
5210
- fio_pubsub_create_message(int32_t filter, fio_str_info_s ch,
5211
- fio_str_info_s data, int8_t is_json, int8_t cpy) {
5212
- fio_meta_ary_s t = FIO_ARY_INIT;
5213
- if (!filter)
5214
- t = fio_postoffice_meta_copy_new();
5215
- fio_msg_internal_s *m = fio_malloc(sizeof(*m) + (sizeof(*m->meta) * t.end) +
5216
- (ch.len + 1) + (data.len + 1));
5217
- *m = (fio_msg_internal_s){
5218
- .filter = filter,
5219
- .channel =
5220
- (fio_str_info_s){.data = (char *)(m->meta + t.end), .len = ch.len},
5221
- .data = (fio_str_info_s){.data = ((char *)(m->meta + t.end) + ch.len + 1),
5222
- .len = data.len},
5223
- .is_json = is_json,
5224
- .ref = 1,
5225
- .meta_len = t.end,
5226
- };
5227
- // m->channel.data[ch.len] = 0; /* redundant, fio_malloc is all zero */
5228
- // m->data.data[data.len] = 0; /* redundant, fio_malloc is all zero */
5229
- if (cpy) {
5230
- memcpy(m->channel.data, ch.data, ch.len);
5231
- memcpy(m->data.data, data.data, data.len);
5232
- while (t.end) {
5233
- --t.end;
5234
- m->meta[t.end] = t.arry[t.end](m->channel, m->data, is_json);
5235
- }
5236
- }
5237
- fio_postoffice_meta_copy_free(t);
5238
- return m;
5209
+ static inline void fio_postoffice_meta_copy_free(fio_meta_ary_s *cpy) {
5210
+ fio_meta_ary_free(cpy);
5239
5211
  }
5240
5212
 
5241
- static void fio_pubsub_create_message_update_meta(fio_msg_internal_s *m) {
5213
+ static void fio_postoffice_meta_update(fio_msg_internal_s *m) {
5242
5214
  if (m->filter || !m->meta_len)
5243
5215
  return;
5244
5216
  fio_meta_ary_s t = fio_postoffice_meta_copy_new();
@@ -5249,119 +5221,102 @@ static void fio_pubsub_create_message_update_meta(fio_msg_internal_s *m) {
5249
5221
  --t.end;
5250
5222
  m->meta[t.end] = t.arry[t.end](m->channel, m->data, m->is_json);
5251
5223
  }
5252
- fio_postoffice_meta_copy_free(t);
5253
- }
5254
-
5255
- #else
5256
-
5257
- /** returns the pub/sub metadata count safely (locks) */
5258
- static size_t fio_postoffice_meta_count(void) {
5259
- size_t count;
5260
- fio_lock(&fio_postoffice.meta.lock);
5261
- count = fio_meta_ary_count(&fio_postoffice.meta.ary);
5262
- fio_unlock(&fio_postoffice.meta.lock);
5263
- return count;
5264
- }
5265
- /** collects a callback by index, from within a loop */
5266
- static fio_msg_metadata_fn fio_postoffice_meta_index(intptr_t index) {
5267
- fio_msg_metadata_fn cb;
5268
- fio_lock(&fio_postoffice.meta.lock);
5269
- cb = fio_meta_ary_get(&fio_postoffice.meta.ary, index);
5270
- fio_unlock(&fio_postoffice.meta.lock);
5271
- return cb;
5224
+ fio_postoffice_meta_copy_free(&t);
5272
5225
  }
5273
5226
 
5274
5227
  static fio_msg_internal_s *
5275
- fio_pubsub_create_message(int32_t filter, fio_str_info_s ch,
5276
- fio_str_info_s data, int8_t is_json, int8_t cpy) {
5277
- size_t meta_len = 0;
5228
+ fio_msg_internal_create(int32_t filter, uint32_t type, fio_str_info_s ch,
5229
+ fio_str_info_s data, int8_t is_json, int8_t cpy) {
5230
+ fio_meta_ary_s t = FIO_ARY_INIT;
5278
5231
  if (!filter)
5279
- meta_len = fio_postoffice_meta_count();
5280
- fio_msg_internal_s *m =
5281
- fio_malloc(sizeof(*m) + (sizeof(*m->meta) * meta_len) + (ch.len + 1) +
5282
- (data.len + 1));
5232
+ t = fio_postoffice_meta_copy_new();
5233
+ fio_msg_internal_s *m = fio_malloc(sizeof(*m) + (sizeof(*m->meta) * t.end) +
5234
+ (ch.len) + (data.len) + 16 + 2);
5235
+ FIO_ASSERT_ALLOC(m);
5283
5236
  *m = (fio_msg_internal_s){
5284
5237
  .filter = filter,
5285
- .channel =
5286
- (fio_str_info_s){.data = (char *)(m->meta + meta_len), .len = ch.len},
5287
- .data =
5288
- (fio_str_info_s){.data = ((char *)(m->meta + meta_len) + ch.len + 1),
5289
- .len = data.len},
5238
+ .channel = (fio_str_info_s){.data = (char *)(m->meta + t.end) + 16,
5239
+ .len = ch.len},
5240
+ .data = (fio_str_info_s){.data = ((char *)(m->meta + t.end) + ch.len +
5241
+ 16 + 1),
5242
+ .len = data.len},
5290
5243
  .is_json = is_json,
5291
5244
  .ref = 1,
5292
- .meta_len = meta_len,
5245
+ .meta_len = t.end,
5293
5246
  };
5247
+ fio_u2str32((uint8_t *)(m + 1) + (sizeof(*m->meta) * t.end), ch.len);
5248
+ fio_u2str32((uint8_t *)(m + 1) + (sizeof(*m->meta) * t.end) + 4, data.len);
5249
+ fio_u2str32((uint8_t *)(m + 1) + (sizeof(*m->meta) * t.end) + 8, type);
5250
+ fio_u2str32((uint8_t *)(m + 1) + (sizeof(*m->meta) * t.end) + 12,
5251
+ (uint32_t)filter);
5294
5252
  // m->channel.data[ch.len] = 0; /* redundant, fio_malloc is all zero */
5295
5253
  // m->data.data[data.len] = 0; /* redundant, fio_malloc is all zero */
5296
5254
  if (cpy) {
5297
5255
  memcpy(m->channel.data, ch.data, ch.len);
5298
5256
  memcpy(m->data.data, data.data, data.len);
5299
- while (meta_len) {
5300
- --meta_len;
5301
- fio_msg_metadata_fn cb = fio_postoffice_meta_index(meta_len);
5302
- if (cb)
5303
- m->meta[meta_len] = cb(m->channel, m->data, is_json);
5257
+ while (t.end) {
5258
+ --t.end;
5259
+ m->meta[t.end] = t.arry[t.end](m->channel, m->data, is_json);
5304
5260
  }
5305
5261
  }
5262
+ fio_postoffice_meta_copy_free(&t);
5306
5263
  return m;
5307
5264
  }
5308
5265
 
5309
- static void fio_pubsub_create_message_update_meta(fio_msg_internal_s *m) {
5310
- if (m->filter || !m->meta_len)
5266
+ /** frees the internal message data */
5267
+ static inline void fio_msg_internal_finalize(fio_msg_internal_s *m) {
5268
+ if (!m->channel.len)
5269
+ m->channel.data = NULL;
5270
+ if (!m->data.len)
5271
+ m->data.data = NULL;
5272
+ }
5273
+
5274
+ /** frees the internal message data */
5275
+ static inline void fio_msg_internal_free(fio_msg_internal_s *m) {
5276
+ if (fio_atomic_sub(&m->ref, 1))
5311
5277
  return;
5312
- size_t meta_len = m->meta_len;
5313
- while (meta_len) {
5314
- --meta_len;
5315
- fio_msg_metadata_fn cb = fio_postoffice_meta_index(meta_len);
5316
- if (cb)
5317
- m->meta[meta_len] = cb(m->channel, m->data, m->is_json);
5278
+ while (m->meta_len) {
5279
+ --m->meta_len;
5280
+ if (m->meta[m->meta_len].on_finish) {
5281
+ fio_msg_s tmp_msg = {
5282
+ .channel = m->channel,
5283
+ .msg = m->data,
5284
+ };
5285
+ m->meta[m->meta_len].on_finish(&tmp_msg, m->meta[m->meta_len].metadata);
5286
+ }
5318
5287
  }
5288
+ fio_free(m);
5319
5289
  }
5320
5290
 
5321
- #endif
5291
+ static void fio_msg_internal_free2(void *m) { fio_msg_internal_free(m); }
5322
5292
 
5323
- /* *****************************************************************************
5324
- Cluster forking handler
5325
- ***************************************************************************** */
5293
+ /* add reference count to fio_msg_internal_s */
5294
+ static inline fio_msg_internal_s *fio_msg_internal_dup(fio_msg_internal_s *m) {
5295
+ fio_atomic_add(&m->ref, 1);
5296
+ return m;
5297
+ }
5326
5298
 
5327
- static void fio_pubsub_on_fork(void) {
5328
- fio_postoffice.filters.lock = FIO_LOCK_INIT;
5329
- fio_postoffice.pubsub.lock = FIO_LOCK_INIT;
5330
- fio_postoffice.patterns.lock = FIO_LOCK_INIT;
5331
- fio_postoffice.engines.lock = FIO_LOCK_INIT;
5332
- fio_postoffice.meta.lock = FIO_LOCK_INIT;
5333
- FIO_SET_FOR_LOOP(&fio_postoffice.filters.channels, pos) {
5334
- if (!pos->hash)
5335
- continue;
5336
- pos->obj->lock = FIO_LOCK_INIT;
5337
- FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
5338
- FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
5339
- }
5340
- }
5341
- FIO_SET_FOR_LOOP(&fio_postoffice.pubsub.channels, pos) {
5342
- if (!pos->hash)
5343
- continue;
5344
- pos->obj->lock = FIO_LOCK_INIT;
5345
- FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
5346
- FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
5347
- }
5348
- }
5349
- FIO_SET_FOR_LOOP(&fio_postoffice.patterns.channels, pos) {
5350
- if (!pos->hash)
5351
- continue;
5352
- pos->obj->lock = FIO_LOCK_INIT;
5353
- FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
5354
- FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
5355
- }
5356
- }
5299
+ /** internal helper */
5300
+
5301
+ static inline ssize_t fio_msg_internal_send_dup(intptr_t uuid,
5302
+ fio_msg_internal_s *m) {
5303
+ return fio_write2(uuid, .data.buffer = fio_msg_internal_dup(m),
5304
+ .offset = (sizeof(*m) + (m->meta_len * sizeof(*m->meta))),
5305
+ .length = 16 + m->data.len + m->channel.len + 2,
5306
+ .after.dealloc = fio_msg_internal_free2);
5357
5307
  }
5358
5308
 
5309
+ /**
5310
+ * A mock pub/sub callback for external subscriptions.
5311
+ */
5312
+ static void fio_mock_on_message(fio_msg_s *msg) { (void)msg; }
5313
+
5359
5314
  /* *****************************************************************************
5360
5315
  Channel Subscription Management
5361
5316
  ***************************************************************************** */
5362
5317
 
5363
- static void pubsub_on_channel_create(channel_s *ch);
5364
- static void pubsub_on_channel_destroy(channel_s *ch);
5318
+ static void fio_pubsub_on_channel_create(channel_s *ch);
5319
+ static void fio_pubsub_on_channel_destroy(channel_s *ch);
5365
5320
 
5366
5321
  /* some comon tasks extracted */
5367
5322
  static inline channel_s *fio_filter_dup_lock_internal(channel_s *ch,
@@ -5399,7 +5354,7 @@ static channel_s *fio_channel_dup_lock(fio_str_info_s name) {
5399
5354
  channel_s *ch_p =
5400
5355
  fio_filter_dup_lock_internal(&ch, hashed_name, &fio_postoffice.pubsub);
5401
5356
  if (fio_ls_embd_is_empty(&ch_p->subscriptions)) {
5402
- pubsub_on_channel_create(ch_p);
5357
+ fio_pubsub_on_channel_create(ch_p);
5403
5358
  }
5404
5359
  return ch_p;
5405
5360
  }
@@ -5419,7 +5374,7 @@ static channel_s *fio_channel_match_dup_lock(fio_str_info_s name,
5419
5374
  channel_s *ch_p =
5420
5375
  fio_filter_dup_lock_internal(&ch, hashed_name, &fio_postoffice.patterns);
5421
5376
  if (fio_ls_embd_is_empty(&ch_p->subscriptions)) {
5422
- pubsub_on_channel_create(ch_p);
5377
+ fio_pubsub_on_channel_create(ch_p);
5423
5378
  }
5424
5379
  return ch_p;
5425
5380
  }
@@ -5436,6 +5391,9 @@ static inline void fio_subscription_free(subscription_s *s) {
5436
5391
  fio_free(s);
5437
5392
  }
5438
5393
 
5394
+ /** SublimeText 3 marker */
5395
+ subscription_s *fio_subscribe___(subscribe_args_s args);
5396
+
5439
5397
  /** Subscribes to a filter, pub/sub channle or patten */
5440
5398
  subscription_s *fio_subscribe FIO_IGNORE_MACRO(subscribe_args_s args) {
5441
5399
  if (!args.on_message)
@@ -5495,7 +5453,7 @@ void fio_unsubscribe(subscription_s *s) {
5495
5453
  }
5496
5454
  fio_unlock(&ch->lock);
5497
5455
  if (removed) {
5498
- pubsub_on_channel_destroy(ch);
5456
+ fio_pubsub_on_channel_destroy(ch);
5499
5457
  }
5500
5458
 
5501
5459
  /* promise the subscription will be inactive */
@@ -5525,7 +5483,7 @@ static inline void fio_cluster_inform_root_about_channel(channel_s *ch,
5525
5483
  int add);
5526
5484
 
5527
5485
  /* runs in lock(!) let'm all know */
5528
- static void pubsub_on_channel_create(channel_s *ch) {
5486
+ static void fio_pubsub_on_channel_create(channel_s *ch) {
5529
5487
  fio_lock(&fio_postoffice.engines.lock);
5530
5488
  FIO_SET_FOR_LOOP(&fio_postoffice.engines.set, pos) {
5531
5489
  if (!pos->hash)
@@ -5539,7 +5497,7 @@ static void pubsub_on_channel_create(channel_s *ch) {
5539
5497
  }
5540
5498
 
5541
5499
  /* runs in lock(!) let'm all know */
5542
- static void pubsub_on_channel_destroy(channel_s *ch) {
5500
+ static void fio_pubsub_on_channel_destroy(channel_s *ch) {
5543
5501
  fio_lock(&fio_postoffice.engines.lock);
5544
5502
  FIO_SET_FOR_LOOP(&fio_postoffice.engines.set, pos) {
5545
5503
  if (!pos->hash)
@@ -5689,29 +5647,6 @@ static channel_s *fio_channel_find_dup(fio_str_info_s name) {
5689
5647
  return ch;
5690
5648
  }
5691
5649
 
5692
- /** frees the internal message data */
5693
- static inline void fio_msg_internal_free(fio_msg_internal_s *msg) {
5694
- if (fio_atomic_sub(&msg->ref, 1))
5695
- return;
5696
- while (msg->meta_len) {
5697
- --msg->meta_len;
5698
- if (msg->meta[msg->meta_len].on_finish) {
5699
- fio_msg_s tmp_msg = {
5700
- .channel = msg->channel,
5701
- .msg = msg->data,
5702
- };
5703
- msg->meta[msg->meta_len].on_finish(&tmp_msg,
5704
- msg->meta[msg->meta_len].metadata);
5705
- }
5706
- }
5707
- fio_free(msg);
5708
- }
5709
- /* add reference count to fio_msg_internal_s */
5710
- static inline fio_msg_internal_s *fio_msg_internal_dup(fio_msg_internal_s *m) {
5711
- fio_atomic_add(&m->ref, 1);
5712
- return m;
5713
- }
5714
-
5715
5650
  /* defers the callback (mark only) */
5716
5651
  void fio_message_defer(fio_msg_s *msg_) {
5717
5652
  fio_msg_client_s *cl = (fio_msg_client_s *)msg_;
@@ -5756,7 +5691,7 @@ static void fio_perform_subscription_callback(void *s_, void *msg_) {
5756
5691
  static void fio_publish2channel(channel_s *ch, fio_msg_internal_s *msg) {
5757
5692
  FIO_LS_EMBD_FOR(&ch->subscriptions, pos) {
5758
5693
  subscription_s *s = FIO_LS_EMBD_OBJ(subscription_s, node, pos);
5759
- if (!s) {
5694
+ if (!s || s->on_message == fio_mock_on_message) {
5760
5695
  continue;
5761
5696
  }
5762
5697
  fio_atomic_add(&s->ref, 1);
@@ -5783,6 +5718,7 @@ finish:
5783
5718
 
5784
5719
  /** Publishes the message to the current process and frees the strings. */
5785
5720
  static void fio_publish2process(fio_msg_internal_s *m) {
5721
+ fio_msg_internal_finalize(m);
5786
5722
  channel_s *ch;
5787
5723
  if (m->filter) {
5788
5724
  ch = fio_filter_find_dup(m->filter);
@@ -5842,7 +5778,7 @@ typedef struct cluster_pr_s {
5842
5778
  fio_protocol_s protocol;
5843
5779
  fio_msg_internal_s *msg;
5844
5780
  void (*handler)(struct cluster_pr_s *pr);
5845
- void (*sender)(fio_str_s *data, intptr_t avoid_uuid);
5781
+ void (*sender)(void *data, intptr_t avoid_uuid);
5846
5782
  fio_sub_hash_s pubsub;
5847
5783
  fio_sub_hash_s patterns;
5848
5784
  intptr_t uuid;
@@ -5928,36 +5864,14 @@ static void fio_cluster_init(void) {
5928
5864
  * Cluster Protocol callbacks
5929
5865
  **************************************************************************** */
5930
5866
 
5931
- typedef struct cluster_msg_s {
5932
- fio_msg_s message;
5933
- size_t ref;
5934
- } cluster_msg_s;
5935
-
5936
- static inline fio_str_s *
5937
- fio_cluster_wrap_message(uint32_t ch_len, uint32_t msg_len, uint32_t type,
5938
- int32_t filter, void *ch_data, void *msg_data) {
5939
- fio_str_s *buf = fio_str_new2();
5940
- fio_str_info_s i = fio_str_resize(buf, ch_len + msg_len + 16);
5941
- fio_u2str32((uint8_t *)i.data, ch_len);
5942
- fio_u2str32((uint8_t *)(i.data + 4), msg_len);
5943
- fio_u2str32((uint8_t *)(i.data + 8), type);
5944
- fio_u2str32((uint8_t *)(i.data + 12), (uint32_t)filter);
5945
- if (ch_len && ch_data) {
5946
- memcpy((i.data + 16), ch_data, ch_len);
5947
- }
5948
- if (msg_len && msg_data) {
5949
- memcpy((i.data + 16 + ch_len), msg_data, msg_len);
5950
- }
5951
- return buf;
5952
- }
5953
-
5954
5867
  static inline void fio_cluster_protocol_free(void *pr) { fio_free(pr); }
5955
5868
 
5956
5869
  static uint8_t fio_cluster_on_shutdown(intptr_t uuid, fio_protocol_s *pr_) {
5957
5870
  cluster_pr_s *p = (cluster_pr_s *)pr_;
5958
- p->sender(
5959
- fio_cluster_wrap_message(0, 0, FIO_CLUSTER_MSG_SHUTDOWN, 0, NULL, NULL),
5960
- -1);
5871
+ p->sender(fio_msg_internal_create(0, FIO_CLUSTER_MSG_SHUTDOWN,
5872
+ (fio_str_info_s){.len = 0},
5873
+ (fio_str_info_s){.len = 0}, 0, 1),
5874
+ -1);
5961
5875
  return 255;
5962
5876
  (void)pr_;
5963
5877
  (void)uuid;
@@ -5975,12 +5889,12 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
5975
5889
  if (!c->exp_channel && !c->exp_msg) {
5976
5890
  if (c->length - i < 16)
5977
5891
  break;
5978
- c->exp_channel = fio_str2u32(c->buffer + i);
5979
- c->exp_msg = fio_str2u32(c->buffer + i + 4);
5892
+ c->exp_channel = fio_str2u32(c->buffer + i) + 1;
5893
+ c->exp_msg = fio_str2u32(c->buffer + i + 4) + 1;
5980
5894
  c->type = fio_str2u32(c->buffer + i + 8);
5981
5895
  c->filter = (int32_t)fio_str2u32(c->buffer + i + 12);
5982
5896
  if (c->exp_channel) {
5983
- if (c->exp_channel >= (1024 * 1024 * 16)) {
5897
+ if (c->exp_channel >= (1024 * 1024 * 16) + 1) {
5984
5898
  FIO_LOG_FATAL("(%d) cluster message name too long (16Mb limit): %u\n",
5985
5899
  getpid(), (unsigned int)c->exp_channel);
5986
5900
  exit(1);
@@ -5988,18 +5902,19 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
5988
5902
  }
5989
5903
  }
5990
5904
  if (c->exp_msg) {
5991
- if (c->exp_msg >= (1024 * 1024 * 64)) {
5905
+ if (c->exp_msg >= (1024 * 1024 * 64) + 1) {
5992
5906
  FIO_LOG_FATAL("(%d) cluster message data too long (64Mb limit): %u\n",
5993
5907
  getpid(), (unsigned int)c->exp_msg);
5994
5908
  exit(1);
5995
5909
  return;
5996
5910
  }
5997
5911
  }
5998
- c->msg = fio_pubsub_create_message(
5999
- c->filter,
6000
- (fio_str_info_s){.data = (char *)(c->msg + 1), .len = c->exp_channel},
5912
+ c->msg = fio_msg_internal_create(
5913
+ c->filter, c->type,
5914
+ (fio_str_info_s){.data = (char *)(c->msg + 1),
5915
+ .len = c->exp_channel - 1},
6001
5916
  (fio_str_info_s){.data = ((char *)(c->msg + 1) + c->exp_channel + 1),
6002
- .len = c->exp_msg},
5917
+ .len = c->exp_msg - 1},
6003
5918
  (int8_t)(c->type == FIO_CLUSTER_MSG_JSON ||
6004
5919
  c->type == FIO_CLUSTER_MSG_ROOT_JSON),
6005
5920
  0);
@@ -6007,13 +5922,15 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
6007
5922
  }
6008
5923
  if (c->exp_channel) {
6009
5924
  if (c->exp_channel + i > c->length) {
6010
- memcpy(c->msg->channel.data + (c->msg->channel.len - c->exp_channel),
5925
+ memcpy(c->msg->channel.data +
5926
+ ((c->msg->channel.len + 1) - c->exp_channel),
6011
5927
  (char *)c->buffer + i, (size_t)(c->length - i));
6012
5928
  c->exp_channel -= (c->length - i);
6013
5929
  i = c->length;
6014
5930
  break;
6015
5931
  } else {
6016
- memcpy(c->msg->channel.data + (c->msg->channel.len - c->exp_channel),
5932
+ memcpy(c->msg->channel.data +
5933
+ ((c->msg->channel.len + 1) - c->exp_channel),
6017
5934
  (char *)c->buffer + i, (size_t)(c->exp_channel));
6018
5935
  i += c->exp_channel;
6019
5936
  c->exp_channel = 0;
@@ -6021,19 +5938,19 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
6021
5938
  }
6022
5939
  if (c->exp_msg) {
6023
5940
  if (c->exp_msg + i > c->length) {
6024
- memcpy(c->msg->data.data + (c->msg->data.len - c->exp_msg),
5941
+ memcpy(c->msg->data.data + ((c->msg->data.len + 1) - c->exp_msg),
6025
5942
  (char *)c->buffer + i, (size_t)(c->length - i));
6026
5943
  c->exp_msg -= (c->length - i);
6027
5944
  i = c->length;
6028
5945
  break;
6029
5946
  } else {
6030
- memcpy(c->msg->data.data + (c->msg->data.len - c->exp_msg),
5947
+ memcpy(c->msg->data.data + ((c->msg->data.len + 1) - c->exp_msg),
6031
5948
  (char *)c->buffer + i, (size_t)(c->exp_msg));
6032
5949
  i += c->exp_msg;
6033
5950
  c->exp_msg = 0;
6034
5951
  }
6035
5952
  }
6036
- fio_pubsub_create_message_update_meta(c->msg);
5953
+ fio_postoffice_meta_update(c->msg);
6037
5954
  c->handler(c);
6038
5955
  fio_msg_internal_free(c->msg);
6039
5956
  c->msg = NULL;
@@ -6046,8 +5963,11 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
6046
5963
  }
6047
5964
 
6048
5965
  static void fio_cluster_ping(intptr_t uuid, fio_protocol_s *pr_) {
6049
- fio_str_send_free2(uuid, fio_cluster_wrap_message(0, 0, FIO_CLUSTER_MSG_PING,
6050
- 0, NULL, NULL));
5966
+ fio_msg_internal_s *m = fio_msg_internal_create(
5967
+ 0, FIO_CLUSTER_MSG_PING, (fio_str_info_s){.len = 0},
5968
+ (fio_str_info_s){.len = 0}, 0, 1);
5969
+ fio_msg_internal_send_dup(uuid, m);
5970
+ fio_msg_internal_free(m);
6051
5971
  (void)pr_;
6052
5972
  }
6053
5973
 
@@ -6084,7 +6004,7 @@ static void fio_cluster_on_close(intptr_t uuid, fio_protocol_s *pr_) {
6084
6004
  static inline fio_protocol_s *
6085
6005
  fio_cluster_protocol_alloc(intptr_t uuid,
6086
6006
  void (*handler)(struct cluster_pr_s *pr),
6087
- void (*sender)(fio_str_s *data, intptr_t auuid)) {
6007
+ void (*sender)(void *data, intptr_t auuid)) {
6088
6008
  cluster_pr_s *p = fio_mmap(sizeof(*p));
6089
6009
  if (!p) {
6090
6010
  FIO_LOG_FATAL("Cluster protocol allocation failed.");
@@ -6109,35 +6029,28 @@ fio_cluster_protocol_alloc(intptr_t uuid,
6109
6029
  * Master (server) IPC Connections
6110
6030
  **************************************************************************** */
6111
6031
 
6112
- /**
6113
- * A mock pub/sub callback for external subscriptions.
6114
- */
6115
- static void fio_mock_on_message(fio_msg_s *msg) { (void)msg; }
6116
-
6117
- static void fio_cluster_server_sender(fio_str_s *data, intptr_t avoid_uuid) {
6032
+ static void fio_cluster_server_sender(void *m_, intptr_t avoid_uuid) {
6033
+ fio_msg_internal_s *m = m_;
6118
6034
  fio_lock(&cluster_data.lock);
6119
6035
  FIO_LS_FOR(&cluster_data.clients, pos) {
6120
6036
  if ((intptr_t)pos->obj != -1) {
6121
6037
  if ((intptr_t)pos->obj != avoid_uuid) {
6122
- fio_str_send_free2((intptr_t)pos->obj, fio_str_dup(data));
6038
+ fio_msg_internal_send_dup((intptr_t)pos->obj, m);
6123
6039
  }
6124
6040
  }
6125
6041
  }
6126
6042
  fio_unlock(&cluster_data.lock);
6127
- fio_str_free2(data);
6043
+ fio_msg_internal_free(m);
6128
6044
  }
6129
6045
 
6130
6046
  static void fio_cluster_server_handler(struct cluster_pr_s *pr) {
6131
6047
  /* what to do? */
6048
+ // fprintf(stderr, "-");
6132
6049
  switch ((fio_cluster_message_type_e)pr->type) {
6133
6050
 
6134
6051
  case FIO_CLUSTER_MSG_FORWARD: /* fallthrough */
6135
6052
  case FIO_CLUSTER_MSG_JSON: {
6136
- fio_cluster_server_sender(
6137
- fio_cluster_wrap_message(pr->msg->channel.len, pr->msg->data.len,
6138
- pr->type, pr->msg->filter,
6139
- pr->msg->channel.data, pr->msg->data.data),
6140
- pr->uuid);
6053
+ fio_cluster_server_sender(fio_msg_internal_dup(pr->msg), pr->uuid);
6141
6054
  fio_publish2process(fio_msg_internal_dup(pr->msg));
6142
6055
  break;
6143
6056
  }
@@ -6262,9 +6175,7 @@ static void fio_listen2cluster(void *ignore) {
6262
6175
  .ping = mock_ping_eternal,
6263
6176
  .on_close = fio_cluster_listen_on_close,
6264
6177
  };
6265
- #if DEBUG
6266
6178
  FIO_LOG_DEBUG("(%d) Listening to cluster: %s", getpid(), cluster_data.name);
6267
- #endif
6268
6179
  fio_attach(cluster_data.uuid, p);
6269
6180
  (void)ignore;
6270
6181
  }
@@ -6296,15 +6207,16 @@ static void fio_cluster_client_handler(struct cluster_pr_s *pr) {
6296
6207
  break;
6297
6208
  }
6298
6209
  }
6299
- static void fio_cluster_client_sender(fio_str_s *data, intptr_t ignr_) {
6210
+ static void fio_cluster_client_sender(void *m_, intptr_t ignr_) {
6211
+ fio_msg_internal_s *m = m_;
6300
6212
  if (!uuid_is_valid(cluster_data.uuid) && fio_data->active) {
6301
6213
  /* delay message delivery until we have a vaild uuid */
6302
- fio_defer_push_task((void (*)(void *, void *))fio_cluster_client_sender,
6303
- data, (void *)ignr_);
6214
+ fio_defer_push_task((void (*)(void *, void *))fio_cluster_client_sender, m_,
6215
+ (void *)ignr_);
6304
6216
  return;
6305
6217
  }
6306
- fio_str_send_free2(cluster_data.uuid, data);
6307
- (void)ignr_;
6218
+ fio_msg_internal_send_dup(cluster_data.uuid, m);
6219
+ fio_msg_internal_free(m);
6308
6220
  }
6309
6221
 
6310
6222
  /** The address of the server we are connecting to. */
@@ -6357,15 +6269,17 @@ static void fio_cluster_on_fail(intptr_t uuid, void *udata) {
6357
6269
  }
6358
6270
 
6359
6271
  static void fio_connect2cluster(void *ignore) {
6272
+ if (cluster_data.uuid)
6273
+ fio_force_close(cluster_data.uuid);
6274
+ cluster_data.uuid = 0;
6360
6275
  /* this is called for each child, but not for single a process worker. */
6361
- cluster_data.uuid = fio_connect(.address = cluster_data.name, .port = NULL,
6362
- .on_connect = fio_cluster_on_connect,
6363
- .on_fail = fio_cluster_on_fail);
6276
+ fio_connect(.address = cluster_data.name, .port = NULL,
6277
+ .on_connect = fio_cluster_on_connect,
6278
+ .on_fail = fio_cluster_on_fail);
6364
6279
  (void)ignore;
6365
6280
  }
6366
6281
 
6367
- static void fio_send2cluster(int32_t filter, fio_str_info_s ch,
6368
- fio_str_info_s msg, uint8_t is_json) {
6282
+ static void fio_send2cluster(fio_msg_internal_s *m) {
6369
6283
  if (!fio_is_running()) {
6370
6284
  FIO_LOG_ERROR("facio.io cluster inactive, can't send message.");
6371
6285
  return;
@@ -6375,19 +6289,9 @@ static void fio_send2cluster(int32_t filter, fio_str_info_s ch,
6375
6289
  return;
6376
6290
  }
6377
6291
  if (fio_is_master()) {
6378
- fio_cluster_server_sender(
6379
- fio_cluster_wrap_message(
6380
- ch.len, msg.len,
6381
- (is_json ? FIO_CLUSTER_MSG_JSON : FIO_CLUSTER_MSG_FORWARD), filter,
6382
- ch.data, msg.data),
6383
- -1);
6292
+ fio_cluster_server_sender(fio_msg_internal_dup(m), -1);
6384
6293
  } else {
6385
- fio_cluster_client_sender(
6386
- fio_cluster_wrap_message(
6387
- ch.len, msg.len,
6388
- (is_json ? FIO_CLUSTER_MSG_JSON : FIO_CLUSTER_MSG_FORWARD), filter,
6389
- ch.data, msg.data),
6390
- -1);
6294
+ fio_cluster_client_sender(fio_msg_internal_dup(m), -1);
6391
6295
  }
6392
6296
  }
6393
6297
 
@@ -6418,13 +6322,13 @@ static inline void fio_cluster_inform_root_about_channel(channel_s *ch,
6418
6322
  }
6419
6323
 
6420
6324
  fio_cluster_client_sender(
6421
- fio_cluster_wrap_message(ch_name.len, msg.len,
6422
- (ch->match
6423
- ? (add ? FIO_CLUSTER_MSG_PATTERN_SUB
6424
- : FIO_CLUSTER_MSG_PATTERN_UNSUB)
6425
- : (add ? FIO_CLUSTER_MSG_PUBSUB_SUB
6426
- : FIO_CLUSTER_MSG_PUBSUB_UNSUB)),
6427
- 0, ch_name.data, msg.data),
6325
+ fio_msg_internal_create(0,
6326
+ (ch->match
6327
+ ? (add ? FIO_CLUSTER_MSG_PATTERN_SUB
6328
+ : FIO_CLUSTER_MSG_PATTERN_UNSUB)
6329
+ : (add ? FIO_CLUSTER_MSG_PUBSUB_SUB
6330
+ : FIO_CLUSTER_MSG_PUBSUB_UNSUB)),
6331
+ ch_name, msg, 0, 1),
6428
6332
  -1);
6429
6333
  }
6430
6334
 
@@ -6432,13 +6336,9 @@ static inline void fio_cluster_inform_root_about_channel(channel_s *ch,
6432
6336
  * Initialization
6433
6337
  **************************************************************************** */
6434
6338
 
6435
- static void fio_connect_after_fork(void *ignore) {
6436
- if (fio_parent_pid() == getpid()) {
6437
- /* prevent `accept` backlog in parent */
6438
- fio_cluster_listen_accept(cluster_data.uuid, NULL);
6439
- } else {
6440
- /* this is called for each child. */
6441
- }
6339
+ static void fio_accept_after_fork(void *ignore) {
6340
+ /* prevent `accept` backlog in parent */
6341
+ fio_cluster_listen_accept(cluster_data.uuid, NULL);
6442
6342
  (void)ignore;
6443
6343
  }
6444
6344
 
@@ -6497,12 +6397,50 @@ static void fio_cluster_at_exit(void *ignore) {
6497
6397
  static void fio_pubsub_initialize(void) {
6498
6398
  fio_cluster_init();
6499
6399
  fio_state_callback_add(FIO_CALL_PRE_START, fio_listen2cluster, NULL);
6500
- fio_state_callback_add(FIO_CALL_AFTER_FORK, fio_connect_after_fork, NULL);
6400
+ fio_state_callback_add(FIO_CALL_IN_MASTER, fio_accept_after_fork, NULL);
6501
6401
  fio_state_callback_add(FIO_CALL_IN_CHILD, fio_connect2cluster, NULL);
6502
6402
  fio_state_callback_add(FIO_CALL_ON_FINISH, fio_cluster_cleanup, NULL);
6503
6403
  fio_state_callback_add(FIO_CALL_AT_EXIT, fio_cluster_at_exit, NULL);
6504
6404
  }
6505
6405
 
6406
+ /* *****************************************************************************
6407
+ Cluster forking handler
6408
+ ***************************************************************************** */
6409
+
6410
+ static void fio_pubsub_on_fork(void) {
6411
+ fio_postoffice.filters.lock = FIO_LOCK_INIT;
6412
+ fio_postoffice.pubsub.lock = FIO_LOCK_INIT;
6413
+ fio_postoffice.patterns.lock = FIO_LOCK_INIT;
6414
+ fio_postoffice.engines.lock = FIO_LOCK_INIT;
6415
+ fio_postoffice.meta.lock = FIO_LOCK_INIT;
6416
+ cluster_data.lock = FIO_LOCK_INIT;
6417
+ cluster_data.uuid = 0;
6418
+ FIO_SET_FOR_LOOP(&fio_postoffice.filters.channels, pos) {
6419
+ if (!pos->hash)
6420
+ continue;
6421
+ pos->obj->lock = FIO_LOCK_INIT;
6422
+ FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
6423
+ FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
6424
+ }
6425
+ }
6426
+ FIO_SET_FOR_LOOP(&fio_postoffice.pubsub.channels, pos) {
6427
+ if (!pos->hash)
6428
+ continue;
6429
+ pos->obj->lock = FIO_LOCK_INIT;
6430
+ FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
6431
+ FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
6432
+ }
6433
+ }
6434
+ FIO_SET_FOR_LOOP(&fio_postoffice.patterns.channels, pos) {
6435
+ if (!pos->hash)
6436
+ continue;
6437
+ pos->obj->lock = FIO_LOCK_INIT;
6438
+ FIO_LS_EMBD_FOR(&pos->obj->subscriptions, n) {
6439
+ FIO_LS_EMBD_OBJ(subscription_s, node, n)->lock = FIO_LOCK_INIT;
6440
+ }
6441
+ }
6442
+ }
6443
+
6506
6444
  /* *****************************************************************************
6507
6445
  * External API
6508
6446
  **************************************************************************** */
@@ -6513,15 +6451,11 @@ static void fio_cluster_signal_children(void) {
6513
6451
  kill(getpid(), SIGINT);
6514
6452
  return;
6515
6453
  }
6516
- fio_cluster_server_sender(
6517
- fio_cluster_wrap_message(0, 0, FIO_CLUSTER_MSG_SHUTDOWN, 0, NULL, NULL),
6518
- -1);
6519
- }
6520
-
6521
- static inline void fio_publish2process2(int32_t filter, fio_str_info_s ch_name,
6522
- fio_str_info_s msg, uint8_t is_json) {
6523
- fio_publish2process(
6524
- fio_pubsub_create_message(filter, ch_name, msg, is_json, 1));
6454
+ fio_cluster_server_sender(fio_msg_internal_create(0, FIO_CLUSTER_MSG_SHUTDOWN,
6455
+ (fio_str_info_s){.len = 0},
6456
+ (fio_str_info_s){.len = 0},
6457
+ 0, 1),
6458
+ -1);
6525
6459
  }
6526
6460
 
6527
6461
  /* Sublime Text marker */
@@ -6549,29 +6483,40 @@ void fio_publish FIO_IGNORE_MACRO(fio_publish_args_s args) {
6549
6483
  } else if (!args.engine) {
6550
6484
  args.engine = FIO_PUBSUB_DEFAULT;
6551
6485
  }
6486
+ fio_msg_internal_s *m = NULL;
6552
6487
  switch ((uintptr_t)args.engine) {
6553
6488
  case 0UL: /* fallthrough (missing default) */
6554
6489
  case 1UL: // ((uintptr_t)FIO_PUBSUB_CLUSTER):
6555
- fio_send2cluster(args.filter, args.channel, args.message, args.is_json);
6556
- fio_publish2process2(args.filter, args.channel, args.message, args.is_json);
6490
+ m = fio_msg_internal_create(
6491
+ args.filter,
6492
+ (args.is_json ? FIO_CLUSTER_MSG_JSON : FIO_CLUSTER_MSG_FORWARD),
6493
+ args.channel, args.message, args.is_json, 1);
6494
+ fio_send2cluster(m);
6495
+ fio_publish2process(m);
6557
6496
  break;
6558
6497
  case 2UL: // ((uintptr_t)FIO_PUBSUB_PROCESS):
6559
- fio_publish2process2(args.filter, args.channel, args.message, args.is_json);
6498
+ m = fio_msg_internal_create(args.filter, 0, args.channel, args.message,
6499
+ args.is_json, 1);
6500
+ fio_publish2process(m);
6560
6501
  break;
6561
6502
  case 3UL: // ((uintptr_t)FIO_PUBSUB_SIBLINGS):
6562
- fio_send2cluster(args.filter, args.channel, args.message, args.is_json);
6503
+ m = fio_msg_internal_create(
6504
+ args.filter,
6505
+ (args.is_json ? FIO_CLUSTER_MSG_JSON : FIO_CLUSTER_MSG_FORWARD),
6506
+ args.channel, args.message, args.is_json, 1);
6507
+ fio_send2cluster(m);
6508
+ fio_msg_internal_free(m);
6509
+ m = NULL;
6563
6510
  break;
6564
6511
  case 4UL: // ((uintptr_t)FIO_PUBSUB_ROOT):
6512
+ m = fio_msg_internal_create(
6513
+ args.filter,
6514
+ (args.is_json ? FIO_CLUSTER_MSG_ROOT_JSON : FIO_CLUSTER_MSG_ROOT),
6515
+ args.channel, args.message, args.is_json, 1);
6565
6516
  if (fio_data->is_worker == 0 || fio_data->workers == 1) {
6566
- fio_publish2process2(args.filter, args.channel, args.message,
6567
- args.is_json);
6517
+ fio_publish2process(m);
6568
6518
  } else {
6569
- fio_cluster_client_sender(
6570
- fio_cluster_wrap_message(
6571
- args.channel.len, args.message.len,
6572
- (args.is_json ? FIO_CLUSTER_MSG_ROOT_JSON : FIO_CLUSTER_MSG_ROOT),
6573
- args.filter, args.channel.data, args.message.data),
6574
- -1);
6519
+ fio_cluster_client_sender(m, -1);
6575
6520
  }
6576
6521
  break;
6577
6522
  default:
@@ -6582,8 +6527,6 @@ void fio_publish FIO_IGNORE_MACRO(fio_publish_args_s args) {
6582
6527
  }
6583
6528
  args.engine->publish(args.engine, args.channel, args.message, args.is_json);
6584
6529
  }
6585
- // fio_str_free2(ch);
6586
- // fio_str_free2(msg);
6587
6530
  return;
6588
6531
  }
6589
6532
 
@@ -9145,7 +9088,8 @@ FIO_FUNC inline void fio_str_test(void) {
9145
9088
  FIO_ASSERT(str.dealloc, "Missing static string deallocation function"
9146
9089
  " after `fio_str_write`.");
9147
9090
 
9148
- fprintf(stderr, "* reviewing `fio_str_detach`.\n (%zu): %s\n", fio_str_info(&str).len, fio_str_info(&str).data);
9091
+ fprintf(stderr, "* reviewing `fio_str_detach`.\n (%zu): %s\n",
9092
+ fio_str_info(&str).len, fio_str_info(&str).data);
9149
9093
  char *cstr = fio_str_detach(&str);
9150
9094
  FIO_ASSERT(cstr, "`fio_str_detach` returned NULL");
9151
9095
  FIO_ASSERT(!memcmp(cstr, "Welcome Home\0", 13),
@@ -9460,9 +9404,12 @@ FIO_FUNC void fio_socket_test(void) {
9460
9404
  ssize_t r = -1;
9461
9405
  ssize_t timer_junk;
9462
9406
  fio_write(client1, "Hello World", 11);
9463
- if (!uuid_data(client1).packet)
9464
- unlink(__FILE__ ".sock");
9465
- FIO_ASSERT(uuid_data(client1).packet, "fio_write error, no packet!")
9407
+ if (0) {
9408
+ /* packet may have been sent synchronously, don't test */
9409
+ if (!uuid_data(client1).packet)
9410
+ unlink(__FILE__ ".sock");
9411
+ FIO_ASSERT(uuid_data(client1).packet, "fio_write error, no packet!")
9412
+ }
9466
9413
  /* prevent poll from hanging */
9467
9414
  fio_run_every(5, 1, fio_timer_test_task, &timer_junk, fio_timer_test_task);
9468
9415
  errno = EAGAIN;