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

Sign up to get free protection for your applications and to get access to all the features.
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