eventmachine 1.0.0.beta.4-x86-mswin32-60 → 1.0.0.rc.1-x86-mswin32-60

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/Rakefile CHANGED
@@ -1,10 +1,6 @@
1
- require 'rubygems' unless defined?(Gem)
2
- require 'rake' unless defined?(Rake)
3
- import *Dir['tasks/*.rake']
1
+ require 'rubygems'
2
+ GEMSPEC = Gem::Specification.load('eventmachine.gemspec')
4
3
 
5
- GEMSPEC = eval(File.read(File.expand_path('../eventmachine.gemspec', __FILE__)))
6
-
7
- require 'yard'
8
4
  require 'rake/clean'
9
5
  task :clobber => :clean
10
6
 
@@ -12,8 +8,13 @@ desc "Build eventmachine, then run tests."
12
8
  task :default => [:compile, :test]
13
9
 
14
10
  desc 'Generate documentation'
15
- YARD::Rake::YardocTask.new do |t|
16
- t.files = ['lib/**/*.rb', '-', 'docs/*.md']
17
- t.options = ['--main', 'README.md', '--no-private']
18
- t.options = ['--exclude', 'lib/jeventmachine', '--exclude', 'lib/pr_eventmachine']
11
+ begin
12
+ require 'yard'
13
+ YARD::Rake::YardocTask.new do |t|
14
+ t.files = ['lib/**/*.rb', '-', 'docs/*.md']
15
+ t.options = ['--main', 'README.md', '--no-private']
16
+ t.options = ['--exclude', 'lib/jeventmachine', '--exclude', 'lib/pr_eventmachine']
17
+ end
18
+ rescue LoadError
19
+ task :yard do puts "Please install yard first!"; end
19
20
  end
data/eventmachine.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.add_development_dependency 'rake-compiler', '0.7.9'
17
17
  s.add_development_dependency 'yard', ">= 0.7.2"
18
- s.add_development_dependency 'bluecloth'
18
+ #s.add_development_dependency 'bluecloth'
19
19
 
20
20
  s.summary = 'Ruby/EventMachine library'
21
21
  s.description = "EventMachine implements a fast, single-threaded engine for arbitrary network
data/ext/cmain.cpp CHANGED
@@ -253,6 +253,15 @@ extern "C" int evma_is_paused (const unsigned long binding)
253
253
  return 0;
254
254
  }
255
255
 
256
+ /************************
257
+ evma_num_close_scheduled
258
+ ************************/
259
+
260
+ extern "C" int evma_num_close_scheduled ()
261
+ {
262
+ return EventMachine->NumCloseScheduled;
263
+ }
264
+
256
265
  /**********************
257
266
  evma_create_tcp_server
258
267
  **********************/
@@ -804,6 +813,35 @@ extern "C" void evma_stop_proxy (const unsigned long from)
804
813
  ed->StopProxy();
805
814
  }
806
815
 
816
+ /******************
817
+ evma_proxied_bytes
818
+ *******************/
819
+
820
+ extern "C" unsigned long evma_proxied_bytes (const unsigned long from)
821
+ {
822
+ ensure_eventmachine("evma_proxied_bytes");
823
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
824
+ if (ed)
825
+ return ed->GetProxiedBytes();
826
+ else
827
+ return 0;
828
+ }
829
+
830
+
831
+ /***************************
832
+ evma_get_last_activity_time
833
+ ****************************/
834
+
835
+ extern "C" uint64_t evma_get_last_activity_time(const unsigned long from)
836
+ {
837
+ ensure_eventmachine("evma_get_last_activity_time");
838
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
839
+ if (ed)
840
+ return ed->GetLastActivity();
841
+ else
842
+ return 0;
843
+ }
844
+
807
845
 
