Skip to content

allow clients to connect over unix domain sockets #166

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

Closed
Closed
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 @@ -28,7 +28,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 @@ -98,6 +99,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
39 changes: 26 additions & 13 deletions lib/ruby-debug-ide.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ def interrupt_last
end
end

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

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

start_server(options.host, options.port, options.notify_dispatcher)
start_server(options.host, options.port, options.notify_dispatcher, socket_path: options.socket_path)

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

Expand Down Expand Up @@ -111,25 +111,38 @@ def run_prog_script
end
end

def start_control(host, port, notify_dispatcher)
def start_control(host, port, notify_dispatcher, socket_path: nil)
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: 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 Down
4 changes: 3 additions & 1 deletion 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 Down
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
4 changes: 4 additions & 0 deletions test/rd_expression_info_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ class RDExpressionInfoTest < RDTestBase

end

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

end

class RDUNIXInspectTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include InspectTest
end
4 changes: 4 additions & 0 deletions test/rd_stepping_breakpoints_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ def test_breakpoint_and_continue_from_other_file

end

class RDUNIXSteppingAndBreakpointsTest < RDTestBase
include TestBase::UseUNIXDomainSocket
include SteppingAndBreakpointsTest
end
Loading