openvas-cli 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/Gemfile.lock +50 -0
- data/VERSION +1 -1
- data/lib/openvas-cli/configuration.rb +25 -0
- data/lib/openvas-cli/conn_addin.rb +27 -0
- data/lib/openvas-cli/immutable_children_validator.rb +15 -0
- data/lib/openvas-cli/vas_administrator.rb +7 -0
- data/lib/openvas-cli/vas_base.rb +20 -30
- data/lib/openvas-cli/vas_config.rb +127 -0
- data/lib/openvas-cli/vas_connection.rb +140 -0
- data/lib/openvas-cli/vas_exceptions.rb +9 -7
- data/lib/openvas-cli/vas_lsc_credential.rb +110 -0
- data/lib/openvas-cli/vas_nvt.rb +64 -64
- data/lib/openvas-cli/vas_nvt_family.rb +39 -30
- data/lib/openvas-cli/vas_override.rb +6 -4
- data/lib/openvas-cli/vas_period.rb +89 -0
- data/lib/openvas-cli/vas_preference.rb +139 -49
- data/lib/openvas-cli/vas_report.rb +110 -103
- data/lib/openvas-cli/vas_result.rb +90 -89
- data/lib/openvas-cli/vas_schedule.rb +163 -55
- data/lib/openvas-cli/vas_target.rb +200 -23
- data/lib/openvas-cli/vas_task.rb +229 -30
- data/lib/openvas-cli/vas_task_progress.rb +29 -0
- data/lib/openvas-cli/xml_addin.rb +34 -0
- data/lib/openvas_cli.rb +19 -0
- data/openvas-cli.gemspec +28 -6
- data/spec/openvas-cli/vas_administrator_spec.rb +6 -0
- data/spec/openvas-cli/vas_config_spec.rb +81 -0
- data/spec/openvas-cli/vas_lsc_credential_spec.rb +72 -0
- data/spec/openvas-cli/vas_nvt_family_spec.rb +7 -5
- data/spec/openvas-cli/vas_nvt_spec.rb +30 -26
- data/spec/openvas-cli/vas_period_spec.rb +7 -0
- data/spec/openvas-cli/vas_preference_spec.rb +23 -21
- data/spec/openvas-cli/vas_report_spec.rb +65 -63
- data/spec/openvas-cli/vas_result_spec.rb +94 -93
- data/spec/openvas-cli/vas_schedule_spec.rb +154 -57
- data/spec/openvas-cli/vas_target_spec.rb +140 -28
- data/spec/openvas-cli/vas_task_spec.rb +92 -11
- data/spec/spec_helper.rb +15 -5
- metadata +72 -24
- data/lib/openvas-cli/openvas-cli.rb +0 -273
- data/spec/openvas-cli/openvas-cli_spec.rb +0 -45
data/Gemfile
CHANGED
@@ -3,7 +3,9 @@ source "http://rubygems.org"
|
|
3
3
|
# Example:
|
4
4
|
gem "activesupport", ">= 3.0.5"
|
5
5
|
gem 'activerecord', '>= 3.0.5'
|
6
|
+
gem 'rails', '>=3.0.5'
|
6
7
|
gem 'nokogiri', '>= 1.4.4'
|
8
|
+
gem 'ipaddress', '>=0.7.0'
|
7
9
|
|
8
10
|
# Add dependencies to develop your gem here.
|
9
11
|
# Include everything needed to run rake, tests, features, etc.
|
data/Gemfile.lock
CHANGED
@@ -2,6 +2,20 @@ GEM
|
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
4
|
ZenTest (4.5.0)
|
5
|
+
abstract (1.0.0)
|
6
|
+
actionmailer (3.0.5)
|
7
|
+
actionpack (= 3.0.5)
|
8
|
+
mail (~> 2.2.15)
|
9
|
+
actionpack (3.0.5)
|
10
|
+
activemodel (= 3.0.5)
|
11
|
+
activesupport (= 3.0.5)
|
12
|
+
builder (~> 2.1.2)
|
13
|
+
erubis (~> 2.6.6)
|
14
|
+
i18n (~> 0.4)
|
15
|
+
rack (~> 1.2.1)
|
16
|
+
rack-mount (~> 0.6.13)
|
17
|
+
rack-test (~> 0.5.7)
|
18
|
+
tzinfo (~> 0.3.23)
|
5
19
|
activemodel (3.0.5)
|
6
20
|
activesupport (= 3.0.5)
|
7
21
|
builder (~> 2.1.2)
|
@@ -11,18 +25,49 @@ GEM
|
|
11
25
|
activesupport (= 3.0.5)
|
12
26
|
arel (~> 2.0.2)
|
13
27
|
tzinfo (~> 0.3.23)
|
28
|
+
activeresource (3.0.5)
|
29
|
+
activemodel (= 3.0.5)
|
30
|
+
activesupport (= 3.0.5)
|
14
31
|
activesupport (3.0.5)
|
15
32
|
arel (2.0.9)
|
16
33
|
builder (2.1.2)
|
17
34
|
diff-lcs (1.1.2)
|
35
|
+
erubis (2.6.6)
|
36
|
+
abstract (>= 1.0.0)
|
18
37
|
git (1.2.5)
|
19
38
|
i18n (0.5.0)
|
39
|
+
ipaddress (0.7.0)
|
20
40
|
jeweler (1.5.2)
|
21
41
|
bundler (~> 1.0.0)
|
22
42
|
git (>= 1.2.5)
|
23
43
|
rake
|
24
44
|
log4r (1.1.9)
|
45
|
+
mail (2.2.15)
|
46
|
+
activesupport (>= 2.3.6)
|
47
|
+
i18n (>= 0.4.0)
|
48
|
+
mime-types (~> 1.16)
|
49
|
+
treetop (~> 1.4.8)
|
50
|
+
mime-types (1.16)
|
25
51
|
nokogiri (1.4.4)
|
52
|
+
polyglot (0.3.1)
|
53
|
+
rack (1.2.2)
|
54
|
+
rack-mount (0.6.13)
|
55
|
+
rack (>= 1.0.0)
|
56
|
+
rack-test (0.5.7)
|
57
|
+
rack (>= 1.0)
|
58
|
+
rails (3.0.5)
|
59
|
+
actionmailer (= 3.0.5)
|
60
|
+
actionpack (= 3.0.5)
|
61
|
+
activerecord (= 3.0.5)
|
62
|
+
activeresource (= 3.0.5)
|
63
|
+
activesupport (= 3.0.5)
|
64
|
+
bundler (~> 1.0)
|
65
|
+
railties (= 3.0.5)
|
66
|
+
railties (3.0.5)
|
67
|
+
actionpack (= 3.0.5)
|
68
|
+
activesupport (= 3.0.5)
|
69
|
+
rake (>= 0.8.7)
|
70
|
+
thor (~> 0.14.4)
|
26
71
|
rake (0.8.7)
|
27
72
|
rcov (0.9.9)
|
28
73
|
rspec (2.3.0)
|
@@ -33,6 +78,9 @@ GEM
|
|
33
78
|
rspec-expectations (2.3.0)
|
34
79
|
diff-lcs (~> 1.1.2)
|
35
80
|
rspec-mocks (2.3.0)
|
81
|
+
thor (0.14.6)
|
82
|
+
treetop (1.4.9)
|
83
|
+
polyglot (>= 0.3.1)
|
36
84
|
tzinfo (0.3.24)
|
37
85
|
|
38
86
|
PLATFORMS
|
@@ -43,8 +91,10 @@ DEPENDENCIES
|
|
43
91
|
activerecord (>= 3.0.5)
|
44
92
|
activesupport (>= 3.0.5)
|
45
93
|
bundler (~> 1.0.0)
|
94
|
+
ipaddress (>= 0.7.0)
|
46
95
|
jeweler (~> 1.5.2)
|
47
96
|
log4r
|
48
97
|
nokogiri (>= 1.4.4)
|
98
|
+
rails (>= 3.0.5)
|
49
99
|
rcov
|
50
100
|
rspec (~> 2.3.0)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module OpenvasCli
|
2
|
+
class Configuration
|
3
|
+
def initialize
|
4
|
+
config_opts = {
|
5
|
+
:username => "admin",
|
6
|
+
:password => "",
|
7
|
+
:host => "localhost",
|
8
|
+
:port => 9390,
|
9
|
+
:buffer_size => 512,
|
10
|
+
:time_out => 60,
|
11
|
+
:auto_login => true,
|
12
|
+
:max_tries => 3
|
13
|
+
}
|
14
|
+
|
15
|
+
config_opts.each { |key, value|
|
16
|
+
add_configuration(key, value)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_configuration(name, default)
|
21
|
+
Configuration.send :attr_accessor, name.to_sym
|
22
|
+
instance_variable_set("@#{name.to_s}".to_sym, default)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'vas_connection'
|
2
|
+
module OpenvasCli
|
3
|
+
module ConnAddin
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def has_vas_connection(connection_type=:manager)
|
10
|
+
@@config = {:password => "Password"}
|
11
|
+
if connection_type == :manager
|
12
|
+
@@config[:port] = 9390
|
13
|
+
elsif connection_type == :administrator
|
14
|
+
@@config[:port] = 9393
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def establish_connection
|
19
|
+
VasConnection.new(@@config)
|
20
|
+
end
|
21
|
+
|
22
|
+
def connection
|
23
|
+
@@connection ||= establish_connection
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module OpenvasCli
|
4
|
+
class ImmutableChildrenValidator < ActiveModel::Validator
|
5
|
+
def validate(record)
|
6
|
+
if record.id
|
7
|
+
record.errors[:base] << "Configuration cannot change after creation." \
|
8
|
+
if record.config_id_changed?
|
9
|
+
|
10
|
+
record.errors[:base] << "Target cannot change after creation." \
|
11
|
+
if record.target_id_changed? || record.target.changed?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/openvas-cli/vas_base.rb
CHANGED
@@ -1,40 +1,30 @@
|
|
1
1
|
require 'active_model'
|
2
|
+
require 'base64'
|
2
3
|
Dir["#{File.dirname(__FILE__)}/*_validator.rb"].each {|f| require f}
|
4
|
+
require 'vas_exceptions'
|
5
|
+
require 'xml_addin'
|
6
|
+
require 'conn_addin'
|
3
7
|
|
4
8
|
# Provides a base from which to build objects that utilize the OpenvasCli object.
|
5
9
|
# Includes support for ActiveModel validations and a helper method (extract_value_from)
|
6
10
|
# to assist in OpenVAS object implementations.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
ret = ""
|
21
|
-
if x_str =~ /@/
|
22
|
-
ret = n.at_xpath(x_str).value if n.at_xpath(x_str)
|
23
|
-
else
|
24
|
-
tn = n.at_xpath(x_str)
|
25
|
-
if tn
|
26
|
-
if tn.children.count > 0
|
27
|
-
tn.children.each { |tnc|
|
28
|
-
if tnc.text?
|
29
|
-
ret = tnc.text
|
30
|
-
end
|
31
|
-
}
|
32
|
-
else
|
33
|
-
ret = tn.text
|
34
|
-
end
|
35
|
-
end
|
11
|
+
module OpenvasCli
|
12
|
+
class VasBase
|
13
|
+
include ActiveModel::Validations
|
14
|
+
include ActiveModel::Dirty
|
15
|
+
include XmlAddin
|
16
|
+
include ConnAddin
|
17
|
+
|
18
|
+
has_vas_connection(:manager)
|
19
|
+
|
20
|
+
attr_accessor :id
|
21
|
+
|
22
|
+
def new_record?
|
23
|
+
@id == nil || @id.empty?
|
36
24
|
end
|
37
25
|
|
38
|
-
|
26
|
+
def reset_changes
|
27
|
+
@changed_attributes.clear if @changed_attributes
|
28
|
+
end
|
39
29
|
end
|
40
30
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'vas_base'
|
2
|
+
require 'vas_task'
|
3
|
+
require 'vas_nvt_family'
|
4
|
+
require 'vas_preference'
|
5
|
+
require 'vas_exceptions'
|
6
|
+
|
7
|
+
module OpenvasCli
|
8
|
+
class VasConfig < VasBase
|
9
|
+
attr_accessor :name
|
10
|
+
attr_accessor :comment
|
11
|
+
attr_accessor :families_grow
|
12
|
+
attr_accessor :rules_grow
|
13
|
+
attr_accessor :in_use
|
14
|
+
|
15
|
+
define_attribute_methods [:name, :comment, :families_grow, :in_use, :tasks,
|
16
|
+
:preferences, :families]
|
17
|
+
|
18
|
+
validates :id, :UUID => true, :if => Proc.new { |o| o.id }
|
19
|
+
validates :name, :presence=>true, :length => {:minimum=>1, :maximum=>80}
|
20
|
+
|
21
|
+
def initialize(attributes = {})
|
22
|
+
@id = attributes[:id] if attributes[:id]
|
23
|
+
@name = attributes[:name] if attributes[:name]
|
24
|
+
@comment = attributes[:comment] if attributes[:comment]
|
25
|
+
@families_grow = attributes[:families_grow] if attributes[:families_grow]
|
26
|
+
@rules_grow = attributes[:rules_grow] if attributes[:rules_grow]
|
27
|
+
end
|
28
|
+
|
29
|
+
def tasks
|
30
|
+
@tasks ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
def preferences
|
34
|
+
@preferences ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def families
|
38
|
+
@families ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.get_all(options = {})
|
42
|
+
params = {:sort_field => "name"}
|
43
|
+
if options[:show_details] && options[:show_details] == true
|
44
|
+
params.merge!({:families => "1", :preferences => "1"})
|
45
|
+
end
|
46
|
+
params[:config_id] = options[:id] if options[:id]
|
47
|
+
req = Nokogiri::XML::Builder.new { |xml|
|
48
|
+
xml.get_configs(params)
|
49
|
+
}
|
50
|
+
|
51
|
+
resp = connection.send_receive(req.doc)
|
52
|
+
|
53
|
+
ret = []
|
54
|
+
resp.xpath("/get_configs_response/config").each { |xml|
|
55
|
+
cfg = VasConfig.new
|
56
|
+
cfg.id = extract_value_from("@id", xml)
|
57
|
+
cfg.name = extract_value_from("name", xml)
|
58
|
+
cfg.comment = extract_value_from("comment", xml)
|
59
|
+
cfg.families_grow = extract_value_from("family_count/growing", xml).to_i > 0
|
60
|
+
cfg.rules_grow = extract_value_from("nvt_count/growing", xml).to_i > 0
|
61
|
+
cfg.in_use = extract_value_from("in_use", xml).to_i > 0
|
62
|
+
|
63
|
+
xml.xpath("tasks/task").each { |t| cfg.tasks << VasTask.from_xml_node(t) }
|
64
|
+
xml.xpath("families/family").each { |f| cfg.families << VasNVTFamily.from_xml_node(f) }
|
65
|
+
xml.xpath("preferences/preference").each { |p|
|
66
|
+
p = VasPreference.from_xml_node(p)
|
67
|
+
p.config_id = cfg.id
|
68
|
+
p.reset_changes
|
69
|
+
cfg.preferences << p
|
70
|
+
}
|
71
|
+
|
72
|
+
cfg.reset_changes
|
73
|
+
|
74
|
+
ret << cfg
|
75
|
+
}
|
76
|
+
|
77
|
+
ret
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.copy_config(id, name)
|
81
|
+
begin
|
82
|
+
req = Nokogiri::XML::Builder.new { |xml|
|
83
|
+
xml.create_config {
|
84
|
+
xml.copy { xml.text(id) }
|
85
|
+
xml.name { xml.text(name) }
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
resp = connection.send_receive(req.doc)
|
90
|
+
new_id = extract_value_from("/create_config_response/@id", resp)
|
91
|
+
|
92
|
+
get_all(:id => new_id, :show_details => true)[0]
|
93
|
+
rescue VasExceptions::CommandException => e
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def save!
|
99
|
+
@previously_changed = changes
|
100
|
+
preferences.each{ |p| p.save! if p.changed? }
|
101
|
+
@changed_attributes.clear
|
102
|
+
end
|
103
|
+
|
104
|
+
def destroy
|
105
|
+
begin
|
106
|
+
destroy!
|
107
|
+
|
108
|
+
true
|
109
|
+
rescue Exception => e
|
110
|
+
# logger = OpenvasCli.logger
|
111
|
+
# logger.error("Could Not Destroy Configuration: (#{e.class})#{e.message}") if logger
|
112
|
+
|
113
|
+
false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def destroy!
|
118
|
+
tasks.each { |t| t.destroy! }
|
119
|
+
|
120
|
+
req = Nokogiri::XML::Builder.new { |xml|
|
121
|
+
xml.delete_config(:config_id => @id)
|
122
|
+
}
|
123
|
+
|
124
|
+
VasConfig.connection.send_receive(req.doc)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'vas_exceptions'
|
3
|
+
require 'xml_addin'
|
4
|
+
require 'openssl'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
module OpenvasCli
|
8
|
+
class VasConnection
|
9
|
+
include XmlAddin
|
10
|
+
# Initializes the client, connectes to the OpenVas Managment service specified
|
11
|
+
# by host & port, and unless auto_login is set to +false+, loggs in using
|
12
|
+
# username and password.
|
13
|
+
def initialize(config={})
|
14
|
+
@logger = OpenvasCli.logger
|
15
|
+
@config = OpenvasCli.configuration
|
16
|
+
|
17
|
+
connect
|
18
|
+
if @config.auto_login == true
|
19
|
+
login
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Closes the active connection and sets it up for re-connection.
|
24
|
+
def close
|
25
|
+
@socket.close if @socket
|
26
|
+
@socket = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def config
|
30
|
+
@config ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Logs into the OpenVAS Management service using the specified username and
|
34
|
+
# passoword. By default, this method is called by new unless auto_login is
|
35
|
+
# set to +false+.
|
36
|
+
def login
|
37
|
+
log_message("Logging in: :user => #{@config.username}", :info)
|
38
|
+
areq = Nokogiri::XML::Builder.new { |xml|
|
39
|
+
xml.authenticate {
|
40
|
+
xml.credentials {
|
41
|
+
xml.username { xml.text(@config.username) }
|
42
|
+
xml.password { xml.text(@config.password) }
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
send_receive(areq.doc)
|
48
|
+
end
|
49
|
+
|
50
|
+
def state
|
51
|
+
@socket ? @socket.state : "closed"
|
52
|
+
end
|
53
|
+
|
54
|
+
def send_receive(request)
|
55
|
+
if request.kind_of? String
|
56
|
+
tosend = request
|
57
|
+
else
|
58
|
+
tosend = request.to_xml
|
59
|
+
end
|
60
|
+
|
61
|
+
tries = 0
|
62
|
+
|
63
|
+
begin
|
64
|
+
unless @socket && @socket.state =~ /sslok/i
|
65
|
+
log_message("Socket closed, Reconnecting", :info)
|
66
|
+
connect
|
67
|
+
login
|
68
|
+
end
|
69
|
+
log_message("Sending: #{tosend}", :debug)
|
70
|
+
|
71
|
+
@socket.puts(tosend)
|
72
|
+
|
73
|
+
rbuf=''
|
74
|
+
size=0
|
75
|
+
begin
|
76
|
+
timeout(@config.time_out) {
|
77
|
+
a = @socket.sysread(@config.buffer_size)
|
78
|
+
size = a.length
|
79
|
+
rbuf << a
|
80
|
+
}
|
81
|
+
end while size >= @config.buffer_size
|
82
|
+
rescue Timeout::Error
|
83
|
+
msg = "Command Timed Out [#{tries}] (#{$!})\nCommand: #{tosend}"
|
84
|
+
log_message msg, :error
|
85
|
+
tries += 1
|
86
|
+
@socket = nil
|
87
|
+
retry if tries < @config.max_tries
|
88
|
+
raise VasExceptions::CommunicationException.new(msg)
|
89
|
+
rescue EOFError
|
90
|
+
msg = "EOFError [#{tries}] (#{$!})\nReceived: #{rbuf}\nCommand: #{tosend}"
|
91
|
+
log_message msg, :error
|
92
|
+
tries += 1
|
93
|
+
@socket = nil
|
94
|
+
retry if tries < @config.max_tries
|
95
|
+
raise VasExceptions::CommunicationException.new(msg)
|
96
|
+
end
|
97
|
+
|
98
|
+
response = Nokogiri::XML(rbuf)
|
99
|
+
|
100
|
+
log_message "RECEIVED: #{response.to_xml}", :debug
|
101
|
+
|
102
|
+
unless VasConnection.extract_value_from("//@status", response) =~ /20\d/
|
103
|
+
msg = "Command Failed: #{VasConnection.extract_value_from("//@status_text", response)}\n" +
|
104
|
+
"Command Status: #{VasConnection.extract_value_from("//@status", response)}\n" +
|
105
|
+
"Command: #{tosend}\n" +
|
106
|
+
"Response: #{response.to_xml}"
|
107
|
+
log_message msg, :error
|
108
|
+
raise VasExceptions::CommandException.new(msg)
|
109
|
+
end
|
110
|
+
|
111
|
+
response
|
112
|
+
end
|
113
|
+
private
|
114
|
+
def log_message(msg, level)
|
115
|
+
if @logger
|
116
|
+
case level
|
117
|
+
when :debug
|
118
|
+
@logger.debug msg
|
119
|
+
when :info
|
120
|
+
@logger.info msg
|
121
|
+
when :warn
|
122
|
+
@logger.warn msg
|
123
|
+
when :error
|
124
|
+
@logger.error msg
|
125
|
+
when :fatal
|
126
|
+
@logger.fatal msg
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def connect
|
132
|
+
log_message("Connecting: :host => #{@config.host}, :port => #{@config.port}", :info)
|
133
|
+
plain_socket = TCPSocket.open(@config.host, @config.port)
|
134
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
135
|
+
@socket = OpenSSL::SSL::SSLSocket.new(plain_socket, ssl_context)
|
136
|
+
@socket.sync_close = true
|
137
|
+
@socket.connect
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|