eventmachine-eventmachine 0.12.5 → 0.12.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -0
- data/Rakefile +66 -3
- data/docs/ChangeLog +38 -10
- data/eventmachine.gemspec +32 -0
- data/ext/cmain.cpp +45 -3
- data/ext/cplusplus.cpp +21 -0
- data/ext/ed.cpp +34 -1
- data/ext/ed.h +12 -0
- data/ext/em.cpp +23 -3
- data/ext/em.h +6 -2
- data/ext/eventmachine.h +9 -1
- data/ext/eventmachine_cpp.h +1 -0
- data/ext/extconf.rb +8 -29
- data/ext/fastfilereader/extconf.rb +50 -134
- data/ext/fastfilereader/mapper.cpp +12 -0
- data/ext/fastfilereader/mapper.h +1 -1
- data/ext/kb.cpp +0 -286
- data/ext/pipe.cpp +30 -13
- data/ext/rubymain.cpp +127 -12
- data/ext/ssl.cpp +15 -0
- data/ext/ssl.h +4 -0
- data/java/.classpath +8 -0
- data/java/.project +17 -0
- data/lib/em/processes.rb +45 -0
- data/lib/eventmachine.rb +260 -102
- data/lib/eventmachine_version.rb +1 -1
- data/lib/pr_eventmachine.rb +1 -1
- data/lib/protocols/httpcli2.rb +10 -1
- data/lib/protocols/httpclient.rb +2 -2
- data/lib/protocols/memcache.rb +293 -0
- data/lib/protocols/smtpserver.rb +1 -1
- data/setup.rb +1585 -0
- data/tasks/tests.rake +1 -0
- data/tests/test_attach.rb +19 -2
- data/tests/test_basic.rb +2 -2
- data/tests/test_connection_count.rb +45 -0
- data/tests/test_error_handler.rb +35 -0
- data/tests/test_errors.rb +3 -3
- data/tests/test_exc.rb +2 -2
- data/tests/test_handler_check.rb +37 -0
- data/tests/test_httpclient2.rb +1 -1
- data/tests/test_kb.rb +2 -2
- data/tests/test_next_tick.rb +7 -0
- data/tests/test_processes.rb +39 -0
- data/tests/test_pure.rb +2 -2
- data/tests/test_send_file.rb +1 -1
- data/tests/test_ssl_args.rb +3 -3
- data/tests/test_ssl_methods.rb +50 -0
- data/tests/test_timers.rb +3 -1
- data/web/whatis +7 -0
- metadata +88 -84
data/ext/ssl.cpp
CHANGED
@@ -210,6 +210,7 @@ SslBox_t::SslBox_t
|
|
210
210
|
|
211
211
|
SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile):
|
212
212
|
bIsServer (is_server),
|
213
|
+
bHandshakeCompleted (false),
|
213
214
|
pSSL (NULL),
|
214
215
|
pbioRead (NULL),
|
215
216
|
pbioWrite (NULL)
|
@@ -289,6 +290,7 @@ int SslBox_t::GetPlaintext (char *buf, int bufsize)
|
|
289
290
|
else
|
290
291
|
return 0;
|
291
292
|
}
|
293
|
+
bHandshakeCompleted = true;
|
292
294
|
// If handshake finished, FALL THROUGH and return the available plaintext.
|
293
295
|
}
|
294
296
|
|
@@ -403,6 +405,19 @@ int SslBox_t::PutPlaintext (const char *buf, int bufsize)
|
|
403
405
|
return 0;
|
404
406
|
}
|
405
407
|
|
408
|
+
/**********************
|
409
|
+
SslBox_t::GetPeerCert
|
410
|
+
**********************/
|
411
|
+
|
412
|
+
X509 *SslBox_t::GetPeerCert()
|
413
|
+
{
|
414
|
+
X509 *cert = NULL;
|
415
|
+
|
416
|
+
if (pSSL)
|
417
|
+
cert = SSL_get_peer_certificate(pSSL);
|
418
|
+
|
419
|
+
return cert;
|
420
|
+
}
|
406
421
|
|
407
422
|
#endif // WITH_SSL
|
408
423
|
|
data/ext/ssl.h
CHANGED
@@ -66,6 +66,9 @@ class SslBox_t
|
|
66
66
|
bool PutCiphertext (const char*, int);
|
67
67
|
bool CanGetCiphertext();
|
68
68
|
int GetCiphertext (char*, int);
|
69
|
+
bool IsHandshakeCompleted() {return bHandshakeCompleted;}
|
70
|
+
|
71
|
+
X509 *GetPeerCert();
|
69
72
|
|
70
73
|
void Shutdown();
|
71
74
|
|
@@ -73,6 +76,7 @@ class SslBox_t
|
|
73
76
|
SslContext_t *Context;
|
74
77
|
|
75
78
|
bool bIsServer;
|
79
|
+
bool bHandshakeCompleted;
|
76
80
|
SSL *pSSL;
|
77
81
|
BIO *pbioRead;
|
78
82
|
BIO *pbioWrite;
|
data/java/.classpath
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<classpath>
|
3
|
+
<classpathentry kind="src" path="src"/>
|
4
|
+
<classpathentry excluding="src/" kind="src" path=""/>
|
5
|
+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
6
|
+
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
7
|
+
<classpathentry kind="output" path="src"/>
|
8
|
+
</classpath>
|
data/java/.project
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<projectDescription>
|
3
|
+
<name>em_reactor</name>
|
4
|
+
<comment></comment>
|
5
|
+
<projects>
|
6
|
+
</projects>
|
7
|
+
<buildSpec>
|
8
|
+
<buildCommand>
|
9
|
+
<name>org.eclipse.jdt.core.javabuilder</name>
|
10
|
+
<arguments>
|
11
|
+
</arguments>
|
12
|
+
</buildCommand>
|
13
|
+
</buildSpec>
|
14
|
+
<natures>
|
15
|
+
<nature>org.eclipse.jdt.core.javanature</nature>
|
16
|
+
</natures>
|
17
|
+
</projectDescription>
|
data/lib/em/processes.rb
CHANGED
@@ -63,6 +63,51 @@ module EventMachine
|
|
63
63
|
succeed( @data.join )
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
class SystemCmd < EventMachine::Connection # :nodoc:
|
68
|
+
def initialize cb
|
69
|
+
@cb = cb
|
70
|
+
@output = []
|
71
|
+
end
|
72
|
+
def receive_data data
|
73
|
+
@output << data
|
74
|
+
end
|
75
|
+
def unbind
|
76
|
+
@cb.call @output.join(''), get_status if @cb
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# EM::system is a simple wrapper for EM::popen. It is similar to Kernel::system, but requires a
|
81
|
+
# single string argument for the command and performs no shell expansion.
|
82
|
+
#
|
83
|
+
# The block or proc passed to EM::system is called with two arguments: the output generated by the command,
|
84
|
+
# and a Process::Status that contains information about the command's execution.
|
85
|
+
#
|
86
|
+
# EM.run{
|
87
|
+
# EM.system('ls'){ |output,status| puts output if status.exitstatus == 0 }
|
88
|
+
# }
|
89
|
+
#
|
90
|
+
# You can also supply an additional proc to send some data to the process:
|
91
|
+
#
|
92
|
+
# EM.run{
|
93
|
+
# EM.system('sh', proc{ |process|
|
94
|
+
# process.send_data("echo hello\n")
|
95
|
+
# process.send_data("exit\n")
|
96
|
+
# }, proc{ |out,status|
|
97
|
+
# puts(out)
|
98
|
+
# })
|
99
|
+
# }
|
100
|
+
#
|
101
|
+
# Like EM::popen, EM::system currently does not work on windows.
|
102
|
+
#
|
103
|
+
def EventMachine::system cmd, *args, &cb
|
104
|
+
cb ||= args.pop if args.last.is_a? Proc
|
105
|
+
init = args.pop if args.last.is_a? Proc
|
106
|
+
|
107
|
+
EM.popen(cmd, SystemCmd, cb) do |c|
|
108
|
+
init[c] if init
|
109
|
+
end
|
110
|
+
end
|
66
111
|
end
|
67
112
|
|
68
113
|
|
data/lib/eventmachine.rb
CHANGED
@@ -234,6 +234,9 @@ module EventMachine
|
|
234
234
|
@reactor_running = true
|
235
235
|
initialize_event_machine
|
236
236
|
(b = blk || block) and add_timer(0, b)
|
237
|
+
if @next_tick_queue && !@next_tick_queue.empty?
|
238
|
+
add_timer(0) { signal_loopbreak }
|
239
|
+
end
|
237
240
|
run_machine
|
238
241
|
ensure
|
239
242
|
begin
|
@@ -535,12 +538,15 @@ module EventMachine
|
|
535
538
|
begin
|
536
539
|
port = Integer(port)
|
537
540
|
rescue ArgumentError, TypeError
|
541
|
+
# there was no port, so server must be a unix domain socket
|
542
|
+
# the port argument is actually the handler, and the handler is one of the args
|
538
543
|
args.unshift handler if handler
|
539
544
|
handler = port
|
540
545
|
port = nil
|
541
546
|
end if port
|
542
547
|
|
543
548
|
klass = if (handler and handler.is_a?(Class))
|
549
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
544
550
|
handler
|
545
551
|
else
|
546
552
|
Class.new( Connection ) {handler and include handler}
|
@@ -676,12 +682,15 @@ module EventMachine
|
|
676
682
|
begin
|
677
683
|
port = Integer(port)
|
678
684
|
rescue ArgumentError, TypeError
|
685
|
+
# there was no port, so server must be a unix domain socket
|
686
|
+
# the port argument is actually the handler, and the handler is one of the args
|
679
687
|
args.unshift handler if handler
|
680
688
|
handler = port
|
681
689
|
port = nil
|
682
690
|
end if port
|
683
691
|
|
684
692
|
klass = if (handler and handler.is_a?(Class))
|
693
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
685
694
|
handler
|
686
695
|
else
|
687
696
|
Class.new( Connection ) {handler and include handler}
|
@@ -749,6 +758,7 @@ module EventMachine
|
|
749
758
|
# Thanks to Riham Aldakkak (eSpace Technologies) for the initial patch
|
750
759
|
def EventMachine::attach io, handler=nil, *args
|
751
760
|
klass = if (handler and handler.is_a?(Class))
|
761
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
752
762
|
handler
|
753
763
|
else
|
754
764
|
Class.new( Connection ) {handler and include handler}
|
@@ -880,6 +890,7 @@ module EventMachine
|
|
880
890
|
#
|
881
891
|
def self::open_datagram_socket address, port, handler=nil, *args
|
882
892
|
klass = if (handler and handler.is_a?(Class))
|
893
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
883
894
|
handler
|
884
895
|
else
|
885
896
|
Class.new( Connection ) {handler and include handler}
|
@@ -924,6 +935,35 @@ module EventMachine
|
|
924
935
|
set_max_timer_count ct
|
925
936
|
end
|
926
937
|
|
938
|
+
# Gets the current maximum number of allowed timers
|
939
|
+
#
|
940
|
+
def self::get_max_timers
|
941
|
+
get_max_timer_count
|
942
|
+
end
|
943
|
+
|
944
|
+
# Returns the total number of connections (file descriptors) currently held by the reactor.
|
945
|
+
# Note that a tick must pass after the 'initiation' of a connection for this number to increment.
|
946
|
+
#
|
947
|
+
# For example, $count will be 0 in this case:
|
948
|
+
#
|
949
|
+
# EM.run {
|
950
|
+
# EM.connect("rubyeventmachine.com", 80)
|
951
|
+
# $count = EM.connection_count
|
952
|
+
# }
|
953
|
+
#
|
954
|
+
# In this example, $count will be 1 since the connection has been established in the next loop of the reactor.
|
955
|
+
#
|
956
|
+
# EM.run {
|
957
|
+
# EM.connect("rubyeventmachine.com", 80)
|
958
|
+
# EM.next_tick {
|
959
|
+
# $count = EM.connection_count
|
960
|
+
# }
|
961
|
+
# }
|
962
|
+
#
|
963
|
+
def self::connection_count
|
964
|
+
self::get_connection_count
|
965
|
+
end
|
966
|
+
|
927
967
|
#--
|
928
968
|
# The is the responder for the loopback-signalled event.
|
929
969
|
# It can be fired either by code running on a separate thread (EM#defer) or on
|
@@ -1050,7 +1090,7 @@ module EventMachine
|
|
1050
1090
|
def self::next_tick pr=nil, &block
|
1051
1091
|
raise "no argument or block given" unless ((pr && pr.respond_to?(:call)) or block)
|
1052
1092
|
(@next_tick_queue ||= []) << ( pr || block )
|
1053
|
-
|
1093
|
+
signal_loopbreak if reactor_running?
|
1054
1094
|
=begin
|
1055
1095
|
(@next_tick_procs ||= []) << (pr || block)
|
1056
1096
|
if @next_tick_procs.length == 1
|
@@ -1099,13 +1139,33 @@ module EventMachine
|
|
1099
1139
|
|
1100
1140
|
|
1101
1141
|
|
1102
|
-
#
|
1103
|
-
#
|
1142
|
+
# Run an external process. This does not currently work on Windows.
|
1143
|
+
#
|
1144
|
+
# module RubyCounter
|
1145
|
+
# def post_init
|
1146
|
+
# # count up to 5
|
1147
|
+
# send_data "5\n"
|
1148
|
+
# end
|
1149
|
+
# def receive_data data
|
1150
|
+
# puts "ruby sent me: #{data}"
|
1151
|
+
# end
|
1152
|
+
# def unbind
|
1153
|
+
# puts "ruby died with exit status: #{get_status.exitstatus}"
|
1154
|
+
# end
|
1155
|
+
# end
|
1156
|
+
#
|
1157
|
+
# EM.run{
|
1158
|
+
# EM.popen("ruby -e' $stdout.sync = true; gets.to_i.times{ |i| puts i+1; sleep 1 } '", RubyCounter)
|
1159
|
+
# }
|
1160
|
+
#
|
1161
|
+
# Also see EM::DeferrableChildProcess and EM::system
|
1104
1162
|
#--
|
1163
|
+
# At this moment, it's only available on Unix.
|
1105
1164
|
# Perhaps misnamed since the underlying function uses socketpair and is full-duplex.
|
1106
1165
|
#
|
1107
1166
|
def self::popen cmd, handler=nil, *args
|
1108
1167
|
klass = if (handler and handler.is_a?(Class))
|
1168
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
1109
1169
|
handler
|
1110
1170
|
else
|
1111
1171
|
Class.new( Connection ) {handler and include handler}
|
@@ -1141,6 +1201,7 @@ module EventMachine
|
|
1141
1201
|
#
|
1142
1202
|
def EventMachine::open_keyboard handler=nil, *args
|
1143
1203
|
klass = if (handler and handler.is_a?(Class))
|
1204
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
1144
1205
|
handler
|
1145
1206
|
else
|
1146
1207
|
Class.new( Connection ) {handler and include handler}
|
@@ -1159,7 +1220,19 @@ module EventMachine
|
|
1159
1220
|
c
|
1160
1221
|
end
|
1161
1222
|
|
1162
|
-
|
1223
|
+
# Catch-all for errors raised during event loop callbacks.
|
1224
|
+
#
|
1225
|
+
# EM.error_handler{ |e|
|
1226
|
+
# puts "Error raised during event loop: #{e.message}"
|
1227
|
+
# }
|
1228
|
+
#
|
1229
|
+
def EventMachine::error_handler cb = nil, &blk
|
1230
|
+
if cb or blk
|
1231
|
+
@error_handler = cb || blk
|
1232
|
+
elsif instance_variable_defined? :@error_handler
|
1233
|
+
remove_instance_variable :@error_handler
|
1234
|
+
end
|
1235
|
+
end
|
1163
1236
|
|
1164
1237
|
private
|
1165
1238
|
def EventMachine::event_callback conn_binding, opcode, data
|
@@ -1177,10 +1250,7 @@ module EventMachine
|
|
1177
1250
|
# runs down open connections). It should go on the other calls to user
|
1178
1251
|
# code, but the performance impact may be too large.
|
1179
1252
|
#
|
1180
|
-
if opcode ==
|
1181
|
-
c = @conns[conn_binding] or raise ConnectionNotBound, "received data #{data} for unknown signature: #{conn_binding}"
|
1182
|
-
c.receive_data data
|
1183
|
-
elsif opcode == ConnectionUnbound
|
1253
|
+
if opcode == ConnectionUnbound
|
1184
1254
|
if c = @conns.delete( conn_binding )
|
1185
1255
|
begin
|
1186
1256
|
c.unbind
|
@@ -1200,12 +1270,17 @@ module EventMachine
|
|
1200
1270
|
@conns[data] = c
|
1201
1271
|
blk and blk.call(c)
|
1202
1272
|
c # (needed?)
|
1203
|
-
elsif opcode == TimerFired
|
1204
|
-
t = @timers.delete( data ) or raise UnknownTimerFired, "timer data: #{data}"
|
1205
|
-
t.call
|
1206
1273
|
elsif opcode == ConnectionCompleted
|
1207
1274
|
c = @conns[conn_binding] or raise ConnectionNotBound, "received ConnectionCompleted for unknown signature: #{conn_binding}"
|
1208
1275
|
c.connection_completed
|
1276
|
+
##
|
1277
|
+
# The remaining code is a fallback for the pure ruby reactor. Usually these events are handled in the C event_callback() in rubymain.cpp
|
1278
|
+
elsif opcode == TimerFired
|
1279
|
+
t = @timers.delete( data ) or raise UnknownTimerFired, "timer data: #{data}"
|
1280
|
+
t.call
|
1281
|
+
elsif opcode == ConnectionData
|
1282
|
+
c = @conns[conn_binding] or raise ConnectionNotBound, "received data #{data} for unknown signature: #{conn_binding}"
|
1283
|
+
c.receive_data data
|
1209
1284
|
elsif opcode == LoopbreakSignalled
|
1210
1285
|
run_deferred_callbacks
|
1211
1286
|
elsif opcode == ConnectionNotifyReadable
|
@@ -1217,98 +1292,102 @@ module EventMachine
|
|
1217
1292
|
end
|
1218
1293
|
end
|
1219
1294
|
|
1220
|
-
private
|
1221
|
-
def EventMachine::original_event_callback conn_binding, opcode, data
|
1222
|
-
#
|
1223
|
-
# Added 03Oct07: Any code path that invokes user-written code must
|
1224
|
-
# wrap itself in a begin/rescue for RuntimeErrors, that calls the
|
1225
|
-
# user-overridable class method #handle_runtime_error.
|
1226
|
-
#
|
1227
|
-
if opcode == ConnectionData
|
1228
|
-
c = @conns[conn_binding] or raise ConnectionNotBound
|
1229
|
-
begin
|
1230
|
-
c.receive_data data
|
1231
|
-
rescue
|
1232
|
-
EventMachine.handle_runtime_error
|
1233
|
-
end
|
1234
|
-
elsif opcode == ConnectionUnbound
|
1235
|
-
if c = @conns.delete( conn_binding )
|
1236
|
-
begin
|
1237
|
-
c.unbind
|
1238
|
-
rescue
|
1239
|
-
EventMachine.handle_runtime_error
|
1240
|
-
end
|
1241
|
-
elsif c = @acceptors.delete( conn_binding )
|
1242
|
-
# no-op
|
1243
|
-
else
|
1244
|
-
raise ConnectionNotBound
|
1245
|
-
end
|
1246
|
-
elsif opcode == ConnectionAccepted
|
1247
|
-
accep,args,blk = @acceptors[conn_binding]
|
1248
|
-
raise NoHandlerForAcceptedConnection unless accep
|
1249
|
-
c = accep.new data, *args
|
1250
|
-
@conns[data] = c
|
1251
|
-
begin
|
1252
|
-
blk and blk.call(c)
|
1253
|
-
rescue
|
1254
|
-
EventMachine.handle_runtime_error
|
1255
|
-
end
|
1256
|
-
c # (needed?)
|
1257
|
-
elsif opcode == TimerFired
|
1258
|
-
t = @timers.delete( data ) or raise UnknownTimerFired
|
1259
|
-
begin
|
1260
|
-
t.call
|
1261
|
-
rescue
|
1262
|
-
EventMachine.handle_runtime_error
|
1263
|
-
end
|
1264
|
-
elsif opcode == ConnectionCompleted
|
1265
|
-
c = @conns[conn_binding] or raise ConnectionNotBound
|
1266
|
-
begin
|
1267
|
-
c.connection_completed
|
1268
|
-
rescue
|
1269
|
-
EventMachine.handle_runtime_error
|
1270
|
-
end
|
1271
|
-
elsif opcode == LoopbreakSignalled
|
1272
|
-
begin
|
1273
|
-
run_deferred_callbacks
|
1274
|
-
rescue
|
1275
|
-
EventMachine.handle_runtime_error
|
1276
|
-
end
|
1277
|
-
end
|
1278
|
-
end
|
1279
|
-
|
1280
|
-
|
1281
|
-
# Default handler for RuntimeErrors that are raised in user code.
|
1282
|
-
# The default behavior is to re-raise the error, which ends your program.
|
1283
|
-
# To override the default behavior, re-implement this method in your code.
|
1284
|
-
# For example:
|
1285
|
-
#
|
1286
|
-
# module EventMachine
|
1287
|
-
# def self.handle_runtime_error
|
1288
|
-
# $>.puts $!
|
1289
|
-
# end
|
1290
|
-
# end
|
1291
|
-
#
|
1292
1295
|
#--
|
1293
|
-
#
|
1294
|
-
#
|
1295
|
-
#
|
1296
|
-
#
|
1297
|
-
#
|
1298
|
-
#
|
1299
|
-
#
|
1300
|
-
#
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
#
|
1306
|
-
#
|
1307
|
-
#
|
1308
|
-
#
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1296
|
+
# The original event_callback below handled runtime errors in ruby and degraded performance significantly.
|
1297
|
+
# An optional C-based error handler is now available via EM::error_handler
|
1298
|
+
#
|
1299
|
+
# private
|
1300
|
+
# def EventMachine::original_event_callback conn_binding, opcode, data
|
1301
|
+
# #
|
1302
|
+
# # Added 03Oct07: Any code path that invokes user-written code must
|
1303
|
+
# # wrap itself in a begin/rescue for RuntimeErrors, that calls the
|
1304
|
+
# # user-overridable class method #handle_runtime_error.
|
1305
|
+
# #
|
1306
|
+
# if opcode == ConnectionData
|
1307
|
+
# c = @conns[conn_binding] or raise ConnectionNotBound
|
1308
|
+
# begin
|
1309
|
+
# c.receive_data data
|
1310
|
+
# rescue
|
1311
|
+
# EventMachine.handle_runtime_error
|
1312
|
+
# end
|
1313
|
+
# elsif opcode == ConnectionUnbound
|
1314
|
+
# if c = @conns.delete( conn_binding )
|
1315
|
+
# begin
|
1316
|
+
# c.unbind
|
1317
|
+
# rescue
|
1318
|
+
# EventMachine.handle_runtime_error
|
1319
|
+
# end
|
1320
|
+
# elsif c = @acceptors.delete( conn_binding )
|
1321
|
+
# # no-op
|
1322
|
+
# else
|
1323
|
+
# raise ConnectionNotBound
|
1324
|
+
# end
|
1325
|
+
# elsif opcode == ConnectionAccepted
|
1326
|
+
# accep,args,blk = @acceptors[conn_binding]
|
1327
|
+
# raise NoHandlerForAcceptedConnection unless accep
|
1328
|
+
# c = accep.new data, *args
|
1329
|
+
# @conns[data] = c
|
1330
|
+
# begin
|
1331
|
+
# blk and blk.call(c)
|
1332
|
+
# rescue
|
1333
|
+
# EventMachine.handle_runtime_error
|
1334
|
+
# end
|
1335
|
+
# c # (needed?)
|
1336
|
+
# elsif opcode == TimerFired
|
1337
|
+
# t = @timers.delete( data ) or raise UnknownTimerFired
|
1338
|
+
# begin
|
1339
|
+
# t.call
|
1340
|
+
# rescue
|
1341
|
+
# EventMachine.handle_runtime_error
|
1342
|
+
# end
|
1343
|
+
# elsif opcode == ConnectionCompleted
|
1344
|
+
# c = @conns[conn_binding] or raise ConnectionNotBound
|
1345
|
+
# begin
|
1346
|
+
# c.connection_completed
|
1347
|
+
# rescue
|
1348
|
+
# EventMachine.handle_runtime_error
|
1349
|
+
# end
|
1350
|
+
# elsif opcode == LoopbreakSignalled
|
1351
|
+
# begin
|
1352
|
+
# run_deferred_callbacks
|
1353
|
+
# rescue
|
1354
|
+
# EventMachine.handle_runtime_error
|
1355
|
+
# end
|
1356
|
+
# end
|
1357
|
+
# end
|
1358
|
+
#
|
1359
|
+
#
|
1360
|
+
# # Default handler for RuntimeErrors that are raised in user code.
|
1361
|
+
# # The default behavior is to re-raise the error, which ends your program.
|
1362
|
+
# # To override the default behavior, re-implement this method in your code.
|
1363
|
+
# # For example:
|
1364
|
+
# #
|
1365
|
+
# # module EventMachine
|
1366
|
+
# # def self.handle_runtime_error
|
1367
|
+
# # $>.puts $!
|
1368
|
+
# # end
|
1369
|
+
# # end
|
1370
|
+
# #
|
1371
|
+
# #--
|
1372
|
+
# # We need to ensure that any code path which invokes user code rescues RuntimeError
|
1373
|
+
# # and calls this method. The obvious place to do that is in #event_callback,
|
1374
|
+
# # but, scurrilously, it turns out that we need to be finer grained that that.
|
1375
|
+
# # Periodic timers, in particular, wrap their invocations of user code inside
|
1376
|
+
# # procs that do other stuff we can't not do, like schedule the next invocation.
|
1377
|
+
# # This is a potential non-robustness, since we need to remember to hook in the
|
1378
|
+
# # error handler whenever and wherever we change how user code is invoked.
|
1379
|
+
# #
|
1380
|
+
# def EventMachine::handle_runtime_error
|
1381
|
+
# @runtime_error_hook ? @runtime_error_hook.call : raise
|
1382
|
+
# end
|
1383
|
+
#
|
1384
|
+
# # Sets a handler for RuntimeErrors that are raised in user code.
|
1385
|
+
# # Pass a block with no parameters. You can also call this method without a block,
|
1386
|
+
# # which restores the default behavior (see #handle_runtime_error).
|
1387
|
+
# #
|
1388
|
+
# def EventMachine::set_runtime_error_hook &blk
|
1389
|
+
# @runtime_error_hook = blk
|
1390
|
+
# end
|
1312
1391
|
|
1313
1392
|
# Documentation stub
|
1314
1393
|
#--
|
@@ -1317,6 +1396,7 @@ module EventMachine
|
|
1317
1396
|
class << self
|
1318
1397
|
def _open_file_for_writing filename, handler=nil
|
1319
1398
|
klass = if (handler and handler.is_a?(Class))
|
1399
|
+
raise ArgumentError, 'must provide module or subclass of EventMachine::Connection' unless Connection > handler
|
1320
1400
|
handler
|
1321
1401
|
else
|
1322
1402
|
Class.new( Connection ) {handler and include handler}
|
@@ -1426,6 +1506,16 @@ class Connection
|
|
1426
1506
|
puts "............>>>#{data.length}"
|
1427
1507
|
end
|
1428
1508
|
|
1509
|
+
# #ssl_handshake_completed is called by EventMachine when the SSL/TLS handshake has
|
1510
|
+
# been completed, as a result of calling #start_tls to initiate SSL/TLS on the connection.
|
1511
|
+
#
|
1512
|
+
# This callback exists because #post_init and #connection_completed are <b>not</b> reliable
|
1513
|
+
# for indicating when an SSL/TLS connection is ready to have it's certificate queried for.
|
1514
|
+
#
|
1515
|
+
# See #get_peer_cert for application and example.
|
1516
|
+
def ssl_handshake_completed
|
1517
|
+
end
|
1518
|
+
|
1429
1519
|
# EventMachine::Connection#unbind is called by the framework whenever a connection
|
1430
1520
|
# (either a server or client connection) is closed. The close can occur because
|
1431
1521
|
# your code intentionally closes it (see close_connection and close_connection_after_writing),
|
@@ -1572,6 +1662,73 @@ class Connection
|
|
1572
1662
|
EventMachine::start_tls @signature
|
1573
1663
|
end
|
1574
1664
|
|
1665
|
+
# If SSL/TLS is active on the connection, #get_peer_cert returns the remote X509 certificate
|
1666
|
+
# as a String, in the popular PEM format. This can then be used for arbitrary validation
|
1667
|
+
# of a peer's certificate in your code.
|
1668
|
+
#
|
1669
|
+
# This should be called in/after the #ssl_handshake_completed callback, which indicates
|
1670
|
+
# that SSL/TLS is active. Using this callback is important, because the certificate may not
|
1671
|
+
# be available until the time it is executed. Using #post_init or #connection_completed is
|
1672
|
+
# not adequate, because the SSL handshake may still be taking place.
|
1673
|
+
#
|
1674
|
+
# #get_peer_cert will return <b>nil</b> if:
|
1675
|
+
#
|
1676
|
+
# * EventMachine is not built with OpenSSL support
|
1677
|
+
# * SSL/TLS is not active on the connection
|
1678
|
+
# * SSL/TLS handshake is not yet complete
|
1679
|
+
# * Remote peer for any other reason has not presented a certificate
|
1680
|
+
#
|
1681
|
+
# === Example:
|
1682
|
+
#
|
1683
|
+
# module Handler
|
1684
|
+
#
|
1685
|
+
# def post_init
|
1686
|
+
# puts "Starting TLS"
|
1687
|
+
# start_tls
|
1688
|
+
# end
|
1689
|
+
#
|
1690
|
+
# def ssl_handshake_completed
|
1691
|
+
# puts get_peer_cert
|
1692
|
+
# close_connection
|
1693
|
+
# end
|
1694
|
+
#
|
1695
|
+
# def unbind
|
1696
|
+
# EventMachine::stop_event_loop
|
1697
|
+
# end
|
1698
|
+
#
|
1699
|
+
# end
|
1700
|
+
#
|
1701
|
+
# EM.run {
|
1702
|
+
# EventMachine::connect "mail.google.com", 443, Handler
|
1703
|
+
# }
|
1704
|
+
#
|
1705
|
+
# Output:
|
1706
|
+
# -----BEGIN CERTIFICATE-----
|
1707
|
+
# MIIDIjCCAougAwIBAgIQbldpChBPqv+BdPg4iwgN8TANBgkqhkiG9w0BAQUFADBM
|
1708
|
+
# MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
|
1709
|
+
# THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wODA1MDIxNjMyNTRaFw0w
|
1710
|
+
# OTA1MDIxNjMyNTRaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
|
1711
|
+
# MRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRgw
|
1712
|
+
# FgYDVQQDEw9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
|
1713
|
+
# AoGBALlkxdh2QXegdElukCSOV2+8PKiONIS+8Tu9K7MQsYpqtLNC860zwOPQ2NLI
|
1714
|
+
# 3Zp4jwuXVTrtzGuiqf5Jioh35Ig3CqDXtLyZoypjZUQcq4mlLzHlhIQ4EhSjDmA7
|
1715
|
+
# Ffw9y3ckSOQgdBQWNLbquHh9AbEUjmhkrYxIqKXeCnRKhv6nAgMBAAGjgecwgeQw
|
1716
|
+
# KAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwNgYDVR0f
|
1717
|
+
# BC8wLTAroCmgJ4YlaHR0cDovL2NybC50aGF3dGUuY29tL1RoYXd0ZVNHQ0NBLmNy
|
1718
|
+
# bDByBggrBgEFBQcBAQRmMGQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0
|
1719
|
+
# ZS5jb20wPgYIKwYBBQUHMAKGMmh0dHA6Ly93d3cudGhhd3RlLmNvbS9yZXBvc2l0
|
1720
|
+
# b3J5L1RoYXd0ZV9TR0NfQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEF
|
1721
|
+
# BQADgYEAsRwpLg1dgCR1gYDK185MFGukXMeQFUvhGqF8eT/CjpdvezyKVuz84gSu
|
1722
|
+
# 6ccMXgcPQZGQN/F4Xug+Q01eccJjRSVfdvR5qwpqCj+6BFl5oiKDBsveSkrmL5dz
|
1723
|
+
# s2bn7TdTSYKcLeBkjXxDLHGBqLJ6TNCJ3c4/cbbG5JhGvoema94=
|
1724
|
+
# -----END CERTIFICATE-----
|
1725
|
+
#
|
1726
|
+
# You can do whatever you want with the certificate String, such as load it
|
1727
|
+
# as a certificate object using the OpenSSL library, and check it's fields.
|
1728
|
+
def get_peer_cert
|
1729
|
+
EventMachine::get_peer_cert @signature
|
1730
|
+
end
|
1731
|
+
|
1575
1732
|
|
1576
1733
|
# send_datagram is for sending UDP messages.
|
1577
1734
|
# This method may be called from any Connection object that refers
|
@@ -1755,6 +1912,7 @@ module Protocols
|
|
1755
1912
|
autoload :SmtpClient, 'protocols/smtpclient'
|
1756
1913
|
autoload :SmtpServer, 'protocols/smtpserver'
|
1757
1914
|
autoload :SASLauth, 'protocols/saslauth'
|
1915
|
+
autoload :Memcache, 'protocols/memcache'
|
1758
1916
|
|
1759
1917
|
#require 'protocols/postgres' UNCOMMENT THIS LINE WHEN THE POSTGRES CODE IS READY FOR PRIME TIME.
|
1760
1918
|
end
|