808
846
  /***************************
809
847
  evma_get_heartbeat_interval
data/ext/ed.cpp CHANGED
@@ -54,12 +54,14 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
54
54
  bCloseNow (false),
55
55
  bCloseAfterWriting (false),
56
56
  MySocket (sd),
57
+ bAttached (false),
57
58
  bWatchOnly (false),
58
59
  EventCallback (NULL),
59
60
  bCallbackUnbind (true),
60
61
  UnbindReasonCode (0),
61
62
  ProxyTarget(NULL),
62
63
  ProxiedFrom(NULL),
64
+ ProxiedBytes(0),
63
65
  MaxOutboundBufSize(0),
64
66
  MyEventMachine (em),
65
67
  PendingConnectTimeout(20000000),
@@ -115,6 +117,7 @@ EventableDescriptor::~EventableDescriptor()
115
117
  (*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
116
118
  ProxiedFrom->StopProxy();
117
119
  }
120
+ MyEventMachine->NumCloseScheduled--;
118
121
  StopProxy();
119
122
  Close();
120
123
  }
@@ -179,7 +182,7 @@ void EventableDescriptor::Close()
179
182
  MyEventMachine->Deregister (this);
180
183
 
181
184
  // Do not close STDIN, STDOUT, STDERR
182
- if (MySocket > 2 && !bWatchOnly) {
185
+ if (MySocket > 2 && !bAttached) {
183
186
  shutdown (MySocket, 1);
184
187
  close (MySocket);
185
188
  }
@@ -214,6 +217,7 @@ EventableDescriptor::ScheduleClose
214
217
 
215
218
  void EventableDescriptor::ScheduleClose (bool after_writing)
216
219
  {
220
+ MyEventMachine->NumCloseScheduled++;
217
221
  // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
218
222
  if (after_writing)
219
223
  bCloseAfterWriting = true;
@@ -244,6 +248,7 @@ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long
244
248
  StopProxy();
245
249
  ProxyTarget = ed;
246
250
  BytesToProxy = length;
251
+ ProxiedBytes = 0;
247
252
  ed->SetProxiedFrom(this, bufsize);
248
253
  return;
249
254
  }
@@ -290,6 +295,7 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
290
295
  if (BytesToProxy > 0) {
291
296
  unsigned long proxied = min(BytesToProxy, (unsigned long) size);
292
297
  ProxyTarget->SendOutboundData(buf, proxied);
298
+ ProxiedBytes += (unsigned long) proxied;
293
299
  BytesToProxy -= proxied;
294
300
  if (BytesToProxy == 0) {
295
301
  StopProxy();
@@ -300,6 +306,7 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
300
306
  }
301
307
  } else {
302
308
  ProxyTarget->SendOutboundData(buf, size);
309
+ ProxiedBytes += (unsigned long) size;
303
310
  }
304
311
  } else {
305
312
  (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
@@ -457,6 +464,16 @@ void ConnectionDescriptor::SetConnectPending(bool f)
457
464
  }
458
465
 
459
466
 
467
+ /**********************************
468
+ ConnectionDescriptor::SetAttached
469
+ ***********************************/
470
+
471
+ void ConnectionDescriptor::SetAttached(bool state)
472
+ {
473
+ bAttached = state;
474
+ }
475
+
476
+
460
477
  /**********************************
461
478
  ConnectionDescriptor::SetWatchOnly
462
479
  ***********************************/
data/ext/ed.h CHANGED
@@ -79,6 +79,7 @@ class EventableDescriptor: public Bindable_t
79
79
  virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
80
80
  uint64_t GetPendingConnectTimeout();
81
81
  int SetPendingConnectTimeout (uint64_t value);
82
+ uint64_t GetLastActivity() { return LastActivity; }
82
83
 
83
84
  #ifdef HAVE_EPOLL
84
85
  struct epoll_event *GetEpollEvent() { return &EpollEvent; }
@@ -86,6 +87,7 @@ class EventableDescriptor: public Bindable_t
86
87
 
87
88
  virtual void StartProxy(const unsigned long, const unsigned long, const unsigned long);
88
89
  virtual void StopProxy();
90
+ virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; };
89
91
  virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
90
92
  virtual int SendOutboundData(const char*,int){ return -1; }
91
93
  virtual bool IsPaused(){ return bPaused; }
@@ -103,6 +105,7 @@ class EventableDescriptor: public Bindable_t
103
105
 
104
106
  protected:
105
107
  int MySocket;
108
+ bool bAttached;
106
109
  bool bWatchOnly;
107
110
 
108
111
  EMCallback EventCallback;
@@ -115,6 +118,7 @@ class EventableDescriptor: public Bindable_t
115
118
  unsigned long BytesToProxy;
116
119
  EventableDescriptor *ProxyTarget;
117
120
  EventableDescriptor *ProxiedFrom;
121
+ unsigned long ProxiedBytes;
118
122
 
119
123
  unsigned long MaxOutboundBufSize;
120
124
 
@@ -169,6 +173,7 @@ class ConnectionDescriptor: public EventableDescriptor
169
173
 
