eventmachine 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,9 @@
1
- script: rake compile test
1
+ script: bundle exec rake compile test
2
+ env:
3
+ global:
4
+ - TESTOPTS=-v
2
5
  language: ruby
6
+ sudo: false
3
7
  rvm:
4
8
  - 1.8.7
5
9
  - 1.9.3
@@ -8,3 +12,10 @@ rvm:
8
12
  - 2.2
9
13
  - rbx
10
14
  - jruby
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: rbx
18
+ - rvm: jruby
19
+ include:
20
+ - rvm: 2.0.0
21
+ os: osx
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.5 (February 2, 2015)
4
+ * use monotonic clocks on Linux, OS X, Solaris, and Windows [#563]
5
+ * use the rb_fd_* API to get autosized fd_sets [#502]
6
+ * add basic tests that the DNS resolver isn't leaking timers [#571]
7
+ * update to test-unit 2.x and improve various unit tests [#551]
8
+ * remove EventMachine_t::Popen code marked by ifdef OBSOLETE [#551]
9
+ * ruby 2.0 may fail at Queue.pop, so rescue and complain to $stderr [#551]
10
+ * set file handle to INVALID_HANDLE_VALUE after closing the file [#565]
11
+ * use `defined?` instead of rescuing NameError for flow control [#535]
12
+ * fix closing files and sockets on Windows [#564]
13
+ * fix file uploads in Windows [#562]
14
+ * catch failure to fork [#539]
15
+ * use chunks for SSL write [#545]
16
+
3
17
  ## 1.0.4 (December 19, 2014)
4
18
  * add starttls_options to smtp server [#552]
5
19
  * fix closesocket on windows [#497]
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
18
18
 
19
+ s.add_development_dependency 'test-unit', '~> 2.0'
19
20
  s.add_development_dependency 'rake-compiler', '~> 0.8.3'
20
21
  s.add_development_dependency 'yard', ">= 0.8.5.2"
21
22
  s.add_development_dependency 'bluecloth' unless RUBY_PLATFORM =~ /java/
@@ -762,8 +762,11 @@ extern "C" int evma_send_file_data_to_connection (const unsigned long binding, c
762
762
 
763
763
  ensure_eventmachine("evma_send_file_data_to_connection");
764
764
 
765
+ #if defined(OS_WIN32)
766
+ int Fd = open (filename, O_RDONLY|O_BINARY);
767
+ #else
765
768
  int Fd = open (filename, O_RDONLY);
766
-
769
+ #endif
767
770
  if (Fd < 0)
768
771
  return errno;
769
772
  // From here on, all early returns MUST close Fd.
@@ -785,7 +788,6 @@ extern "C" int evma_send_file_data_to_connection (const unsigned long binding, c
785
788
  return -1;
786
789
  }
787
790
 
788
-
789
791
  r = read (Fd, data, filesize);
790
792
  if (r != filesize) {
791
793
  int e = errno;
data/ext/ed.cpp CHANGED
@@ -566,11 +566,25 @@ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
566
566
  #ifdef WITH_SSL
567
567
  if (SslBox) {
568
568
  if (length > 0) {
569
- int w = SslBox->PutPlaintext (data, length);
570
- if (w < 0)
571
- ScheduleClose (false);
572
- else
573
- _DispatchCiphertext();
569
+ int writed = 0;
570
+ char *p = (char*)data;
571
+
572
+ while (writed < length) {
573
+ int to_write = SSLBOX_INPUT_CHUNKSIZE;
574
+ int remaining = length - writed;
575
+
576
+ if (remaining < SSLBOX_INPUT_CHUNKSIZE)
577
+ to_write = remaining;
578
+
579
+ int w = SslBox->PutPlaintext (p, to_write);
580
+ if (w < 0) {
581
+ ScheduleClose (false);
582
+ }else
583
+ _DispatchCiphertext();
584
+
585
+ p += to_write;
586
+ writed += to_write;
587
+ }
574
588
  }
575
589
  // TODO: What's the correct return value?
576
590
  return 1; // That's a wild guess, almost certainly wrong.
@@ -602,7 +616,6 @@ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
602
616
 
603
617
  if (IsCloseScheduled())
604
618
  return 0;
605
-
606
619
  // 25Mar10: Ignore 0 length packets as they are not meaningful in TCP (as opposed to UDP)
607
620
  // and can cause the assert(nbytes>0) to fail when OutboundPages has a bunch of 0 length pages.
608
621
  if (length == 0)
@@ -1226,7 +1239,7 @@ void ConnectionDescriptor::_DispatchCiphertext()
1226
1239
  assert (SslBox);
1227
1240
 
1228
1241
 
1229
- char BigBuf [2048];
1242
+ char BigBuf [SSLBOX_OUTPUT_CHUNKSIZE];
1230
1243
  bool did_work;
1231
1244
 
1232
1245
  do {
data/ext/em.cpp CHANGED
@@ -85,6 +85,11 @@ EventMachine_t::EventMachine_t (EMCallback event_callback):
85
85
  Quantum.tv_sec = 0;
86
86
  Quantum.tv_usec = 90000;
87
87
 
88
+ /* Initialize monotonic timekeeping on OS X before the first call to GetRealTime */
89
+ #ifdef OS_DARWIN
90
+ (void) mach_timebase_info(&mach_timebase);
91
+ #endif
92
+
88
93
  // Make sure the current loop time is sane, in case we do any initializations of
89
94
  // objects before we start running.
90
95
  _UpdateTime();
@@ -352,16 +357,49 @@ void EventMachine_t::_UpdateTime()
352
357
  EventMachine_t::GetRealTime
353
358
  ***************************/
354
359
 
360
+ // Two great writeups of cross-platform monotonic time are at:
361
+ // http://www.python.org/dev/peps/pep-0418
362
+ // http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking
363
+ // Uncomment the #pragma messages to confirm which compile-time option was used
355
364
  uint64_t EventMachine_t::GetRealTime()
356
365
  {
357
366
  uint64_t current_time;
358
367
 
359
- #if defined(OS_UNIX)
368
+ #if defined(HAVE_CONST_CLOCK_MONOTONIC_RAW)
369
+ // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC_RAW"
370
+ // Linux 2.6.28 and above
371
+ struct timespec tv;
372
+ clock_gettime (CLOCK_MONOTONIC_RAW, &tv);
373
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
374
+
375
+ #elif defined(HAVE_CONST_CLOCK_MONOTONIC)
376
+ // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC"
377
+ // Linux, FreeBSD 5.0 and above, Solaris 8 and above, OpenBSD, NetBSD, DragonflyBSD
378
+ struct timespec tv;
379
+ clock_gettime (CLOCK_MONOTONIC, &tv);
380
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
381
+
382
+ #elif defined(HAVE_GETHRTIME)
383
+ // #pragma message "GetRealTime: gethrtime"
384
+ // Solaris and HP-UX
385
+ current_time = (uint64_t)gethrtime() / 1000;
386
+
387
+ #elif defined(OS_DARWIN)
388
+ // #pragma message "GetRealTime: mach_absolute_time"
389
+ // Mac OS X
390
+ // https://developer.apple.com/library/mac/qa/qa1398/_index.html
391
+ current_time = mach_absolute_time() * mach_timebase.numer / mach_timebase.denom / 1000;
392
+
393
+ #elif defined(OS_UNIX)
394
+ // #pragma message "GetRealTime: gettimeofday"
395
+ // Unix fallback
360
396
  struct timeval tv;
361
397
  gettimeofday (&tv, NULL);
362
398
  current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
363
399
 
364
400
  #elif defined(OS_WIN32)
401
+ // #pragma message "GetRealTime: GetTickCount"
402
+ // Future improvement: use GetTickCount64 in Windows Vista / Server 2008
365
403
  unsigned tick = GetTickCount();
366
404
  if (tick < LastTickCount)
367
405
  TickCountTickover += 1;
@@ -370,6 +408,8 @@ uint64_t EventMachine_t::GetRealTime()
370
408
  current_time *= 1000; // convert to microseconds
371
409
 
372
410
  #else
411
+ // #pragma message "GetRealTime: time"
412
+ // Universal fallback
373
413
  current_time = (uint64_t)time(NULL) * 1000000LL;
374
414
  #endif
375
415
 
@@ -536,12 +576,12 @@ void EventMachine_t::_RunEpollOnce()
536
576
  #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
537
577
  if ((ret = rb_wait_for_single_fd(epfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) {
538
578
  #else
539
- fd_set fdreads;
579
+ rb_fdset_t fdreads;
540
580
 
541
- FD_ZERO(&fdreads);
542
- FD_SET(epfd, &fdreads);
581
+ rb_fd_init(&fdreads);
582
+ rb_fd_set(epfd, &fdreads);
543
583
 
544
- if ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
584
+ if ((ret = rb_thread_fd_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
545
585
  #endif
546
586
  if (ret == -1) {
547
587
  assert(errno != EINVAL);
@@ -613,12 +653,12 @@ void EventMachine_t::_RunKqueueOnce()
613
653
  #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
614
654
  if ((ret = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) {
615
655
  #else
616
- fd_set fdreads;
656
+ rb_fdset_t fdreads;
617
657
 
618
- FD_ZERO(&fdreads);
619
- FD_SET(kqfd, &fdreads);
658
+ rb_fd_init(&fdreads);
659
+ rb_fd_set(kqfd, &fdreads);
620
660
 
621
- if ((ret = rb_thread_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
661
+ if ((ret = rb_thread_fd_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
622
662
  #endif
623
663
  if (ret == -1) {
624
664
  assert(errno != EINVAL);
@@ -806,9 +846,9 @@ SelectData_t::SelectData_t
806
846
  SelectData_t::SelectData_t()
807
847
  {
808
848
  maxsocket = 0;
809
- FD_ZERO (&fdreads);
810
- FD_ZERO (&fdwrites);
811
- FD_ZERO (&fderrors);
849
+ rb_fd_init (&fdreads);
850
+ rb_fd_init (&fdwrites);
851
+ rb_fd_init (&fderrors);
812
852
  }
813
853
 
814
854
 
@@ -821,7 +861,7 @@ _SelectDataSelect
821
861
  static VALUE _SelectDataSelect (void *v)
822
862
  {
823
863
  SelectData_t *sd = (SelectData_t*)v;
824
- sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
864
+ sd->nSockets = rb_fd_select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
825
865
  return Qnil;
826
866
  }
827
867
  #endif
@@ -863,9 +903,9 @@ void EventMachine_t::_RunSelectOnce()
863
903
 
864
904
  SelectData_t SelectData;
865
905
  /*
866
- fd_set fdreads, fdwrites;
867
- FD_ZERO (&fdreads);
868
- FD_ZERO (&fdwrites);
906
+ rb_fdset_t fdreads, fdwrites;
907
+ rb_fd_init (&fdreads);
908
+ rb_fd_init (&fdwrites);
869
909
 
870
910
  int maxsocket = 0;
871
911
  */
@@ -875,7 +915,7 @@ void EventMachine_t::_RunSelectOnce()
875
915
  // running on localhost with a randomly-chosen port. (*Puke*)
876
916
  // Windows has a version of the Unix pipe() library function, but it doesn't
877
917
  // give you back descriptors that are selectable.
878
- FD_SET (LoopBreakerReader, &(SelectData.fdreads));
918
+ rb_fd_set (LoopBreakerReader, &(SelectData.fdreads));
879
919
  if (SelectData.maxsocket < LoopBreakerReader)
880
920
  SelectData.maxsocket = LoopBreakerReader;
881
921
 
@@ -890,15 +930,15 @@ void EventMachine_t::_RunSelectOnce()
890
930
  assert (sd != INVALID_SOCKET);
891
931
 
892
932
  if (ed->SelectForRead())
893
- FD_SET (sd, &(SelectData.fdreads));
933
+ rb_fd_set (sd, &(SelectData.fdreads));
894
934
  if (ed->SelectForWrite())
895
- FD_SET (sd, &(SelectData.fdwrites));
935
+ rb_fd_set (sd, &(SelectData.fdwrites));
896
936
 
897
937
  #ifdef OS_WIN32
898
938
  /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable.
899
939
  Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html
900
940
  */
901
- FD_SET (sd, &(SelectData.fderrors));
941
+ rb_fd_set (sd, &(SelectData.fderrors));
902
942
  #endif
903
943
 
904
944
  if (SelectData.maxsocket < sd)
@@ -933,15 +973,15 @@ void EventMachine_t::_RunSelectOnce()
933
973
  continue;
934
974
  assert (sd != INVALID_SOCKET);
935
975
 
936
- if (FD_ISSET (sd, &(SelectData.fdwrites)))
976
+ if (rb_fd_isset (sd, &(SelectData.fdwrites)))
937
977
  ed->Write();
938
- if (FD_ISSET (sd, &(SelectData.fdreads)))
978
+ if (rb_fd_isset (sd, &(SelectData.fdreads)))
939
979
  ed->Read();
940
- if (FD_ISSET (sd, &(SelectData.fderrors)))
980
+ if (rb_fd_isset (sd, &(SelectData.fderrors)))
941
981
  ed->HandleError();
942
982
  }
943
983
 
944
- if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads)))
984
+ if (rb_fd_isset (LoopBreakerReader, &(SelectData.fdreads)))
945
985
  _ReadLoopBreaker();
946
986
  }
947
987
  else if (s < 0) {
@@ -979,11 +1019,11 @@ void EventMachine_t::_CleanBadDescriptors()
979
1019
  tv.tv_sec = 0;
980
1020
  tv.tv_usec = 0;
981
1021
 
982
- fd_set fds;
983
- FD_ZERO(&fds);
984
- FD_SET(sd, &fds);
1022
+ rb_fdset_t fds;
1023
+ rb_fd_init(&fds);
1024
+ rb_fd_set(sd, &fds);
985
1025
 
986
- int ret = select(sd + 1, &fds, NULL, NULL, &tv);
1026
+ int ret = rb_fd_select(sd + 1, &fds, NULL, NULL, &tv);
987
1027
 
988
1028
  if (ret == -1) {
989
1029
  if (errno == EBADF)
@@ -1923,47 +1963,6 @@ const unsigned long EventMachine_t::AttachSD (int sd_accept)
1923
1963
  }
1924
1964
 
1925
1965
 
1926
- /*********************
1927
- EventMachine_t::Popen
1928
- *********************/
1929
- #if OBSOLETE
1930
- const char *EventMachine_t::Popen (const char *cmd, const char *mode)
1931
- {
1932
- #ifdef OS_WIN32
1933
- throw std::runtime_error ("popen is currently unavailable on this platform");
1934
- #endif
1935
-
1936
- // The whole rest of this function is only compiled on Unix systems.
1937
- // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1938
- #ifdef OS_UNIX
1939
- const char *output_binding = NULL;
1940
-
1941
- FILE *fp = popen (cmd, mode);
1942
- if (!fp)
1943
- return NULL;
1944
-
1945
- // From here, all early returns must pclose the stream.
1946
-
1947
- // According to the pipe(2) manpage, descriptors returned from pipe have both
1948
- // CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.
1949
- if (!SetSocketNonblocking (fileno (fp))) {
1950
- pclose (fp);
1951
- return NULL;
1952
- }
1953
-
1954
- { // Looking good.
1955
- PipeDescriptor *pd = new PipeDescriptor (fp, this);
1956
- if (!pd)
1957
- throw std::runtime_error ("unable to allocate pipe");
1958
- Add (pd);
1959
- output_binding = pd->GetBinding();
1960
- }
1961
-
1962
- return output_binding;
1963
- #endif
1964
- }
1965
- #endif // OBSOLETE
1966
-
1967
1966
  /**************************
1968
1967
  EventMachine_t::Socketpair
1969
1968
  **************************/
data/ext/em.h CHANGED
@@ -22,12 +22,7 @@ See the file COPYING for complete licensing information.
22
22
 
23
23
  #ifdef BUILD_FOR_RUBY
24
24
  #include <ruby.h>
25
-
26
- #ifdef HAVE_RB_THREAD_FD_SELECT
27
- #define EmSelect rb_thread_fd_select
28
- #else
29
- #define EmSelect rb_thread_select
30
- #endif
25
+ #define EmSelect rb_thread_fd_select
31
26
 
32
27
  #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
33
28
  #include <ruby/thread.h>
@@ -66,7 +61,31 @@ See the file COPYING for complete licensing information.
66
61
  #define RSTRING_LENINT(str) RSTRING_LEN(str)
67
62
  #endif
68
63
  #else
69
- #define EmSelect select
64
+ #define EmSelect rb_fd_select
65
+ #endif
66
+
67
+ #ifndef rb_fd_max
68
+ #define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n)))
69
+ // These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3,
70
+ // with this change: any macros that read or write the nth element of an
71
+ // fdset first call fd_check to make sure n is in bounds.
72
+ typedef fd_set rb_fdset_t;
73
+ #define rb_fd_zero(f) FD_ZERO(f)
74
+ #define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0)
75
+ #define rb_fd_clr(n, f) do { if (fd_check(n)) FD_CLR((n), (f)); } while(0)
76
+ #define rb_fd_isset(n, f) (fd_check(n) ? FD_ISSET((n), (f)) : 0)
77
+ #define rb_fd_copy(d, s, n) (*(d) = *(s))
78
+ #define rb_fd_dup(d, s) (*(d) = *(s))
79
+ #define rb_fd_resize(n, f) ((void)(f))
80
+ #define rb_fd_ptr(f) (f)
81
+ #define rb_fd_init(f) FD_ZERO(f)
82
+ #define rb_fd_init_copy(d, s) (*(d) = *(s))
83
+ #define rb_fd_term(f) ((void)(f))
84
+ #define rb_fd_max(f) FD_SETSIZE
85
+ #define rb_fd_select(n, rfds, wfds, efds, timeout) \
86
+ select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
87
+ #define rb_thread_fd_select(n, rfds, wfds, efds, timeout) \
88
+ rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout))
70
89
  #endif
71
90
 
72
91
  class EventableDescriptor;
@@ -213,6 +232,10 @@ class EventMachine_t
213
232
  unsigned LastTickCount;
214
233
  #endif
215
234
 
235
+ #ifdef OS_DARWIN
236
+ mach_timebase_info_data_t mach_timebase;
237
+ #endif
238
+
216
239
  private:
217
240
  bool bTerminateSignalReceived;
218
241
 
@@ -243,9 +266,9 @@ struct SelectData_t
243
266
  int _Select();
244
267
 
245
268
  int maxsocket;
246
- fd_set fdreads;
247
- fd_set fdwrites;
248
- fd_set fderrors;
269
+ rb_fdset_t fdreads;
270
+ rb_fdset_t fdwrites;
271
+ rb_fdset_t fderrors;
249
272
  timeval tv;
250
273
  int nSockets;
251
274
  };
@@ -42,7 +42,7 @@ end
42
42
  if ENV['CROSS_COMPILING']
43
43
  openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.1i")
44
44
  openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/")
45
- if File.exists?(openssl_dir)
45
+ if File.exist?(openssl_dir)
46
46
  FileUtils.mkdir_p Dir.pwd+"/openssl/"
47
47
  FileUtils.cp Dir[openssl_dir+"/include/openssl/*.h"], Dir.pwd+"/openssl/", :verbose => true
48
48
  FileUtils.cp Dir[openssl_dir+"/lib*.a"], Dir.pwd, :verbose => true
@@ -139,6 +139,8 @@ when /openbsd/
139
139
  CONFIG['LDSHAREDXX'] = "$(CXX) -shared -lstdc++ -fPIC"
140
140
 
141
141
  when /darwin/
142
+ add_define 'OS_DARWIN'
143
+
142
144
  # on Unix we need a g++ link, not gcc.
143
145
  # Ff line contributed by Daniel Harple.
144
146
  CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
@@ -166,6 +168,14 @@ else
166
168
  CONFIG['LDSHARED'] = "$(CXX) -shared"
167
169
  end
168
170
 
171
+ # Platform-specific time functions
172
+ if have_func('clock_gettime')
173
+ # clock_gettime is POSIX, but the monotonic clocks are not
174
+ have_const('CLOCK_MONOTONIC_RAW', 'time.h') # Linux
175
+ have_const('CLOCK_MONOTONIC', 'time.h') # Linux, Solaris, BSDs
176
+ else
177
+ have_func('gethrtime') # Older Solaris and HP-UX
178
+ end
169
179
 
170
180
  # solaris c++ compiler doesn't have make_pair()
171
181
  TRY_LINK.sub!('$(CC)', '$(CXX)')
@@ -195,7 +195,7 @@ void Mapper_t::Close()
195
195
  }
196
196
  if (hFile != INVALID_HANDLE_VALUE) {
197
197
  CloseHandle (hFile);
198
- hMapping = INVALID_HANDLE_VALUE;
198
+ hFile = INVALID_HANDLE_VALUE;
199
199
  }
200
200
  }
201
201
 
@@ -78,6 +78,11 @@ typedef int SOCKET;
78
78
  #endif
79
79
  #endif /* _AIX */
80
80
 
81
+ #ifdef OS_DARWIN
82
+ #include <mach/mach.h>
83
+ #include <mach/mach_time.h>
84
+ #endif /* OS_DARWIN */
85
+
81
86
  #endif /* OS_UNIX */
82
87
 
83
88
  #ifdef OS_WIN32
@@ -85,7 +90,9 @@ typedef int SOCKET;
85
90
  // 18Jun12: fd_setsize must be changed in the ruby binary (not in this extension). redefining it also causes segvs, see eventmachine/eventmachine#333
86
91
  //#define FD_SETSIZE 1024
87
92
 
93
+ // WIN32_LEAN_AND_MEAN excludes APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets.
88
94
  #define WIN32_LEAN_AND_MEAN
95
+
89
96
  #include <windows.h>
90
97
  #include <winsock2.h>
91
98
  #include <ws2tcpip.h>
@@ -93,13 +100,10 @@ typedef int SOCKET;
93
100
  #include <fcntl.h>
94
101
  #include <assert.h>
95
102
 
96
- #define close closesocket
97
-
98
- typedef int socklen_t;
99
- #ifndef _PID_T_
100
- #define _PID_T_
101
- typedef int pid_t;
102
- #endif /* _PID_T_ */
103
+ // Use the Win32 wrapper library that Ruby owns to be able to close sockets with the close() function
104
+ #define RUBY_EXPORT
105
+ #include <ruby/defines.h>
106
+ #include <ruby/win32.h>
103
107
  #endif /* OS_WIN32 */
104
108
 
105
109
  #if !defined(_MSC_VER) || _MSC_VER > 1500
@@ -833,7 +833,12 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
833
833
  }
834
834
  strings[len] = NULL;
835
835
 
836
- const unsigned long f = evma_popen (strings);
836
+ unsigned long f = 0;
837
+ try {
838
+ f = evma_popen (strings);
839
+ } catch (std::runtime_error e) {
840
+ f = 0; // raise exception below
841
+ }
837
842
  if (!f) {
838
843
  char *err = strerror (errno);
839
844
  char buf[100];
@@ -392,13 +392,16 @@ int SslBox_t::PutPlaintext (const char *buf, int bufsize)
392
392
 
393
393
  bool fatal = false;
394
394
  bool did_work = false;
395
+ int pending = BIO_pending(pbioWrite);
395
396
 
396
- while (OutboundQ.HasPages()) {
397
+ while (OutboundQ.HasPages() && pending < SSLBOX_WRITE_BUFFER_SIZE) {
397
398
  const char *page;
398
399
  int length;
399
400
  OutboundQ.Front (&page, &length);
400
401
  assert (page && (length > 0));
401
402
  int n = SSL_write (pSSL, page, length);
403
+ pending = BIO_pending(pbioWrite);
404
+
402
405
  if (n > 0) {
403
406
  did_work = true;
404
407
  OutboundQ.PopFront();
data/ext/ssl.h CHANGED
@@ -54,6 +54,10 @@ class SslContext_t
54
54
  class SslBox_t
55
55
  **************/
56
56
 
57
+ #define SSLBOX_INPUT_CHUNKSIZE 2019
58
+ #define SSLBOX_OUTPUT_CHUNKSIZE 2048
59
+ #define SSLBOX_WRITE_BUFFER_SIZE 8192 // (SSLBOX_OUTPUT_CHUNKSIZE * 4)
60
+
57
61
  class SslBox_t
58
62
  {
59
63
  public:
@@ -409,7 +409,7 @@ module EventMachine
409
409
  [priv_key, cert_chain].each do |file|
410
410
  next if file.nil? or file.empty?
411
411
  raise FileNotFoundException,
412
- "Could not find #{file} for start_tls" unless File.exists? file
412
+ "Could not find #{file} for start_tls" unless File.exist? file
413
413
  end
414
414
 
415
415
  EventMachine::set_tls_parms(@signature, priv_key || '', cert_chain || '', verify_peer)
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -1042,7 +1042,12 @@ module EventMachine
1042
1042
  thread = Thread.new do
1043
1043
  Thread.current.abort_on_exception = true
1044
1044
  while true
1045
- op, cback = *@threadqueue.pop
1045
+ begin
1046
+ op, cback = *@threadqueue.pop
1047
+ rescue ThreadError
1048
+ $stderr.puts $!.message
1049
+ break # Ruby 2.0 may fail at Queue.pop
1050
+ end
1046
1051
  result = op.call
1047
1052
  @resultqueue << [result, cback]
1048
1053
  EventMachine.signal_loopbreak
@@ -1521,9 +1526,9 @@ module EventMachine
1521
1526
  raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
1522
1527
  handler
1523
1528
  elsif handler
1524
- begin
1529
+ if defined?(handler::EM_CONNECTION_CLASS)
1525
1530
  handler::EM_CONNECTION_CLASS
1526
- rescue NameError
1531
+ else
1527
1532
  handler::const_set(:EM_CONNECTION_CLASS, Class.new(klass) {include handler})
1528
1533
  end
1529
1534
  else
@@ -65,7 +65,7 @@ end
65
65
  require "\#{$1}/#{File.basename(t.name, '.rb')}"
66
66
  eoruby
67
67
  end
68
- at_exit{ FileUtils.rm t.name if File.exists?(t.name) }
68
+ at_exit{ FileUtils.rm t.name if File.exist?(t.name) }
69
69
  end
70
70
  end
71
71
 
@@ -67,6 +67,7 @@ class TestAttach < Test::Unit::TestCase
67
67
  end
68
68
 
69
69
  def test_attach_server
70
+ omit_if(jruby?)
70
71
  $before = TCPServer.new("127.0.0.1", @port)
71
72
  sig = nil
72
73
  EM.run {
@@ -179,18 +179,15 @@ class TestBasic < Test::Unit::TestCase
179
179
  assert x
180
180
  end
181
181
 
182
- if EM.respond_to? :set_heartbeat_interval
183
- def test_set_heartbeat_interval
184
- interval = 0.5
185
- EM.run {
186
- EM.set_heartbeat_interval interval
187
- $interval = EM.get_heartbeat_interval
188
- EM.stop
189
- }
190
- assert_equal(interval, $interval)
191
- end
192
- else
193
- warn "EM.set_heartbeat_interval not implemented, skipping a test in #{__FILE__}"
182
+ def test_set_heartbeat_interval
183
+ omit_if(jruby?)
184
+ interval = 0.5
185
+ EM.run {
186
+ EM.set_heartbeat_interval interval
187
+ $interval = EM.get_heartbeat_interval
188
+ EM.stop
189
+ }
190
+ assert_equal(interval, $interval)
194
191
  end
195
192
 
196
193
  module PostInitRaiser
@@ -226,6 +223,7 @@ class TestBasic < Test::Unit::TestCase
226
223
  end
227
224
 
228
225
  def test_schedule_close
226
+ omit_if(jruby?)
229
227
  localhost, port = '127.0.0.1', 9000
230
228
  timer_ran = false
231
229
  num_close_scheduled = nil
@@ -247,22 +245,21 @@ class TestBasic < Test::Unit::TestCase
247
245
  end
248
246
 
249
247
  def test_fork_safe
250
- return unless cpid = fork { exit! } rescue false
248
+ omit_if(jruby?)
251
249
 
252
250
  read, write = IO.pipe
253
251
  EM.run do
254
- cpid = fork do
252
+ fork do
255
253
  write.puts "forked"
256
254
  EM.run do
257
255
  EM.next_tick do
258
256
  write.puts "EM ran"
259
- exit!
257
+ EM.stop
260
258
  end
261
259
  end
262
260
  end
263
261
  EM.stop
264
262
  end
265
- Process.waitall
266
263
  assert_equal "forked\n", read.readline
267
264
  assert_equal "EM ran\n", read.readline
268
265
  ensure
@@ -43,6 +43,7 @@ class TestConnectionCount < Test::Unit::TestCase
43
43
  end
44
44
 
45
45
  def test_num_close_scheduled
46
+ omit_if(jruby?)
46
47
  EM.run {
47
48
  assert_equal(0, EM.num_close_scheduled)
48
49
  EM.connect("127.0.0.1", 9999, DoubleCloseClient) # nothing listening on 9999
@@ -25,19 +25,16 @@ class TestEpoll < Test::Unit::TestCase
25
25
  end
26
26
 
27
27
 
28
- if windows? || jruby?
29
- warn "EM.set_descriptor_table_size not implemented, skipping test in #{__FILE__}"
30
- else
31
- # We can set the rlimit/nofile of a process but we can only set it
32
- # higher if we're running as root.
33
- # On most systems, the default value is 1024.
34
- def test_rlimit
35
- unless EM.set_descriptor_table_size >= 1024
36
- a = EM.set_descriptor_table_size
37
- assert( a <= 1024 )
38
- a = EM.set_descriptor_table_size( 1024 )
39
- assert( a == 1024 )
40
- end
28
+ # We can set the rlimit/nofile of a process but we can only set it
29
+ # higher if we're running as root.
30
+ # On most systems, the default value is 1024.
31
+ def test_rlimit
32
+ omit_if(windows? || jruby?)
33
+ unless EM.set_descriptor_table_size >= 1024
34
+ a = EM.set_descriptor_table_size
35
+ assert( a <= 1024 )
36
+ a = EM.set_descriptor_table_size( 1024 )
37
+ assert( a == 1024 )
41
38
  end
42
39
  end
43
40
 
@@ -97,7 +94,7 @@ class TestEpoll < Test::Unit::TestCase
97
94
  assert_equal( "abcdefghij", $out )
98
95
  end
99
96
 
100
- # XXX this test fails randomly..
97
+ # XXX this test fails randomly...
101
98
  def _test_unix_domain
102
99
  fn = "/tmp/xxx.chain"
103
100
  EM.epoll
@@ -18,7 +18,7 @@ class TestIterator < Test::Unit::TestCase
18
18
  }, proc {EM.stop})
19
19
  }
20
20
  assert_equal(10, items.keys.size)
21
- assert_equal((list).to_a, items.values.flatten)
21
+ assert_equal(list.to_a.sort, items.values.flatten.sort)
22
22
  end
23
23
 
24
24
  def test_concurrency_bigger_than_list_size
@@ -33,7 +33,7 @@ class TestIterator < Test::Unit::TestCase
33
33
  }, proc {EM.stop})
34
34
  }
35
35
  assert_equal(1, items.keys.size)
36
- assert_equal((list).to_a, items.values.flatten)
36
+ assert_equal(list.to_a.sort, items.values.flatten.sort)
37
37
  end
38
38
 
39
39
 
@@ -56,7 +56,7 @@ class TestIterator < Test::Unit::TestCase
56
56
  }
57
57
  }
58
58
  assert_equal(9, items.keys.size)
59
- assert_equal((list).to_a, items.values.flatten)
59
+ assert_equal(list.to_a.sort, items.values.flatten.sort)
60
60
  end
61
61
 
62
62
  def test_map
@@ -65,7 +65,7 @@ class TestIterator < Test::Unit::TestCase
65
65
  EM::Iterator.new(list).map(proc{ |num,iter|
66
66
  EM.add_timer(0.01){ iter.return(num) }
67
67
  }, proc{ |results|
68
- assert_equal((list).to_a.size, results.size)
68
+ assert_equal(list.to_a.size, results.size)
69
69
  EM.stop
70
70
  })
71
71
  }
@@ -80,7 +80,7 @@ class TestIterator < Test::Unit::TestCase
80
80
  iter.return(hash)
81
81
  }
82
82
  }, proc{ |results|
83
- assert_equal(results.keys, list)
83
+ assert_equal(results.keys.sort, list.sort)
84
84
  EM.stop
85
85
  })
86
86
  }
@@ -94,4 +94,4 @@ class TestIterator < Test::Unit::TestCase
94
94
  EM.stop
95
95
  }
96
96
  end
97
- end
97
+ end
@@ -2,33 +2,27 @@ require 'em_test_helper'
2
2
 
3
3
  class TestKeyboardEvents < Test::Unit::TestCase
4
4
 
5
- if !jruby?
6
- module KbHandler
7
- include EM::Protocols::LineText2
8
- def receive_line d
9
- EM::stop if d == "STOP"
10
- end
5
+ module KbHandler
6
+ include EM::Protocols::LineText2
7
+ def receive_line d
8
+ EM::stop if d == "STOP"
11
9
  end
10
+ end
12
11
 
13
- # This test doesn't actually do anything useful but is here to
14
- # illustrate the usage. If you removed the timer and ran this test
15
- # by itself on a console, and then typed into the console, it would
16
- # work.
17
- # I don't know how to get the test harness to simulate actual keystrokes.
18
- # When someone figures that out, then we can make this a real test.
19
- #
20
- def test_kb
21
- EM.run {
22
- EM.open_keyboard KbHandler
23
- EM::Timer.new(1) { EM.stop }
24
- } if $stdout.tty? # don't run the test unless it stands a chance of validity.
25
- end
26
- else
27
- warn "EM.open_keyboard not implemented, skipping tests in #{__FILE__}"
28
-
29
- # Because some rubies will complain if a TestCase class has no tests
30
- def test_em_open_keyboard_unsupported
31
- assert true
12
+ # This test doesn't actually do anything useful but is here to
13
+ # illustrate the usage. If you removed the timer and ran this test
14
+ # by itself on a console, and then typed into the console, it would
15
+ # work.
16
+ # I don't know how to get the test harness to simulate actual keystrokes.
17
+ # When someone figures that out, then we can make this a real test.
18
+ #
19
+ def test_kb
20
+ omit_if(jruby?)
21
+ omit_if(!$stdout.tty?) # don't run the test unless it stands a chance of validity.
22
+ EM.run do
23
+ EM.open_keyboard KbHandler
24
+ EM::Timer.new(1) { EM.stop }
32
25
  end
33
26
  end
27
+
34
28
  end
@@ -0,0 +1,22 @@
1
+ require 'em_test_helper'
2
+ require 'socket'
3
+
4
+ class TestManyFDs < Test::Unit::TestCase
5
+ def setup
6
+ @port = next_port
7
+ end
8
+
9
+ def test_connection_class_cache
10
+ mod = Module.new
11
+ a = nil
12
+ Process.setrlimit(Process::RLIMIT_NOFILE,4096);
13
+ EM.run {
14
+ EM.start_server '127.0.0.1', @port, mod
15
+ 1100.times do
16
+ a = EM.connect '127.0.0.1', @port, mod
17
+ assert_kind_of EM::Connection, a
18
+ end
19
+ EM.stop
20
+ }
21
+ end
22
+ end
@@ -27,6 +27,7 @@ if EM.kqueue?
27
27
  end
28
28
 
29
29
  def test_events
30
+ omit_if(jruby?)
30
31
  EM.run{
31
32
  # watch ourselves for a fork notification
32
33
  EM.watch_process(Process.pid, ParentProcessWatcher)
@@ -37,8 +37,8 @@ class TestProcesses < Test::Unit::TestCase
37
37
  }
38
38
 
39
39
  assert( $out.length > 0 )
40
- assert_equal($status.exitstatus, 0)
41
- assert_equal($status.class, Process::Status)
40
+ assert_equal(0, $status.exitstatus)
41
+ assert_kind_of(Process::Status, $status)
42
42
  end
43
43
 
44
44
  def test_em_system_pid
@@ -57,8 +57,8 @@ class TestProcesses < Test::Unit::TestCase
57
57
  }
58
58
 
59
59
  assert( $out.length > 0 )
60
- assert_equal($status.exitstatus, 0)
61
- assert_equal($status.class, Process::Status)
60
+ assert_equal(0, $status.exitstatus)
61
+ assert_kind_of(Process::Status, $status)
62
62
  end
63
63
 
64
64
  def test_em_system_with_two_procs
@@ -111,9 +111,9 @@ class TestProcesses < Test::Unit::TestCase
111
111
  end
112
112
  end
113
113
 
114
- EM.run{
115
- EM.popen('cat /dev/random', test_client)
116
- }
114
+ EM.run do
115
+ EM.popen('echo 1', test_client)
116
+ end
117
117
 
118
118
  assert_equal 1, c_rx
119
119
  end
@@ -33,7 +33,7 @@ class TestResolver < Test::Unit::TestCase
33
33
  d = EM::DNS::Resolver.resolve "google.com"
34
34
  d.errback { assert false }
35
35
  d.callback { |r|
36
- assert_equal(Array, r.class)
36
+ assert_kind_of(Array, r)
37
37
  assert r.size > 1
38
38
  EM.stop
39
39
  }
@@ -45,11 +45,37 @@ class TestResolver < Test::Unit::TestCase
45
45
  d = EM::DNS::Resolver.resolve "localhost"
46
46
  d.errback { assert false }
47
47
  d.callback { |r|
48
- assert_equal("127.0.0.1", r.first)
49
- assert_equal(Array, r.class)
48
+ assert_include(["127.0.0.1", "::1"], r.first)
49
+ assert_kind_of(Array, r)
50
50
 
51
51
  EM.stop
52
52
  }
53
53
  }
54
54
  end
55
- end
55
+
56
+ def test_timer_cleanup
57
+ EM.run {
58
+ d = EM::DNS::Resolver.resolve "google.com"
59
+ d.errback { assert false }
60
+ d.callback { |r|
61
+ # This isn't a great test, but it's hard to get more canonical
62
+ # confirmation that the timer is cancelled
63
+ assert_nil(EM::DNS::Resolver.socket.instance_variable_get(:@timer))
64
+
65
+ EM.stop
66
+ }
67
+ }
68
+ end
69
+
70
+ def test_failure_timer_cleanup
71
+ EM.run {
72
+ d = EM::DNS::Resolver.resolve "asdfasdf"
73
+ d.callback { assert false }
74
+ d.errback {
75
+ assert_nil(EM::DNS::Resolver.socket.instance_variable_get(:@timer))
76
+
77
+ EM.stop
78
+ }
79
+ }
80
+ end
81
+ end
@@ -45,7 +45,7 @@ class TestSslArgs < Test::Unit::TestCase
45
45
  def test_tls_params_file_doesnt_exist
46
46
  priv_file, cert_file = 'foo_priv_key', 'bar_cert_file'
47
47
  [priv_file, cert_file].all? do |f|
48
- assert(!File.exists?(f), "Cert file #{f} seems to exist, and should not for the tests")
48
+ assert(!File.exist?(f), "Cert file #{f} seems to exist, and should not for the tests")
49
49
  end
50
50
 
51
51
  # associate_callback_target is a pain! (build!)
@@ -75,4 +75,4 @@ class TestSslArgs < Test::Unit::TestCase
75
75
  assert(false, 'should not have raised an exception')
76
76
  end
77
77
  end
78
- end if EM.ssl?
78
+ end if EM.ssl?
@@ -3,7 +3,6 @@ require 'em_test_helper'
3
3
  class TestSSLMethods < Test::Unit::TestCase
4
4
 
5
5
  module ServerHandler
6
-
7
6
  def post_init
8
7
  start_tls
9
8
  end
@@ -12,11 +11,9 @@ class TestSSLMethods < Test::Unit::TestCase
12
11
  $server_called_back = true
13
12
  $server_cert_value = get_peer_cert
14
13
  end
15
-
16
14
  end
17
15
 
18
16
  module ClientHandler
19
-
20
17
  def post_init
21
18
  start_tls
22
19
  end
@@ -26,10 +23,10 @@ class TestSSLMethods < Test::Unit::TestCase
26
23
  $client_cert_value = get_peer_cert
27
24
  EM.stop_event_loop
28
25
  end
29
-
30
26
  end
31
27
 
32
28
  def test_ssl_methods
29
+ omit_unless(EM.ssl?)
33
30
  $server_called_back, $client_called_back = false, false
34
31
  $server_cert_value, $client_cert_value = nil, nil
35
32
 
@@ -45,4 +42,4 @@ class TestSSLMethods < Test::Unit::TestCase
45
42
  assert($client_cert_value.is_a?(String))
46
43
  end
47
44
 
48
- end if EM.ssl?
45
+ end
@@ -1,82 +1,80 @@
1
1
  require 'em_test_helper'
2
2
 
3
- if EM.ssl?
4
- class TestSslVerify < Test::Unit::TestCase
5
- def setup
6
- $dir = File.dirname(File.expand_path(__FILE__)) + '/'
7
- $cert_from_file = File.read($dir+'client.crt')
8
- end
3
+ class TestSslVerify < Test::Unit::TestCase
4
+ def setup
5
+ $dir = File.dirname(File.expand_path(__FILE__)) + '/'
6
+ $cert_from_file = File.read($dir+'client.crt')
7
+ end
9
8
 
10
- module Client
11
- def connection_completed
12
- start_tls(:private_key_file => $dir+'client.key', :cert_chain_file => $dir+'client.crt')
13
- end
9
+ module Client
10
+ def connection_completed
11
+ start_tls(:private_key_file => $dir+'client.key', :cert_chain_file => $dir+'client.crt')
12
+ end
14
13
 
15
- def ssl_handshake_completed
16
- $client_handshake_completed = true
17
- close_connection
18
- end
14
+ def ssl_handshake_completed
15
+ $client_handshake_completed = true
16
+ close_connection
17
+ end
19
18
 
20
- def unbind
21
- EM.stop_event_loop
22
- end
19
+ def unbind
20
+ EM.stop_event_loop
23
21
  end
22
+ end
24
23
 
25
- module AcceptServer
26
- def post_init
27
- start_tls(:verify_peer => true)
28
- end
24
+ module AcceptServer
25
+ def post_init
26
+ start_tls(:verify_peer => true)
27
+ end
29
28
 
30
- def ssl_verify_peer(cert)
31
- $cert_from_server = cert
32
- true
33
- end
29
+ def ssl_verify_peer(cert)
30
+ $cert_from_server = cert
31
+ true
32
+ end
34
33
 
35
- def ssl_handshake_completed
36
- $server_handshake_completed = true
37
- end
34
+ def ssl_handshake_completed
35
+ $server_handshake_completed = true
38
36
  end
37
+ end
39
38
 
40
- module DenyServer
41
- def post_init
42
- start_tls(:verify_peer => true)
43
- end
39
+ module DenyServer
40
+ def post_init
41
+ start_tls(:verify_peer => true)
42
+ end
44
43
 
45
- def ssl_verify_peer(cert)
46
- $cert_from_server = cert
47
- # Do not accept the peer. This should now cause the connection to shut down without the SSL handshake being completed.
48
- false
49
- end
44
+ def ssl_verify_peer(cert)
45
+ $cert_from_server = cert
46
+ # Do not accept the peer. This should now cause the connection to shut down without the SSL handshake being completed.
47
+ false
48
+ end
50
49
 
51
- def ssl_handshake_completed
52
- $server_handshake_completed = true
53
- end
50
+ def ssl_handshake_completed
51
+ $server_handshake_completed = true
54
52
  end
53
+ end
55
54
 
56
- def test_accept_server
57
- $client_handshake_completed, $server_handshake_completed = false, false
58
- EM.run {
59
- EM.start_server("127.0.0.1", 16784, AcceptServer)
60
- EM.connect("127.0.0.1", 16784, Client).instance_variable_get("@signature")
61
- }
55
+ def test_accept_server
56
+ omit_unless(EM.ssl?)
57
+ $client_handshake_completed, $server_handshake_completed = false, false
58
+ EM.run {
59
+ EM.start_server("127.0.0.1", 16784, AcceptServer)
60
+ EM.connect("127.0.0.1", 16784, Client).instance_variable_get("@signature")
61
+ }
62
62
 
63
- assert_equal($cert_from_file, $cert_from_server)
64
- assert($client_handshake_completed)
65
- assert($server_handshake_completed)
66
- end
63
+ assert_equal($cert_from_file, $cert_from_server)
64
+ assert($client_handshake_completed)
65
+ assert($server_handshake_completed)
66
+ end
67
67
 
68
- def test_deny_server
69
- $client_handshake_completed, $server_handshake_completed = false, false
70
- EM.run {
71
- EM.start_server("127.0.0.1", 16784, DenyServer)
72
- EM.connect("127.0.0.1", 16784, Client)
73
- }
68
+ def test_deny_server
69
+ omit_unless(EM.ssl?)
70
+ $client_handshake_completed, $server_handshake_completed = false, false
71
+ EM.run {
72
+ EM.start_server("127.0.0.1", 16784, DenyServer)
73
+ EM.connect("127.0.0.1", 16784, Client)
74
+ }
74
75
 
75
- assert_equal($cert_from_file, $cert_from_server)
76
- assert(!$client_handshake_completed)
77
- assert(!$server_handshake_completed)
78
- end
76
+ assert_equal($cert_from_file, $cert_from_server)
77
+ assert(!$client_handshake_completed)
78
+ assert(!$server_handshake_completed)
79
79
  end
80
- else
81
- warn "EM built without SSL support, skipping tests in #{__FILE__}"
82
80
  end
@@ -15,6 +15,10 @@ class TestThreadedResource < Test::Unit::TestCase
15
15
 
16
16
  def test_dispatch_completion
17
17
  EM.run do
18
+ EM.add_timer(3) do
19
+ EM.stop
20
+ fail 'Resource dispatch timed out'
21
+ end
18
22
  completion = resource.dispatch do |o|
19
23
  o[:foo] = :bar
20
24
  :foo
@@ -23,6 +27,10 @@ class TestThreadedResource < Test::Unit::TestCase
23
27
  assert_equal :foo, result
24
28
  EM.stop
25
29
  end
30
+ completion.errback do |error|
31
+ EM.stop
32
+ fail "Unexpected error: #{error.message}"
33
+ end
26
34
  end
27
35
  assert_equal :bar, object[:foo]
28
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,8 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-12-19 00:00:00.000000000 Z
13
+ date: 2015-02-02 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: test-unit
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '2.0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '2.0'
15
31
  - !ruby/object:Gem::Dependency
16
32
  name: rake-compiler
17
33
  requirement: !ruby/object:Gem::Requirement
@@ -240,6 +256,7 @@ files:
240
256
  - tests/test_line_protocol.rb
241
257
  - tests/test_ltp.rb
242
258
  - tests/test_ltp2.rb
259
+ - tests/test_many_fds.rb
243
260
  - tests/test_next_tick.rb
244
261
  - tests/test_object_protocol.rb
245
262
  - tests/test_pause.rb
@@ -305,4 +322,3 @@ signing_key:
305
322
  specification_version: 3
306
323
  summary: Ruby/EventMachine library
307
324
  test_files: []
308
- has_rdoc: