eventmachine 1.0.0.beta.4 → 1.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -82,7 +82,8 @@ typedef int SOCKET;
82
82
 
83
83
  #ifdef OS_WIN32
84
84
  // 21Sep09: windows limits select() to 64 sockets by default, we increase it to 1024 here (before including winsock2.h)
85
- #define FD_SETSIZE 1024
85
+ // 18Jun12: fd_setsize must be changed in the ruby binary (not in this extension). redefining it also causes segvs, see eventmachine/eventmachine#333
86
+ //#define FD_SETSIZE 1024
86
87
 
87
88
  #define WIN32_LEAN_AND_MEAN
88
89
  #include <windows.h>
@@ -507,7 +507,7 @@ static VALUE t_connect_server (VALUE self, VALUE server, VALUE port)
507
507
  rb_raise (EM_eConnectionError, "no connection");
508
508
  return ULONG2NUM (f);
509
509
  } catch (std::runtime_error e) {
510
- rb_raise (EM_eConnectionError, e.what());
510
+ rb_raise (EM_eConnectionError, "%s", e.what());
511
511
  }
512
512
  return Qnil;
513
513
  }
@@ -528,7 +528,7 @@ static VALUE t_bind_connect_server (VALUE self, VALUE bind_addr, VALUE bind_port
528
528
  rb_raise (EM_eConnectionError, "no connection");
529
529
  return ULONG2NUM (f);
530
530
  } catch (std::runtime_error e) {
531
- rb_raise (EM_eConnectionError, e.what());
531
+ rb_raise (EM_eConnectionError, "%s", e.what());
532
532
  }
533
533
  return Qnil;
534
534
  }
@@ -615,7 +615,7 @@ static VALUE t_set_sock_opt (VALUE self, VALUE signature, VALUE lev, VALUE optna
615
615
  }
616
616
 
617
617
 
618
- if (setsockopt(fd, level, option, v, len) < 0)
618
+ if (setsockopt(fd, level, option, (char *)v, len) < 0)
619
619
  rb_sys_fail("setsockopt");
620
620
 
621
621
  return INT2FIX(0);
@@ -686,6 +686,15 @@ static VALUE t_paused_p (VALUE self, VALUE signature)
686
686
  return evma_is_paused(NUM2ULONG (signature)) ? Qtrue : Qfalse;
687
687
  }
688
688
 
689
+ /*********************
690
+ t_num_close_scheduled
691
+ *********************/
692
+
693
+ static VALUE t_num_close_scheduled (VALUE self)
694
+ {
695
+ return INT2FIX(evma_num_close_scheduled());
696
+ }
697
+
689
698
  /*****************
690
699
  t_open_udp_socket
691
700
  *****************/
@@ -839,7 +848,7 @@ static VALUE t_watch_filename (VALUE self, VALUE fname)
839
848
  try {
840
849
  return ULONG2NUM(evma_watch_filename(StringValuePtr(fname)));
841
850
  } catch (std::runtime_error e) {
842
- rb_raise (EM_eUnsupported, e.what());
851
+ rb_raise (EM_eUnsupported, "%s", e.what());
843
852
  }
844
853
  return Qnil;
845
854
  }
@@ -865,7 +874,7 @@ static VALUE t_watch_pid (VALUE self, VALUE pid)
865
874
  try {
866
875
  return ULONG2NUM(evma_watch_pid(NUM2INT(pid)));
867
876
  } catch (std::runtime_error e) {
868
- rb_raise (EM_eUnsupported, e.what());
877
+ rb_raise (EM_eUnsupported, "%s", e.what());
869
878
  }
870
879
  return Qnil;
871
880
  }
@@ -1065,7 +1074,7 @@ static VALUE t_start_proxy (VALUE self, VALUE from, VALUE to, VALUE bufsize, VAL
1065
1074
  try {
1066
1075
  evma_start_proxy(NUM2ULONG (from), NUM2ULONG (to), NUM2ULONG(bufsize), NUM2ULONG(length));
1067
1076
  } catch (std::runtime_error e) {
1068
- rb_raise (EM_eConnectionError, e.what());
1077
+ rb_raise (EM_eConnectionError, "%s", e.what());
1069
1078
  }
1070
1079
  return Qnil;
1071
1080
  }
@@ -1080,11 +1089,49 @@ static VALUE t_stop_proxy (VALUE self, VALUE from)
1080
1089
  try{
1081
1090
  evma_stop_proxy(NUM2ULONG (from));
1082
1091
  } catch (std::runtime_error e) {
1083
- rb_raise (EM_eConnectionError, e.what());
1092
+ rb_raise (EM_eConnectionError, "%s", e.what());
1084
1093
  }
