eventmachine 0.9.0 → 0.10.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.
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: pipe.cpp 494 2007-08-15 06:23:09Z blackhedd $
3
+ $Id: pipe.cpp 585 2007-11-27 14:29:34Z blackhedd $
4
4
 
5
5
  File: pipe.cpp
6
6
  Date: 30May07
@@ -71,15 +71,32 @@ PipeDescriptor::~PipeDescriptor()
71
71
  * Since we want to have a signal processor integrated into the
72
72
  * client-visible API, let's wait until that is done before cleaning
73
73
  * this up.
74
+ *
75
+ * Added a very ugly hack to support passing the subprocess's exit
76
+ * status to the user. It only makes logical sense for user code to access
77
+ * the subprocess exit status in the unbind callback. But unbind is called
78
+ * back during the EventableDescriptor destructor. So by that time there's
79
+ * no way to call back this object through an object binding, because it's
80
+ * already been cleaned up. We might have added a parameter to the unbind
81
+ * callback, but that would probably break a huge amount of existing code.
82
+ * So the hack-solution is to define an instance variable in the EventMachine
83
+ * object and stick the exit status in there, where it can easily be accessed
84
+ * with an accessor visible to user code.
85
+ * User code should ONLY access the exit status from within the unbind callback.
86
+ * Otherwise there's no guarantee it'll be valid.
87
+ * This hack won't make it impossible to run multiple EventMachines in a single
88
+ * process, but it will make it impossible to reliably nest unbind calls
89
+ * within other unbind calls. (Not sure if that's even possible.)
74
90
  */
75
91
 
76
92
  struct timespec req = {0, 10000000};
77
93
  kill (SubprocessPid, SIGTERM);
78
94
  nanosleep (&req, NULL);
79
- if (waitpid (SubprocessPid, NULL, WNOHANG) == 0) {
95
+ assert (MyEventMachine);
96
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) {
80
97
  kill (SubprocessPid, SIGKILL);
81
98
  nanosleep (&req, NULL);
82
- if (waitpid (SubprocessPid, NULL, WNOHANG) == 0)
99
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0)
83
100
  throw std::runtime_error ("unable to reap subprocess");
84
101
  }
85
102
  }
@@ -302,5 +319,6 @@ bool PipeDescriptor::GetSubprocessPid (pid_t *pid)
302
319
  return ok;
303
320
  }
304
321
 
322
+
305
323
  #endif // OS_UNIX
306
324
 
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: rubymain.cpp 502 2007-08-24 09:29:53Z blackhedd $
3
+ $Id: rubymain.cpp 584 2007-11-27 07:27:32Z blackhedd $
4
4
 
5
5
  File: rubymain.cpp
6
6
  Date: 06Apr06
@@ -181,6 +181,20 @@ static VALUE t_get_subprocess_pid (VALUE self, VALUE signature)
181
181
  return Qnil;
182
182
  }
183
183
 
184
+ /***********************
185
+ t_get_subprocess_status
186
+ ***********************/
187
+
188
+ static VALUE t_get_subprocess_status (VALUE self, VALUE signature)
189
+ {
190
+ int status;
191
+ if (evma_get_subprocess_status (StringValuePtr (signature), &status)) {
192
+ return INT2NUM (status);
193
+ }
194
+
195
+ return Qnil;
196
+ }
197
+
184
198
  /*****************************
185
199
  t_get_comm_inactivity_timeout
186
200
  *****************************/
@@ -227,6 +241,16 @@ static VALUE t_close_connection (VALUE self, VALUE signature, VALUE after_writin
227
241
  return Qnil;
228
242
  }
229
243
 
244
+ /********************************
245
+ t_report_connection_error_status
246
+ ********************************/
247
+
248
+ static VALUE t_report_connection_error_status (VALUE self, VALUE signature)
249
+ {
250
+ int b = evma_report_connection_error_status (StringValuePtr (signature));
251
+ return INT2NUM (b);
252
+ }
253
+
230
254
 
231
255
 
232
256
  /****************
@@ -323,6 +347,16 @@ static VALUE t_set_timer_quantum (VALUE self, VALUE interval)
323
347
  return Qnil;
324
348
  }
325
349
 
350
+ /********************
351
+ t_set_max_timer_count
352
+ ********************/
353
+
354
+ static VALUE t_set_max_timer_count (VALUE self, VALUE ct)
355
+ {
356
+ evma_set_max_timer_count (FIX2INT (ct));
357
+ return Qnil;
358
+ }
359
+
326
360
  /***************
327
361
  t_setuid_string
328
362
  ***************/
