Skip to content

Commit 2e0607a

Browse files
authored
Merge pull request #183 from tdyas/unix_socket_support
unix socket support
2 parents b041a25 + 825ae23 commit 2e0607a

16 files changed

+210
-69
lines changed

bin/rdebug-ide

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ options = OpenStruct.new(
2929
'value_as_nested_element' => false,
3030
'attach_mode' => false,
3131
'cli_debug' => false,
32-
'key_value_mode' => false
32+
'key_value_mode' => false,
33+
'socket_path' => nil
3334
)
3435

3536
opts = OptionParser.new do |opts|
@@ -100,6 +101,9 @@ EOB
100101
opts.on("--value-as-nested-element", "Allow to pass variable's value as nested element instead of attribute") do
101102
options.value_as_nested_element = true
102103
end
104+
opts.on("--socket-path PATH", "Listen for debugger on the given UNIX domain socket path") do |path|
105+
options.socket_path = path
106+
end
103107
opts.separator ""
104108
opts.separator "Common options:"
105109
opts.on_tail("-v", "--version", "Show version") do

lib/ruby-debug-ide.rb

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,22 @@ def interrupt_last
7474
end
7575

7676
def start_server(host = nil, port = 1234, notify_dispatcher = false)
77-
return if started?
78-
start
79-
start_control(host, port, notify_dispatcher)
77+
_start_server_common(host, port, nil, notify_dispatcher)
78+
end
79+
80+
def start_server_unix(socket_path, notify_dispatcher = false)
81+
_start_server_common(nil, 0, socket_path, notify_dispatcher)
8082
end
8183

8284
def prepare_debugger(options)
8385
@mutex = Mutex.new
8486
@proceed = ConditionVariable.new
8587

86-
start_server(options.host, options.port, options.notify_dispatcher)
88+
if options.socket_path.nil?
89+
start_server(options.host, options.port, options.notify_dispatcher)
90+
else
91+
start_server_unix(options.socket_path, options.notify_dispatcher)
92+
end
8793

8894
raise "Control thread did not start (#{@control_thread}}" unless @control_thread && @control_thread.alive?
8995

@@ -112,24 +118,53 @@ def run_prog_script
112118
end
113119

114120
def start_control(host, port, notify_dispatcher)
121+
_start_control_common(host, port, nil, notify_dispatcher)
122+
end
123+
124+
def start_control_unix(socket_path, notify_dispatcher)
125+
_start_control_common(nil, 0, socket_path, notify_dispatcher)
126+
end
127+
128+
private
129+
130+
def _start_server_common(host, port, socket_path, notify_dispatcher)
131+
return if started?
132+
start
133+
_start_control_common(host, port, socket_path, notify_dispatcher)
134+
end
135+
136+
def _start_control_common(host, port, socket_path, notify_dispatcher)
115137
raise "Debugger is not started" unless started?
116138
return if @control_thread
117139
@control_thread = DebugThread.new do
118140
begin
119-
# 127.0.0.1 seemingly works with all systems and with IPv6 as well.
120-
# "localhost" and nil have problems on some systems.
121-
host ||= '127.0.0.1'
122-
123-
server = notify_dispatcher_if_needed(host, port, notify_dispatcher) do |real_port, port_changed|
124-
s = TCPServer.new(host, real_port)
125-
print_greeting_msg $stderr, host, real_port, port_changed ? "Subprocess" : "Fast" if defined? IDE_VERSION
126-
s
141+
if socket_path.nil?
142+
# 127.0.0.1 seemingly works with all systems and with IPv6 as well.
143+
# "localhost" and nil have problems on some systems.
144+
host ||= '127.0.0.1'
145+
146+
server = notify_dispatcher_if_needed(host, port, notify_dispatcher) do |real_port, port_changed|
147+
s = TCPServer.new(host, real_port)
148+
print_greeting_msg $stderr, host, real_port, port_changed ? "Subprocess" : "Fast" if defined? IDE_VERSION
149+
s
150+
end
151+
else
152+
raise "Cannot specify host and socket_file at the same time" if host
153+
File.delete(socket_path) if File.exist?(socket_path)
154+
server = UNIXServer.new(socket_path)
155+
print_greeting_msg $stderr, nil, nil, "Fast", socket_path if defined? IDE_VERSION
127156
end
128157

129158
return unless server
130159

131160
while (session = server.accept)
132-
$stderr.puts "Connected from #{session.peeraddr[2]}" if Debugger.cli_debug
161+
if Debugger.cli_debug
162+
if session.peeraddr == 'AF_INET'
163+
$stderr.puts "Connected from #{session.peeraddr[2]}"
164+
else
165+
$stderr.puts "Connected from local client"
166+
end
167+
end
133168
dispatcher = ENV['IDE_PROCESS_DISPATCHER']
134169
if dispatcher
135170
ENV['IDE_PROCESS_DISPATCHER'] = "#{session.peeraddr[2]}:#{dispatcher}" unless dispatcher.include?(":")
@@ -153,8 +188,6 @@ def start_control(host, port, notify_dispatcher)
153188
end
154189
end
155190

