fluentd 1.20.0-aarch64-mingw-ucrt

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 (341) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +116 -0
  3. data/ADOPTERS.md +5 -0
  4. data/AGENTS.md +46 -0
  5. data/AUTHORS +2 -0
  6. data/CHANGELOG.md +3324 -0
  7. data/CONTRIBUTING.md +45 -0
  8. data/GOVERNANCE.md +55 -0
  9. data/GithubWorkflow.md +78 -0
  10. data/LICENSE +202 -0
  11. data/MAINTAINERS.md +19 -0
  12. data/README.md +73 -0
  13. data/Rakefile +89 -0
  14. data/SECURITY.md +47 -0
  15. data/bin/fluent-binlog-reader +7 -0
  16. data/bin/fluent-ca-generate +6 -0
  17. data/bin/fluent-cap-ctl +7 -0
  18. data/bin/fluent-cat +5 -0
  19. data/bin/fluent-ctl +7 -0
  20. data/bin/fluent-debug +5 -0
  21. data/bin/fluent-gem +9 -0
  22. data/bin/fluent-plugin-config-format +5 -0
  23. data/bin/fluent-plugin-generate +5 -0
  24. data/bin/fluentd +15 -0
  25. data/code-of-conduct.md +3 -0
  26. data/docs/SECURITY_AUDIT.pdf +0 -0
  27. data/example/copy_roundrobin.conf +39 -0
  28. data/example/counter.conf +18 -0
  29. data/example/filter_stdout.conf +22 -0
  30. data/example/in_forward.conf +14 -0
  31. data/example/in_forward_client.conf +37 -0
  32. data/example/in_forward_shared_key.conf +15 -0
  33. data/example/in_forward_tls.conf +14 -0
  34. data/example/in_forward_users.conf +24 -0
  35. data/example/in_forward_workers.conf +21 -0
  36. data/example/in_http.conf +16 -0
  37. data/example/in_out_forward.conf +17 -0
  38. data/example/in_sample_blocks.conf +17 -0
  39. data/example/in_sample_with_compression.conf +23 -0
  40. data/example/in_syslog.conf +15 -0
  41. data/example/in_tail.conf +14 -0
  42. data/example/in_tcp.conf +13 -0
  43. data/example/in_udp.conf +13 -0
  44. data/example/logevents.conf +25 -0
  45. data/example/multi_filters.conf +61 -0
  46. data/example/out_copy.conf +20 -0
  47. data/example/out_exec_filter.conf +42 -0
  48. data/example/out_file.conf +13 -0
  49. data/example/out_forward.conf +35 -0
  50. data/example/out_forward_buf_file.conf +23 -0
  51. data/example/out_forward_client.conf +109 -0
  52. data/example/out_forward_heartbeat_none.conf +16 -0
  53. data/example/out_forward_sd.conf +17 -0
  54. data/example/out_forward_shared_key.conf +36 -0
  55. data/example/out_forward_tls.conf +18 -0
  56. data/example/out_forward_users.conf +65 -0
  57. data/example/out_null.conf +36 -0
  58. data/example/sd.yaml +8 -0
  59. data/example/secondary_file.conf +42 -0
  60. data/example/suppress_config_dump.conf +7 -0
  61. data/example/v0_12_filter.conf +78 -0
  62. data/example/v1_literal_example.conf +36 -0
  63. data/example/worker_section.conf +36 -0
  64. data/fluent.conf +139 -0
  65. data/lib/fluent/agent.rb +168 -0
  66. data/lib/fluent/capability.rb +87 -0
  67. data/lib/fluent/clock.rb +66 -0
  68. data/lib/fluent/command/binlog_reader.rb +244 -0
  69. data/lib/fluent/command/bundler_injection.rb +45 -0
  70. data/lib/fluent/command/ca_generate.rb +184 -0
  71. data/lib/fluent/command/cap_ctl.rb +174 -0
  72. data/lib/fluent/command/cat.rb +365 -0
  73. data/lib/fluent/command/ctl.rb +180 -0
  74. data/lib/fluent/command/debug.rb +103 -0
  75. data/lib/fluent/command/fluentd.rb +385 -0
  76. data/lib/fluent/command/plugin_config_formatter.rb +308 -0
  77. data/lib/fluent/command/plugin_generator.rb +365 -0
  78. data/lib/fluent/compat/call_super_mixin.rb +76 -0
  79. data/lib/fluent/compat/detach_process_mixin.rb +33 -0
  80. data/lib/fluent/compat/exec_util.rb +144 -0
  81. data/lib/fluent/compat/file_util.rb +54 -0
  82. data/lib/fluent/compat/filter.rb +68 -0
  83. data/lib/fluent/compat/formatter.rb +117 -0
  84. data/lib/fluent/compat/formatter_utils.rb +85 -0
  85. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
  86. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  87. data/lib/fluent/compat/input.rb +49 -0
  88. data/lib/fluent/compat/output.rb +721 -0
  89. data/lib/fluent/compat/output_chain.rb +60 -0
  90. data/lib/fluent/compat/parser.rb +310 -0
  91. data/lib/fluent/compat/parser_utils.rb +40 -0
  92. data/lib/fluent/compat/propagate_default.rb +62 -0
  93. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  94. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  95. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  96. data/lib/fluent/compat/socket_util.rb +165 -0
  97. data/lib/fluent/compat/string_util.rb +34 -0
  98. data/lib/fluent/compat/structured_format_mixin.rb +26 -0
  99. data/lib/fluent/compat/type_converter.rb +90 -0
  100. data/lib/fluent/config/basic_parser.rb +122 -0
  101. data/lib/fluent/config/configure_proxy.rb +424 -0
  102. data/lib/fluent/config/dsl.rb +152 -0
  103. data/lib/fluent/config/element.rb +265 -0
  104. data/lib/fluent/config/error.rb +44 -0
  105. data/lib/fluent/config/literal_parser.rb +305 -0
  106. data/lib/fluent/config/parser.rb +119 -0
  107. data/lib/fluent/config/section.rb +272 -0
  108. data/lib/fluent/config/types.rb +257 -0
  109. data/lib/fluent/config/v1_parser.rb +200 -0
  110. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  111. data/lib/fluent/config/yaml_parser/loader.rb +124 -0
  112. data/lib/fluent/config/yaml_parser/parser.rb +179 -0
  113. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  114. data/lib/fluent/config/yaml_parser.rb +56 -0
  115. data/lib/fluent/config.rb +89 -0
  116. data/lib/fluent/configurable.rb +202 -0
  117. data/lib/fluent/counter/base_socket.rb +44 -0
  118. data/lib/fluent/counter/client.rb +297 -0
  119. data/lib/fluent/counter/error.rb +86 -0
  120. data/lib/fluent/counter/mutex_hash.rb +163 -0
  121. data/lib/fluent/counter/server.rb +273 -0
  122. data/lib/fluent/counter/store.rb +205 -0
  123. data/lib/fluent/counter/validator.rb +145 -0
  124. data/lib/fluent/counter.rb +23 -0
  125. data/lib/fluent/daemon.rb +14 -0
  126. data/lib/fluent/daemonizer.rb +88 -0
  127. data/lib/fluent/engine.rb +269 -0
  128. data/lib/fluent/env.rb +45 -0
  129. data/lib/fluent/error.rb +37 -0
  130. data/lib/fluent/event.rb +369 -0
  131. data/lib/fluent/event_router.rb +315 -0
  132. data/lib/fluent/ext_monitor_require.rb +28 -0
  133. data/lib/fluent/file_wrapper.rb +137 -0
  134. data/lib/fluent/filter.rb +21 -0
  135. data/lib/fluent/fluent_log_event_router.rb +139 -0
  136. data/lib/fluent/formatter.rb +23 -0
  137. data/lib/fluent/input.rb +21 -0
  138. data/lib/fluent/label.rb +46 -0
  139. data/lib/fluent/load.rb +33 -0
  140. data/lib/fluent/log/console_adapter.rb +66 -0
  141. data/lib/fluent/log.rb +775 -0
  142. data/lib/fluent/match.rb +187 -0
  143. data/lib/fluent/mixin.rb +31 -0
  144. data/lib/fluent/msgpack_factory.rb +111 -0
  145. data/lib/fluent/oj_options.rb +61 -0
  146. data/lib/fluent/output.rb +29 -0
  147. data/lib/fluent/output_chain.rb +23 -0
  148. data/lib/fluent/parser.rb +23 -0
  149. data/lib/fluent/plugin/bare_output.rb +88 -0
  150. data/lib/fluent/plugin/base.rb +219 -0
  151. data/lib/fluent/plugin/buf_file.rb +256 -0
  152. data/lib/fluent/plugin/buf_file_single.rb +272 -0
  153. data/lib/fluent/plugin/buf_memory.rb +34 -0
  154. data/lib/fluent/plugin/buffer/chunk.rb +313 -0
  155. data/lib/fluent/plugin/buffer/file_chunk.rb +432 -0
  156. data/lib/fluent/plugin/buffer/file_single_chunk.rb +325 -0
  157. data/lib/fluent/plugin/buffer/memory_chunk.rb +91 -0
  158. data/lib/fluent/plugin/buffer.rb +1063 -0
  159. data/lib/fluent/plugin/compressable.rb +87 -0
  160. data/lib/fluent/plugin/exec_util.rb +22 -0
  161. data/lib/fluent/plugin/extractor.rb +132 -0
  162. data/lib/fluent/plugin/file_util.rb +22 -0
  163. data/lib/fluent/plugin/filter.rb +119 -0
  164. data/lib/fluent/plugin/filter_grep.rb +189 -0
  165. data/lib/fluent/plugin/filter_parser.rb +124 -0
  166. data/lib/fluent/plugin/filter_record_transformer.rb +325 -0
  167. data/lib/fluent/plugin/filter_stdout.rb +53 -0
  168. data/lib/fluent/plugin/formatter.rb +75 -0
  169. data/lib/fluent/plugin/formatter_csv.rb +92 -0
  170. data/lib/fluent/plugin/formatter_hash.rb +35 -0
  171. data/lib/fluent/plugin/formatter_json.rb +62 -0
  172. data/lib/fluent/plugin/formatter_ltsv.rb +44 -0
  173. data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
  174. data/lib/fluent/plugin/formatter_out_file.rb +55 -0
  175. data/lib/fluent/plugin/formatter_single_value.rb +36 -0
  176. data/lib/fluent/plugin/formatter_stdout.rb +76 -0
  177. data/lib/fluent/plugin/formatter_tsv.rb +40 -0
  178. data/lib/fluent/plugin/in_debug_agent.rb +71 -0
  179. data/lib/fluent/plugin/in_dummy.rb +18 -0
  180. data/lib/fluent/plugin/in_exec.rb +124 -0
  181. data/lib/fluent/plugin/in_forward.rb +489 -0
  182. data/lib/fluent/plugin/in_gc_stat.rb +72 -0
  183. data/lib/fluent/plugin/in_http.rb +737 -0
  184. data/lib/fluent/plugin/in_monitor_agent.rb +406 -0
  185. data/lib/fluent/plugin/in_object_space.rb +93 -0
  186. data/lib/fluent/plugin/in_sample.rb +148 -0
  187. data/lib/fluent/plugin/in_syslog.rb +346 -0
  188. data/lib/fluent/plugin/in_tail/compatibility.rb +111 -0
  189. data/lib/fluent/plugin/in_tail/dir_watcher.rb +713 -0
  190. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  191. data/lib/fluent/plugin/in_tail/io_handler.rb +391 -0
  192. data/lib/fluent/plugin/in_tail/line_feeder.rb +230 -0
  193. data/lib/fluent/plugin/in_tail/position_file.rb +269 -0
  194. data/lib/fluent/plugin/in_tail/stat_watcher.rb +52 -0
  195. data/lib/fluent/plugin/in_tail/tail_watcher.rb +276 -0
  196. data/lib/fluent/plugin/in_tail/worker_pool.rb +298 -0
  197. data/lib/fluent/plugin/in_tail.rb +917 -0
  198. data/lib/fluent/plugin/in_tcp.rb +230 -0
  199. data/lib/fluent/plugin/in_udp.rb +101 -0
  200. data/lib/fluent/plugin/in_unix.rb +197 -0
  201. data/lib/fluent/plugin/input.rb +71 -0
  202. data/lib/fluent/plugin/metrics.rb +119 -0
  203. data/lib/fluent/plugin/metrics_local.rb +96 -0
  204. data/lib/fluent/plugin/multi_output.rb +179 -0
  205. data/lib/fluent/plugin/out_buffer.rb +40 -0
  206. data/lib/fluent/plugin/out_copy.rb +120 -0
  207. data/lib/fluent/plugin/out_exec.rb +105 -0
  208. data/lib/fluent/plugin/out_exec_filter.rb +319 -0
  209. data/lib/fluent/plugin/out_file.rb +371 -0
  210. data/lib/fluent/plugin/out_forward/ack_handler.rb +176 -0
  211. data/lib/fluent/plugin/out_forward/connection_manager.rb +131 -0
  212. data/lib/fluent/plugin/out_forward/error.rb +28 -0
  213. data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
  214. data/lib/fluent/plugin/out_forward/handshake_protocol.rb +125 -0
  215. data/lib/fluent/plugin/out_forward/load_balancer.rb +114 -0
  216. data/lib/fluent/plugin/out_forward/socket_cache.rb +177 -0
  217. data/lib/fluent/plugin/out_forward.rb +865 -0
  218. data/lib/fluent/plugin/out_http.rb +419 -0
  219. data/lib/fluent/plugin/out_null.rb +74 -0
  220. data/lib/fluent/plugin/out_relabel.rb +32 -0
  221. data/lib/fluent/plugin/out_roundrobin.rb +84 -0
  222. data/lib/fluent/plugin/out_secondary_file.rb +148 -0
  223. data/lib/fluent/plugin/out_stdout.rb +81 -0
  224. data/lib/fluent/plugin/out_stream.rb +130 -0
  225. data/lib/fluent/plugin/output.rb +1688 -0
  226. data/lib/fluent/plugin/owned_by_mixin.rb +41 -0
  227. data/lib/fluent/plugin/parser.rb +274 -0
  228. data/lib/fluent/plugin/parser_apache.rb +28 -0
  229. data/lib/fluent/plugin/parser_apache2.rb +88 -0
  230. data/lib/fluent/plugin/parser_apache_error.rb +26 -0
  231. data/lib/fluent/plugin/parser_csv.rb +124 -0
  232. data/lib/fluent/plugin/parser_json.rb +118 -0
  233. data/lib/fluent/plugin/parser_ltsv.rb +49 -0
  234. data/lib/fluent/plugin/parser_msgpack.rb +72 -0
  235. data/lib/fluent/plugin/parser_multiline.rb +152 -0
  236. data/lib/fluent/plugin/parser_nginx.rb +28 -0
  237. data/lib/fluent/plugin/parser_none.rb +36 -0
  238. data/lib/fluent/plugin/parser_regexp.rb +68 -0
  239. data/lib/fluent/plugin/parser_syslog.rb +543 -0
  240. data/lib/fluent/plugin/parser_tsv.rb +47 -0
  241. data/lib/fluent/plugin/sd_file.rb +157 -0
  242. data/lib/fluent/plugin/sd_srv.rb +135 -0
  243. data/lib/fluent/plugin/sd_static.rb +58 -0
  244. data/lib/fluent/plugin/service_discovery.rb +65 -0
  245. data/lib/fluent/plugin/socket_util.rb +22 -0
  246. data/lib/fluent/plugin/storage.rb +84 -0
  247. data/lib/fluent/plugin/storage_local.rb +166 -0
  248. data/lib/fluent/plugin/string_util.rb +22 -0
  249. data/lib/fluent/plugin.rb +206 -0
  250. data/lib/fluent/plugin_helper/cert_option.rb +199 -0
  251. data/lib/fluent/plugin_helper/child_process.rb +369 -0
  252. data/lib/fluent/plugin_helper/compat_parameters.rb +343 -0
  253. data/lib/fluent/plugin_helper/counter.rb +51 -0
  254. data/lib/fluent/plugin_helper/event_emitter.rb +112 -0
  255. data/lib/fluent/plugin_helper/event_loop.rb +170 -0
  256. data/lib/fluent/plugin_helper/extract.rb +104 -0
  257. data/lib/fluent/plugin_helper/formatter.rb +147 -0
  258. data/lib/fluent/plugin_helper/http_server/app.rb +81 -0
  259. data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
  260. data/lib/fluent/plugin_helper/http_server/request.rb +53 -0
  261. data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
  262. data/lib/fluent/plugin_helper/http_server/server.rb +116 -0
  263. data/lib/fluent/plugin_helper/http_server/ssl_context_builder.rb +41 -0
  264. data/lib/fluent/plugin_helper/http_server.rb +129 -0
  265. data/lib/fluent/plugin_helper/inject.rb +154 -0
  266. data/lib/fluent/plugin_helper/metrics.rb +136 -0
  267. data/lib/fluent/plugin_helper/parser.rb +147 -0
  268. data/lib/fluent/plugin_helper/record_accessor.rb +207 -0
  269. data/lib/fluent/plugin_helper/retry_state.rb +219 -0
  270. data/lib/fluent/plugin_helper/server.rb +840 -0
  271. data/lib/fluent/plugin_helper/service_discovery/manager.rb +146 -0
  272. data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
  273. data/lib/fluent/plugin_helper/service_discovery.rb +125 -0
  274. data/lib/fluent/plugin_helper/socket.rb +288 -0
  275. data/lib/fluent/plugin_helper/socket_option.rb +98 -0
  276. data/lib/fluent/plugin_helper/storage.rb +349 -0
  277. data/lib/fluent/plugin_helper/thread.rb +180 -0
  278. data/lib/fluent/plugin_helper/timer.rb +92 -0
  279. data/lib/fluent/plugin_helper.rb +75 -0
  280. data/lib/fluent/plugin_id.rb +93 -0
  281. data/lib/fluent/process.rb +22 -0
  282. data/lib/fluent/registry.rb +117 -0
  283. data/lib/fluent/root_agent.rb +468 -0
  284. data/lib/fluent/rpc.rb +95 -0
  285. data/lib/fluent/source_only_buffer_agent.rb +102 -0
  286. data/lib/fluent/static_config_analysis.rb +195 -0
  287. data/lib/fluent/supervisor.rb +1347 -0
  288. data/lib/fluent/system_config.rb +213 -0
  289. data/lib/fluent/test/base.rb +83 -0
  290. data/lib/fluent/test/driver/base.rb +231 -0
  291. data/lib/fluent/test/driver/base_owned.rb +83 -0
  292. data/lib/fluent/test/driver/base_owner.rb +135 -0
  293. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  294. data/lib/fluent/test/driver/filter.rb +61 -0
  295. data/lib/fluent/test/driver/formatter.rb +30 -0
  296. data/lib/fluent/test/driver/input.rb +31 -0
  297. data/lib/fluent/test/driver/multi_output.rb +53 -0
  298. data/lib/fluent/test/driver/output.rb +102 -0
  299. data/lib/fluent/test/driver/parser.rb +30 -0
  300. data/lib/fluent/test/driver/storage.rb +30 -0
  301. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  302. data/lib/fluent/test/filter_test.rb +77 -0
  303. data/lib/fluent/test/formatter_test.rb +65 -0
  304. data/lib/fluent/test/helpers.rb +138 -0
  305. data/lib/fluent/test/input_test.rb +174 -0
  306. data/lib/fluent/test/log.rb +79 -0
  307. data/lib/fluent/test/output_test.rb +156 -0
  308. data/lib/fluent/test/parser_test.rb +70 -0
  309. data/lib/fluent/test/startup_shutdown.rb +44 -0
  310. data/lib/fluent/test.rb +61 -0
  311. data/lib/fluent/time.rb +513 -0
  312. data/lib/fluent/timezone.rb +171 -0
  313. data/lib/fluent/tls.rb +105 -0
  314. data/lib/fluent/unique_id.rb +39 -0
  315. data/lib/fluent/variable_store.rb +40 -0
  316. data/lib/fluent/version.rb +21 -0
  317. data/lib/fluent/win32api.rb +38 -0
  318. data/lib/fluent/winsvc.rb +130 -0
  319. data/templates/new_gem/.gitignore +8 -0
  320. data/templates/new_gem/Gemfile +3 -0
  321. data/templates/new_gem/README.md.erb +43 -0
  322. data/templates/new_gem/Rakefile +13 -0
  323. data/templates/new_gem/fluent-plugin.gemspec.erb +28 -0
  324. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
  325. data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
  326. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
  327. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
  328. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
  329. data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
  330. data/templates/new_gem/test/helper.rb.erb +7 -0
  331. data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
  332. data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
  333. data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
  334. data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
  335. data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
  336. data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
  337. data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
  338. data/templates/plugin_config_formatter/param.md-table.erb +10 -0
  339. data/templates/plugin_config_formatter/param.md.erb +34 -0
  340. data/templates/plugin_config_formatter/section.md.erb +12 -0
  341. metadata +996 -0