@@ -485,6 +519,7 @@ extern "C" void Init_rubyeventmachine()
485
519
  rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3);
486
520
  rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5);
487
521
  rb_define_module_function (EmModule, "close_connection", (VALUE(*)(...))t_close_connection, 2);
522
+ rb_define_module_function (EmModule, "report_connection_error_status", (VALUE(*)(...))t_report_connection_error_status, 1);
488
523
  rb_define_module_function (EmModule, "connect_server", (VALUE(*)(...))t_connect_server, 2);
489
524
  rb_define_module_function (EmModule, "connect_unix_server", (VALUE(*)(...))t_connect_unix_server, 1);
490
525
  rb_define_module_function (EmModule, "open_udp_socket", (VALUE(*)(...))t_open_udp_socket, 2);
@@ -494,6 +529,7 @@ extern "C" void Init_rubyeventmachine()
494
529
  rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0);
495
530
  rb_define_module_function (EmModule, "library_type", (VALUE(*)(...))t_library_type, 0);
496
531
  rb_define_module_function (EmModule, "set_timer_quantum", (VALUE(*)(...))t_set_timer_quantum, 1);
532
+ rb_define_module_function (EmModule, "set_max_timer_count", (VALUE(*)(...))t_set_max_timer_count, 1);
497
533
  rb_define_module_function (EmModule, "setuid_string", (VALUE(*)(...))t_setuid_string, 1);
498
534
  rb_define_module_function (EmModule, "invoke_popen", (VALUE(*)(...))t_invoke_popen, 1);
499
535
  rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2);
@@ -503,6 +539,7 @@ extern "C" void Init_rubyeventmachine()
503
539
 
504
540
  rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1);
505
541
  rb_define_module_function (EmModule, "get_subprocess_pid", (VALUE(*)(...))t_get_subprocess_pid, 1);
542
+ rb_define_module_function (EmModule, "get_subprocess_status", (VALUE(*)(...))t_get_subprocess_status, 1);
506
543
  rb_define_module_function (EmModule, "get_comm_inactivity_timeout", (VALUE(*)(...))t_get_comm_inactivity_timeout, 1);
507
544
  rb_define_module_function (EmModule, "set_comm_inactivity_timeout", (VALUE(*)(...))t_set_comm_inactivity_timeout, 2);
508
545
  rb_define_module_function (EmModule, "set_rlimit_nofile", (VALUE(*)(...))t_set_rlimit_nofile, 1);
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: ssl.cpp 498 2007-08-15 14:03:32Z blackhedd $
3
+ $Id: ssl.cpp 574 2007-11-19 23:36:04Z blackhedd $
4
4
 
5
5
  File: ssl.cpp
6
6
  Date: 30Apr06
@@ -155,9 +155,15 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
155
155
  if (is_server) {
156
156
  // The SSL_CTX calls here do NOT allocate memory.
157
157
  int e;
158
- e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey);
158
+ if (privkeyfile.length() > 0)
159
+ e = SSL_CTX_use_PrivateKey_file (pCtx, privkeyfile.c_str(), SSL_FILETYPE_PEM);
160
+ else
161
+ e = SSL_CTX_use_PrivateKey (pCtx, DefaultPrivateKey);
159
162
  assert (e > 0);
160
- e = SSL_CTX_use_certificate (pCtx, DefaultCertificate);
163
+ if (certchainfile.length() > 0)
164
+ e = SSL_CTX_use_certificate_chain_file (pCtx, certchainfile.c_str());
165
+ else
166
+ e = SSL_CTX_use_certificate (pCtx, DefaultCertificate);
161
167
  assert (e > 0);
162
168
  }
163
169
 
@@ -1,4 +1,4 @@
1
- # $Id: streamer.rb 476 2007-07-27 03:32:51Z blackhedd $
1
+ # $Id: streamer.rb 599 2007-12-05 14:24:11Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -49,7 +49,6 @@ module EventMachine
49
49
 
50
50
  def stream_without_mapping filename
51
51
  if @http_chunks
52
- #@connection.send_data "#{format("%x",@size)}\r\n"
53
52
  @connection.send_data "#{@size.to_s(16)}\r\n"
54
53
  @connection.send_file_data filename
55
54
  @connection.send_data "\r\n0\r\n\r\n"
@@ -79,7 +78,6 @@ module EventMachine
79
78
  len = @size - @position