156-
private
157-
158191
def notify_dispatcher_if_needed(host, port, need_notify)
159192
return yield port unless need_notify
160193

lib/ruby-debug-ide/greeter.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
module Debugger
1111

1212
class << self
13-
def print_greeting_msg(stream, host, port, debugger_name = "Fast")
13+
def print_greeting_msg(stream, host, port, debugger_name = "Fast", socket_path = nil)
1414
base_gem_name = if defined?(JRUBY_VERSION) || RUBY_VERSION < '1.9.0'
1515
'ruby-debug-base'
1616
elsif RUBY_VERSION < '2.0.0'
@@ -27,6 +27,8 @@ def print_greeting_msg(stream, host, port, debugger_name = "Fast")
2727

2828
if host && port
2929
listens_on = " listens on #{host}:#{port}\n"
30+
elsif socket_path
31+
listens_on = " listens on #{socket_path}\n"
3032
else
3133
listens_on = "\n"
3234
end
@@ -37,4 +39,4 @@ def print_greeting_msg(stream, host, port, debugger_name = "Fast")
3739
end
3840
end
3941

40-
end
42+
end

test-base/catchpoint_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env ruby
2+
3+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4+
5+
require 'test_base'
6+
7+
module CatchpointTest
8+
9+
def test_catchpoint_basics
10+
create_socket ['sleep 0.01', '5/0', 'sleep 0.01']
11+
run_to_line(1)
12+
send_next
13+
assert_suspension(@test_path, 2, 1)
14+
send_ruby('catch ZeroDivisionError')
15+
assert_catchpoint_set('ZeroDivisionError')
16+
send_next
17+
assert_exception(@test_path, 2, 'ZeroDivisionError')
18+
send_next
19+
end
20+
21+
end

test-base/enable_disable_test.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env ruby
2+
3+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
4+
5+
require 'test_base'
6+
7+
module EnableDisableTest
8+
9+
def test_enable_disable_basics
10+
create_socket ['1.upto(10) do', 'sleep 0.01', 'sleep 0.01', 'end']
11+
12+
send_test_breakpoint(2)
13+
assert_breakpoint_added_no(1)
14+
send_test_breakpoint(3)
15+
assert_breakpoint_added_no(2)
16+
17+
start_debugger
18+
assert_test_breakpoint(2)
19+
send_cont
20+
assert_test_breakpoint(3)
21+
send_cont
22+
assert_test_breakpoint(2)
23+
send_ruby('disable 2')
24+
assert_breakpoint_disabled(2)
25+
send_cont
26+
assert_test_breakpoint(2)
27+
send_cont
28+
assert_test_breakpoint(2)
29+
send_ruby('enable 2')
30+
assert_breakpoint_enabled(2)
31+
send_cont
32+
assert_test_breakpoint(3)
33+
send_cont
34+
assert_test_breakpoint(2)
35+
send_cont
36+
assert_test_breakpoint(3)
37+
send_ruby('disable 1')
38+
assert_breakpoint_disabled(1)
39+
send_ruby('disable 2')
40+
assert_breakpoint_disabled(2)
41+
send_cont
42+
end
43+
44+
end

test-base/test_base.rb

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
require 'socket'
88
require 'readers'
99
require 'test/unit'
10+
require 'thread'
1011
require 'tmpdir'
1112
require 'open3'
1213
require 'yaml'
@@ -24,6 +25,14 @@ def initialize(name)
2425
@port = nil
2526
@parser = nil
2627
@fast_fail = nil
28+
@socket_path = nil
29+
end
30+
31+
module UseUNIXDomainSocket
32+
def setup
33+
super
34+
@use_unix_socket = true
35+
end
2736
end
2837

2938
def setup
@@ -36,6 +45,9 @@ def setup
3645

3746
# XXX: tmpdir unique to test, probably parse out from self.name
3847
FileUtils.mkdir_p(TMP_DIR)
48+
49+
@use_unix_socket = false
50+
@socket_path = nil
3951
end
4052

4153
# Loads key from the _config_._yaml_ file.
@@ -83,8 +95,12 @@ def debug_jruby?
8395
end
8496

8597
def start_ruby_process(script, additional_opts = '')
86-
@port = TestBase.find_free_port
87-
cmd = debug_command(script, @port, additional_opts)
98+
if !@use_unix_socket
99+
@port = TestBase.find_free_port
100+
else
101+
@socket_path = TestBase.next_socket_path
102+
end
103+
cmd = debug_command(script, @port, @socket_path, additional_opts)
88104
debug "Starting: #{cmd}\n"
89105

