Skip to content

Commit

Permalink
Merge pull request #183 from tdyas/unix_socket_support
Browse files Browse the repository at this point in the history
unix socket support
  • Loading branch information
ViugiNick authored Dec 11, 2019
2 parents b041a25 + 825ae23 commit 2e0607a
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 69 deletions.
6 changes: 5 additions & 1 deletion bin/rdebug-ide
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ options = OpenStruct.new(
'value_as_nested_element' => false,
'attach_mode' => false,
'cli_debug' => false,
'key_value_mode' => false
'key_value_mode' => false,
'socket_path' => nil
)

opts = OptionParser.new do |opts|
Expand Down Expand Up @@ -100,6 +101,9 @@ EOB
opts.on("--value-as-nested-element", "Allow to pass variable's value as nested element instead of attribute") do
options.value_as_nested_element = true
end
opts.on("--socket-path PATH", "Listen for debugger on the given UNIX domain socket path") do |path|
options.socket_path = path
end
opts.separator ""
opts.separator "Common options:"
opts.on_tail("-v", "--version", "Show version") do
Expand Down
63 changes: 48 additions & 15 deletions lib/ruby-debug-ide.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,22 @@ def interrupt_last
end

def start_server(host = nil, port = 1234, notify_dispatcher = false)
return if started?
start
start_control(host, port, notify_dispatcher)
_start_server_common(host, port, nil, notify_dispatcher)
end

def start_server_unix(socket_path, notify_dispatcher = false)
_start_server_common(nil, 0, socket_path, notify_dispatcher)
end

def prepare_debugger(options)
@mutex = Mutex.new
@proceed = ConditionVariable.new

start_server(options.host, options.port, options.notify_dispatcher)
if options.socket_path.nil?
start_server(options.host, options.port, options.notify_dispatcher)
else
start_server_unix(options.socket_path, options.notify_dispatcher)
end

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

Expand Down Expand Up @@ -112,24 +118,53 @@ def run_prog_script
end

def start_control(host, port, notify_dispatcher)
_start_control_common(host, port, nil, notify_dispatcher)
end

def start_control_unix(socket_path, notify_dispatcher)
_start_control_common(nil, 0, socket_path, notify_dispatcher)
end

private

def _start_server_common(host, port, socket_path, notify_dispatcher)
return if started?
start
_start_control_common(host, port, socket_path, notify_dispatcher)
end

def _start_control_common(host, port, socket_path, notify_dispatcher)
raise "Debugger is not started" unless started?
return if @control_thread
@control_thread = DebugThread.new do
begin
# 127.0.0.1 seemingly works with all systems and with IPv6 as well.
# "localhost" and nil have problems on some systems.
host ||= '127.0.0.1'

server = notify_dispatcher_if_needed(host, port, notify_dispatcher) do |real_port, port_changed|
s = TCPServer.new(host, real_port)
print_greeting_msg $stderr, host, real_port, port_changed ? "Subprocess" : "Fast" if defined? IDE_VERSION
s
if socket_path.nil?
# 127.0.0.1 seemingly works with all systems and with IPv6 as well.
# "localhost" and nil have problems on some systems.
host ||= '127.0.0.1'

server = notify_dispatcher_if_needed(host, port, notify_dispatcher) do |real_port, port_changed|
s = TCPServer.new(host, real_port)
print_greeting_msg $stderr, host, real_port, port_changed ? "Subprocess" : "Fast" if defined? IDE_VERSION
s
end
else
raise "Cannot specify host and socket_file at the same time" if host
File.delete(socket_path) if File.exist?(socket_path)
server = UNIXServer.new(socket_path)
print_greeting_msg $stderr, nil, nil, "Fast", socket_path if defined? IDE_VERSION
end

return unless server

while (session = server.accept)
$stderr.puts "Connected from #{session.peeraddr[2]}" if Debugger.cli_debug
if Debugger.cli_debug
if session.peeraddr == 'AF_INET'
$stderr.puts "Connected from #{session.peeraddr[2]}"
else
$stderr.puts "Connected from local client"
end
end
dispatcher = ENV['IDE_PROCESS_DISPATCHER']
if dispatcher
ENV['IDE_PROCESS_DISPATCHER'] = "#{session.peeraddr[2]}:#{dispatcher}" unless dispatcher.include?(":")
Expand All @@ -153,8 +188,6 @@ def start_control(host, port, notify_dispatcher)
end
end

private

def notify_dispatcher_if_needed(host, port, need_notify)
return yield port unless need_notify

Expand Down
6 changes: 4 additions & 2 deletions lib/ruby-debug-ide/greeter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
module Debugger

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

if host && port
listens_on = " listens on #{host}:#{port}\n"
elsif socket_path
listens_on = " listens on #{socket_path}\n"
else
listens_on = "\n"
end
Expand All @@ -37,4 +39,4 @@ def print_greeting_msg(stream, host, port, debugger_name = "Fast")
end
end

end
end
21 changes: 21 additions & 0 deletions test-base/catchpoint_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env ruby

$:.unshift File.join(File.dirname(__FILE__), "..", "lib")

require 'test_base'

module CatchpointTest

def test_catchpoint_basics
create_socket ['sleep 0.01', '5/0', 'sleep 0.01']
run_to_line(1)
send_next
assert_suspension(@test_path, 2, 1)
send_ruby('catch ZeroDivisionError')
assert_catchpoint_set('ZeroDivisionError')
send_next
assert_exception(@test_path, 2, 'ZeroDivisionError')
send_next
end

end
44 changes: 44 additions & 0 deletions test-base/enable_disable_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env ruby

