Skip to content

unix socket support #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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