rev 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +16 -0
- data/README +1 -0
- data/Rakefile +10 -0
- data/ext/http11_client/http11_parser.c +563 -502
- data/ext/http11_client/http11_parser.rl +1 -1
- data/ext/libev/Changes +39 -1
- data/ext/libev/ev.c +286 -105
- data/ext/libev/ev.h +102 -34
- data/ext/libev/ev_poll.c +17 -14
- data/ext/libev/ev_select.c +4 -4
- data/ext/libev/ev_vars.h +14 -1
- data/ext/libev/ev_wrap.h +14 -0
- data/ext/rev/extconf.rb +15 -11
- data/ext/rev/rev_loop.c +35 -34
- data/ext/rev/rev_ssl.c +90 -3
- data/lib/rev.rb +8 -2
- data/lib/rev/http_client.rb +6 -6
- data/lib/rev/io.rb +53 -29
- data/lib/rev/io_watcher.rb +2 -1
- data/lib/rev/{watcher.rb → meta.rb} +3 -3
- data/lib/rev/server.rb +2 -2
- data/lib/rev/socket.rb +27 -21
- data/lib/rev/ssl.rb +35 -49
- data/lib/rev/timer_watcher.rb +1 -0
- data/rev.gemspec +2 -2
- metadata +3 -3
data/ext/rev/rev_ssl.c
CHANGED
@@ -38,6 +38,44 @@ static VALUE Rev_SSL_IO_start_ssl(VALUE self, int (*func)(), const char *funcnam
|
|
38
38
|
static VALUE Rev_SSL_IO_read_nonblock(int argc, VALUE *argv, VALUE self);
|
39
39
|
static VALUE Rev_SSL_IO_write_nonblock(VALUE self, VALUE str);
|
40
40
|
|
41
|
+
/*
|
42
|
+
* Time to monkey patch some C code!
|
43
|
+
*/
|
44
|
+
|
45
|
+
/* Ruby 1.8 leaves us no recourse but to commonly couple to the OpenSSL native
|
46
|
+
extension through externs. Ugh */
|
47
|
+
#if RUBY_VERSION_CODE < 190
|
48
|
+
|
49
|
+
/* Externs from Ruby's OpenSSL native extension , in ossl_ssl.c*/
|
50
|
+
extern int ossl_ssl_ex_vcb_idx;
|
51
|
+
extern int ossl_ssl_ex_store_p;
|
52
|
+
extern int ossl_ssl_ex_ptr_idx;
|
53
|
+
extern int ossl_ssl_ex_client_cert_cb_idx;
|
54
|
+
extern int ossl_ssl_ex_tmp_dh_callback_idx;
|
55
|
+
|
56
|
+
/* #defines shamelessly copied and pasted from ossl_ssl.c */
|
57
|
+
#define ossl_ssl_get_io(o) rb_iv_get((o),"@io")
|
58
|
+
#define ossl_ssl_get_ctx(o) rb_iv_get((o),"@context")
|
59
|
+
#define ossl_sslctx_get_verify_cb(o) rb_iv_get((o),"@verify_callback")
|
60
|
+
#define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb")
|
61
|
+
#define ossl_sslctx_get_tmp_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback")
|
62
|
+
|
63
|
+
#ifdef _WIN32
|
64
|
+
# define TO_SOCKET(s) _get_osfhandle(s)
|
65
|
+
#else
|
66
|
+
# define TO_SOCKET(s) s
|
67
|
+
#endif
|
68
|
+
|
69
|
+
#endif
|
70
|
+
|
71
|
+
#ifndef HAVE_RB_STR_SET_LEN
|
72
|
+
static void rb_str_set_len(VALUE str, long len)
|
73
|
+
{
|
74
|
+
RSTRING(str)->len = len;
|
75
|
+
RSTRING(str)->ptr[len] = '\0';
|
76
|
+
}
|
77
|
+
#endif
|
78
|
+
|
41
79
|
void Init_rev_ssl()
|
42
80
|
{
|
43
81
|
rb_require("openssl");
|
@@ -63,6 +101,47 @@ void Init_rev_ssl()
|
|
63
101
|
rb_define_method(cRev_SSL_IO, "write_nonblock", Rev_SSL_IO_write_nonblock, 1);
|
64
102
|
}
|
65
103
|
|
104
|
+
#if RUBY_VERSION_CODE < 190
|
105
|
+
/* SSL initialization for Ruby 1.8 */
|
106
|
+
static VALUE
|
107
|
+
Rev_SSL_IO_ssl_setup(VALUE self)
|
108
|
+
{
|
109
|
+
VALUE io, v_ctx, cb;
|
110
|
+
SSL_CTX *ctx;
|
111
|
+
SSL *ssl;
|
112
|
+
OpenFile *fptr;
|
113
|
+
|
114
|
+
Data_Get_Struct(self, SSL, ssl);
|
115
|
+
if(!ssl) {
|
116
|
+
v_ctx = ossl_ssl_get_ctx(self);
|
117
|
+
Data_Get_Struct(v_ctx, SSL_CTX, ctx);
|
118
|
+
|
119
|
+
ssl = SSL_new(ctx);
|
120
|
+
if (!ssl) {
|
121
|
+
ossl_raise(eSSLError, "SSL_new:");
|
122
|
+
}
|
123
|
+
DATA_PTR(self) = ssl;
|
124
|
+
|
125
|
+
io = ossl_ssl_get_io(self);
|
126
|
+
GetOpenFile(io, fptr);
|
127
|
+
rb_io_check_readable(fptr);
|
128
|
+
rb_io_check_writable(fptr);
|
129
|
+
SSL_set_fd(ssl, TO_SOCKET(fileno(fptr->f)));
|
130
|
+
SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self);
|
131
|
+
cb = ossl_sslctx_get_verify_cb(v_ctx);
|
132
|
+
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb);
|
133
|
+
cb = ossl_sslctx_get_client_cert_cb(v_ctx);
|
134
|
+
SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb);
|
135
|
+
cb = ossl_sslctx_get_tmp_dh_cb(v_ctx);
|
136
|
+
SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb);
|
137
|
+
}
|
138
|
+
|
139
|
+
return Qtrue;
|
140
|
+
}
|
141
|
+
#endif
|
142
|
+
|
143
|
+
#if RUBY_VERSION_CODE >= 190
|
144
|
+
/* Slightly less insane SSL setup for Ruby 1.9 */
|
66
145
|
static VALUE
|
67
146
|
Rev_SSL_IO_ssl_setup(VALUE self)
|
68
147
|
{
|
@@ -95,15 +174,13 @@ Rev_SSL_IO_ssl_setup(VALUE self)
|
|
95
174
|
*/
|
96
175
|
rb_funcall(self, rb_intern("session="), 1, Qnil);
|
97
176
|
}
|
177
|
+
#endif
|
98
178
|
|
99
179
|
/* Ensure the error raised by calling #session= with a dummy argument is
|
100
180
|
* the one we were expecting */
|
101
181
|
static VALUE
|
102
182
|
Rev_SSL_IO_ssl_setup_check(VALUE dummy, VALUE err)
|
103
183
|
{
|
104
|
-
if(!rb_obj_is_kind_of(err, rb_eTypeError))
|
105
|
-
rb_raise(rb_eRuntimeError, "Rev::SSL not supported in this Ruby version, sorry");
|
106
|
-
|
107
184
|
return Qnil;
|
108
185
|
}
|
109
186
|
|
@@ -114,7 +191,12 @@ Rev_SSL_IO_ssl_setup_check(VALUE dummy, VALUE err)
|
|
114
191
|
static VALUE
|
115
192
|
Rev_SSL_IO_connect_nonblock(VALUE self)
|
116
193
|
{
|
194
|
+
#if RUBY_VERSION_CODE >= 190
|
117
195
|
rb_rescue(Rev_SSL_IO_ssl_setup, self, Rev_SSL_IO_ssl_setup_check, Qnil);
|
196
|
+
#else
|
197
|
+
Rev_SSL_IO_ssl_setup(self);
|
198
|
+
#endif
|
199
|
+
|
118
200
|
return Rev_SSL_IO_start_ssl(self, SSL_connect, "SSL_connect");
|
119
201
|
}
|
120
202
|
|
@@ -125,7 +207,12 @@ Rev_SSL_IO_connect_nonblock(VALUE self)
|
|
125
207
|
static VALUE
|
126
208
|
Rev_SSL_IO_accept_nonblock(VALUE self)
|
127
209
|
{
|
210
|
+
#if RUBY_VERSION_CODE >= 190
|
128
211
|
rb_rescue(Rev_SSL_IO_ssl_setup, self, 0, 0);
|
212
|
+
#else
|
213
|
+
Rev_SSL_IO_ssl_setup(self);
|
214
|
+
#endif
|
215
|
+
|
129
216
|
return Rev_SSL_IO_start_ssl(self, SSL_accept, "SSL_accept");
|
130
217
|
}
|
131
218
|
|
data/lib/rev.rb
CHANGED
@@ -4,9 +4,15 @@
|
|
4
4
|
# See file LICENSE for details
|
5
5
|
#++
|
6
6
|
|
7
|
+
# Pull in the OpenSSL extension if available
|
8
|
+
begin
|
9
|
+
require 'openssl'
|
10
|
+
rescue LoadError
|
11
|
+
end
|
12
|
+
|
7
13
|
require File.dirname(__FILE__) + '/rev_ext'
|
8
14
|
require File.dirname(__FILE__) + '/rev/loop'
|
9
|
-
require File.dirname(__FILE__) + '/rev/
|
15
|
+
require File.dirname(__FILE__) + '/rev/meta'
|
10
16
|
require File.dirname(__FILE__) + '/rev/io_watcher'
|
11
17
|
require File.dirname(__FILE__) + '/rev/timer_watcher'
|
12
18
|
require File.dirname(__FILE__) + '/rev/async_watcher'
|
@@ -18,6 +24,6 @@ require File.dirname(__FILE__) + '/rev/server'
|
|
18
24
|
require File.dirname(__FILE__) + '/rev/http_client'
|
19
25
|
|
20
26
|
module Rev
|
21
|
-
Rev::VERSION = '0.2.
|
27
|
+
Rev::VERSION = '0.2.1' unless defined? Rev::VERSION
|
22
28
|
def self.version() VERSION end
|
23
29
|
end
|
data/lib/rev/http_client.rb
CHANGED
@@ -68,7 +68,7 @@ module Rev
|
|
68
68
|
|
69
69
|
# Map all header keys to a downcased string version
|
70
70
|
def munge_header_keys(head)
|
71
|
-
head.
|
71
|
+
head.inject({}) { |h, (k, v)| h[k.to_s.downcase] = v; h }
|
72
72
|
end
|
73
73
|
|
74
74
|
# HTTP is kind of retarded that you have to specify
|
@@ -98,15 +98,15 @@ module Rev
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def encode_headers(head)
|
101
|
-
head.
|
101
|
+
head.inject('') do |result, (key, value)|
|
102
102
|
# Munge keys from foo-bar-baz to Foo-Bar-Baz
|
103
|
-
|
104
|
-
result << encode_field(
|
103
|
+
key = key.split('-').map { |k| k.capitalize }.join('-')
|
104
|
+
result << encode_field(key, value)
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
108
|
def encode_cookies(cookies)
|
109
|
-
cookies.
|
109
|
+
cookies.inject('') { |result, (k, v)| result << encode_field('Cookie', encode_param(k, v)) }
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
@@ -167,7 +167,7 @@ module Rev
|
|
167
167
|
# Specify the request body (you must encode it for now)
|
168
168
|
#
|
169
169
|
def request(method, path, options = {})
|
170
|
-
raise ArgumentError, "invalid request path" unless
|
170
|
+
raise ArgumentError, "invalid request path" unless /^\// === path
|
171
171
|
raise RuntimeError, "request already sent" if @requested
|
172
172
|
|
173
173
|
@method, @path, @options = method, path, options
|
data/lib/rev/io.rb
CHANGED
@@ -13,16 +13,44 @@ module Rev
|
|
13
13
|
# This class is primarily meant as a base class for other streams
|
14
14
|
# which need non-blocking writing, and is used to implement Rev's
|
15
15
|
# Socket class and its associated subclasses.
|
16
|
-
class IO
|
16
|
+
class IO
|
17
|
+
extend Meta
|
18
|
+
|
17
19
|
# Maximum number of bytes to consume at once
|
18
20
|
INPUT_SIZE = 16384
|
19
21
|
|
20
22
|
def initialize(io)
|
21
|
-
@
|
22
|
-
@
|
23
|
-
|
23
|
+
@_io = io
|
24
|
+
@_write_buffer = Rev::Buffer.new
|
25
|
+
@_read_watcher = Watcher.new(io, self, :r)
|
26
|
+
@_write_watcher = Watcher.new(io, self, :w)
|
24
27
|
end
|
25
28
|
|
29
|
+
#
|
30
|
+
# Watcher methods, delegated to @_read_watcher
|
31
|
+
#
|
32
|
+
|
33
|
+
# Attach to the event loop
|
34
|
+
def attach(loop); @_read_watcher.attach loop; self; end
|
35
|
+
|
36
|
+
# Detach from the event loop
|
37
|
+
def detach; @_read_watcher.detach; self; end
|
38
|
+
|
39
|
+
# Enable the watcher
|
40
|
+
def enable; @_read_watcher.enable; self; end
|
41
|
+
|
42
|
+
# Disable the watcher
|
43
|
+
def disable; @_read_watcher.disable; self; end
|
44
|
+
|
45
|
+
# Is the watcher attached?
|
46
|
+
def attached?; @_read_watcher.attached?; end
|
47
|
+
|
48
|
+
# Is the watcher enabled?
|
49
|
+
def enabled?; @_read_watcher.enabled?; end
|
50
|
+
|
51
|
+
# Obtain the event loop associated with this object
|
52
|
+
def evloop; @_read_watcher.evloop; end
|
53
|
+
|
26
54
|
#
|
27
55
|
# Callbacks for asynchronous events
|
28
56
|
#
|
@@ -45,21 +73,21 @@ module Rev
|
|
45
73
|
|
46
74
|
# Write data in a buffered, non-blocking manner
|
47
75
|
def write(data)
|
48
|
-
@
|
76
|
+
@_write_buffer << data
|
49
77
|
schedule_write
|
50
78
|
data.size
|
51
79
|
end
|
52
80
|
|
53
81
|
# Number of bytes are currently in the output buffer
|
54
82
|
def output_buffer_size
|
55
|
-
@
|
83
|
+
@_write_buffer.size
|
56
84
|
end
|
57
85
|
|
58
86
|
# Close the IO stream
|
59
87
|
def close
|
60
88
|
detach if attached?
|
61
89
|
detach_write_watcher
|
62
|
-
@
|
90
|
+
@_io.close unless @_io.closed?
|
63
91
|
|
64
92
|
on_close
|
65
93
|
nil
|
@@ -67,7 +95,7 @@ module Rev
|
|
67
95
|
|
68
96
|
# Is the IO object closed?
|
69
97
|
def closed?
|
70
|
-
@
|
98
|
+
@_io.closed?
|
71
99
|
end
|
72
100
|
|
73
101
|
#########
|
@@ -77,7 +105,8 @@ module Rev
|
|
77
105
|
# Read from the input buffer and dispatch to on_read
|
78
106
|
def on_readable
|
79
107
|
begin
|
80
|
-
on_read @
|
108
|
+
on_read @_io.read_nonblock(INPUT_SIZE)
|
109
|
+
rescue Errno::EAGAIN
|
81
110
|
rescue Errno::ECONNRESET, EOFError
|
82
111
|
close
|
83
112
|
end
|
@@ -86,12 +115,12 @@ module Rev
|
|
86
115
|
# Write the contents of the output buffer
|
87
116
|
def on_writable
|
88
117
|
begin
|
89
|
-
@
|
118
|
+
@_write_buffer.write_to(@_io)
|
90
119
|
rescue Errno::EPIPE, Errno::ECONNRESET
|
91
120
|
return close
|
92
121
|
end
|
93
122
|
|
94
|
-
if @
|
123
|
+
if @_write_buffer.empty?
|
95
124
|
disable_write_watcher
|
96
125
|
on_write_complete
|
97
126
|
end
|
@@ -105,37 +134,32 @@ module Rev
|
|
105
134
|
end
|
106
135
|
end
|
107
136
|
|
108
|
-
# Return a handle to the writing IOWatcher
|
109
|
-
def write_watcher
|
110
|
-
@write_watcher ||= WriteWatcher.new(@io, self)
|
111
|
-
end
|
112
|
-
|
113
137
|
def enable_write_watcher
|
114
|
-
if
|
115
|
-
|
138
|
+
if @_write_watcher.attached?
|
139
|
+
@_write_watcher.enable unless @_write_watcher.enabled?
|
116
140
|
else
|
117
|
-
|
141
|
+
@_write_watcher.attach(evloop)
|
118
142
|
end
|
119
143
|
end
|
120
144
|
|
121
145
|
def disable_write_watcher
|
122
|
-
@
|
146
|
+
@_write_watcher.disable if @_write_watcher and @_write_watcher.enabled?
|
123
147
|
end
|
124
148
|
|
125
149
|
def detach_write_watcher
|
126
|
-
@
|
150
|
+
@_write_watcher.detach if @_write_watcher and @_write_watcher.attached?
|
127
151
|
end
|
128
|
-
|
129
|
-
class
|
130
|
-
|
152
|
+
|
153
|
+
# Internal class implementing watchers used by Rev::IO
|
154
|
+
class Watcher < IOWatcher
|
155
|
+
def initialize(ruby_io, rev_io, flags)
|
131
156
|
@rev_io = rev_io
|
132
|
-
super(ruby_io,
|
157
|
+
super(ruby_io, flags)
|
133
158
|
end
|
134
159
|
|
135
|
-
#
|
136
|
-
def
|
137
|
-
|
138
|
-
end
|
160
|
+
# Configure IOWatcher event callbacks to call the method passed to #initialize
|
161
|
+
def on_readable; @rev_io.__send__(:on_readable); end
|
162
|
+
def on_writable; @rev_io.__send__(:on_writable); end
|
139
163
|
end
|
140
164
|
end
|
141
165
|
end
|
data/lib/rev/io_watcher.rb
CHANGED
@@ -5,12 +5,13 @@
|
|
5
5
|
#++
|
6
6
|
|
7
7
|
module Rev
|
8
|
-
class IOWatcher
|
8
|
+
class IOWatcher
|
9
9
|
# The actual implementation of this class resides in the C extension
|
10
10
|
# Here we metaprogram proper event_callbacks for the callback methods
|
11
11
|
# These can take a block and store it to be called when the event
|
12
12
|
# is actually fired.
|
13
13
|
|
14
|
+
extend Meta
|
14
15
|
event_callback :on_readable, :on_writable
|
15
16
|
end
|
16
17
|
end
|
@@ -5,12 +5,12 @@
|
|
5
5
|
#++
|
6
6
|
|
7
7
|
module Rev
|
8
|
-
|
8
|
+
module Meta
|
9
9
|
# Use an alternate watcher with the attach/detach/enable/disable methods
|
10
10
|
# if it is presently assigned. This is useful if you are waiting for
|
11
11
|
# an event to occur before the current watcher can be used in earnest,
|
12
12
|
# such as making an outgoing TCP connection.
|
13
|
-
def
|
13
|
+
def watcher_delegate(proxy_var)
|
14
14
|
%w{attach detach enable disable}.each do |method|
|
15
15
|
module_eval <<-EOD
|
16
16
|
def #{method}(*args)
|
@@ -29,7 +29,7 @@ module Rev
|
|
29
29
|
# This is done by giving a block to the callback method, which is captured
|
30
30
|
# as a proc and stored for later. If the method is called without a block,
|
31
31
|
# the stored block is executed if present, otherwise it's a noop.
|
32
|
-
def
|
32
|
+
def event_callback(*methods)
|
33
33
|
methods.each do |method|
|
34
34
|
module_eval <<-EOD
|
35
35
|
def #{method}(*args, &block)
|
data/lib/rev/server.rb
CHANGED
@@ -11,8 +11,8 @@ module Rev
|
|
11
11
|
# connections is a Socket, but any subclass of IOWatcher is acceptable.
|
12
12
|
def initialize(listen_socket, klass = Socket, *args, &block)
|
13
13
|
# Ensure the provided class responds to attach
|
14
|
-
unless klass.allocate.is_a?
|
15
|
-
raise ArgumentError, "
|
14
|
+
unless klass.allocate.is_a? IO
|
15
|
+
raise ArgumentError, "can't convert #{klass} to Rev::IO"
|
16
16
|
end
|
17
17
|
|
18
18
|
# Verify the arity of the provided arguments
|
data/lib/rev/socket.rb
CHANGED
@@ -10,19 +10,19 @@ require 'resolv'
|
|
10
10
|
module Rev
|
11
11
|
class Socket < IO
|
12
12
|
def self.connect(socket, *args)
|
13
|
-
new(socket, *args).instance_eval
|
14
|
-
@
|
13
|
+
new(socket, *args).instance_eval do
|
14
|
+
@_connector = Connector.new(self, socket)
|
15
15
|
self
|
16
|
-
|
16
|
+
end
|
17
17
|
end
|
18
18
|
|
19
|
-
watcher_delegate :@
|
19
|
+
watcher_delegate :@_connector
|
20
20
|
|
21
21
|
def attach(evloop)
|
22
|
-
raise RuntimeError, "connection failed" if @
|
22
|
+
raise RuntimeError, "connection failed" if @_failed
|
23
23
|
|
24
|
-
if @
|
25
|
-
@
|
24
|
+
if @_connector
|
25
|
+
@_connector.attach(evloop)
|
26
26
|
return self
|
27
27
|
end
|
28
28
|
|
@@ -56,11 +56,11 @@ module Rev
|
|
56
56
|
detach
|
57
57
|
|
58
58
|
if connect_successful?
|
59
|
-
@rev_socket.instance_eval { @
|
59
|
+
@rev_socket.instance_eval { @_connector = nil }
|
60
60
|
@rev_socket.attach(evl)
|
61
61
|
@rev_socket.__send__(:on_connect)
|
62
62
|
else
|
63
|
-
@rev_socket.instance_eval { @
|
63
|
+
@rev_socket.instance_eval { @_failed = true }
|
64
64
|
@rev_socket.__send__(:on_connect_failed)
|
65
65
|
end
|
66
66
|
end
|
@@ -77,7 +77,7 @@ module Rev
|
|
77
77
|
|
78
78
|
class TCPSocket < Socket
|
79
79
|
attr_reader :remote_host, :remote_addr, :remote_port, :address_family
|
80
|
-
watcher_delegate :@
|
80
|
+
watcher_delegate :@_resolver
|
81
81
|
|
82
82
|
# Similar to .new, but used in cases where the resulting object is in a
|
83
83
|
# "half-open" state. This is primarily used for when asynchronous
|
@@ -114,7 +114,7 @@ module Rev
|
|
114
114
|
# Called by precreate during asyncronous DNS resolution
|
115
115
|
def preinitialize(addr, port, *args)
|
116
116
|
@remote_host, @remote_addr, @remote_port = addr, addr, port
|
117
|
-
@
|
117
|
+
@_resolver = TCPConnectResolver.new(self, addr, port, *args)
|
118
118
|
end
|
119
119
|
|
120
120
|
private :preinitialize
|
@@ -168,22 +168,28 @@ module Rev
|
|
168
168
|
def on_success(addr)
|
169
169
|
host, port, args = @host, @port, @args
|
170
170
|
|
171
|
-
@sock.instance_eval
|
172
|
-
# DNSResolver only supports IPv4 so we can safely assume
|
173
|
-
|
171
|
+
@sock.instance_eval do
|
172
|
+
# DNSResolver only supports IPv4 so we can safely assume IPv4 address
|
173
|
+
begin
|
174
|
+
socket = TCPConnectSocket.new(::Socket::AF_INET, addr, port, host)
|
175
|
+
rescue Errno::ENETUNREACH
|
176
|
+
on_connect_failed
|
177
|
+
return
|
178
|
+
end
|
179
|
+
|
174
180
|
initialize(socket, *args)
|
175
|
-
@
|
176
|
-
@
|
177
|
-
|
181
|
+
@_connector = Socket::Connector.new(self, socket)
|
182
|
+
@_resolver = nil
|
183
|
+
end
|
178
184
|
@sock.attach(evloop)
|
179
185
|
end
|
180
186
|
|
181
187
|
def on_failure
|
182
188
|
@sock.__send__(:on_resolve_failed)
|
183
|
-
@sock.instance_eval
|
184
|
-
@
|
185
|
-
@
|
186
|
-
|
189
|
+
@sock.instance_eval do
|
190
|
+
@_resolver = nil
|
191
|
+
@_failed = true
|
192
|
+
end
|
187
193
|
return
|
188
194
|
end
|
189
195
|
end
|