80
79
  len = ChunkSize if (len > ChunkSize)
81
80
 
82
- #@connection.send_data( "#{format("%x",len)}\r\n" ) if @http_chunks
83
81
  @connection.send_data( "#{len.to_s(16)}\r\n" ) if @http_chunks
84
82
  @connection.send_data( @mapping.get_chunk( @position, len ))
85
83
  @connection.send_data("\r\n") if @http_chunks
@@ -1,4 +1,4 @@
1
- # $Id: eventmachine.rb 521 2007-09-04 18:22:07Z blackhedd $
1
+ # $Id: eventmachine.rb 594 2007-12-05 11:41:39Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -32,6 +32,14 @@
32
32
  # till now. The reason I'm disabling it is because the pure-Ruby
33
33
  # code will have problems of its own, and it's not nearly as fast
34
34
  # anyway. Suggested by a problem report from Moshe Litvin. 05Jun07.
35
+ #
36
+ # 05Dec07: Re-enabled the pure-ruby mechanism, but without the automatic
37
+ # fallback feature that tripped up Moshe Litvin. We shouldn't fail over to
38
+ # the pure Ruby version because it's possible that the user intended to
39
+ # run the extension but failed to do so because of a compilation or
40
+ # similar error. So we require either a global variable or an environment
41
+ # string be set in order to select the pure-Ruby version.
42
+ #
35
43
 
36
44
  =begin
37
45
  $eventmachine_library ||= nil
@@ -56,7 +64,11 @@ if RUBY_PLATFORM =~ /java/
56
64
  require 'java'
57
65
  require 'jeventmachine'
58
66
  else
59
- require 'rubyeventmachine'
67
+ if $eventmachine_library == :pure_ruby or ENV['EVENTMACHINE_LIBRARY'] == "pure_ruby"
68
+ require 'pr_eventmachine'
69
+ else
70
+ require 'rubyeventmachine'
71
+ end
60
72
  end
61
73
 
62
74
 
@@ -153,17 +165,6 @@ require 'shellwords'
153
165
  #
154
166
  #
155
167
  # == Questions and Futures
156
- # Encryption: EventMachine needs the capability to run SSL/TLS on any
157
- # of its clients and servers. Coming soon.
158
- #
159
- # <tt>epoll(4):</tt> EventMachine currently is based on the <tt>select(2)</tt>
160
- # system call in order to be compatible with the widest variety of platforms,
161
- # but it would be interesting to re-base it on <tt>epoll(4).</tt>
162
- # While requiring a Linux 2.6 kernel, this might possibly give much better
163
- # performance and scalability. EventMachine's C++ antecedents already work
164
- # with <tt>kqueue</tt> from the BSD world, but it's not yet clear that this
165
- # is worth doing. Depends on how many people ask for it.
166
- #
167
168
  # Would it be useful for EventMachine to incorporate the Observer pattern
168
169
  # and make use of the corresponding Ruby <tt>observer</tt> package?
169
170
  # Interesting thought.
@@ -483,15 +484,21 @@ module EventMachine
483
484
  # }
484
485
  #
485
486
  #
486
- def EventMachine::start_server server, port, handler=nil, &block
487
+ def EventMachine::start_server server, port, handler=nil, *args, &block
487
488
  klass = if (handler and handler.is_a?(Class))
488
489
  handler
489
490
  else
490
491
  Class.new( Connection ) {handler and include handler}
491
492
  end
492
493
 
494
+ arity = klass.instance_method(:initialize).arity
495
+ expected = arity >= 0 ? arity : -(arity + 1)
496
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
497
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
498
+ end
499
+
493
500
  s = start_tcp_server server, port
494
- @acceptors[s] = [klass,block]
501
+ @acceptors[s] = [klass,args,block]
495
502
  s
496
503
  end
497
504
 
@@ -505,15 +512,21 @@ module EventMachine
505
512
  EventMachine::stop_tcp_server signature
506
513
  end
507
514
 
508
- def EventMachine::start_unix_domain_server filename, handler=nil, &block
515
+ def EventMachine::start_unix_domain_server filename, handler=nil, *args, &block
509
516
  klass = if (handler and handler.is_a?(Class))
510
517
  handler
511
518
  else
512
519
  Class.new( Connection ) {handler and include handler}
513
520
  end
514
521
 
522
+ arity = klass.instance_method(:initialize).arity
523
+ expected = arity >= 0 ? arity : -(arity + 1)
524
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
525
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
526
+ end
527
+
515
528
  s = start_unix_server filename
