shogi-server source
修订版 | 452e4e0ddfb420fbd61224bd2fe914e0276c96e0 (tree) |
---|---|
时间 | 2020-10-05 00:06:13 |
作者 | Mizar <mizar.jp@gmai...> |
Commiter | Mizar |
tcp_keepalive
@@ -28,6 +28,7 @@ $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "..")) | ||
28 | 28 | require 'shogi_server' |
29 | 29 | require 'logger' |
30 | 30 | require 'socket' |
31 | +require 'timeout' | |
31 | 32 | |
32 | 33 | # Global variables |
33 | 34 |
@@ -103,7 +104,12 @@ def parse_command_line | ||
103 | 104 | ["--password", GetoptLong::REQUIRED_ARGUMENT], |
104 | 105 | ["--ponder", GetoptLong::NO_ARGUMENT], |
105 | 106 | ["--port", GetoptLong::REQUIRED_ARGUMENT], |
106 | - ["--floodgate", GetoptLong::NO_ARGUMENT]) | |
107 | + ["--floodgate", GetoptLong::NO_ARGUMENT], | |
108 | + ["--ignoremultiselect", GetoptLong::NO_ARGUMENT], | |
109 | + ["--tcpkeepalive", GetoptLong::REQUIRED_ARGUMENT], | |
110 | + ["--tcpkeepalive-idle", GetoptLong::REQUIRED_ARGUMENT], | |
111 | + ["--tcpkeepalive-intvl", GetoptLong::REQUIRED_ARGUMENT], | |
112 | + ["--tcpkeepalive-cnt", GetoptLong::REQUIRED_ARGUMENT]) | |
107 | 113 | parser.quiet = true |
108 | 114 | begin |
109 | 115 | parser.each_option do |name, arg| |
@@ -131,6 +137,15 @@ def parse_command_line | ||
131 | 137 | options[:port] ||= ENV["PORT"] || 4081 |
132 | 138 | options[:port] = options[:port].to_i |
133 | 139 | options[:floodgate] ||= ENV["FLOODGATE"] || false |
140 | + options[:ignoremultiselect] ||= ENV["IGNORE_MULTISELECT"] || false | |
141 | + options[:tcpkeepalive] ||= ENV["TCPKEEPALIVE"] || 0 | |
142 | + options[:tcpkeepalive] = options[:tcpkeepalive].to_i | |
143 | + options[:tcpkeepalive_idle] ||= ENV["TCPKEEPALIVE_IDLE"] || 50 | |
144 | + options[:tcpkeepalive_idle] = options[:tcpkeepalive_idle].to_i | |
145 | + options[:tcpkeepalive_intvl] ||= ENV["TCPKEEPALIVE_INTVL"] || 5 | |
146 | + options[:tcpkeepalive_intvl] = options[:tcpkeepalive_intvl].to_i | |
147 | + options[:tcpkeepalive_cnt] ||= ENV["TCPKEEPALIVE_CNT"] || 9 | |
148 | + options[:tcpkeepalive_cnt] = options[:tcpkeepalive_cnt].to_i | |
134 | 149 | |
135 | 150 | return options |
136 | 151 | end |
@@ -466,7 +481,14 @@ class BridgeState | ||
466 | 481 | throw "Bad state at event_engine_recv: #@state" |
467 | 482 | end |
468 | 483 | |
469 | - str = $server.gets | |
484 | + str = nil | |
485 | + begin | |
486 | + Timeout.timeout(0.001){ | |
487 | + str = $server.gets | |
488 | + } | |
489 | + rescue Timeout::Error | |
490 | + $logger.error "event_server_recv timeout" | |
491 | + end | |
470 | 492 | return if str.nil? || str.strip.empty? |
471 | 493 | log_server_recv str |
472 | 494 |
@@ -619,6 +641,30 @@ def login | ||
619 | 641 | begin |
620 | 642 | $server = TCPSocket.open($options[:host], $options[:port]) |
621 | 643 | $server.sync = true |
644 | + if $options[:tcpkeepalive] > 0 && | |
645 | + Socket.const_defined?(:SOL_SOCKET) && | |
646 | + Socket.const_defined?(:SO_KEEPALIVE) && | |
647 | + Socket.const_defined?(:IPPROTO_TCP) | |
648 | + $server.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
649 | + if Socket.const_defined?(:TCP_KEEPIDLE) && | |
650 | + Socket.const_defined?(:TCP_KEEPINTVL) && | |
651 | + Socket.const_defined?(:TCP_KEEPCNT) | |
652 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, $options[:tcpkeepalive_idle]) | |
653 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, $options[:tcpkeepalive_intvl]) | |
654 | + $server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, $options[:tcpkeepalive_cnt]) | |
655 | + elsif RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin|bccwin/ | |
656 | + # Windows 10 (1709 or later) ws2ipdef.h | |
657 | + # https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options | |
658 | + $server.setsockopt(Socket::IPPROTO_TCP, 3, $options[:tcpkeepalive_idle]) | |
659 | + $server.setsockopt(Socket::IPPROTO_TCP, 17, $options[:tcpkeepalive_intvl]) | |
660 | + $server.setsockopt(Socket::IPPROTO_TCP, 16, $options[:tcpkeepalive_cnt]) | |
661 | + elsif RUBY_PLATFORM.downcase =~ /darwin/ | |
662 | + # macOS 10.12.6 (Sierra) /usr/include/netinet/tcp.h | |
663 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x10, $options[:tcpkeepalive_idle]) | |
664 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x101, $options[:tcpkeepalive_intvl]) | |
665 | + $server.setsockopt(Socket::IPPROTO_TCP, 0x102, $options[:tcpkeepalive_cnt]) | |
666 | + end | |
667 | + end | |
622 | 668 | rescue |
623 | 669 | log_error "Failed to connect to the server" |
624 | 670 | $server = nil |
@@ -663,7 +709,7 @@ end | ||
663 | 709 | # |
664 | 710 | def main_loop |
665 | 711 | while true |
666 | - ret, = select([$server, $engine], nil, nil, 60) | |
712 | + ret, = select([$engine, $server], nil, nil, 60) | |
667 | 713 | unless ret |
668 | 714 | # Send keep-alive |
669 | 715 | if $bridge_state.too_quiet? |
@@ -673,12 +719,14 @@ def main_loop | ||
673 | 719 | next |
674 | 720 | end |
675 | 721 | |
676 | - ret.each do |io| | |
677 | - case io | |
678 | - when $engine | |
679 | - $bridge_state.do_engine_recv | |
680 | - when $server | |
681 | - $bridge_state.do_sever_recv | |
722 | + ret.each_with_index do |io, idx| | |
723 | + if (!$options[:ignoremultiselect] || idx == 0) | |
724 | + case io | |
725 | + when $engine | |
726 | + $bridge_state.do_engine_recv | |
727 | + when $server | |
728 | + $bridge_state.do_sever_recv | |
729 | + end | |
682 | 730 | end |
683 | 731 | end |
684 | 732 |
@@ -208,7 +208,10 @@ def parse_command_line | ||
208 | 208 | ["--least-time-per-move", GetoptLong::REQUIRED_ARGUMENT], |
209 | 209 | ["--max-moves", GetoptLong::REQUIRED_ARGUMENT], |
210 | 210 | ["--pid-file", GetoptLong::REQUIRED_ARGUMENT], |
211 | - ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT]) | |
211 | + ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT], | |
212 | + ["--tcpkeepalive-idle", GetoptLong::REQUIRED_ARGUMENT], | |
213 | + ["--tcpkeepalive-intvl", GetoptLong::REQUIRED_ARGUMENT], | |
214 | + ["--tcpkeepalive-cnt", GetoptLong::REQUIRED_ARGUMENT]) | |
212 | 215 | parser.quiet = true |
213 | 216 | begin |
214 | 217 | parser.each_option do |name, arg| |
@@ -283,6 +286,15 @@ def check_command_line | ||
283 | 286 | |
284 | 287 | $options["least-time-per-move"] ||= ShogiServer::Default_Least_Time_Per_Move |
285 | 288 | $options["least-time-per-move"] = $options["least-time-per-move"].to_i |
289 | + | |
290 | + $options["tcpkeepalive-idle"] ||= ShogiServer::Default_TcpKeepAlive_Idle | |
291 | + $options["tcpkeepalive-idle"] = $options["tcpkeepalive-idle"].to_i | |
292 | + | |
293 | + $options["tcpkeepalive-intvl"] ||= ShogiServer::Default_TcpKeepAlive_Intvl | |
294 | + $options["tcpkeepalive-intvl"] = $options["tcpkeepalive-intvl"].to_i | |
295 | + | |
296 | + $options["tcpkeepalive-cnt"] ||= ShogiServer::Default_TcpKeepAlive_Cnt | |
297 | + $options["tcpkeepalive-cnt"] = $options["tcpkeepalive-cnt"].to_i | |
286 | 298 | end |
287 | 299 | |
288 | 300 | # See if a file can be created in the directory. |
@@ -455,8 +467,30 @@ def main | ||
455 | 467 | server.start do |client| |
456 | 468 | begin |
457 | 469 | # client.sync = true # this is already set in WEBrick |
458 | - client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
459 | - # Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time | |
470 | + if Socket.const_defined?(:SOL_SOCKET) && | |
471 | + Socket.const_defined?(:SO_KEEPALIVE) && | |
472 | + Socket.const_defined?(:IPPROTO_TCP) | |
473 | + client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) | |
474 | + # Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time | |
475 | + if Socket.const_defined?(:TCP_KEEPIDLE) && | |
476 | + Socket.const_defined?(:TCP_KEEPINTVL) && | |
477 | + Socket.const_defined?(:TCP_KEEPCNT) | |
478 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPIDLE, $options["tcpkeepalive-idle"]) | |
479 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPINTVL, $options["tcpkeepalive-intvl"]) | |
480 | + client.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_KEEPCNT, $options["tcpkeepalive-cnt"]) | |
481 | + elsif RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin|bccwin/ | |
482 | + # Windows 10 (1709 or later) ws2ipdef.h | |
483 | + # https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options | |
484 | + client.setsockopt(Socket::IPPROTO_TCP, 3, $options["tcpkeepalive-idle"]) | |
485 | + client.setsockopt(Socket::IPPROTO_TCP, 17, $options["tcpkeepalive-intvl"]) | |
486 | + client.setsockopt(Socket::IPPROTO_TCP, 16, $options["tcpkeepalive-cnt"]) | |
487 | + elsif RUBY_PLATFORM.downcase =~ /darwin/ | |
488 | + # macOS 10.12.6 (Sierra) /usr/include/netinet/tcp.h | |
489 | + client.setsockopt(Socket::IPPROTO_TCP, 0x10, $options["tcpkeepalive-idle"]) | |
490 | + client.setsockopt(Socket::IPPROTO_TCP, 0x101, $options["tcpkeepalive-intvl"]) | |
491 | + client.setsockopt(Socket::IPPROTO_TCP, 0x102, $options["tcpkeepalive-cnt"]) | |
492 | + end | |
493 | + end | |
460 | 494 | player, login = login_loop(client) # loop |
461 | 495 | unless player |
462 | 496 | log_error("Detected a timed out login attempt") |
@@ -50,6 +50,9 @@ Default_Timeout = 60 # for single socket operation | ||
50 | 50 | Default_Game_Name = "default-1500-0" |
51 | 51 | Default_Max_Moves = 256 |
52 | 52 | Default_Least_Time_Per_Move = 0 |
53 | +Default_TcpKeepAlive_Idle = 50 | |
54 | +Default_TcpKeepAlive_Intvl = 5 | |
55 | +Default_TcpKeepAlive_Cnt = 9 | |
53 | 56 | One_Time = 10 |
54 | 57 | Login_Time = 300 # time for LOGIN |
55 | 58 | Revision = "20201004" |