1085
1094
  return Qnil;
1086
1095
  }
1087
1096
 
1097
+ /***************
1098
+ t_proxied_bytes
1099
+ ****************/
1100
+
1101
+ static VALUE t_proxied_bytes (VALUE self, VALUE from)
1102
+ {
1103
+ try{
1104
+ return ULONG2NUM(evma_proxied_bytes(NUM2ULONG (from)));
1105
+ } catch (std::runtime_error e) {
1106
+ rb_raise (EM_eConnectionError, "%s", e.what());
1107
+ }
1108
+ return Qnil;
1109
+ }
1110
+
1111
+ /***************
1112
+ t_get_idle_time
1113
+ ****************/
1114
+
1115
+ static VALUE t_get_idle_time (VALUE self, VALUE from)
1116
+ {
1117
+ try{
1118
+ uint64_t current_time = evma_get_current_loop_time();
1119
+ uint64_t time = evma_get_last_activity_time(NUM2ULONG (from));
1120
+ if (current_time != 0 && time != 0) {
1121
+ if (time >= current_time)
1122
+ return ULONG2NUM(0);
1123
+ else {
1124
+ uint64_t diff = current_time - time;
1125
+ float seconds = diff / (1000.0*1000.0);
1126
+ return rb_float_new(seconds);
1127
+ }
1128
+ return Qnil;
1129
+ }
1130
+ } catch (std::runtime_error e) {
1131
+ rb_raise (EM_eConnectionError, "%s", e.what());
1132
+ }
1133
+ return Qnil;
1134
+ }
1088
1135
 