$:.unshift File.join(File.dirname(__FILE__), "..", "lib")

require 'test_base'

module EnableDisableTest

def test_enable_disable_basics
create_socket ['1.upto(10) do', 'sleep 0.01', 'sleep 0.01', 'end']

send_test_breakpoint(2)
assert_breakpoint_added_no(1)
send_test_breakpoint(3)
assert_breakpoint_added_no(2)

start_debugger
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(3)
send_cont
assert_test_breakpoint(2)
send_ruby('disable 2')
assert_breakpoint_disabled(2)
send_cont
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(2)
send_ruby('enable 2')
assert_breakpoint_enabled(2)
send_cont
assert_test_breakpoint(3)
send_cont
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(3)
send_ruby('disable 1')
assert_breakpoint_disabled(1)
send_ruby('disable 2')
assert_breakpoint_disabled(2)
send_cont
end

end
40 changes: 37 additions & 3 deletions test-base/test_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'socket'
require 'readers'
require 'test/unit'
require 'thread'
require 'tmpdir'
require 'open3'
require 'yaml'
Expand All @@ -24,6 +25,14 @@ def initialize(name)
@port = nil
@parser = nil
@fast_fail = nil
@socket_path = nil
end

module UseUNIXDomainSocket
def setup
super
@use_unix_socket = true
end
end

def setup
Expand All @@ -36,6 +45,9 @@ def setup

# XXX: tmpdir unique to test, probably parse out from self.name
FileUtils.mkdir_p(TMP_DIR)

@use_unix_socket = false
@socket_path = nil
end

# Loads key from the _config_._yaml_ file.
Expand Down Expand Up @@ -83,8 +95,12 @@ def debug_jruby?
end

def start_ruby_process(script, additional_opts = '')
@port = TestBase.find_free_port
cmd = debug_command(script, @port, additional_opts)
if !@use_unix_socket
@port = TestBase.find_free_port
else
@socket_path = TestBase.next_socket_path
end
cmd = debug_command(script, @port, @socket_path, additional_opts)
debug "Starting: #{cmd}\n"

Thread.new do
Expand Down Expand Up @@ -131,6 +147,17 @@ def TestBase.find_free_port(port = 1098)
end
end

@@socket_path_seq_mutex = Mutex.new
@@socket_path_sequence_num = 0
def self.next_socket_path
seq_num = @@socket_path_seq_mutex.synchronize do
i = @@socket_path_sequence_num
@@socket_path_sequence_num += 1
i
end
File.join(TMP_DIR, "d#{seq_num}.sock")
end

def create_file(script_name, lines)
file = File.join(TMP_DIR, script_name)
script_path = RUBY_VERSION >= "1.9" ? File.realdirpath(file) : file.to_s
Expand Down Expand Up @@ -161,11 +188,18 @@ def socket
debug "Trying to connect to the debugger..."
(config_load('server_start_up_timeout')*4).downto(1) do |i|
begin
@socket = TCPSocket.new("127.0.0.1", @port)
if @socket_path
@socket = UNIXSocket.new(@socket_path)
else
@socket = TCPSocket.new("127.0.0.1", @port)
end
break
rescue Errno::ECONNREFUSED
debug '.'
sleep 0.5
rescue Errno::ENOENT
debug '.'
sleep 0.5
end
end
debug "\n"
Expand Down
5 changes: 5 additions & 0 deletions test/rd_basic_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ class RDSteppingAndBreakpointsTest < RDTestBase

include BasicTest

end

class RDUNIXSteppingAndBreakpointsTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include BasicTest
end
19 changes: 7 additions & 12 deletions test/rd_catchpoint_test.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
#!/usr/bin/env ruby

require 'rd_test_base'
require 'catchpoint_test'

class RDCatchpointTest < RDTestBase

def test_catchpoint_basics
create_socket ['sleep 0.01', '5/0', 'sleep 0.01']
run_to_line(1)
send_next
assert_suspension(@test_path, 2, 1)
send_ruby('catch ZeroDivisionError')
assert_catchpoint_set('ZeroDivisionError')
send_next
assert_exception(@test_path, 2, 'ZeroDivisionError')
send_next
end

include CatchpointTest

end

class RDUNIXCatchpointTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include CatchpointTest
end
4 changes: 4 additions & 0 deletions test/rd_condition_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ class RDConditionTest < RDTestBase

end

class RDUNIXConditionTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include ConditionTest
end
40 changes: 6 additions & 34 deletions test/rd_enable_disable_test.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,15 @@
#!/usr/bin/env ruby

require 'rd_test_base'
require 'enable_disable_test'

class RDEnableDisableTest < RDTestBase

def test_enable_disable_basics
create_socket ['1.upto(10) do', 'sleep 0.01', 'sleep 0.01', 'end']

send_test_breakpoint(2)
assert_breakpoint_added_no(1)
send_test_breakpoint(3)
assert_breakpoint_added_no(2)

start_debugger
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(3)
send_cont
assert_test_breakpoint(2)
send_ruby('disable 2')
assert_breakpoint_disabled(2)
send_cont
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(2)
send_ruby('enable 2')
assert_breakpoint_enabled(2)
send_cont
assert_test_breakpoint(3)
send_cont
assert_test_breakpoint(2)
send_cont
assert_test_breakpoint(3)
send_ruby('disable 1')
assert_breakpoint_disabled(1)
send_ruby('disable 2')
assert_breakpoint_disabled(2)
send_cont
end
include EnableDisableTest

end

class RDUNIXEnableDisableTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include EnableDisableTest
end
Loading

0 comments on commit 2e0607a

Please sign in to comment.