@@ -0,0 +1,840 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'fluent/plugin_helper/event_loop'
18
+
19
+ require 'serverengine'
20
+ require 'cool.io'
21
+ require 'socket'
22
+ require 'ipaddr'
23
+ require 'fcntl'
24
+ require 'openssl'
25
+
26
+ require_relative 'socket_option'
27
+ require_relative 'cert_option'
28
+
29
+ module Fluent
30
+ module PluginHelper
31
+ module Server
32
+ include Fluent::PluginHelper::EventLoop
33
+ include Fluent::PluginHelper::SocketOption
34
+ include Fluent::PluginHelper::CertOption
35
+
36
+ # This plugin helper doesn't support these things for now:
37
+ # * TCP/TLS keepalive
38
+ # * TLS session cache/tickets
39
+ # * unix domain sockets
40
+
41
+ # stop : [-]
42
+ # shutdown : detach server event handler from event loop (event_loop)
43
+ # close : close listening sockets
44
+ # terminate: remote all server instances
45
+
46
+ attr_reader :_servers # for tests
47
+
48
+ def server_wait_until_start
49
+ # event_loop_wait_until_start works well for this
50
+ end
51
+
52
+ def server_wait_until_stop
53
+ sleep 0.1 while @_servers.any?{|si| si.server.attached? }
54
+ @_servers.each{|si| si.server.close rescue nil }
55
+ end
56
+
57
+ PROTOCOLS = [:tcp, :udp, :tls, :unix]
58
+ CONNECTION_PROTOCOLS = [:tcp, :tls, :unix]
59
+
60
+ # server_create_connection(:title, @port) do |conn|
61
+ # # on connection
62
+ # source_addr = conn.remote_host
63
+ # source_port = conn.remote_port
64
+ # conn.data do |data|
65
+ # # on data
66
+ # conn.write resp # ...
67
+ # conn.close
68
+ # end
69
+ # end
70
+ def server_create_connection(title, port, proto: nil, bind: '0.0.0.0', shared: true, backlog: nil, tls_options: nil, **socket_options, &block)
71
+ proto ||= (@transport_config && @transport_config.protocol == :tls) ? :tls : :tcp
72
+
73
+ raise ArgumentError, "BUG: title must be a symbol" unless title && title.is_a?(Symbol)
74
+ raise ArgumentError, "BUG: port must be an integer" unless port && port.is_a?(Integer)
75
+ raise ArgumentError, "BUG: invalid protocol name" unless PROTOCOLS.include?(proto)
76
+ raise ArgumentError, "BUG: cannot create connection for UDP" unless CONNECTION_PROTOCOLS.include?(proto)
77
+
78
+ raise ArgumentError, "BUG: tls_options is available only for tls" if tls_options && proto != :tls
79
+
80
+ raise ArgumentError, "BUG: block not specified which handles connection" unless block_given?
81
+ raise ArgumentError, "BUG: block must have just one argument" unless block.arity == 1
82
+
83
+ if proto == :tcp || proto == :tls
84
+ socket_options[:linger_timeout] ||= @transport_config&.linger_timeout || 0
85
+ end
86
+
87
+ socket_options[:receive_buffer_size] ||= @transport_config&.receive_buffer_size
88
+
89
+ socket_option_validate!(proto, **socket_options)
90
+ socket_option_setter = ->(sock){ socket_option_set(sock, **socket_options) }
91
+
92
+ case proto
93
+ when :tcp
94
+ server = server_create_for_tcp_connection(shared, bind, port, backlog, socket_option_setter, &block)
95
+ when :tls
96
+ transport_config = if tls_options
97
+ server_create_transport_section_object(tls_options)
98
+ elsif @transport_config && @transport_config.protocol == :tls
99
+ @transport_config
100
+ else
101
+ raise ArgumentError, "BUG: TLS transport specified, but certification options are not specified"
102
+ end
103
+ server = server_create_for_tls_connection(shared, bind, port, transport_config, backlog, socket_option_setter, &block)
104
+ when :unix
105
+ raise "not implemented yet"
106
+ else
107
+ raise "unknown protocol #{proto}"
108
+ end
109
+
110
+ server_attach(title, proto, port, bind, shared, server)
111
+ end
112
+
113
+ # server_create(:title, @port) do |data|
114
+ # # ...
115
+ # end
116
+ # server_create(:title, @port) do |data, conn|
117
+ # # ...
118
+ # end
119
+ # server_create(:title, @port, proto: :udp, max_bytes: 2048) do |data, sock|
120
+ # sock.remote_host
121
+ # sock.remote_port
122
+ # # ...
123
+ # end
124
+ def server_create(title, port, proto: nil, bind: '0.0.0.0', shared: true, socket: nil, backlog: nil, tls_options: nil, max_bytes: nil, flags: 0, **socket_options, &callback)
125
+ proto ||= (@transport_config && @transport_config.protocol == :tls) ? :tls : :tcp
126
+
127
+ raise ArgumentError, "BUG: title must be a symbol" unless title && title.is_a?(Symbol)
128
+ raise ArgumentError, "BUG: port must be an integer" unless port && port.is_a?(Integer)
129
+ raise ArgumentError, "BUG: invalid protocol name" unless PROTOCOLS.include?(proto)
130
+
131
+ raise ArgumentError, "BUG: socket option is available only for udp" if socket && proto != :udp
132
+ raise ArgumentError, "BUG: tls_options is available only for tls" if tls_options && proto != :tls
133
+
134
+ raise ArgumentError, "BUG: block not specified which handles received data" unless block_given?
135
+ raise ArgumentError, "BUG: block must have 1 or 2 arguments" unless callback.arity == 1 || callback.arity == 2
136
+
137
+ if proto == :tcp || proto == :tls
138
+ socket_options[:linger_timeout] ||= @transport_config&.linger_timeout || 0
139
+ end
140
+
141
+ socket_options[:receive_buffer_size] ||= @transport_config&.receive_buffer_size
142
+
143
+ unless socket
144
+ socket_option_validate!(proto, **socket_options)
145
+ socket_option_setter = ->(sock){ socket_option_set(sock, **socket_options) }
146
+ end
147
+
148
+ if proto != :tcp && proto != :tls && proto != :unix # options to listen/accept connections
149
+ raise ArgumentError, "BUG: backlog is available for tcp/tls" if backlog
150
+ end
151
+ if proto != :udp # UDP options
152
+ raise ArgumentError, "BUG: max_bytes is available only for udp" if max_bytes
153
+ raise ArgumentError, "BUG: flags is available only for udp" if flags != 0
154
+ end
155
+
156
+ case proto
157
+ when :tcp
158
+ server = server_create_for_tcp_connection(shared, bind, port, backlog, socket_option_setter) do |conn|
159
+ conn.data(&callback)
160
+ end
161
+ when :tls
162
+ transport_config = if tls_options
163
+ server_create_transport_section_object(tls_options)
164
+ elsif @transport_config && @transport_config.protocol == :tls
165
+ @transport_config
166
+ else
167
+ raise ArgumentError, "BUG: TLS transport specified, but certification options are not specified"
168
+ end
169
+ server = server_create_for_tls_connection(shared, bind, port, transport_config, backlog, socket_option_setter) do |conn|
170
+ conn.data(&callback)
171
+ end
172
+ when :udp
173
+ raise ArgumentError, "BUG: max_bytes must be specified for UDP" unless max_bytes
174
+ if socket
175
+ sock = socket
176
+ close_socket = false
177
+ else
178
+ sock = server_create_udp_socket(shared, bind, port)
179
+ socket_option_setter.call(sock)
180
+ close_socket = true
181
+ end
182
+ server = EventHandler::UDPServer.new(sock, max_bytes, flags, close_socket, @log, @under_plugin_development, &callback)
183
+ when :unix
184
+ raise "not implemented yet"
185
+ else
186
+ raise "BUG: unknown protocol #{proto}"
187
+ end
188
+
189
+ server_attach(title, proto, port, bind, shared, server)
190
+ end
191
+
192
+ def server_create_tcp(title, port, **kwargs, &callback)
193
+ server_create(title, port, proto: :tcp, **kwargs, &callback)
194
+ end
195
+
196
+ def server_create_udp(title, port, **kwargs, &callback)
197
+ server_create(title, port, proto: :udp, **kwargs, &callback)
198
+ end
199
+
200
+ def server_create_tls(title, port, **kwargs, &callback)
201
+ server_create(title, port, proto: :tls, **kwargs, &callback)
202
+ end
203
+
204
+ def server_create_unix(title, port, **kwargs, &callback)
205
+ server_create(title, port, proto: :unix, **kwargs, &callback)
206
+ end
207
+
208
+ ServerInfo = Struct.new(:title, :proto, :port, :bind, :shared, :server)
209
+
210
+ def server_attach(title, proto, port, bind, shared, server)
211
+ @_servers << ServerInfo.new(title, proto, port, bind, shared, server)
212
+ event_loop_attach(server)
213
+ end
214
+
215
+ def server_create_for_tcp_connection(shared, bind, port, backlog, socket_option_setter, &block)
216
+ sock = server_create_tcp_socket(shared, bind, port)
217
+ socket_option_setter.call(sock)
218
+ close_callback = ->(conn){ @_server_mutex.synchronize{ @_server_connections.delete(conn) } }
219
+ server = Coolio::TCPServer.new(sock, nil, EventHandler::TCPServer, socket_option_setter, close_callback, @log, @under_plugin_development, block) do |conn|
220
+ unless conn.closing
221
+ @_server_mutex.synchronize do
222
+ @_server_connections << conn
223
+ end
224
+ end
225
+ end
226
+ server.listen(backlog) if backlog
227
+ server
228
+ end
229
+
230
+ def server_create_for_tls_connection(shared, bind, port, conf, backlog, socket_option_setter, &block)
231
+ context = cert_option_create_context(conf.version, conf.insecure, conf.ciphers, conf)
232
+ sock = server_create_tcp_socket(shared, bind, port)
233
+ socket_option_setter.call(sock)
234
+ close_callback = ->(conn){ @_server_mutex.synchronize{ @_server_connections.delete(conn) } }
235
+ server = Coolio::TCPServer.new(sock, nil, EventHandler::TLSServer, context, socket_option_setter, close_callback, @log, @under_plugin_development, block) do |conn|
236
+ unless conn.closing
237
+ @_server_mutex.synchronize do
238
+ @_server_connections << conn
239
+ end
240
+ end
241
+ end
242
+ server.listen(backlog) if backlog
243
+ server
244
+ end
245
+
246
+ SERVER_TRANSPORT_PARAMS = [
247
+ :protocol, :version, :min_version, :max_version, :ciphers, :insecure,
248
+ :ca_path, :cert_path, :private_key_path, :private_key_passphrase, :client_cert_auth,
249
+ :ca_cert_path, :ca_private_key_path, :ca_private_key_passphrase,
250
+ :cert_verifier, :generate_private_key_length,
251
+ :generate_cert_country, :generate_cert_state, :generate_cert_state,
252
+ :generate_cert_locality, :generate_cert_common_name,
253
+ :generate_cert_expiration, :generate_cert_digest,
254
+ :ensure_fips,
255
+ ]
256
+
257
+ def server_create_transport_section_object(opts)
258
+ transport_section = configured_section_create(:transport)
259
+ SERVER_TRANSPORT_PARAMS.each do |param|
260
+ if opts.has_key?(param)
261
+ transport_section[param] = opts[param]
262
+ end
263
+ end
264
+ transport_section
265
+ end
266
+
267
+ module ServerTransportParams
268
+ include Fluent::Configurable
269
+ config_section :transport, required: false, multi: false, init: true, param_name: :transport_config do
270
+ config_argument :protocol, :enum, list: [:tcp, :tls], default: :tcp
271
+
272
+ ### Socket Params ###
273
+
274
+ desc "The max size of socket receive buffer. SO_RCVBUF"
275
+ config_param :receive_buffer_size, :size, default: nil
276
+
277
+ # SO_LINGER 0 to send RST rather than FIN to avoid lots of connections sitting in TIME_WAIT at src.
278
+ # Set positive value if needing to send FIN on closing on non-Windows.
279
+ # (On Windows, Fluentd can send FIN with zero `linger_timeout` since Fluentd doesn't set 0 to SO_LINGER on Windows.
280
+ # See `socket_option.rb`.)
281
+ # NOTE:
282
+ # Socket-options can be specified from each plugin as needed, so most of them is not defined here for now.
283
+ # This is because there is no positive reason to do so.
284
+ # `linger_timeout` option in particular needs to be defined here
285
+ # although it can be specified from each plugin as well.
286
+ # This is because this helper fixes the default value to `0` for its own reason
287
+ # and it has a critical effect on the behavior.
288
+ desc 'The timeout time used to set linger option.'
289
+ config_param :linger_timeout, :integer, default: 0
290
+
291
+ ### TLS Params ###
292
+
293
+ config_param :version, :enum, list: Fluent::TLS::SUPPORTED_VERSIONS, default: Fluent::TLS::DEFAULT_VERSION
294
+ config_param :min_version, :enum, list: Fluent::TLS::SUPPORTED_VERSIONS, default: nil
295
+ config_param :max_version, :enum, list: Fluent::TLS::SUPPORTED_VERSIONS, default: nil
296
+ config_param :ciphers, :string, default: Fluent::TLS::CIPHERS_DEFAULT
297
+ config_param :insecure, :bool, default: false
298
+ config_param :ensure_fips, :bool, default: false
299
+
300
+ # Cert signed by public CA
301
+ config_param :ca_path, :string, default: nil
302
+ config_param :cert_path, :string, default: nil
303
+ config_param :private_key_path, :string, default: nil
304
+ config_param :private_key_passphrase, :string, default: nil, secret: true
305
+ config_param :client_cert_auth, :bool, default: false
306
+
307
+ # Cert generated and signed by private CA Certificate
308
+ config_param :ca_cert_path, :string, default: nil
309
+ config_param :ca_private_key_path, :string, default: nil
310
+ config_param :ca_private_key_passphrase, :string, default: nil, secret: true
311
+
312
+ config_param :cert_verifier, :string, default: nil
313
+
314
+ # Options for generating certs by private CA certs or self-signed
315
+ config_param :generate_private_key_length, :integer, default: 2048
316
+ config_param :generate_cert_country, :string, default: 'US'
317
+ config_param :generate_cert_state, :string, default: 'CA'
318
+ config_param :generate_cert_locality, :string, default: 'Mountain View'
319
+ config_param :generate_cert_common_name, :string, default: nil
320
+ config_param :generate_cert_expiration, :time, default: 10 * 365 * 86400 # 10years later
321
+ config_param :generate_cert_digest, :enum, list: [:sha1, :sha256, :sha384, :sha512], default: :sha256
322
+ end
323
+ end
324
+
325
+ def self.included(mod)
326
+ mod.include ServerTransportParams
327
+ end
328
+
329
+ def initialize
330
+ super
331
+ @_servers = []
332
+ @_server_connections = []
333
+ @_server_mutex = Mutex.new
334
+ end
335
+
336
+ def configure(conf)
337
+ super
338
+
339
+ if @transport_config
340
+ if @transport_config.protocol == :tls
341
+ cert_option_server_validate!(@transport_config)
342
+ end
343
+ end
344
+ end
345
+
346
+ def stop
347
+ @_server_mutex.synchronize do
348
+ @_servers.each do |si|
349
+ si.server.detach if si.server.attached?
350
+ # to refuse more connections: (connected sockets are still alive here)
351
+ si.server.close rescue nil
352
+ end
353
+ end
354
+
355
+ super
356
+ end
357
+
358
+ def shutdown
359
+ # When it invokes conn.cose, it reduces elements in @_server_connections by close_callback,
360
+ # and it reduces the number of loops. This prevents the connection closing.
361
+ # So, it requires invoking #dup to avoid the problem.
362
+ @_server_connections.dup.each do |conn|
363
+ conn.close rescue nil
364
+ end
365
+
366
+ super
367
+ end
368
+
369
+ def terminate
370
+ @_servers = []
371
+ super
372
+ end
373
+
374
+ def server_socket_manager_client
375
+ socket_manager_path = ENV['SERVERENGINE_SOCKETMANAGER_PATH']
376
+ if Fluent.windows?
377
+ socket_manager_path = socket_manager_path.to_i
378
+ end
379
+ ServerEngine::SocketManager::Client.new(socket_manager_path)
380
+ end
381
+
382
+ def server_create_tcp_socket(shared, bind, port)
383
+ sock = if shared
384
+ server_socket_manager_client.listen_tcp(bind, port)
385
+ else
386
+ # TCPServer.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
387
+ # backlog will be set by the caller, we don't need to set backlog here
388
+ tsock = Addrinfo.tcp(bind, port).listen
389
+ tsock.autoclose = false
390
+ TCPServer.for_fd(tsock.fileno)
391
+ end
392
+ # close-on-exec is set by default in Ruby 2.0 or later (, and it's unavailable on Windows)
393
+ sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) # nonblock
394
+ sock
395
+ end
396
+
397
+ def server_create_udp_socket(shared, bind, port)
398
+ sock = if shared
399
+ server_socket_manager_client.listen_udp(bind, port)
400
+ else
401
+ # UDPSocket.new doesn't set IPV6_V6ONLY flag, so use Addrinfo class instead.
402
+ usock = Addrinfo.udp(bind, port).bind
403
+ usock.autoclose = false
404
+ UDPSocket.for_fd(usock.fileno)
405
+ end
406
+ # close-on-exec is set by default in Ruby 2.0 or later (, and it's unavailable on Windows)
407
+ sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) # nonblock
408
+ sock
409
+ end
410
+
411
+ # Use string "?" for port, not integer or nil. "?" is clear than -1 or nil in the log.
412
+ PEERADDR_FAILED = ["?", "?", "name resolution failed", "?"]
413
+
414
+ class CallbackSocket
415
+ def initialize(server_type, sock, enabled_events = [], close_socket: true)
416
+ @server_type = server_type
417
+ @sock = sock
418
+ @peeraddr = nil
419
+ @enabled_events = enabled_events
420
+ @close_socket = close_socket
421
+ end
422
+
423
+ def remote_addr
424
+ @peeraddr[3]
425
+ end
426
+
427
+ def remote_host
428
+ @peeraddr[2]
429
+ end
430
+
431
+ def remote_port
432
+ @peeraddr[1]
433
+ end
434
+
435
+ def send(data, flags = 0)
436
+ @sock.send(data, flags)
437
+ end
438
+
439
+ def write(data)
440
+ raise "not implemented here"
441
+ end
442
+
443
+ def close_after_write_complete
444
+ @sock.close_after_write_complete = true
445
+ end
446
+
447
+ def close
448
+ @sock.close if @close_socket
449
+ end
450
+
451
+ def data(&callback)
452
+ on(:data, &callback)
453
+ end
454
+
455
+ def on(event, &callback)
456
+ raise "BUG: this event is disabled for #{@server_type}: #{event}" unless @enabled_events.include?(event)
457
+ case event
458
+ when :data
459
+ @sock.data(&callback)
460
+ when :write_complete
461
+ cb = ->(){ callback.call(self) }
462
+ @sock.on_write_complete(&cb)
463
+ when :close
464
+ cb = ->(){ callback.call(self) }
465
+ @sock.on_close(&cb)
466
+ else
467
+ raise "BUG: unknown event: #{event}"
468
+ end
469
+ end
470
+ end
471
+
472
+ class TCPCallbackSocket < CallbackSocket
473
+ ENABLED_EVENTS = [:data, :write_complete, :close]
474
+
475
+ attr_accessor :buffer
476
+
477
+ def initialize(sock)
478
+ super("tcp", sock, ENABLED_EVENTS)
479
+ @peeraddr = (@sock.peeraddr rescue PEERADDR_FAILED)
480
+ @buffer = ''
481
+ end
482
+
483
+ def write(data)
484
+ @sock.write(data)
485
+ end
486
+ end
487
+
488
+ class TLSCallbackSocket < CallbackSocket
489
+ ENABLED_EVENTS = [:data, :write_complete, :close]
490
+
491
+ attr_accessor :buffer
492
+
493
+ def initialize(sock)
494
+ super("tls", sock, ENABLED_EVENTS)
495
+ @peeraddr = (@sock.to_io.peeraddr rescue PEERADDR_FAILED)
496
+ @buffer = ''
497
+ end
498
+
499
+ def write(data)
500
+ @sock.write(data)
501
+ end
502
+ end
503
+
504
+ class UDPCallbackSocket < CallbackSocket
505
+ ENABLED_EVENTS = []
506
+
507
+ def initialize(sock, peeraddr, **kwargs)
508
+ super("udp", sock, ENABLED_EVENTS, **kwargs)
509
+ @peeraddr = peeraddr
510
+ end
511
+
512
+ def remote_addr
513
+ @peeraddr[3]
514
+ end
515
+
516
+ def remote_host
517
+ @peeraddr[2]
518
+ end
519
+
520
+ def remote_port
521
+ @peeraddr[1]
522
+ end
523
+
524
+ def write(data)
525
+ @sock.send(data, 0, @peeraddr[3], @peeraddr[1])
526
+ end
527
+ end
528
+
529
+ module EventHandler
530
+ class UDPServer < Coolio::IO
531
+ attr_writer :close_after_write_complete # dummy for consistent method call in callbacks
532
+
533
+ def initialize(sock, max_bytes, flags, close_socket, log, under_plugin_development, &callback)
534
+ raise ArgumentError, "socket must be a UDPSocket: sock = #{sock}" unless sock.is_a?(UDPSocket)
535
+
536
+ super(sock)
537
+
538
+ @sock = sock
539
+ @max_bytes = max_bytes
540
+ @flags = flags
541
+ @close_socket = close_socket
542
+ @log = log
543
+ @under_plugin_development = under_plugin_development
544
+ @callback = callback
545
+
546
+ on_readable_impl = case @callback.arity
547
+ when 1 then :on_readable_without_sock
548
+ when 2 then :on_readable_with_sock
549
+ else
550
+ raise "BUG: callback block must have 1 or 2 arguments"
551
+ end
552
+ self.define_singleton_method(:on_readable, method(on_readable_impl))
553
+ end
554
+
555
+ def on_readable_without_sock
556
+ begin
557
+ data = @sock.recv(@max_bytes, @flags)
558
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINTR, Errno::ECONNRESET, IOError, Errno::EBADF
559
+ return
560
+ rescue Errno::EMSGSIZE
561
+ # Windows ONLY: This happens when the data size is larger than `@max_bytes`.
562
+ @log.info "A received data was ignored since it was too large."
563
+ return
564
+ end
565
+ @callback.call(data)
566
+ rescue => e
567
+ @log.error "unexpected error in processing UDP data", error: e
568
+ @log.error_backtrace
569
+ raise if @under_plugin_development
570
+ end
571
+
572
+ def on_readable_with_sock
573
+ begin
574
+ data, addr = @sock.recvfrom(@max_bytes)
575
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINTR, Errno::ECONNRESET, IOError, Errno::EBADF
576
+ return
577
+ rescue Errno::EMSGSIZE
578
+ # Windows ONLY: This happens when the data size is larger than `@max_bytes`.
579
+ @log.info "A received data was ignored since it was too large."
580
+ return
581
+ end
582
+ @callback.call(data, UDPCallbackSocket.new(@sock, addr, close_socket: @close_socket))
583
+ rescue => e
584
+ @log.error "unexpected error in processing UDP data", error: e
585
+ @log.error_backtrace
586
+ raise if @under_plugin_development
587
+ end
588
+ end
589
+
590
+ class TCPServer < Coolio::TCPSocket
591
+ attr_reader :closing
592
+ attr_writer :close_after_write_complete
593
+
594
+ def initialize(sock, socket_option_setter, close_callback, log, under_plugin_development, connect_callback)
595
+ raise ArgumentError, "socket must be a TCPSocket: sock=#{sock}" unless sock.is_a?(TCPSocket)
596
+
597
+ socket_option_setter.call(sock)
598
+
599
+ @_handler_socket = sock
600
+ super(sock)
601
+
602
+ @log = log
603
+ @under_plugin_development = under_plugin_development
604
+
605
+ @connect_callback = connect_callback
606
+ @data_callback = nil
607
+ @close_callback = close_callback
608
+
609
+ @callback_connection = nil
610
+ @close_after_write_complete = false
611
+ @closing = false
612
+
613
+ @mutex = Mutex.new # to serialize #write and #close
614
+ end
615
+
616
+ def to_io
617
+ @_handler_socket
618
+ end
619
+
620
+ def data(&callback)
621
+ raise "data callback can be registered just once, but registered twice" if self.singleton_methods.include?(:on_read)
622
+ @data_callback = callback
623
+ on_read_impl = case callback.arity
624
+ when 1 then :on_read_without_connection
625
+ when 2 then :on_read_with_connection
626
+ else
627
+ raise "BUG: callback block must have 1 or 2 arguments"
628
+ end
629
+ self.define_singleton_method(:on_read, method(on_read_impl))
630
+ end
631
+
632
+ def write(data)
633
+ @mutex.synchronize do
634
+ super
635
+ end
636
+ end
637
+
638
+ def on_writable
639
+ super
640
+ close if @close_after_write_complete
641
+ end
642
+
643
+ def on_connect
644
+ @callback_connection = TCPCallbackSocket.new(self)
645
+ @connect_callback.call(@callback_connection)
646
+ unless @data_callback
647
+ raise "connection callback must call #data to set data callback"
648
+ end
649
+ end
650
+
651
+ def on_read_without_connection(data)
652
+ @data_callback.call(data)
653
+ rescue => e
654
+ @log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
655
+ @log.error_backtrace
656
+ close rescue nil
657
+ raise if @under_plugin_development
658
+ end
659
+
660
+ def on_read_with_connection(data)
661
+ @data_callback.call(data, @callback_connection)
662
+ rescue => e
663
+ @log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
664
+ @log.error_backtrace
665
+ close rescue nil
666
+ raise if @under_plugin_development
667
+ end
668
+
669
+ def close
670
+ @mutex.synchronize do
671
+ return if @closing
672
+ @closing = true
673
+ @close_callback.call(self)
674
+ super
675
+ end
676
+ end
677
+ end
678
+
679
+ class TLSServer < Coolio::Socket
680
+ attr_reader :closing
681
+ attr_writer :close_after_write_complete
682
+
683
+ # It can't use Coolio::TCPSocket, because Coolio::TCPSocket checks that underlying socket (1st argument of super) is TCPSocket.
684
+ def initialize(sock, context, socket_option_setter, close_callback, log, under_plugin_development, connect_callback)
685
+ raise ArgumentError, "socket must be a TCPSocket: sock=#{sock}" unless sock.is_a?(TCPSocket)
686
+
687
+ socket_option_setter.call(sock)
688
+ @_handler_socket = OpenSSL::SSL::SSLSocket.new(sock, context)
689
+ @_handler_socket.sync_close = true
690
+ @_handler_write_buffer = ''.force_encoding('ascii-8bit')
691
+ @_handler_accepted = false
692
+ super(@_handler_socket)
693
+
694
+ @log = log
695
+ @under_plugin_development = under_plugin_development
696
+
697
+ @connect_callback = connect_callback
698
+ @data_callback = nil
699
+ @close_callback = close_callback
700
+
701
+ @callback_connection = nil
702
+ @close_after_write_complete = false
703
+ @closing = false
704
+
705
+ @mutex = Mutex.new # to serialize #write and #close
706
+ end
707
+
708
+ def to_io
709
+ @_handler_socket.to_io
710
+ end
711
+
712
+ def data(&callback)
713
+ raise "data callback can be registered just once, but registered twice" if self.singleton_methods.include?(:on_read)
714
+ @data_callback = callback
715
+ on_read_impl = case callback.arity
716
+ when 1 then :on_read_without_connection
717
+ when 2 then :on_read_with_connection
718
+ else
719
+ raise "BUG: callback block must have 1 or 2 arguments"
720
+ end
721
+ self.define_singleton_method(:on_read, method(on_read_impl))
722
+ end
723
+
724
+ def write(data)
725
+ @mutex.synchronize do
726
+ @_handler_write_buffer << data
727
+ schedule_write
728
+ data.bytesize
729
+ end
730
+ end
731
+
732
+ def try_tls_accept
733
+ return true if @_handler_accepted
734
+
735
+ begin
736
+ result = @_handler_socket.accept_nonblock(exception: false) # this method call actually try to do handshake via TLS
737
+ if result == :wait_readable || result == :wait_writable
738
+ # retry accept_nonblock: there aren't enough data in underlying socket buffer
739
+ else
740
+ @_handler_accepted = true
741
+
742
+ @callback_connection = TLSCallbackSocket.new(self)
743
+ @connect_callback.call(@callback_connection)
744
+ unless @data_callback
745
+ raise "connection callback must call #data to set data callback"
746
+ end
747
+
748
+ return true
749
+ end
750
+ rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
751
+ peeraddr = (@_handler_socket.peeraddr rescue PEERADDR_FAILED)
752
+ @log.trace "unexpected error before accepting TLS connection",
753
+ addr: peeraddr[3], host: peeraddr[2], port: peeraddr[1], error: e
754
+ close rescue nil
755
+ rescue OpenSSL::SSL::SSLError => e
756
+ peeraddr = (@_handler_socket.peeraddr rescue PEERADDR_FAILED)
757
+ # Use same log level as on_readable
758
+ @log.warn "unexpected error before accepting TLS connection by OpenSSL",
759
+ addr: peeraddr[3], host: peeraddr[2], port: peeraddr[1], error: e
760
+ close rescue nil
761
+ end
762
+
763
+ false
764
+ end
765
+
766
+ def on_connect
767
+ try_tls_accept
768
+ end
769
+
770
+ def on_readable
771
+ if try_tls_accept
772
+ super
773
+ end
774
+ rescue IO::WaitReadable, IO::WaitWritable
775
+ # ignore and return with doing nothing
776
+ rescue OpenSSL::SSL::SSLError => e
777
+ @log.warn "close socket due to unexpected ssl error: #{e}"
778
+ close rescue nil
779
+ end
780
+
781
+ def on_writable
782
+ begin
783
+ @mutex.synchronize do
784
+ # Consider write_nonblock with {exception: false} when IO::WaitWritable error happens frequently.
785
+ written_bytes = @_handler_socket.write_nonblock(@_handler_write_buffer)
786
+ @_handler_write_buffer.slice!(0, written_bytes)
787
+ end
788
+
789
+ # No need to call `super` in a synchronized context because TLSServer doesn't use the inner buffer(::IO::Buffer) of Coolio::IO.
790
+ # Instead of using Coolio::IO's inner buffer, TLSServer has own buffer(`@_handler_write_buffer`). See also TLSServer#write.
791
+ # Actually, the only reason calling `super` here is call Coolio::IO#disable_write_watcher.
792
+ # If `super` is called in a synchronized context, it could cause a mutex recursive locking since Coolio::IO#on_write_complete
793
+ # eventually calls TLSServer#close which try to get a lock.
794
+ super
795
+
796
+ close if @close_after_write_complete
797
+ rescue IO::WaitWritable, IO::WaitReadable
798
+ return
799
+ rescue Errno::EINTR
800
+ return
801
+ rescue SystemCallError, IOError, SocketError
802
+ # SystemCallError catches Errno::EPIPE & Errno::ECONNRESET amongst others.
803
+ close rescue nil
804
+ return
805
+ rescue OpenSSL::SSL::SSLError => e
806
+ @log.debug "unexpected SSLError while writing data into socket connected via TLS", error: e
807
+ end
808
+ end
809
+
810
+ def on_read_without_connection(data)
811
+ @data_callback.call(data)
812
+ rescue => e
813
+ @log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
814
+ @log.error_backtrace
815
+ close rescue nil
816
+ raise if @under_plugin_development
817
+ end
818
+
819
+ def on_read_with_connection(data)
820
+ @data_callback.call(data, @callback_connection)
821
+ rescue => e
822
+ @log.error "unexpected error on reading data", host: @callback_connection.remote_host, port: @callback_connection.remote_port, error: e
823
+ @log.error_backtrace
824
+ close rescue nil
825
+ raise if @under_plugin_development
826
+ end
827
+
828
+ def close
829
+ @mutex.synchronize do
830
+ return if @closing
831
+ @closing = true
832
+ @close_callback.call(self)
833
+ super
834
+ end
835
+ end
836
+ end
837
+ end
838
+ end
839
+ end
840
+ end