516
- @acceptors[s] = [klass,block]
529
+ @acceptors[s] = [klass,args,block]
517
530
  end
518
531
 
519
532
  # EventMachine#connect initiates a TCP connection to a remote
@@ -613,16 +626,21 @@ module EventMachine
613
626
  # to have them behave differently with respect to post_init
614
627
  # if at all possible.
615
628
  #
616
- def EventMachine::connect server, port, handler=nil
617
-
629
+ def EventMachine::connect server, port, handler=nil, *args
618
630
  klass = if (handler and handler.is_a?(Class))
619
631
  handler
620
632
  else
621
633
  Class.new( Connection ) {handler and include handler}
622
634
  end
623
635
 
636
+ arity = klass.instance_method(:initialize).arity
637
+ expected = arity >= 0 ? arity : -(arity + 1)
638
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
639
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
640
+ end
641
+
624
642
  s = connect_server server, port
625
- c = klass.new s
643
+ c = klass.new s, *args
626
644
  @conns[s] = c
627
645
  block_given? and yield c
628
646
  c
@@ -668,15 +686,21 @@ module EventMachine
668
686
  # For making connections to Unix-domain sockets.
669
687
  # Eventually this has to get properly documented and unified with the TCP-connect methods.
670
688
  # Note how nearly identical this is to EventMachine#connect
671
- def EventMachine::connect_unix_domain socketname, handler=nil
689
+ def EventMachine::connect_unix_domain socketname, handler=nil, *args
672
690
  klass = if (handler and handler.is_a?(Class))
673
691
  handler
674
692
  else
675
693
  Class.new( Connection ) {handler and include handler}
676
694
  end
677
695
 
696
+ arity = klass.instance_method(:initialize).arity
697
+ expected = arity >= 0 ? arity : -(arity + 1)
698
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
699
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
700
+ end
701
+
678
702
  s = connect_unix_server socketname
679
- c = klass.new s
703
+ c = klass.new s, *args
680
704
  @conns[s] = c
681
705
  block_given? and yield c
682
706
  c
@@ -746,15 +770,21 @@ module EventMachine
746
770
  # Replaced the implementation on 01Oct06. Thanks to Tobias Gustafsson for pointing
747
771
  # out that this originally did not take a class but only a module.
748
772
  #
749
- def self::open_datagram_socket address, port, handler=nil
773
+ def self::open_datagram_socket address, port, handler=nil, *args
750
774
  klass = if (handler and handler.is_a?(Class))
751
775
  handler
752
776
  else
753
777
  Class.new( Connection ) {handler and include handler}
754
778
  end
755
779
 
780
+ arity = klass.instance_method(:initialize).arity
781
+ expected = arity >= 0 ? arity : -(arity + 1)
782
+ if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
783
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size} for #{expected})"
784
+ end
785
+
756
786
  s = open_udp_socket address, port
757
- c = klass.new s
787
+ c = klass.new s, *args
758
788
  @conns[s] = c
759
789
  block_given? and yield c
760
790
  c
@@ -777,6 +807,14 @@ module EventMachine
777
807
  set_timer_quantum mills.to_i
778
808
  end
779
809
 
810
+ # Sets the maximum number of timers and periodic timers that may be outstanding at any
811
+ # given time. You only need to call #set_max_timers if you need more than the default
812
+ # number of timers, which on most platforms is 1000.
813
+ # Call this method before calling EventMachine#run.
814
+ #
815
+ def self::set_max_timers ct
816
+ set_max_timer_count ct
817
+ end
780
818
 
781
819
  #--
782
820
  # The is the responder for the loopback-signalled event.
@@ -1007,36 +1045,97 @@ module EventMachine
1007
1045
 
1008
1046
  private
1009
1047
  def EventMachine::event_callback conn_binding, opcode, data
1048
+ #
1049
+ # Added 03Oct07: Any code path that invokes user-written code must
1050
+ # wrap itself in a begin/rescue for RuntimeErrors, that calls the
1051
+ # user-overridable class method #handle_runtime_error.
1052
+ #
1010
1053
  if opcode == ConnectionData
1011
1054
  c = @conns[conn_binding] or raise ConnectionNotBound
1012
- c.receive_data data
1055
+ begin
1056
+ c.receive_data data
1057
+ rescue
1058
+ EventMachine.handle_runtime_error
1059
+ end
1013
1060
  elsif opcode == ConnectionUnbound
1014
1061
  if c = @conns.delete( conn_binding )