90106
Thread.new do
@@ -131,6 +147,17 @@ def TestBase.find_free_port(port = 1098)
131147
end
132148
end
133149

150+
@@socket_path_seq_mutex = Mutex.new
151+
@@socket_path_sequence_num = 0
152+
def self.next_socket_path
153+
seq_num = @@socket_path_seq_mutex.synchronize do
154+
i = @@socket_path_sequence_num
155+
@@socket_path_sequence_num += 1
156+
i
157+
end
158+
File.join(TMP_DIR, "d#{seq_num}.sock")
159+
end
160+
134161
def create_file(script_name, lines)
135162
file = File.join(TMP_DIR, script_name)
136163
script_path = RUBY_VERSION >= "1.9" ? File.realdirpath(file) : file.to_s
@@ -161,11 +188,18 @@ def socket
161188
debug "Trying to connect to the debugger..."
162189
(config_load('server_start_up_timeout')*4).downto(1) do |i|
163190
begin
164-
@socket = TCPSocket.new("127.0.0.1", @port)
191+
if @socket_path
192+
@socket = UNIXSocket.new(@socket_path)
193+
else
194+
@socket = TCPSocket.new("127.0.0.1", @port)
195+
end
165196
break
166197
rescue Errno::ECONNREFUSED
167198
debug '.'
168199
sleep 0.5
200+
rescue Errno::ENOENT
201+
debug '.'
202+
sleep 0.5
169203
end
170204
end
171205
debug "\n"

test/rd_basic_test.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ class RDSteppingAndBreakpointsTest < RDTestBase
77

88
include BasicTest
99

10+
end
11+
12+
class RDUNIXSteppingAndBreakpointsTest < RDTestBase
13+
include TestBase::UseUNIXDomainSocket
14+
include BasicTest
1015
end

test/rd_catchpoint_test.rb

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
#!/usr/bin/env ruby
22

33
require 'rd_test_base'
4+
require 'catchpoint_test'
45

56
class RDCatchpointTest < RDTestBase
67

7-
def test_catchpoint_basics
8-
create_socket ['sleep 0.01', '5/0', 'sleep 0.01']
9-
run_to_line(1)
10-
send_next
11-
assert_suspension(@test_path, 2, 1)
12-
send_ruby('catch ZeroDivisionError')
13-
assert_catchpoint_set('ZeroDivisionError')
14-
send_next
15-
assert_exception(@test_path, 2, 'ZeroDivisionError')
16-
send_next
17-
end
18-
8+
include CatchpointTest
9+
1910
end
2011

12+
class RDUNIXCatchpointTest < RDTestBase
13+
include TestBase::UseUNIXDomainSocket
14+
include CatchpointTest
15+
end

test/rd_condition_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ class RDConditionTest < RDTestBase
99

1010
end
1111

12+
class RDUNIXConditionTest < RDTestBase
13+
include TestBase::UseUNIXDomainSocket
14+
include ConditionTest
15+
end

test/rd_enable_disable_test.rb

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,15 @@
11
#!/usr/bin/env ruby
22

33
require 'rd_test_base'
4+
require 'enable_disable_test'
45

56
class RDEnableDisableTest < RDTestBase
67

7-
def test_enable_disable_basics
8-
create_socket ['1.upto(10) do', 'sleep 0.01', 'sleep 0.01', 'end']
9-
10-
send_test_breakpoint(2)
11-
assert_breakpoint_added_no(1)
12-
send_test_breakpoint(3)
13-
assert_breakpoint_added_no(2)
14-
15-
start_debugger
16-
assert_test_breakpoint(2)
17-
send_cont
18-
assert_test_breakpoint(3)
19-
send_cont
20-
assert_test_breakpoint(2)
21-
send_ruby('disable 2')
22-
assert_breakpoint_disabled(2)
23-
send_cont
24-
assert_test_breakpoint(2)
25-
send_cont
26-
assert_test_breakpoint(2)
27-
send_ruby('enable 2')
28-
assert_breakpoint_enabled(2)
29-
send_cont
30-
assert_test_breakpoint(3)
31-
send_cont
32-
assert_test_breakpoint(2)
33-
send_cont
34-
assert_test_breakpoint(3)
35-
send_ruby('disable 1')
36-
assert_breakpoint_disabled(1)
37-
send_ruby('disable 2')
38-
assert_breakpoint_disabled(2)
39-
send_cont
40-
end
8+
include EnableDisableTest
419

4210
end
4311

12+
class RDUNIXEnableDisableTest < RDTestBase
13+
include TestBase::UseUNIXDomainSocket
14+
include EnableDisableTest
15+
end

0 commit comments

Comments
 (0)