eventmachine 0.12.4 → 0.12.6
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/.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
|