1089
1136
  /************************
1090
1137
  t_get_heartbeat_interval
@@ -1180,9 +1227,11 @@ extern "C" void Init_rubyeventmachine()
1180
1227
  rb_define_module_function (EmModule, "pause_connection", (VALUE (*)(...))t_pause, 1);
1181
1228
  rb_define_module_function (EmModule, "resume_connection", (VALUE (*)(...))t_resume, 1);
1182
1229
  rb_define_module_function (EmModule, "connection_paused?", (VALUE (*)(...))t_paused_p, 1);
1230
+ rb_define_module_function (EmModule, "num_close_scheduled", (VALUE (*)(...))t_num_close_scheduled, 0);
1183
1231
 
1184
1232
  rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 4);
1185
1233
  rb_define_module_function (EmModule, "stop_proxy", (VALUE (*)(...))t_stop_proxy, 1);
1234
+ rb_define_module_function (EmModule, "get_proxied_bytes", (VALUE (*)(...))t_proxied_bytes, 1);
1186
1235
 
1187
1236
  rb_define_module_function (EmModule, "watch_filename", (VALUE (*)(...))t_watch_filename, 1);
1188
1237
  rb_define_module_function (EmModule, "unwatch_filename", (VALUE (*)(...))t_unwatch_filename, 1);
@@ -1206,6 +1255,7 @@ extern "C" void Init_rubyeventmachine()
1206
1255
  rb_define_module_function (EmModule, "send_file_data", (VALUE(*)(...))t_send_file_data, 2);
1207
1256
  rb_define_module_function (EmModule, "get_heartbeat_interval", (VALUE(*)(...))t_get_heartbeat_interval, 0);
1208
1257
  rb_define_module_function (EmModule, "set_heartbeat_interval", (VALUE(*)(...))t_set_heartbeat_interval, 1);
1258
+ rb_define_module_function (EmModule, "get_idle_time", (VALUE(*)(...))t_get_idle_time, 1);
1209
1259
 
1210
1260
  rb_define_module_function (EmModule, "get_peername", (VALUE(*)(...))t_get_peername, 1);
1211
1261
  rb_define_module_function (EmModule, "get_sockname", (VALUE(*)(...))t_get_sockname, 1);
@@ -137,7 +137,7 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
137
137
  bLibraryInitialized = true;
138
138
  SSL_library_init();
139
139
  OpenSSL_add_ssl_algorithms();
140
- OpenSSL_add_all_algorithms();
140
+ OpenSSL_add_all_algorithms();
141
141
  SSL_load_error_strings();
142
142
  ERR_load_crypto_strings();
143
143
 
@@ -151,6 +151,9 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
151
151
 
152
152
  SSL_CTX_set_options (pCtx, SSL_OP_ALL);
153
153
  //SSL_CTX_set_options (pCtx, (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3));
154
+ #ifdef SSL_MODE_RELEASE_BUFFERS
155
+ SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS);
156
+ #endif
154
157
 
155
158
  if (is_server) {
156
159
  // The SSL_CTX calls here do NOT allocate memory.
@@ -524,6 +524,10 @@ public class EmReactor {
524
524
  return Connections.get(sig).getPeerName();
525
525
  }
526
526
 
527
+ public Object[] getSockName (long sig) {
528
+ return Connections.get(sig).getSockName();
529
+ }
530
+
527
531
  public long attachChannel (SocketChannel sc, boolean watch_mode) {
528
532
  long b = createBinding();
529
533
 
@@ -60,6 +60,7 @@ public interface EventableChannel {
60
60
  public void setCommInactivityTimeout (long seconds);
61
61
 
62
62
  public Object[] getPeerName();
63
+ public Object[] getSockName();
63
64
 
64
65
  public boolean isWatchOnly();
65
66
 
@@ -183,6 +183,12 @@ public class EventableDatagramChannel implements EventableChannel {
183
183
  }
184
184
  }
185
185
 
186
+ public Object[] getSockName () {
187
+ DatagramSocket socket = channel.socket();
188
+ return new Object[]{ socket.getLocalPort(),
189
+ socket.getLocalAddress().getHostAddress() };
190
+ }
191
+
186
192
  public boolean isWatchOnly() { return false; }
187
193
  public boolean isNotifyReadable() { return false; }
188
194
  public boolean isNotifyWritable() { return false; }
@@ -302,6 +302,12 @@ public class EventableSocketChannel implements EventableChannel {
302
302
  return new Object[]{ sock.getPort(), sock.getInetAddress().getHostAddress() };
303
303
  }
304
304
 
305
+ public Object[] getSockName () {
306
+ Socket sock = channel.socket();
307
+ return new Object[]{ sock.getLocalPort(),
308
+ sock.getLocalAddress().getHostAddress() };
309
+ }
310
+
305
311
  public void setWatchOnly() {
306
312
  bWatchOnly = true;
307
313
  updateEvents();
@@ -238,6 +238,12 @@ module EventMachine
238
238
  EventMachine::disable_proxy(self)
239
239
  end
240
240
 
241
+ # The number of bytes proxied to another connection. Reset to zero when
242
+ # EventMachine::Connection#proxy_incoming_to is called, and incremented whenever data is proxied.
243
+ def get_proxied_bytes
244
+ EventMachine::get_proxied_bytes(@signature)
245
+ end
246
+
241
247
  # EventMachine::Connection#close_connection is called only by user code, and never
242
248
  # by the event loop. You may call this method against a connection object in any
243
249
  # callback handler, whether or not the callback was made against the connection
@@ -570,6 +576,11 @@ module EventMachine
570
576
  EventMachine::get_subprocess_status @signature
571
577
  end
572
578
 
579
+ # The number of seconds since the last send/receive activity on this connection.
580
+ def get_idle_time
581
+ EventMachine::get_idle_time @signature
582
+ end
583
+
573
584
  # comm_inactivity_timeout returns the current value (float in seconds) of the inactivity-timeout
574
585
  # property of network-connection and datagram-socket objects. A nonzero value
575
586
  # indicates that the connection or socket will automatically be closed if no read or write
@@ -122,7 +122,10 @@ module EventMachine
122
122
 
123
123
  def failure resource
124
124
  if @on_error
125
+ @contents.delete resource
125
126
  @on_error.call resource
127
+ # Prevent users from calling a leak.
128
+ @removed.delete resource
126
129
  else
127
130
  requeue resource
128
131
  end
@@ -140,7 +143,9 @@ module EventMachine
140
143
  else
141
144
  raise ArgumentError, "deferrable expected from work"
142
145
  end
146
+ rescue Exception
147
+ failure resource
148
+ raise
143
149
  end
144
-
145
150
  end
146
- end
151
+ end
@@ -31,38 +31,38 @@ module EventMachine
31
31
  # Simple SMTP client
32
32
  #
33
33
  # @example
34
- # email = EM::Protocols::SmtpClient.send(
35
- # :domain=>"example.com",
36
- # :host=>'localhost',
37
- # :port=>25, # optional, defaults 25
38
- # :starttls=>true, # use ssl
39
- # :from=>"sender@example.com",
40
- # :to=> ["to_1@example.com", "to_2@example.com"],
41
- # :header=> {"Subject" => "This is a subject line"},
42
- # :body=> "This is the body of the email"
43
- # )
44
- # email.callback{
45
- # puts 'Email sent!'
46
- # }
47
- # email.errback{ |e|
48
- # puts 'Email failed!'
49
- # }
34
+ # email = EM::Protocols::SmtpClient.send(
35
+ # :domain=>"example.com",
36
+ # :host=>'localhost',
37
+ # :port=>25, # optional, defaults 25
38
+ # :starttls=>true, # use ssl
39
+ # :from=>"sender@example.com",
40
+ # :to=> ["to_1@example.com", "to_2@example.com"],
41
+ # :header=> {"Subject" => "This is a subject line"},
42
+ # :body=> "This is the body of the email"
43
+ # )
44
+ # email.callback{
45
+ # puts 'Email sent!'
46
+ # }
47
+ # email.errback{ |e|
48
+ # puts 'Email failed!'
49
+ # }
50
50
  #
51
51
  # Sending generated emails (using mailfactory)
52
52
  #
53
- # mail = MailFactory.new
54
- # mail.to = 'someone@site.co'
55
- # mail.from = 'me@site.com'
56
- # mail.subject = 'hi!'
57
- # mail.text = 'hello world'
58
- # mail.html = '<h1>hello world</h1>'
53
+ # mail = MailFactory.new
54
+ # mail.to = 'someone@site.co'
55
+ # mail.from = 'me@site.com'
56
+ # mail.subject = 'hi!'
57
+ # mail.text = 'hello world'
58
+ # mail.html = '<h1>hello world</h1>'
59
59
  #
60
- # email = EM::P::SmtpClient.send(
61
- # :domain=>'site.com',
62
- # :from=>mail.from,
63
- # :to=>mail.to,
64
- # :content=>"#{mail.to_s}\r\n.\r\n"
65
- # )
60
+ # email = EM::P::SmtpClient.send(
61
+ # :domain=>'site.com',
62
+ # :from=>mail.from,
63
+ # :to=>mail.to,
64
+ # :content=>"#{mail.to_s}\r\n.\r\n"
65
+ # )
66
66
  #
67
67
  class SmtpClient < Connection
68
68
  include EventMachine::Deferrable
@@ -29,7 +29,7 @@ module EventMachine
29
29
  #
30
30
  # # If we don't care about the result:
31
31
  # pool.perform do |dispatcher|
32
- # # The following blcok executes inside a dedicated thread, and should not
32
+ # # The following block executes inside a dedicated thread, and should not
33
33
  # # access EventMachine things:
34
34
  # dispatcher.dispatch do |cassandra|
35
35
  # cassandra.insert(:Things, '10', 'stuff' => 'things')
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.0.beta.4"
2
+ VERSION = "1.0.0.rc.1"
3
3
  end
@@ -82,7 +82,8 @@ module EventMachine
82
82
  @reactor_running = false
83
83
  @next_tick_queue = []
84
84
  @tails = []
85
- @threadpool = nil
85
+ @threadpool = @threadqueue = @resultqueue = nil
86
+ @all_threads_spawned = false
86
87
 
87
88
  # System errnos
88
89
  # @private
@@ -155,7 +156,13 @@ module EventMachine
155
156
  # will start without release_machine being called and will immediately throw
156
157
 
157
158
  #
158
-
159
+ if reactor_running? and @reactor_pid != Process.pid
160
+ # Reactor was started in a different parent, meaning we have forked.
161
+ # Clean up reactor state so a new reactor boots up in this child.
162
+ stop_event_loop
163
+ release_machine
164
+ @reactor_running = false
165
+ end
159
166
 
160
167
  tail and @tails.unshift(tail)
161
168
 
@@ -169,6 +176,7 @@ module EventMachine
169
176
  @next_tick_queue ||= []
170
177
  @tails ||= []
171
178
  begin
179
+ @reactor_pid = Process.pid
172
180
  @reactor_running = true
173
181
  initialize_event_machine
174
182
  (b = blk || block) and add_timer(0, b)
@@ -201,6 +209,7 @@ module EventMachine
201
209
  @threadqueue = nil
202
210
  @resultqueue = nil
203
211
  @threadpool = nil
212
+ @all_threads_spawned = false
204
213
  end
205
214
 
206
215
  @next_tick_queue = []
@@ -252,7 +261,7 @@ module EventMachine
252
261
  if self.reactor_running?
253
262
  self.stop_event_loop
254
263
  self.release_machine
255
- self.instance_variable_set( '@reactor_running', false )
264
+ @reactor_running = false
256
265
  end
257
266
  self.run block
258
267
  end
@@ -425,7 +434,8 @@ module EventMachine
425
434
  # that you must define. When the network server that is started by
426
435
  # start_server accepts a new connection, it instantiates a new
427
436
  # object of an anonymous class that is inherited from {EventMachine::Connection},
428
- # *into which your handler module have been included*.
437
+ # *into which your handler module have been included*. Arguments passed into start_server
438
+ # after the class name are passed into the constructor during the instantiation.
429
439
  #
430
440
  # Your handler module may override any of the methods in {EventMachine::Connection},
431
441
  # such as {EventMachine::Connection#receive_data}, in order to implement the specific behavior
@@ -736,6 +746,7 @@ module EventMachine
736
746
  c = klass.new s, *args
737
747
 
738
748
  c.instance_variable_set(:@io, io)
749
+ c.instance_variable_set(:@watch_mode, watch_mode)
739
750
  c.instance_variable_set(:@fd, fd)
740
751
 
741
752
  @conns[s] = c
@@ -761,7 +772,11 @@ module EventMachine
761
772
  #raise "still connected" if @conns.has_key?(handler.signature)
762
773
  return handler if @conns.has_key?(handler.signature)
763
774
 
764
- s = connect_server server, port
775
+ s = if port
776
+ connect_server server, port
777
+ else
778
+ connect_unix_server server
779
+ end
765
780
  handler.signature = s
766
781
  @conns[s] = handler
767
782
  block_given? and yield handler
@@ -936,10 +951,21 @@ module EventMachine
936
951
  cback.call result if cback
937
952
  end
938
953
 
939
- @next_tick_mutex.synchronize do
940
- jobs, @next_tick_queue = @next_tick_queue, []
941
- jobs
942
- end.each { |j| j.call }
954
+ # Capture the size at the start of this tick...
955
+ size = @next_tick_mutex.synchronize { @next_tick_queue.size }
956
+ size.times do |i|
957
+ callback = @next_tick_mutex.synchronize { @next_tick_queue.shift }
958
+ begin
959
+ callback.call
960
+ ensure
961
+ # This is a little nasty. The problem is, if an exception occurs during
962
+ # the callback, then we need to send a signal to the reactor to actually
963
+ # do some work during the next_tick. The only mechanism we have from the
964
+ # ruby side is next_tick itself, although ideally, we'd just drop a byte
965
+ # on the loopback descriptor.
966
+ EM.next_tick {} if $!
967
+ end
968
+ end
943
969
  end
944
970
 
945
971
 
@@ -991,7 +1017,6 @@ module EventMachine
991
1017
  # has no constructor.
992
1018
 
993
1019
  unless @threadpool
994
- require 'thread'
995
1020
  @threadpool = []
996
1021
  @threadqueue = ::Queue.new
997
1022
  @resultqueue = ::Queue.new
@@ -1016,6 +1041,19 @@ module EventMachine
1016
1041
  end
1017
1042
  @threadpool << thread
1018
1043
  end
1044
+ @all_threads_spawned = true
1045
+ end
1046
+
1047
+ ##
1048
+ # Returns +true+ if all deferred actions are done executing and their
1049
+ # callbacks have been fired.
1050
+ #
1051
+ def self.defers_finished?
1052
+ return false if @threadpool and !@all_threads_spawned
1053
+ return false if @threadqueue and not @threadqueue.empty?
1054
+ return false if @resultqueue and not @resultqueue.empty?
1055
+ return false if @threadpool and @threadqueue.num_waiting != @threadpool.size
1056
+ return true
1019
1057
  end
1020
1058
 
1021
1059
  class << self
@@ -1391,11 +1429,19 @@ module EventMachine
1391
1429
  if opcode == ConnectionUnbound
1392
1430
  if c = @conns.delete( conn_binding )
1393
1431
  begin
1394
- if c.original_method(:unbind).arity == 1
1432
+ if c.original_method(:unbind).arity != 0
1395
1433
  c.unbind(data == 0 ? nil : EventMachine::ERRNOS[data])
1396
1434
  else
1397
1435
  c.unbind
1398
1436
  end
1437
+ # If this is an attached (but not watched) connection, close the underlying io object.
1438
+ if c.instance_variable_defined?(:@io) and !c.instance_variable_get(:@watch_mode)
1439
+ io = c.instance_variable_get(:@io)
1440
+ begin
1441
+ io.close
1442
+ rescue Errno::EBADF, IOError
1443
+ end
1444
+ end
1399
1445
  rescue
1400
1446
  @wrapped_exception = $!
1401
1447
  stop