170
174
  void SetNotifyReadable (bool);
171
175
  void SetNotifyWritable (bool);
176
+ void SetAttached (bool);
172
177
  void SetWatchOnly (bool);
173
178
 
174
179
  bool Pause();
data/ext/em.cpp CHANGED
@@ -73,6 +73,7 @@ EventMachine_t::EventMachine_t (EMCallback event_callback):
73
73
  NextHeartbeatTime (0),
74
74
  LoopBreakerReader (-1),
75
75
  LoopBreakerWriter (-1),
76
+ NumCloseScheduled (0),
76
77
  bTerminateSignalReceived (false),
77
78
  bEpoll (false),
78
79
  epfd (-1),
@@ -197,10 +198,9 @@ EventMachine_t::SetTimerQuantum
197
198
  void EventMachine_t::SetTimerQuantum (int interval)
198
199
  {
199
200
  /* We get a timer-quantum expressed in milliseconds.
200
- * Don't set a quantum smaller than 5 or larger than 2500.
201
201
  */
202
202
 
203
- if ((interval < 5) || (interval > 2500))
203
+ if ((interval < 5) || (interval > 5*60*1000))
204
204
  throw std::runtime_error ("invalid timer-quantum");
205
205
 
206
206
  Quantum.tv_sec = interval / 1000;
@@ -673,7 +673,13 @@ EventMachine_t::_TimeTilNextEvent
673
673
 
674
674
  timeval EventMachine_t::_TimeTilNextEvent()
675
675
  {
676
+ // 29jul11: Changed calculation base from MyCurrentLoopTime to the
677
+ // real time. As MyCurrentLoopTime is set at the beginning of an
678
+ // iteration and this calculation is done at the end, evenmachine
679
+ // will potentially oversleep by the amount of time the iteration
680
+ // took to execute.
676
681
  uint64_t next_event = 0;
682
+ uint64_t current_time = GetRealTime();
677
683
 
678
684
  if (!Heartbeats.empty()) {
679
685
  multimap<uint64_t,EventableDescriptor*>::iterator heartbeats = Heartbeats.begin();
@@ -687,16 +693,16 @@ timeval EventMachine_t::_TimeTilNextEvent()
687
693
  }
688
694
 
689
695
  if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
690
- next_event = MyCurrentLoopTime;
696
+ next_event = current_time;
691
697
  }
692
-
698
+
693
699
  timeval tv;
694
700
 
695
- if (next_event == 0) {
701
+ if (next_event == 0 || NumCloseScheduled > 0) {
696
702
  tv = Quantum;
697
703
  } else {
698
- if (next_event > MyCurrentLoopTime) {
699
- uint64_t duration = next_event - MyCurrentLoopTime;
704
+ if (next_event > current_time) {
705
+ uint64_t duration = next_event - current_time;
700
706
  tv.tv_sec = duration / 1000000;
701
707
  tv.tv_usec = duration % 1000000;
702
708
  } else {
@@ -1356,6 +1362,7 @@ const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
1356
1362
  if (!cd)
1357
1363
  throw std::runtime_error ("no connection allocated");
1358
1364
 
1365
+ cd->SetAttached(true);
1359
1366
  cd->SetWatchOnly(watch_mode);
1360
1367
  cd->SetConnectPending (false);
1361
1368
 
@@ -1395,7 +1402,11 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1395
1402
  if (bKqueue) {
1396
1403
  // remove any read/write events for this fd
1397
1404
  struct kevent k;
1405
+ #ifdef __NetBSD__
1406
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t)ed);
1407
+ #else
1398
1408
  EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, ed);
1409
+ #endif
1399
1410
  int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1400
1411
  if (t < 0 && (errno != ENOENT) && (errno != EBADF)) {
1401
1412
  char buf [200];
@@ -1651,7 +1662,11 @@ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
1651
1662
  if (!ed)
1652
1663
  throw std::runtime_error ("added bad descriptor");
1653
1664
  struct kevent k;
1665
+ #ifdef __NetBSD__
1666
+ EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, (intptr_t)ed);
1667
+ #else
1654
1668
  EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed);
1669
+ #endif
1655
1670
  int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1656
1671
  if (t < 0) {
1657
1672
  char buf [200];
@@ -1673,7 +1688,11 @@ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
1673
1688
  if (!ed)
1674
1689
  throw std::runtime_error ("added bad descriptor");
1675
1690
  struct kevent k;
1691
+ #ifdef __NetBSD__
1692
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
1693
+ #else
1676
1694
  EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1695
+ #endif
1677
1696
  int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1678
1697
  if (t < 0) {
1679
1698
  char buf [200];
@@ -1724,7 +1743,11 @@ void EventMachine_t::_AddNewDescriptors()
1724
1743
  // INCOMPLETE. Some descriptors don't want to be readable.
1725
1744
  assert (kqfd != -1);
1726
1745
  struct kevent k;
1746
+ #ifdef __NetBSD__
1747
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
1748
+ #else
1727
1749
  EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1750
+ #endif
1728
1751
  int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1729
1752
  assert (t == 0);
1730
1753
  }
data/ext/em.h CHANGED
@@ -44,10 +44,10 @@ See the file COPYING for complete licensing information.
44
44
  #define RUBY_UBF_IO RB_UBF_DFL
45
45
  #endif
46
46
  #ifndef RSTRING_PTR
47
- #define RSTRING_PTR(str) RString(str)->ptr
47
+ #define RSTRING_PTR(str) RSTRING(str)->ptr
48
48
  #endif
49
49
  #ifndef RSTRING_LEN
50
- #define RSTRING_LEN(str) RString(str)->len
50
+ #define RSTRING_LEN(str) RSTRING(str)->len
51
51
  #endif
52
52
  #ifndef RSTRING_LENINT
53
53
  #define RSTRING_LENINT(str) RSTRING_LEN(str)
@@ -161,6 +161,7 @@ class EventMachine_t
161
161
  public:
162
162
  void _ReadLoopBreaker();
163
163
  void _ReadInotifyEvents();
164
+ int NumCloseScheduled;
164
165
 
165
166
  private:
166
167
  enum {
data/ext/eventmachine.h CHANGED
@@ -59,6 +59,8 @@ extern "C" {
59
59
  int evma_is_paused(const unsigned long binding);
60
60
  int evma_resume(const unsigned long binding);
61
61
 
62
+ int evma_num_close_scheduled();
63
+
62
64
  void evma_stop_tcp_server (const unsigned long signature);
63
65
  const unsigned long evma_create_tcp_server (const char *address, int port);
64
66
  const unsigned long evma_create_unix_domain_server (const char *filename);
@@ -84,6 +86,7 @@ extern "C" {
84
86
  float evma_get_pending_connect_timeout (const unsigned long binding);
85
87
  int evma_set_pending_connect_timeout (const unsigned long binding, float value);
86
88
  int evma_get_outbound_data_size (const unsigned long binding);
89
+ uint64_t evma_get_last_activity_time (const unsigned long);
87
90
  int evma_send_file_data_to_connection (const unsigned long binding, const char *filename);
88
91
 
89
92
  void evma_close_connection (const unsigned long binding, int after_writing);
@@ -107,6 +110,7 @@ extern "C" {
107
110
 
108
111
  void evma_start_proxy(const unsigned long, const unsigned long, const unsigned long, const unsigned long);
109
112
  void evma_stop_proxy(const unsigned long);
113
+ unsigned long evma_proxied_bytes(const unsigned long);
110
114
 
111
115
  int evma_set_rlimit_nofile (int n_files);
112
116
 
data/ext/extconf.rb CHANGED
@@ -92,7 +92,7 @@ end
92
92
  case RUBY_PLATFORM
93
93
  when /mswin32/, /mingw32/, /bccwin32/
94
94
  check_heads(%w[windows.h winsock.h], true)
95
- check_libs(%w[kernel32 rpcrt4 gdi32], true)# unless ENV['CROSS_COMPILING']
95
+ check_libs(%w[kernel32 rpcrt4 gdi32], true)
96
96
 
97
97
  if GNU_CHAIN
98
98
  CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
@@ -139,6 +139,15 @@ when /linux/
139
139
  when /aix/
140
140
  CONFIG['LDSHARED'] = "$(CXX) -shared -Wl,-G -Wl,-brtl"
141
141
 
142
+ when /cygwin/
143
+ # For rubies built with Cygwin, CXX may be set to CC, which is just
144
+ # a wrapper for gcc.
145
+ # This will compile, but it will not link to the C++ std library.
146
+ # Explicitly set CXX to use g++.
147
+ CONFIG['CXX'] = "g++"
148
+ # on Unix we need a g++ link, not gcc.
149
+ CONFIG['LDSHARED'] = "$(CXX) -shared"
150
+
142
151
  else
143
152
  # on Unix we need a g++ link, not gcc.
144
153
  CONFIG['LDSHARED'] = "$(CXX) -shared"
@@ -154,4 +163,4 @@ add_define 'HAVE_MAKE_PAIR' if try_link(<<SRC, '-lstdc++')
154
163
  SRC
155
164
  TRY_LINK.sub!('$(CXX)', '$(CC)')
156
165
 
157
- create_makefile "rubyeventmachine"
166
+ create_makefile "rubyeventmachine"
@@ -77,9 +77,18 @@ when /aix/
77
77
  # on Unix we need a g++ link, not gcc.
78
78
  CONFIG['LDSHARED'] = "$(CXX) -shared -Wl,-G"
79
79
 
80
+ when /cygwin/
81
+ # For rubies built with Cygwin, CXX may be set to CC, which is just
82
+ # a wrapper for gcc.
83
+ # This will compile, but it will not link to the C++ std library.
84
+ # Explicitly set CXX to use g++.
85
+ CONFIG['CXX'] = "g++"
86
+ # on Unix we need a g++ link, not gcc.
87
+ CONFIG['LDSHARED'] = "$(CXX) -shared"
88
+
80
89
  else
81
90
  # on Unix we need a g++ link, not gcc.
82
91
  CONFIG['LDSHARED'] = "$(CXX) -shared"
83
92
  end
84
93
 
85
- create_makefile "fastfilereaderext"
94
+ create_makefile "fastfilereaderext"
data/ext/project.h CHANGED
@@ -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>
data/ext/rubymain.cpp CHANGED
@@ -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
  }
@@ -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);
data/ext/ssl.cpp CHANGED
@@ -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();
data/lib/em/connection.rb CHANGED
@@ -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
data/lib/em/pool.rb CHANGED
@@ -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')
data/lib/em/version.rb CHANGED
@@ -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
data/lib/eventmachine.rb CHANGED
@@ -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
data/lib/jeventmachine.rb CHANGED
@@ -203,6 +203,11 @@ module EventMachine
203
203
  Socket.pack_sockaddr_in(*peer)
204
204
  end
205
205
  end
206
+ def self.get_sockname sig
207
+ if sockName = @em.getSockName(sig)
208
+ Socket.pack_sockaddr_in(*sockName)
209
+ end
210
+ end
206
211
  # @private
207
212
  def self.attach_fd fileno, watch_mode
208
213
  # 3Aug09: We could pass in the actual SocketChannel, but then it would be modified (set as non-blocking), and
File without changes
File without changes
File without changes
data/tests/test_basic.rb CHANGED
@@ -224,4 +224,71 @@ class TestBasic < Test::Unit::TestCase
224
224
  end
225
225
  end
226
226
  end
227
+
228
+ def test_schedule_close
229
+ localhost, port = '127.0.0.1', 9000
230
+ timer_ran = false
231
+ num_close_scheduled = nil
232
+ EM.run do
233
+ assert_equal 0, EM.num_close_scheduled
234
+ EM.add_timer(1) { timer_ran = true; EM.stop }
235
+ EM.start_server localhost, port do |s|
236
+ s.close_connection
237
+ num_close_scheduled = EM.num_close_scheduled
238
+ end
239
+ EM.connect localhost, port do |c|
240
+ def c.unbind
241
+ EM.stop
242
+ end
243
+ end
244
+ end
245
+ assert !timer_ran
246
+ assert_equal 1, num_close_scheduled
247
+ end
248
+
249
+ def test_fork_safe
250
+ return unless cpid = fork { exit! } rescue false
251
+
252
+ read, write = IO.pipe
253
+ EM.run do
254
+ cpid = fork do
255
+ write.puts "forked"
256
+ EM.run do
257
+ EM.next_tick do
258
+ write.puts "EM ran"
259
+ exit!
260
+ end
261
+ end
262
+ end
263
+ EM.stop
264
+ end
265
+ Process.waitall
266
+ assert_equal "forked\n", read.readline
267
+ assert_equal "EM ran\n", read.readline
268
+ ensure
269
+ read.close rescue nil
270
+ write.close rescue nil
271
+ end
272
+
273
+ def test_error_handler_idempotent # issue 185
274
+ errors = []
275
+ ticks = []
276
+ EM.error_handler do |e|
277
+ errors << e
278
+ end
279
+
280
+ EM.run do
281
+ EM.next_tick do
282
+ ticks << :first
283
+ raise
284
+ end
285
+ EM.next_tick do
286
+ ticks << :second
287
+ end
288
+ EM.add_timer(0.001) { EM.stop }
289
+ end
290
+
291
+ assert_equal 1, errors.size
292
+ assert_equal [:first, :second], ticks
293
+ end
227
294
  end
@@ -0,0 +1,23 @@
1
+ require 'em_test_helper'
2
+
3
+ class TestIdleConnection < Test::Unit::TestCase
4
+ if EM.respond_to?(:get_idle_time)
5
+ def test_idle_time
6
+ EM.run{
7
+ conn = EM.connect 'www.google.com', 80
8
+ EM.add_timer(3){
9
+ $idle_time = conn.get_idle_time
10
+ conn.send_data "GET / HTTP/1.0\r\n\r\n"
11
+ EM.next_tick{
12
+ $idle_time_after_send = conn.get_idle_time
13
+ conn.close_connection
14
+ EM.stop
15
+ }
16
+ }
17
+ }
18
+
19
+ assert_in_delta 3, $idle_time, 0.2
20
+ assert_equal 0, $idle_time_after_send
21
+ end
22
+ end
23
+ end
data/tests/test_pool.rb CHANGED
@@ -115,6 +115,41 @@ class TestPool < Test::Unit::TestCase
115
115
  assert_equal [:res], pool.contents
116
116
  end
117
117
 
118
+ def test_contents_when_perform_errors_and_on_error_is_not_set
119
+ pool.add :res
120
+ assert_equal [:res], pool.contents
121
+
122
+ pool.perform do |r|
123
+ d = EM::DefaultDeferrable.new
124
+ d.fail
125
+ d
126
+ end
127
+
128
+ EM.run { EM.next_tick { EM.stop } }
129
+
130
+ assert_equal [:res], pool.contents
131
+ end
132
+
133
+ def test_contents_when_perform_errors_and_on_error_is_set
134
+ pool.add :res
135
+ res = nil
136
+ pool.on_error do |r|
137
+ res = r
138
+ end
139
+ assert_equal [:res], pool.contents
140
+
141
+ pool.perform do |r|
142
+ d = EM::DefaultDeferrable.new
143
+ d.fail 'foo'
144
+ d
145
+ end
146
+
147
+ EM.run { EM.next_tick { EM.stop } }
148
+
149
+ assert_equal :res, res
150
+ assert_equal [], pool.contents
151
+ end
152
+
118
153
  def test_num_waiting
119
154
  pool.add :res
120
155
  assert_equal 0, pool.num_waiting
@@ -125,4 +160,35 @@ class TestPool < Test::Unit::TestCase
125
160
  assert_equal 10, pool.num_waiting
126
161
  end
127
162
 
128
- end
163
+ def test_exceptions_in_the_work_block_bubble_up_raise_and_fail_the_resource
164
+ pool.add :res
165
+
166
+ res = nil
167
+ pool.on_error { |r| res = r }
168
+ pool.perform { raise 'boom' }
169
+
170
+ assert_raises(RuntimeError) do
171
+ EM.run { EM.next_tick { EM.stop } }
172
+ end
173
+
174
+ assert_equal [], pool.contents
175
+ assert_equal :res, res
176
+ end
177
+
178
+ def test_removed_list_does_not_leak_on_errors
179
+ pool.add :res
180
+
181
+ pool.on_error do |r|
182
+ # This is actually the wrong thing to do, and not required, but some users
183
+ # might do it. When they do, they would find that @removed would cause a
184
+ # slow leak.
185
+ pool.remove r
186
+ end
187
+
188
+ pool.perform { d = EM::DefaultDeferrable.new; d.fail; d }
189
+
190
+ EM.run { EM.next_tick { EM.stop } }
191
+ assert_equal [], pool.instance_variable_get(:@removed)
192
+ end
193
+
194
+ end
@@ -24,6 +24,7 @@ class TestProxyConnection < Test::Unit::TestCase
24
24
  end
25
25
 
26
26
  def unbind
27
+ $proxied_bytes = self.get_proxied_bytes
27
28
  @client.close_connection_after_writing
28
29
  end
29
30
  end
@@ -94,7 +95,7 @@ class TestProxyConnection < Test::Unit::TestCase
94
95
  end
95
96
 
96
97
  def receive_data(data)
97
- EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
98
+ @proxy = EM.connect("127.0.0.1", @port, ProxyConnection, self, data)
98
99
  end
99
100
  end
100
101
 
@@ -134,6 +135,17 @@ class TestProxyConnection < Test::Unit::TestCase
134
135
  assert_equal("I know!", $client_data)
135
136
  end
136
137
 
138
+ def test_proxied_bytes
139
+ EM.run {
140
+ EM.start_server("127.0.0.1", @port, Server)
141
+ EM.start_server("127.0.0.1", @proxy_port, ProxyServer, @port)
142
+ EM.connect("127.0.0.1", @proxy_port, Client)
143
+ }
144
+
145
+ assert_equal("I know!", $client_data)
146
+ assert_equal("I know!".bytesize, $proxied_bytes)
147
+ end
148
+
137
149
  def test_partial_proxy_connection
138
150
  EM.run {
139
151
  EM.start_server("127.0.0.1", @port, Server)
@@ -2,6 +2,15 @@ require 'em_test_helper'
2
2
  require 'socket'
3
3
 
4
4
  class TestUnbindReason < Test::Unit::TestCase
5
+
6
+ class StubConnection < EM::Connection
7
+ attr_reader :error
8
+ def unbind(reason = nil)
9
+ @error = reason
10
+ EM.stop
11
+ end
12
+ end
13
+
5
14
  def test_connect_timeout
6
15
  error = nil
7
16
  EM.run {
@@ -13,7 +22,7 @@ class TestUnbindReason < Test::Unit::TestCase
13
22
  }
14
23
  conn.pending_connect_timeout = 0.1
15
24
  }
16
- assert_equal error, Errno::ETIMEDOUT
25
+ assert_equal Errno::ETIMEDOUT, error
17
26
  end
18
27
 
19
28
  def test_connect_refused
@@ -26,6 +35,14 @@ class TestUnbindReason < Test::Unit::TestCase
26
35
  end
27
36
  }
28
37
  }
29
- assert_equal error, Errno::ECONNREFUSED
38
+ assert_equal Errno::ECONNREFUSED, error
39
+ end
40
+
41
+ def test_optional_argument
42
+ conn = nil
43
+ EM.run {
44
+ conn = EM.connect '127.0.0.1', 12388, StubConnection
45
+ }
46
+ assert_equal Errno::ECONNREFUSED, conn.error
30
47
  end
31
48
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventmachine
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196363
4
+ hash: 379161805
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
- - beta
11
- - 4
12
- version: 1.0.0.beta.4
10
+ - rc
11
+ - 1
12
+ version: 1.0.0.rc.1
13
13
  platform: x86-mswin32-60
14
14
  authors:
15
15
  - Francis Cianfrocca
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-09-15 00:00:00 -07:00
21
+ date: 2012-06-18 00:00:00 -07:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -53,20 +53,6 @@ dependencies:
53
53
  version: 0.7.2
54
54
  type: :development
55
55
  version_requirements: *id002
56
- - !ruby/object:Gem::Dependency
57
- name: bluecloth
58
- prerelease: false
59
- requirement: &id003 !ruby/object:Gem::Requirement
60
- none: false
61
- requirements:
62
- - - ">="
63
- - !ruby/object:Gem::Version
64
- hash: 3
65
- segments:
66
- - 0
67
- version: "0"
68
- type: :development
69
- version_requirements: *id003
70
56
  description: |-
71
57
  EventMachine implements a fast, single-threaded engine for arbitrary network
72
58
  communications. It's extremely easy to use in Ruby. EventMachine wraps all
@@ -206,9 +192,9 @@ files:
206
192
  - lib/em/version.rb
207
193
  - lib/eventmachine.rb
208
194
  - lib/jeventmachine.rb
209
- - tasks/cpp.rake_example
210
- - tasks/package.rake
211
- - tasks/test.rake
195
+ - rakelib/cpp.rake_example
196
+ - rakelib/package.rake
197
+ - rakelib/test.rake
212
198
  - tests/client.crt
213
199
  - tests/client.key
214
200
  - tests/em_test_helper.rb
@@ -229,6 +215,7 @@ files:
229
215
  - tests/test_hc.rb
230
216
  - tests/test_httpclient.rb
231
217
  - tests/test_httpclient2.rb
218
+ - tests/test_idle_connection.rb
232
219
  - tests/test_inactivity_timeout.rb
233
220
  - tests/test_kb.rb
234
221
  - tests/test_ltp.rb