1015
- c.unbind
1062
+ begin
1063
+ c.unbind
1064
+ rescue
1065
+ EventMachine.handle_runtime_error
1066
+ end
1016
1067
  elsif c = @acceptors.delete( conn_binding )
1017
1068
  # no-op
1018
1069
  else
1019
1070
  raise ConnectionNotBound
1020
1071
  end
1021
1072
  elsif opcode == ConnectionAccepted
1022
- accep,blk = @acceptors[conn_binding]
1073
+ accep,args,blk = @acceptors[conn_binding]
1023
1074
  raise NoHandlerForAcceptedConnection unless accep
1024
- c = accep.new data
1075
+ c = accep.new data, *args
1025
1076
  @conns[data] = c
1026
- blk and blk.call(c)
1077
+ begin
1078
+ blk and blk.call(c)
1079
+ rescue
1080
+ EventMachine.handle_runtime_error
1081
+ end
1027
1082
  c # (needed?)
1028
1083
  elsif opcode == TimerFired
1029
1084
  t = @timers.delete( data ) or raise UnknownTimerFired
1030
- t.call
1085
+ begin
1086
+ t.call
1087
+ rescue
1088
+ EventMachine.handle_runtime_error
1089
+ end
1031
1090
  elsif opcode == ConnectionCompleted
1032
1091
  c = @conns[conn_binding] or raise ConnectionNotBound
1033
- c.connection_completed
1092
+ begin
1093
+ c.connection_completed
1094
+ rescue
1095
+ EventMachine.handle_runtime_error
1096
+ end
1034
1097
  elsif opcode == LoopbreakSignalled
1098
+ begin
1035
1099
  run_deferred_callbacks
1100
+ rescue
1101
+ EventMachine.handle_runtime_error
1102
+ end
1036
1103
  end
1037
1104
  end
1038
1105
 
1039
1106
 
1107
+ # Default handler for RuntimeErrors that are raised in user code.
1108
+ # The default behavior is to re-raise the error, which ends your program.
1109
+ # To override the default behavior, re-implement this method in your code.
1110
+ # For example:
1111
+ #
1112
+ # module EventMachine
1113
+ # def self.handle_runtime_error
1114
+ # $>.puts $!
1115
+ # end
1116
+ # end
1117
+ #
1118
+ #--
1119
+ # We need to ensure that any code path which invokes user code rescues RuntimeError
1120
+ # and calls this method. The obvious place to do that is in #event_callback,
1121
+ # but, scurrilously, it turns out that we need to be finer grained that that.
1122
+ # Periodic timers, in particular, wrap their invocations of user code inside
1123
+ # procs that do other stuff we can't not do, like schedule the next invocation.
1124
+ # This is a potential non-robustness, since we need to remember to hook in the
1125
+ # error handler whenever and wherever we change how user code is invoked.
1126
+ #
1127
+ def EventMachine::handle_runtime_error
1128
+ @runtime_error_hook ? @runtime_error_hook.call : raise
1129
+ end
1130
+
1131
+ # Sets a handler for RuntimeErrors that are raised in user code.
1132
+ # Pass a block with no parameters. You can also call this method without a block,
1133
+ # which restores the default behavior (see #handle_runtime_error).
1134
+ #
1135
+ def EventMachine::set_runtime_error_hook &blk
1136
+ @runtime_error_hook = blk
1137
+ end
1138
+
1040
1139
  # Documentation stub
1041
1140
  #--
1042
1141
  # This is a provisional implementation of a stream-oriented file access object.
@@ -1083,14 +1182,33 @@ module EventMachine
1083
1182
  # only by user code.
1084
1183
  #
1085
1184
  class Connection
1086
-
1087
1185
  # EXPERIMENTAL. Added the reconnect methods, which may go away.
1088
1186
  attr_accessor :signature
1089
1187
 
1090
- def initialize sig #:nodoc:
1091
- @signature = sig
1092
- post_init
1093
- end
1188
+ # Override .new so subclasses don't have to call super and can ignore
1189
+ # connection-specific arguments
1190
+ #
1191
+ def self.new sig, *args #:nodoc:
1192
+ allocate.instance_eval do
1193
+ # Call a superclass's #initialize if it has one
1194
+ initialize *args
1195
+
1196
+ # Store signature and run #post_init
1197
+ @signature = sig
1198
+ begin
1199
+ post_init
1200
+ rescue
1201
+ EventMachine::handle_runtime_error
1202
+ end
1203
+
1204
+ self
1205
+ end
1206
+ end
1207
+
1208
+ # Stubbed initialize so legacy superclasses can safely call super
1209
+ #
1210
+ def initialize(*args) #:nodoc:
1211
+ end
1094
1212
 
