shogi-server source
修订版 | 36b41e7cb23be85e2c766bc3ee2b27bce2c870c3 (tree) |
---|---|
时间 | 2020-12-06 18:48:46 |
作者 | Daigo Moriwaki <beatles@sgtp...> |
Commiter | Daigo Moriwaki |
Merge branch 'master' into wdoor-stable
@@ -1,3 +1,20 @@ | ||
1 | +2020-12-06 Daigo Moriwaki <daigo at debian dot org> | |
2 | + | |
3 | + * [shogi-server] Improve timed-up detection (continued). | |
4 | + The server now checks timed up when it receives a-single-space keep | |
5 | + alive messages as well. | |
6 | + Thanks to mizar for reports and patches. | |
7 | + (Closes #40821) | |
8 | + * [shogi-server] Support listening on IPv6 addresses | |
9 | + Thanks to mizar for a patch. | |
10 | + (Closes #40822) | |
11 | + * [shogi-server] Make invalid comments illegal | |
12 | + Some client sent moves with comments in an invalid format like | |
13 | + "+7776FU '* 30 -3334FU +2726FU". Such messages are now deemed | |
14 | + illegal. | |
15 | + Thanks to mizar for a report. | |
16 | + * [shogi-server] Bump up the revision to 20201206 | |
17 | + | |
1 | 18 | 2020-10-04 Daigo Moriwaki <daigo at debian dot org> |
2 | 19 | |
3 | 20 | * [shogi-server] Improve timed-up detection. |
@@ -440,7 +440,7 @@ def main | ||
440 | 440 | $players = Set.new |
441 | 441 | |
442 | 442 | config = {} |
443 | - config[:BindAddress] = "0.0.0.0" | |
443 | + config[:BindAddress] = nil # both IPv4 and IPv6 | |
444 | 444 | config[:Port] = port |
445 | 445 | config[:ServerType] = WEBrick::Daemon if $options["daemon"] |
446 | 446 | config[:Logger] = $logger |
@@ -53,7 +53,7 @@ Default_Max_Moves = 256 | ||
53 | 53 | Default_Least_Time_Per_Move = 0 |
54 | 54 | One_Time = 10 |
55 | 55 | Login_Time = 300 # time for LOGIN |
56 | -Revision = "20201004" | |
56 | +Revision = "20201206" | |
57 | 57 | |
58 | 58 | RELOAD_FILES = ["shogi_server/league/floodgate.rb", |
59 | 59 | "shogi_server/league/persistent.rb", |
@@ -642,7 +642,7 @@ EOF | ||
642 | 642 | # - :max_moves |
643 | 643 | # |
644 | 644 | def handle_one_move(str, sente=nil) |
645 | - if (str =~ /^([\+\-])(\d)(\d)(\d)(\d)([A-Z]{2})/) | |
645 | + if (str =~ /^([\+\-])(\d)(\d)(\d)(\d)([A-Z]{2})$/) | |
646 | 646 | sg = $1 |
647 | 647 | x0 = $2.to_i |
648 | 648 | y0 = $3.to_i |
@@ -28,7 +28,7 @@ module ShogiServer | ||
28 | 28 | def Command.factory(str, player, time=Time.now) |
29 | 29 | cmd = nil |
30 | 30 | case str |
31 | - when "", /^%[^%]/, :timeout | |
31 | + when "", " ", /^%[^%]/, :timeout | |
32 | 32 | cmd = SpecialCommand.new(str, player) |
33 | 33 | when /^[\+\-][^%]/ |
34 | 34 | cmd = MoveCommand.new(str, player) |
@@ -174,9 +174,15 @@ module ShogiServer | ||
174 | 174 | |
175 | 175 | # Command like "%TORYO", :timeout, or keep alive |
176 | 176 | # |
177 | - # Keep Alive is an application-level protocol. Whenever the server receives | |
178 | - # an LF, it sends back an LF. Note that the 30 sec rule (client may not send | |
179 | - # LF again within 30 sec) is not implemented yet. | |
177 | + # Keep Alive is an application-level protocol here. There are two representations: | |
178 | + # 1) LF (empty string) | |
179 | + # The server sends back an LF (empty string). | |
180 | + # Note that the 30 sec rule (client may not send LF again within 30 sec) | |
181 | + # is not implemented yet. | |
182 | + # This is compliant with CSA's protocol in certain situations. | |
183 | + # 2) Space + LF (a single space) | |
184 | + # The sever replies nothing. | |
185 | + # This is an enhancement to CSA's protocol. | |
180 | 186 | # |
181 | 187 | class SpecialCommand < Command |
182 | 188 | def initialize(str, player) |
@@ -186,9 +192,9 @@ module ShogiServer | ||
186 | 192 | def call |
187 | 193 | rc = :continue |
188 | 194 | |
189 | - if @str == "" # keep alive | |
195 | + if @str == "" || @str == " " # keep alive | |
190 | 196 | log_debug("received keep alive from #{@player.name}") |
191 | - @player.write_safe("\n") | |
197 | + @player.write_safe("\n") if @str == "" | |
192 | 198 | # Fall back to :timeout to check the game gets timed up |
193 | 199 | @str = :timeout |
194 | 200 | end |
@@ -998,3 +998,23 @@ class TestSplitMoves < Test::Unit::TestCase | ||
998 | 998 | end |
999 | 999 | end |
1000 | 1000 | end |
1001 | + | |
1002 | + | |
1003 | +class Test_illegal < Test::Unit::TestCase | |
1004 | + def test_invaild_comment | |
1005 | + b = ShogiServer::Board.new | |
1006 | + b.set_from_str(<<EOM) | |
1007 | +P1-KY-KE-GI-KI-OU-KI-GI-KE-KY | |
1008 | +P2 * -HI * * * * * -KA * | |
1009 | +P3-FU-FU-FU-FU-FU-FU-FU-FU-FU | |
1010 | +P4 * * * * * * * * * | |
1011 | +P5 * * * * * * * * * | |
1012 | +P6 * * * * * * * * * | |
1013 | +P7+FU+FU+FU+FU+FU+FU+FU+FU+FU | |
1014 | +P8 * +KA * * * * * +HI * | |
1015 | +P9+KY+KE+GI+KI+OU+KI+GI+KE+KY | |
1016 | +EOM | |
1017 | + | |
1018 | + assert_equal(:illegal, b.handle_one_move("+7776FU '* 30 -3334FU +2726FU")) | |
1019 | + end | |
1020 | +end |
@@ -90,7 +90,12 @@ class TestFactoryMethod < Test::Unit::TestCase | ||
90 | 90 | |
91 | 91 | def test_keep_alive_command |
92 | 92 | cmd = ShogiServer::Command.factory("", @p) |
93 | - assert_instance_of(ShogiServer::KeepAliveCommand, cmd) | |
93 | + assert_instance_of(ShogiServer::SpecialCommand, cmd) | |
94 | + end | |
95 | + | |
96 | + def test_keep_alive_command_space | |
97 | + cmd = ShogiServer::Command.factory(" ", @p) | |
98 | + assert_instance_of(ShogiServer::SpecialCommand, cmd) | |
94 | 99 | end |
95 | 100 | |
96 | 101 | def test_move_command |
@@ -214,7 +219,7 @@ class TestFactoryMethod < Test::Unit::TestCase | ||
214 | 219 | end |
215 | 220 | |
216 | 221 | def test_space_command |
217 | - cmd = ShogiServer::Command.factory(" ", @p) | |
222 | + cmd = ShogiServer::Command.factory(" ", @p) | |
218 | 223 | assert_instance_of(ShogiServer::SpaceCommand, cmd) |
219 | 224 | end |
220 | 225 |
@@ -315,20 +320,6 @@ end | ||
315 | 320 | |
316 | 321 | # |
317 | 322 | # |
318 | -class TestKeepAliveCommand < Test::Unit::TestCase | |
319 | - def setup | |
320 | - @p = MockPlayer.new | |
321 | - end | |
322 | - | |
323 | - def test_call | |
324 | - cmd = ShogiServer::KeepAliveCommand.new("", @p) | |
325 | - rc = cmd.call | |
326 | - assert_equal(:continue, rc) | |
327 | - end | |
328 | -end | |
329 | - | |
330 | -# | |
331 | -# | |
332 | 323 | class TestMoveCommand < Test::Unit::TestCase |
333 | 324 | def setup |
334 | 325 | @p = MockPlayer.new |
@@ -350,6 +341,13 @@ class TestMoveCommand < Test::Unit::TestCase | ||
350 | 341 | assert_equal("'*comment", @game.log.first) |
351 | 342 | end |
352 | 343 | |
344 | + def test_comment_illegal | |
345 | + cmd = ShogiServer::MoveCommand.new("+7776FU 'comment", @p) | |
346 | + rc = cmd.call | |
347 | + assert_equal(:continue, rc) | |
348 | + assert_nil(@game.log.first) | |
349 | + end | |
350 | + | |
353 | 351 | def test_x1_return |
354 | 352 | @game.finish_flag = true |
355 | 353 | @p.protocol = ShogiServer::LoginCSA::PROTOCOL |
@@ -417,6 +415,18 @@ class TestSpecialComand < Test::Unit::TestCase | ||
417 | 415 | rc = cmd.call |
418 | 416 | assert_equal(:continue, rc) |
419 | 417 | end |
418 | + | |
419 | + def test_keep_alive | |
420 | + cmd = ShogiServer::SpecialCommand.new("", @p) | |
421 | + rc = cmd.call | |
422 | + assert_equal(:continue, rc) | |
423 | + end | |
424 | + | |
425 | + def test_keep_alive_space | |
426 | + cmd = ShogiServer::SpecialCommand.new(" ", @p) | |
427 | + rc = cmd.call | |
428 | + assert_equal(:continue, rc) | |
429 | + end | |
420 | 430 | end |
421 | 431 | |
422 | 432 | # |
@@ -822,7 +832,7 @@ class TestSpaceCommand < Test::Unit::TestCase | ||
822 | 832 | end |
823 | 833 | |
824 | 834 | def test_call |
825 | - cmd = ShogiServer::SpaceCommand.new("", @p) | |
835 | + cmd = ShogiServer::SpaceCommand.new(" ", @p) | |
826 | 836 | rc = cmd.call |
827 | 837 | |
828 | 838 | assert_equal(:continue, rc) |
@@ -30,3 +30,7 @@ def log_info(msg) | ||
30 | 30 | $logger.info(msg) |
31 | 31 | end |
32 | 32 | |
33 | +def log_debug(msg) | |
34 | + $logger.info(msg) | |
35 | +end | |
36 | + |