1095
1213
  # EventMachine::Connection#post_init is called by the event loop
1096
1214
  # immediately after the network connection has been established,
@@ -1207,6 +1325,17 @@ class Connection
1207
1325
  EventMachine::send_data @signature, data, data.length
1208
1326
  end
1209
1327
 
1328
+ # Returns true if the connection is in an error state, false otherwise.
1329
+ # In general, you can detect the occurrence of communication errors or unexpected
1330
+ # disconnection by the remote peer by handing the #unbind method. In some cases, however,
1331
+ # it's useful to check the status of the connection using #error? before attempting to send data.
1332
+ # This function is synchronous: it will return immediately without blocking.
1333
+ #
1334
+ #
1335
+ def error?
1336
+ EventMachine::report_connection_error_status(@signature) != 0
1337
+ end
1338
+
1210
1339
  # #connection_completed is called by the event loop when a remote TCP connection
1211
1340
  # attempt completes successfully. You can expect to get this notification after calls
1212
1341
  # to EventMachine#connect. Remember that EventMachine makes remote connections
@@ -1273,10 +1402,13 @@ class Connection
1273
1402
  # but to be really safe, send messages smaller than the Ethernet-packet
1274
1403
  # size (typically about 1400 bytes). Some very restrictive WANs
1275
1404
  # will either drop or truncate packets larger than about 500 bytes.
1405
+ #--
1406
+ # Added the Integer wrapper around the port parameter per suggestion by
1407
+ # Matthieu Riou, after he passed a String and spent hours tearing his hair out.
1276
1408
  #
1277
1409
  def send_datagram data, recipient_address, recipient_port
1278
1410
  data = data.to_s
1279
- EventMachine::send_datagram @signature, data, data.length, recipient_address, recipient_port
1411
+ EventMachine::send_datagram @signature, data, data.length, recipient_address, Integer(recipient_port)
1280
1412
  end
1281
1413
 
1282
1414
 
@@ -1298,6 +1430,13 @@ class Connection
1298
1430
  EventMachine::get_subprocess_pid @signature
1299
1431
  end
1300
1432
 
1433
+ # Returns a subprocess exit status. Only useful for #popen. Call it in your
1434
+ # #unbind handler.
1435
+ #
1436
+ def get_status
1437
+ EventMachine::get_subprocess_status @signature
1438
+ end
1439
+
1301
1440
  # comm_inactivity_timeout returns the current value (in seconds) of the inactivity-timeout
1302
1441
  # property of network-connection and datagram-socket objects. A nonzero value
1303
1442
  # indicates that the connection or socket will automatically be closed if no read or write
@@ -1373,7 +1512,11 @@ class Connection
1373
1512
  EventMachine::add_timer @interval, proc {self.fire}
1374
1513
  end
1375
1514
  def fire
1376
- @code.call
1515
+ begin
1516
+ @code.call
1517
+ rescue
1518
+ EventMachine::handle_runtime_error
1519
+ end
1377
1520
  schedule unless @cancelled
1378
1521
  end
1379
1522
  def cancel
@@ -1398,6 +1541,10 @@ class Connection
1398
1541
 
1399
1542
  end
1400
1543
 
1544
+ module Protocols
1545
+ # In this module, we define standard protocol implementations.
1546
+ # They get included from separate source files.
1547
+ end
1401
1548
 
1402
1549
  end # module EventMachine
1403
1550
 
@@ -1405,6 +1552,7 @@ end # module EventMachine
1405
1552
 
1406
1553
  # Save everyone some typing.
1407
1554
  EM = EventMachine
1555
+ EM::P = EventMachine::Protocols
1408
1556
 
1409
1557
 
1410
1558
  # At the bottom of this module, we load up protocol handlers that depend on some
@@ -1417,7 +1565,11 @@ require 'protocols/httpclient'
1417
1565
  require 'protocols/line_and_text'
1418
1566
  require 'protocols/header_and_content'
1419
1567
  require 'protocols/linetext2'
1568
+ require 'protocols/httpcli2'
1420
1569
  require 'protocols/stomp'
1421
1570
  require 'protocols/smtpclient'
1422
1571
  require 'protocols/smtpserver'
1572
+ require 'protocols/saslauth'
1573
+
1574
+
1423
1575