eventmachine 1.0.3 → 1.0.4

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.
@@ -3,10 +3,8 @@ language: ruby
3
3
  rvm:
4
4
  - 1.8.7
5
5
  - 1.9.3
6
- - rbx-18mode
7
- - rbx-19mode
6
+ - 2.0.0
7
+ - 2.1
8
+ - 2.2
9
+ - rbx
8
10
  - jruby
9
- matrix:
10
- allow_failures:
11
- - rvm: rbx-18mode
12
- - rvm: rbx-19mode
@@ -1,6 +1,25 @@
1
1
  # Changelog
2
2
 
3
- ## 1.0.x
3
+ ## 1.0.4 (December 19, 2014)
4
+ * add starttls_options to smtp server [#552]
5
+ * fix closesocket on windows [#497]
6
+ * fix build on ruby 2.2 [#503]
7
+ * fix build error on ruby 1.9 [#508]
8
+ * fix timer leak during dns resolution [#489]
9
+ * add concurrency validation to EM::Iterator [#468]
10
+ * add get_file_descriptor to get fd for a signature [#467]
11
+ * add EM.attach_server and EM.attach_socket_server [#465, #466]
12
+ * calling pause from receive_data takes effect immediately [#464]
13
+ * reactor_running? returns false after fork [#455]
14
+ * fix infinite loop on double close [edc4d0e6, #441, #445]
15
+ * fix compilation issue on llvm [#433]
16
+ * fix socket error codes on win32 [ff811a81]
17
+ * fix EM.stop latency when timers exist [8b613d05, #426]
18
+ * fix infinite loop when system time changes [1427a2c80, #428]
19
+ * fix crash when callin attach/detach in the same tick [#427]
20
+ * fix compilation issue on solaris [#416]
21
+
22
+ ## 1.0.3 (March 8, 2013)
4
23
  * EM.system was broken in 1.0.2 release [#413]
5
24
 
6
25
  ## 1.0.2 (March 8, 2013)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # About EventMachine #
1
+ # About EventMachine [![Code Climate](https://codeclimate.com/github/eventmachine/eventmachine.png)](https://codeclimate.com/github/eventmachine/eventmachine)
2
2
 
3
3
 
4
4
  ## What is EventMachine ##
@@ -75,7 +75,7 @@ Here's a fully-functional echo server written with EventMachine:
75
75
 
76
76
  def unbind
77
77
  puts "-- someone disconnected from the echo server!"
78
- end
78
+ end
79
79
  end
80
80
 
81
81
  # Note that this will block current thread.
@@ -86,7 +86,7 @@ Here's a fully-functional echo server written with EventMachine:
86
86
 
87
87
  ## EventMachine documentation ##
88
88
 
89
- Currently we only have [reference documentation](http://eventmachine.rubyforge.org) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
89
+ Currently we only have [reference documentation](http://rdoc.info/github/eventmachine/eventmachine/frames) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
90
90
 
91
91
 
92
92
  ## Community and where to get help ##
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.version = EventMachine::VERSION
9
9
  s.homepage = 'http://rubyeventmachine.com'
10
10
  s.rubyforge_project = 'eventmachine'
11
+ s.licenses = ["Ruby", "GPL"]
11
12
 
12
13
  s.authors = ["Francis Cianfrocca", "Aman Gupta"]
13
14
  s.email = ["garbagecat10@gmail.com", "aman@tmm1.net"]
@@ -32,7 +32,7 @@ STATIC Bindable_t::CreateBinding
32
32
  unsigned long Bindable_t::CreateBinding()
33
33
  {
34
34
  static unsigned long num = 0;
35
- while(BindingBag[++num]);
35
+ while(BindingBag[++num]) {}
36
36
  return num;
37
37
  }
38
38
 
@@ -259,6 +259,7 @@ evma_num_close_scheduled
259
259
 
260
260
  extern "C" int evma_num_close_scheduled ()
261
261
  {
262
+ ensure_eventmachine("evma_num_close_scheduled");
262
263
  return EventMachine->NumCloseScheduled;
263
264
  }
264
265
 
@@ -282,6 +283,16 @@ extern "C" const unsigned long evma_create_unix_domain_server (const char *filen
282
283
  return EventMachine->CreateUnixDomainServer (filename);
283
284
  }
284
285
 
286
+ /***********************
287
+ evma_attach_sd
288
+ ************************/
289
+
290
+ extern "C" const unsigned long evma_attach_sd (int sd)
291
+ {
292
+ ensure_eventmachine("evma_attach_sd");
293
+ return EventMachine->AttachSD (sd);
294
+ }
295
+
285
296
  /*************************
286
297
  evma_open_datagram_socket
287
298
  *************************/
data/ext/ed.cpp CHANGED
@@ -217,6 +217,8 @@ EventableDescriptor::ScheduleClose
217
217
 
218
218
  void EventableDescriptor::ScheduleClose (bool after_writing)
219
219
  {
220
+ if (IsCloseScheduled())
221
+ return;
220
222
  MyEventMachine->NumCloseScheduled++;
221
223
  // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
222
224
  if (after_writing)
@@ -765,7 +767,11 @@ void ConnectionDescriptor::Read()
765
767
 
766
768
 
767
769
  int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
770
+ #ifdef OS_WIN32
771
+ int e = WSAGetLastError();
772
+ #else
768
773
  int e = errno;
774
+ #endif
769
775
  //cerr << "<R:" << r << ">";
770
776
 
771
777
  if (r > 0) {
@@ -779,6 +785,8 @@ void ConnectionDescriptor::Read()
779
785
  // a security guard against buffer overflows.
780
786
  readbuffer [r] = 0;
781
787
  _DispatchInboundData (readbuffer, r);
788
+ if (bPaused)
789
+ break;
782
790
  }
783
791
  else if (r == 0) {
784
792
  break;
@@ -981,11 +989,7 @@ void ConnectionDescriptor::_WriteOutboundData()
981
989
  // Max of 16 outbound pages at a time
982
990
  if (iovcnt > 16) iovcnt = 16;
983
991
 
984
- #ifdef CC_SUNWspro
985
- struct iovec iov[16];
986
- #else
987
- struct iovec iov[ iovcnt ];
988
- #endif
992
+ iovec iov[16];
989
993
 
990
994
  for(int i = 0; i < iovcnt; i++){
991
995
  OutboundPage *op = &(OutboundPages[i]);
@@ -1032,7 +1036,11 @@ void ConnectionDescriptor::_WriteOutboundData()
1032
1036
  #endif
1033
1037
 
1034
1038
  bool err = false;
1039
+ #ifdef OS_WIN32
1040
+ int e = WSAGetLastError();
1041
+ #else
1035
1042
  int e = errno;
1043
+ #endif
1036
1044
  if (bytes_written < 0) {
1037
1045
  err = true;
1038
1046
  bytes_written = 0;
@@ -1663,7 +1671,11 @@ void DatagramDescriptor::Write()
1663
1671
 
1664
1672
  // The nasty cast to (char*) is needed because Windows is brain-dead.
1665
1673
  int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1674
+ #ifdef OS_WIN32
1675
+ int e = WSAGetLastError();
1676
+ #else
1666
1677
  int e = errno;
1678
+ #endif
1667
1679
 
1668
1680
  OutboundDataSize -= op->Length;
1669
1681
  op->Free();
data/ext/ed.h CHANGED
@@ -69,14 +69,14 @@ class EventableDescriptor: public Bindable_t
69
69
  virtual bool GetSubprocessPid (pid_t*) {return false;}
70
70
 
71
71
  virtual void StartTls() {}
72
- virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer) {}
72
+ virtual void SetTlsParms (const char *, const char *, bool) {}
73
73
 
74
74
  #ifdef WITH_SSL
75
75
  virtual X509 *GetPeerCert() {return NULL;}
76
76
  #endif
77
77
 
78
78
  virtual uint64_t GetCommInactivityTimeout() {return 0;}
79
- virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
79
+ virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
80
80
  uint64_t GetPendingConnectTimeout();
81
81
  int SetPendingConnectTimeout (uint64_t value);
82
82
  uint64_t GetLastActivity() { return LastActivity; }
@@ -215,7 +215,7 @@ class ConnectionDescriptor: public EventableDescriptor
215
215
  protected:
216
216
  struct OutboundPage {
217
217
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
218
- void Free() {if (Buffer) free ((char*)Buffer); }
218
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
219
219
  const char *Buffer;
220
220
  int Length;
221
221
  int Offset;
@@ -292,7 +292,7 @@ class DatagramDescriptor: public EventableDescriptor
292
292
  protected:
293
293
  struct OutboundPage {
294
294
  OutboundPage (const char *b, int l, struct sockaddr_in f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
295
- void Free() {if (Buffer) free ((char*)Buffer); }
295
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
296
296
  const char *Buffer;
297
297
  int Length;
298
298
  int Offset;
@@ -354,7 +354,7 @@ class PipeDescriptor: public EventableDescriptor
354
354
  protected:
355
355
  struct OutboundPage {
356
356
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
357
- void Free() {if (Buffer) free ((char*)Buffer); }
357
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
358
358
  const char *Buffer;
359
359
  int Length;
360
360
  int Offset;
data/ext/em.cpp CHANGED
@@ -382,15 +382,27 @@ EventMachine_t::_DispatchHeartbeats
382
382
 
383
383
  void EventMachine_t::_DispatchHeartbeats()
384
384
  {
385
+ // Store the first processed heartbeat descriptor and bail out if
386
+ // we see it again. This fixes an infinite loop in case the system time
387
+ // is changed out from underneath MyCurrentLoopTime.
388
+ const EventableDescriptor *head = NULL;
389
+
385
390
  while (true) {
386
391
  multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
387
392
  if (i == Heartbeats.end())
388
393
  break;
389
394
  if (i->first > MyCurrentLoopTime)
390
395
  break;
396
+
391
397
  EventableDescriptor *ed = i->second;
398
+ if (ed == head)
399
+ break;
400
+
392
401
  ed->Heartbeat();
393
402
  QueueHeartbeat(ed);
403
+
404
+ if (head == NULL)
405
+ head = ed;
394
406
  }
395
407
  }
396
408
 
@@ -675,7 +687,7 @@ EventMachine_t::_TimeTilNextEvent
675
687
 
676
688
  timeval EventMachine_t::_TimeTilNextEvent()
677
689
  {
678
- // 29jul11: Changed calculation base from MyCurrentLoopTime to the
690
+ // 29jul11: Changed calculation base from MyCurrentLoopTime to the
679
691
  // real time. As MyCurrentLoopTime is set at the beginning of an
680
692
  // iteration and this calculation is done at the end, evenmachine
681
693
  // will potentially oversleep by the amount of time the iteration
@@ -697,10 +709,12 @@ timeval EventMachine_t::_TimeTilNextEvent()
697
709
  if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
698
710
  next_event = current_time;
699
711
  }
700
-
712
+
701
713
  timeval tv;
702
714
 
703
- if (next_event == 0 || NumCloseScheduled > 0) {
715
+ if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
716
+ tv.tv_sec = tv.tv_usec = 0;
717
+ } else if (next_event == 0) {
704
718
  tv = Quantum;
705
719
  } else {
706
720
  if (next_event > current_time) {
@@ -803,7 +817,7 @@ SelectData_t::SelectData_t()
803
817
  _SelectDataSelect
804
818
  *****************/
805
819
 
806
- #ifdef HAVE_TBR
820
+ #if defined(HAVE_TBR) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
807
821
  static VALUE _SelectDataSelect (void *v)
808
822
  {
809
823
  SelectData_t *sd = (SelectData_t*)v;
@@ -818,12 +832,13 @@ SelectData_t::_Select
818
832
 
819
833
  int SelectData_t::_Select()
820
834
  {
821
- #ifdef HAVE_TBR
835
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
836
+ rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
837
+ return nSockets;
838
+ #elif defined(HAVE_TBR)
822
839
  rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
823
840
  return nSockets;
824
- #endif
825
-
826
- #ifndef HAVE_TBR
841
+ #else
827
842
  return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
828
843
  #endif
829
844
  }
@@ -1399,6 +1414,14 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1399
1414
  // Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
1400
1415
  ModifiedDescriptors.erase (ed);
1401
1416
 
1417
+ // Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
1418
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1419
+ if (ed == NewDescriptors[i]) {
1420
+ NewDescriptors.erase(NewDescriptors.begin() + i);
1421
+ break;
1422
+ }
1423
+ }
1424
+
1402
1425
  // Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
1403
1426
  // and also to prevent anyone from calling close() on the detached fd
1404
1427
  ed->SetSocketInvalid();
@@ -1491,8 +1514,6 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1491
1514
  if (!bind_here)
1492
1515
  return 0;
1493
1516
 
1494
- unsigned long output_binding = 0;
1495
-
1496
1517
  //struct sockaddr_in sin;
1497
1518
 
1498
1519
  int sd_accept = socket (family, SOCK_STREAM, 0);
@@ -1529,25 +1550,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1529
1550
  goto fail;
1530
1551
  }
1531
1552
 
1532
- {
1533
- // Set the acceptor non-blocking.
1534
- // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1535
- if (!SetSocketNonblocking (sd_accept)) {
1536
- //int val = fcntl (sd_accept, F_GETFL, 0);
1537
- //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1538
- goto fail;
1539
- }
1540
- }
1541
-
1542
- { // Looking good.
1543
- AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1544
- if (!ad)
1545
- throw std::runtime_error ("unable to allocate acceptor");
1546
- Add (ad);
1547
- output_binding = ad->GetBinding();
1548
- }
1549
-
1550
- return output_binding;
1553
+ return AttachSD(sd_accept);
1551
1554
 
1552
1555
  fail:
1553
1556
  if (sd_accept != INVALID_SOCKET)
@@ -1838,7 +1841,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1838
1841
 
1839
1842
  // The whole rest of this function is only compiled on Unix systems.
1840
1843
  #ifdef OS_UNIX
1841
- unsigned long output_binding = 0;
1842
1844
 
1843
1845
  struct sockaddr_un s_sun;
1844
1846
 
@@ -1876,6 +1878,24 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1876
1878
  goto fail;
1877
1879
  }
1878
1880
 
1881
+ return AttachSD(sd_accept);
1882
+
1883
+ fail:
1884
+ if (sd_accept != INVALID_SOCKET)
1885
+ close (sd_accept);
1886
+ return 0;
1887
+ #endif // OS_UNIX
1888
+ }
1889
+
1890
+
1891
+ /**************************************
1892
+ EventMachine_t::AttachSD
1893
+ **************************************/
1894
+
1895
+ const unsigned long EventMachine_t::AttachSD (int sd_accept)
1896
+ {
1897
+ unsigned long output_binding = 0;
1898
+
1879
1899
  {
1880
1900
  // Set the acceptor non-blocking.
1881
1901
  // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
@@ -1900,7 +1920,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1900
1920
  if (sd_accept != INVALID_SOCKET)
1901
1921
  close (sd_accept);
1902
1922
  return 0;
1903
- #endif // OS_UNIX
1904
1923
  }
1905
1924
 
1906
1925
 
data/ext/em.h CHANGED
@@ -22,7 +22,16 @@ See the file COPYING for complete licensing information.
22
22
 
23
23
  #ifdef BUILD_FOR_RUBY
24
24
  #include <ruby.h>
25
- #define EmSelect rb_thread_select
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
31
+
32
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
33
+ #include <ruby/thread.h>
34
+ #endif
26
35
 
27
36
  #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
28
37
  #include <ruby/io.h>
@@ -88,6 +97,7 @@ class EventMachine_t
88
97
  const unsigned long CreateTcpServer (const char *, int);
89
98
  const unsigned long OpenDatagramSocket (const char *, int);
90
99
  const unsigned long CreateUnixDomainServer (const char*);
100
+ const unsigned long AttachSD (int);
91
101
  const unsigned long OpenKeyboard();
92
102
  //const char *Popen (const char*, const char*);
93
103
  const unsigned long Socketpair (char* const*);
@@ -64,6 +64,7 @@ extern "C" {
64
64
  void evma_stop_tcp_server (const unsigned long signature);
65
65
  const unsigned long evma_create_tcp_server (const char *address, int port);
66
66
  const unsigned long evma_create_unix_domain_server (const char *filename);
67
+ const unsigned long evma_attach_sd (int sd);
67
68
  const unsigned long evma_open_datagram_socket (const char *server, int port);
68
69
  const unsigned long evma_open_keyboard();
69
70
  void evma_set_tls_parms (const unsigned long binding, const char *privatekey_filename, const char *certchain_filenane, int verify_peer);
@@ -40,7 +40,7 @@ def manual_ssl_config
40
40
  end
41
41
 
42
42
  if ENV['CROSS_COMPILING']
43
- openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.0j")
43
+ openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.1i")
44
44
  openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/")
45
45
  if File.exists?(openssl_dir)
46
46
  FileUtils.mkdir_p Dir.pwd+"/openssl/"
@@ -67,9 +67,11 @@ end
67
67
  add_define 'BUILD_FOR_RUBY'
68
68
  add_define 'HAVE_RBTRAP' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
69
69
  add_define "HAVE_TBR" if have_func('rb_thread_blocking_region')# and have_macro('RUBY_UBF_IO', 'ruby.h')
70
+ add_define "HAVE_RB_THREAD_CALL_WITHOUT_GVL" if have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
70
71
  add_define "HAVE_INOTIFY" if inotify = have_func('inotify_init', 'sys/inotify.h')
71
72
  add_define "HAVE_OLD_INOTIFY" if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h')
72
73
  add_define 'HAVE_WRITEV' if have_func('writev', 'sys/uio.h')
74
+ add_define 'HAVE_RB_THREAD_FD_SELECT' if have_func('rb_thread_fd_select')
73
75
 
74
76
  have_func('rb_wait_for_single_fd')
75
77
  have_func('rb_enable_interrupt')
@@ -106,7 +108,7 @@ when /mswin32/, /mingw32/, /bccwin32/
106
108
  check_libs(%w[kernel32 rpcrt4 gdi32], true)
107
109
 
108
110
  if GNU_CHAIN
109
- CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
111
+ CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
110
112
  else
111
113
  $defs.push "-EHs"
112
114
  $defs.push "-GR"
@@ -170,7 +172,7 @@ TRY_LINK.sub!('$(CC)', '$(CXX)')
170
172
  add_define 'HAVE_MAKE_PAIR' if try_link(<<SRC, '-lstdc++')
171
173
  #include <utility>
172
174
  using namespace std;
173
- int main(){ pair<int,int> tuple = make_pair(1,2); }
175
+ int main(){ pair<const int,int> tuple = make_pair(1,2); }
174
176
  SRC
175
177
  TRY_LINK.sub!('$(CXX)', '$(CC)')
176
178
 
@@ -43,7 +43,7 @@ when /mswin32/, /mingw32/, /bccwin32/
43
43
  check_libs(%w[kernel32 rpcrt4 gdi32], true)
44
44
 
45
45
  if GNU_CHAIN
46
- CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
46
+ CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
47
47
  else
48
48
  $defs.push "-EHs"
49
49
  $defs.push "-GR"
@@ -93,9 +93,14 @@ typedef int SOCKET;
93
93
  #include <fcntl.h>
94
94
  #include <assert.h>
95
95
 
96
+ #define close closesocket
97
+
96
98
  typedef int socklen_t;
99
+ #ifndef _PID_T_
100
+ #define _PID_T_
97
101
  typedef int pid_t;
98
- #endif
102
+ #endif /* _PID_T_ */
103
+ #endif /* OS_WIN32 */
99
104
 
100
105
  #if !defined(_MSC_VER) || _MSC_VER > 1500
101
106
  #include <stdint.h>
@@ -273,6 +273,17 @@ static VALUE t_start_unix_server (VALUE self, VALUE filename)
273
273
  return ULONG2NUM (f);
274
274
  }
275
275
 
276
+ /********************
277
+ t_attach_sd
278
+ ********************/
279
+
280
+ static VALUE t_attach_sd(VALUE self, VALUE sd)
281
+ {
282
+ const unsigned long f = evma_attach_sd(FIX2INT(sd));
283
+ if (!f)
284
+ rb_raise (rb_eRuntimeError, "%s", "no socket descriptor acceptor");
285
+ return ULONG2NUM (f);
286
+ }
276
287
 
277
288
 
278
289
  /***********
@@ -566,6 +577,14 @@ static VALUE t_detach_fd (VALUE self, VALUE signature)
566
577
  return INT2NUM(evma_detach_fd (NUM2ULONG (signature)));
567
578
  }
568
579
 
580
+ /*********************
581
+ t_get_file_descriptor
582
+ *********************/
583
+ static VALUE t_get_file_descriptor (VALUE self, VALUE signature)
584
+ {
585
+ return INT2NUM(evma_get_file_descriptor (NUM2ULONG (signature)));
586
+ }
587
+
569
588
  /**************
570
589
  t_get_sock_opt
571
590
  **************/
@@ -1204,6 +1223,7 @@ extern "C" void Init_rubyeventmachine()
1204
1223
  rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2);
1205
1224
  rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1);
1206
1225
  rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
1226
+ rb_define_module_function (EmModule, "attach_sd", (VALUE(*)(...))t_attach_sd, 1);
1207
1227
  rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 4);
1208
1228
  rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
1209
1229
  rb_define_module_function (EmModule, "get_peer_cert", (VALUE(*)(...))t_get_peer_cert, 1);
@@ -1217,6 +1237,7 @@ extern "C" void Init_rubyeventmachine()
1217
1237
 
1218
1238
  rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2);
1219
1239
  rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1);
1240
+ rb_define_module_function (EmModule, "get_file_descriptor", (VALUE (*)(...))t_get_file_descriptor, 1);
1220
1241
  rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3);
1221
1242
  rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4);
1222
1243
  rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2);
@@ -50,6 +50,7 @@ module EventMachine
50
50
  #
51
51
  def initialize(list, concurrency = 1)
52
52
  raise ArgumentError, 'argument must be an array' unless list.respond_to?(:to_a)
53
+ raise ArgumentError, 'concurrency must be bigger than zero' unless (concurrency > 0)
53
54
  @list = list.to_a.dup
54
55
  @concurrency = concurrency
55
56
 
@@ -224,47 +225,7 @@ module EventMachine
224
225
  end
225
226
  end
226
227
 
227
- if __FILE__ == $0
228
- $:.unshift File.join(File.dirname(__FILE__), '..')
229
- require 'eventmachine'
230
-
231
- # TODO: real tests
232
- # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
233
- # TODO: support iter.pause/resume/stop/break/continue?
234
- # TODO: create some exceptions instead of using RuntimeError
235
- # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
236
-
237
- EM.run{
238
- EM::Iterator.new(1..50).each{ |num,iter| p num; iter.next }
239
- EM::Iterator.new([1,2,3], 10).each{ |num,iter| p num; iter.next }
240
-
241
- i = EM::Iterator.new(1..100, 5)
242
- i.each(proc{|num,iter|
243
- p num.to_s
244
- iter.next
245
- }, proc{
246
- p :done
247
- })
248
- EM.add_timer(0.03){
249
- i.concurrency = 1
250
- }
251
- EM.add_timer(0.04){
252
- i.concurrency = 3
253
- }
254
-
255
- EM::Iterator.new(100..150).map(proc{ |num,iter|
256
- EM.add_timer(0.01){ iter.return(num) }
257
- }, proc{ |results|
258
- p results
259
- })
260
-
261
- EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
262
- EM.system(cmd){ |output,status|
263
- hash[cmd] = status.exitstatus == 0 ? output.strip : nil
264
- iter.return(hash)
265
- }
266
- }, proc{ |results|
267
- p results
268
- })
269
- }
270
- end
228
+ # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
229
+ # TODO: support iter.pause/resume/stop/break/continue?
230
+ # TODO: create some exceptions instead of using RuntimeError
231
+ # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
@@ -409,8 +409,12 @@ module EventMachine
409
409
  #--
410
410
  # STARTTLS may not be issued before EHLO, or unless the user has chosen
411
411
  # to support it.
412
- # TODO, must support user-supplied certificates.
413
412
  #
413
+ # If :starttls_options is present and :starttls is set in the parms
414
+ # pass the options in :starttls_options to start_tls. Do this if you want to use
415
+ # your own certificate
416
+ # e.g. {:cert_chain_file => "/etc/ssl/cert.pem", :private_key_file => "/etc/ssl/private/cert.key"}
417
+
414
418
  def process_starttls
415
419
  if @@parms[:starttls]
416
420
  if @state.include?(:starttls)
@@ -419,7 +423,7 @@ module EventMachine
419
423
  send_data "503 EHLO required before STARTTLS\r\n"
420
424
  else
421
425
  send_data "220 Start TLS negotiation\r\n"
422
- start_tls
426
+ start_tls(@@parms[:starttls_options] || {})
423
427
  @state << :starttls
424
428
  end
425
429
  else
@@ -66,7 +66,15 @@ module EventMachine
66
66
 
67
67
  def post_init
68
68
  @requests = {}
69
- EM.add_periodic_timer(0.1, &method(:tick))
69
+ end
70
+
71
+ def start_timer
72
+ @timer ||= EM.add_periodic_timer(0.1, &method(:tick))
73
+ end
74
+
75
+ def stop_timer
76
+ EM.cancel_timer(@timer)
77
+ @timer = nil
70
78
  end
71
79
 
72
80
  def unbind
@@ -84,6 +92,13 @@ module EventMachine
84
92
  else
85
93
  @requests[id] = req
86
94
  end
95
+
96
+ start_timer
97
+ end
98
+
99
+ def deregister_request(id, req)
100
+ @requests.delete(id)
101
+ stop_timer if @requests.length == 0
87
102
  end
88
103
 
89
104
  def send_packet(pkt)
@@ -109,6 +124,7 @@ module EventMachine
109
124
  req = @requests[msg.id]
110
125
  if req
111
126
  @requests.delete(msg.id)
127
+ stop_timer if @requests.length == 0
112
128
  req.receive_answer(msg)
113
129
  end
114
130
  end
@@ -140,6 +156,7 @@ module EventMachine
140
156
  if @tries < @max_tries
141
157
  send
142
158
  else
159
+ @socket.deregister_request(@id, self)
143
160
  fail 'retries exceeded'
144
161
  end
145
162
  end
@@ -7,25 +7,25 @@ module EventMachine
7
7
  # A TickLoop is useful when one needs to distribute amounts of work
8
8
  # throughout ticks in order to maintain response times. It is also useful for
9
9
  # simple repeated checks and metrics.
10
- #
11
- # # Here we run through an array one item per tick until it is empty,
12
- # # printing each element.
13
- # # When the array is empty, we return :stop from the callback, and the
14
- # # loop will terminate.
15
- # # When the loop terminates, the on_stop callbacks will be called.
16
- # EM.run do
17
- # array = (1..100).to_a
18
- #
19
- # tickloop = EM.tick_loop do
20
- # if array.empty?
21
- # :stop
22
- # else
23
- # puts array.shift
24
- # end
25
- # end
26
- #
27
- # tickloop.on_stop { EM.stop }
28
- # end
10
+ # @example
11
+ # # Here we run through an array one item per tick until it is empty,
12
+ # # printing each element.
13
+ # # When the array is empty, we return :stop from the callback, and the
14
+ # # loop will terminate.
15
+ # # When the loop terminates, the on_stop callbacks will be called.
16
+ # EM.run do
17
+ # array = (1..100).to_a
18
+ #
19
+ # tickloop = EM.tick_loop do
20
+ # if array.empty?
21
+ # :stop
22
+ # else
23
+ # puts array.shift
24
+ # end
25
+ # end
26
+ #
27
+ # tickloop.on_stop { EM.stop }
28
+ # end
29
29
  #
30
30
  class TickLoop
31
31
 
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  end
@@ -156,7 +156,7 @@ module EventMachine
156
156
  # will start without release_machine being called and will immediately throw
157
157
 
158
158
  #
159
- if reactor_running? and @reactor_pid != Process.pid
159
+ if @reactor_running and @reactor_pid != Process.pid
160
160
  # Reactor was started in a different parent, meaning we have forked.
161
161
  # Clean up reactor state so a new reactor boots up in this child.
162
162
  stop_event_loop
@@ -531,6 +531,15 @@ module EventMachine
531
531
  s
532
532
  end
533
533
 
534
+ # Attach to an existing socket's file descriptor. The socket may have been
535
+ # started with {EventMachine.start_server}.
536
+ def self.attach_server sock, handler=nil, *args, &block
537
+ klass = klass_from_handler(Connection, handler, *args)
538
+ sd = sock.respond_to?(:fileno) ? sock.fileno : sock
539
+ s = attach_sd(sd)
540
+ @acceptors[s] = [klass,args,block,sock]
541
+ s
542
+ end
534
543
 
535
544
  # Stop a TCP server socket that was started with {EventMachine.start_server}.
536
545
  # @see EventMachine.start_server
@@ -1181,7 +1190,7 @@ module EventMachine
1181
1190
  #
1182
1191
  # @return [Boolean] true if the EventMachine reactor loop is currently running
1183
1192
  def self.reactor_running?
1184
- (@reactor_running || false)
1193
+ @reactor_running && Process.pid == @reactor_pid
1185
1194
  end
1186
1195
 
1187
1196
 
@@ -31,8 +31,13 @@ else
31
31
  def hack_cross_compilation(ext)
32
32
  # inject 1.8/1.9 pure-ruby entry point
33
33
  # HACK: add these dependencies to the task instead of using cross_compiling
34
- ext.cross_platform.each do |platform|
35
- Rake::Task["native:#{GEMSPEC.name}:#{platform}"].prerequisites.unshift "lib/#{ext.name}.rb"
34
+ if ext.cross_platform.is_a?(Array)
35
+ ext.cross_platform.each do |platform|
36
+ task = "native:#{GEMSPEC.name}:#{platform}"
37
+ if Rake::Task.task_defined?(task)
38
+ Rake::Task[task].prerequisites.unshift "lib/#{ext.name}.rb"
39
+ end
40
+ end
36
41
  end
37
42
  end
38
43
 
@@ -4,6 +4,7 @@ require 'socket'
4
4
  class TestAttach < Test::Unit::TestCase
5
5
  class EchoServer < EM::Connection
6
6
  def receive_data data
7
+ $received_data << data
7
8
  send_data data
8
9
  end
9
10
  end
@@ -31,12 +32,14 @@ class TestAttach < Test::Unit::TestCase
31
32
  def setup
32
33
  @port = next_port
33
34
  $read, $r, $w, $fd = nil
35
+ $received_data = ""
34
36
  end
35
37
 
36
38
  def teardown
37
39
  [$r, $w].each do |io|
38
40
  io.close rescue nil
39
41
  end
42
+ $received_data = nil
40
43
  end
41
44
 
42
45
  def test_attach
@@ -63,6 +66,27 @@ class TestAttach < Test::Unit::TestCase
63
66
  end
64
67
  end
65
68
 
69
+ def test_attach_server
70
+ $before = TCPServer.new("127.0.0.1", @port)
71
+ sig = nil
72
+ EM.run {
73
+ sig = EM.attach_server $before, EchoServer
74
+
75
+ handler = Class.new(EM::Connection) do
76
+ def initialize
77
+ send_data "hello world"
78
+ close_connection_after_writing
79
+ EM.add_timer(0.1) { EM.stop }
80
+ end
81
+ end
82
+ EM.connect("127.0.0.1", @port, handler)
83
+ }
84
+
85
+ assert_equal false, $before.closed?
86
+ assert_equal "hello world", $received_data
87
+ assert sig.is_a?(Integer)
88
+ end
89
+
66
90
  def test_attach_pipe
67
91
  EM.run{
68
92
  $r, $w = IO.pipe
@@ -30,4 +30,24 @@ class TestConnectionCount < Test::Unit::TestCase
30
30
  assert_equal(1, $server_conns)
31
31
  assert_equal(4, $client_conns + $server_conns)
32
32
  end
33
- end
33
+
34
+ module DoubleCloseClient
35
+ def unbind
36
+ close_connection
37
+ $num_close_scheduled_1 = EM.num_close_scheduled
38
+ EM.next_tick do
39
+ $num_close_scheduled_2 = EM.num_close_scheduled
40
+ EM.stop
41
+ end
42
+ end
43
+ end
44
+
45
+ def test_num_close_scheduled
46
+ EM.run {
47
+ assert_equal(0, EM.num_close_scheduled)
48
+ EM.connect("127.0.0.1", 9999, DoubleCloseClient) # nothing listening on 9999
49
+ }
50
+ assert_equal(1, $num_close_scheduled_1)
51
+ assert_equal(0, $num_close_scheduled_2)
52
+ end
53
+ end
@@ -126,5 +126,20 @@ class TestEpoll < Test::Unit::TestCase
126
126
  File.unlink(fn) if File.exist?(fn)
127
127
  end
128
128
 
129
+ def test_attach_detach
130
+ EM.epoll
131
+ EM.run {
132
+ EM.add_timer(0.01) { EM.stop }
133
+
134
+ r, w = IO.pipe
135
+
136
+ # This tests a regression where detach in the same tick as attach crashes EM
137
+ EM.watch(r) do |connection|
138
+ connection.detach
139
+ end
140
+ }
141
+
142
+ assert true
143
+ end
129
144
  end
130
145
 
@@ -9,15 +9,17 @@ class TestIdleConnection < Test::Unit::TestCase
9
9
  $idle_time = conn.get_idle_time
10
10
  conn.send_data "GET / HTTP/1.0\r\n\r\n"
11
11
  EM.next_tick{
12
- $idle_time_after_send = conn.get_idle_time
13
- conn.close_connection
14
- EM.stop
12
+ EM.next_tick{
13
+ $idle_time_after_send = conn.get_idle_time
14
+ conn.close_connection
15
+ EM.stop
16
+ }
15
17
  }
16
18
  }
17
19
  }
18
20
 
19
21
  assert_in_delta 3, $idle_time, 0.2
20
- assert_equal 0, $idle_time_after_send
22
+ assert_in_delta 0, $idle_time_after_send, 0.1
21
23
  end
22
24
  end
23
25
  end
@@ -0,0 +1,97 @@
1
+ require 'em_test_helper'
2
+
3
+ class TestIterator < Test::Unit::TestCase
4
+
5
+ def get_time
6
+ EM.current_time.strftime('%H:%M:%S')
7
+ end
8
+
9
+ def test_default_concurrency
10
+ items = {}
11
+ list = 1..10
12
+ EM.run {
13
+ EM::Iterator.new(list).each( proc {|num,iter|
14
+ time = get_time
15
+ items[time] ||= []
16
+ items[time] << num
17
+ EM::Timer.new(1) {iter.next}
18
+ }, proc {EM.stop})
19
+ }
20
+ assert_equal(10, items.keys.size)
21
+ assert_equal((list).to_a, items.values.flatten)
22
+ end
23
+
24
+ def test_concurrency_bigger_than_list_size
25
+ items = {}
26
+ list = [1,2,3]
27
+ EM.run {
28
+ EM::Iterator.new(list,10).each(proc {|num,iter|
29
+ time = get_time
30
+ items[time] ||= []
31
+ items[time] << num
32
+ EM::Timer.new(1) {iter.next}
33
+ }, proc {EM.stop})
34
+ }
35
+ assert_equal(1, items.keys.size)
36
+ assert_equal((list).to_a, items.values.flatten)
37
+ end
38
+
39
+
40
+ def test_changing_concurrency_affects_active_iteration
41
+ items = {}
42
+ list = 1..25
43
+ EM.run {
44
+ i = EM::Iterator.new(list,5)
45
+ i.each(proc {|num,iter|
46
+ time = get_time
47
+ items[time] ||= []
48
+ items[time] << num
49
+ EM::Timer.new(1) {iter.next}
50
+ }, proc {EM.stop})
51
+ EM.add_timer(1){
52
+ i.concurrency = 1
53
+ }
54
+ EM.add_timer(3){
55
+ i.concurrency = 3
56
+ }
57
+ }
58
+ assert_equal(9, items.keys.size)
59
+ assert_equal((list).to_a, items.values.flatten)
60
+ end
61
+
62
+ def test_map
63
+ list = 100..150
64
+ EM.run {
65
+ EM::Iterator.new(list).map(proc{ |num,iter|
66
+ EM.add_timer(0.01){ iter.return(num) }
67
+ }, proc{ |results|
68
+ assert_equal((list).to_a.size, results.size)
69
+ EM.stop
70
+ })
71
+ }
72
+ end
73
+
74
+ def test_inject
75
+ list = %w[ pwd uptime uname date ]
76
+ EM.run {
77
+ EM::Iterator.new(list, 2).inject({}, proc{ |hash,cmd,iter|
78
+ EM.system(cmd){ |output,status|
79
+ hash[cmd] = status.exitstatus == 0 ? output.strip : nil
80
+ iter.return(hash)
81
+ }
82
+ }, proc{ |results|
83
+ assert_equal(results.keys, list)
84
+ EM.stop
85
+ })
86
+ }
87
+ end
88
+
89
+ def test_concurrency_is_0
90
+ EM.run {
91
+ assert_raise ArgumentError do
92
+ EM::Iterator.new(1..5,0)
93
+ end
94
+ EM.stop
95
+ }
96
+ end
97
+ end
@@ -67,6 +67,30 @@ class TestPause < Test::Unit::TestCase
67
67
  end
68
68
  end
69
69
  end
70
+
71
+ def test_pause_in_receive_data
72
+ incoming = []
73
+
74
+ test_server = Module.new do
75
+ define_method(:receive_data) do |data|
76
+ incoming << data
77
+ pause
78
+ EM.add_timer(0.5){ close_connection }
79
+ end
80
+ define_method(:unbind) do
81
+ EM.stop
82
+ end
83
+ end
84
+
85
+ EM.run do
86
+ EM.start_server "127.0.0.1", @port, test_server
87
+ cli = EM.connect "127.0.0.1", @port
88
+ cli.send_data 'a'*(17*1024)
89
+ end
90
+
91
+ assert_equal 1, incoming.size
92
+ assert_equal 16*1024, incoming[0].bytesize
93
+ end
70
94
  else
71
95
  warn "EM.pause_connection not implemented, skipping tests in #{__FILE__}"
72
96
 
metadata CHANGED
@@ -1,90 +1,93 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: eventmachine
3
- version: !ruby/object:Gem::Version
4
- hash: 17
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 3
10
- version: 1.0.3
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Francis Cianfrocca
14
9
  - Aman Gupta
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2013-03-08 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2014-12-19 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: rake-compiler
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
25
18
  none: false
26
- requirements:
19
+ requirements:
27
20
  - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 57
30
- segments:
31
- - 0
32
- - 8
33
- - 3
21
+ - !ruby/object:Gem::Version
34
22
  version: 0.8.3
35
23
  type: :development
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: yard
39
24
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 0.8.3
31
+ - !ruby/object:Gem::Dependency
32
+ name: yard
33
+ requirement: !ruby/object:Gem::Requirement
41
34
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 31
46
- segments:
47
- - 0
48
- - 8
49
- - 5
50
- - 2
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
51
38
  version: 0.8.5.2
52
39
  type: :development
53
- version_requirements: *id002
54
- - !ruby/object:Gem::Dependency
55
- name: bluecloth
56
40
  prerelease: false
57
- requirement: &id003 !ruby/object:Gem::Requirement
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 0.8.5.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: bluecloth
49
+ requirement: !ruby/object:Gem::Requirement
58
50
  none: false
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
- version: "0"
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
66
55
  type: :development
67
- version_requirements: *id003
68
- description: |-
69
- EventMachine implements a fast, single-threaded engine for arbitrary network
70
- communications. It's extremely easy to use in Ruby. EventMachine wraps all
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ description: ! 'EventMachine implements a fast, single-threaded engine for arbitrary
64
+ network
65
+
66
+ communications. It''s extremely easy to use in Ruby. EventMachine wraps all
67
+
71
68
  interactions with IP sockets, allowing programs to concentrate on the
69
+
72
70
  implementation of network protocols. It can be used to create both network
71
+
73
72
  servers and clients. To create a server or client, a Ruby program only needs
73
+
74
74
  to specify the IP address and port, and provide a Module that implements the
75
+
75
76
  communications protocol. Implementations of several standard network protocols
77
+
76
78
  are provided with the package, primarily to serve as examples. The real goal
79
+
77
80
  of EventMachine is to enable programs to easily interface with other programs
78
- using TCP/IP, especially if custom protocols are required.
79
- email:
81
+
82
+ using TCP/IP, especially if custom protocols are required.'
83
+ email:
80
84
  - garbagecat10@gmail.com
81
85
  - aman@tmm1.net
82
86
  executables: []
83
-
84
- extensions:
87
+ extensions:
85
88
  - ext/extconf.rb
86
89
  - ext/fastfilereader/extconf.rb
87
- extra_rdoc_files:
90
+ extra_rdoc_files:
88
91
  - README.md
89
92
  - docs/DocumentationGuidesIndex.md
90
93
  - docs/GettingStarted.md
@@ -100,7 +103,7 @@ extra_rdoc_files:
100
103
  - docs/old/SMTP
101
104
  - docs/old/SPAWNED_PROCESSES
102
105
  - docs/old/TODO
103
- files:
106
+ files:
104
107
  - .gitignore
105
108
  - .travis.yml
106
109
  - .yardopts
@@ -232,6 +235,7 @@ files:
232
235
  - tests/test_httpclient2.rb
233
236
  - tests/test_idle_connection.rb
234
237
  - tests/test_inactivity_timeout.rb
238
+ - tests/test_iterator.rb
235
239
  - tests/test_kb.rb
236
240
  - tests/test_line_protocol.rb
237
241
  - tests/test_ltp.rb
@@ -267,10 +271,11 @@ files:
267
271
  - tests/test_ud.rb
268
272
  - tests/test_unbind_reason.rb
269
273
  homepage: http://rubyeventmachine.com
270
- licenses: []
271
-
274
+ licenses:
275
+ - Ruby
276
+ - GPL
272
277
  post_install_message:
273
- rdoc_options:
278
+ rdoc_options:
274
279
  - --title
275
280
  - EventMachine
276
281
  - --main
@@ -279,32 +284,25 @@ rdoc_options:
279
284
  - lib/em/version
280
285
  - -x
281
286
  - lib/jeventmachine
282
- require_paths:
287
+ require_paths:
283
288
  - lib
284
- required_ruby_version: !ruby/object:Gem::Requirement
289
+ required_ruby_version: !ruby/object:Gem::Requirement
285
290
  none: false
286
- requirements:
287
- - - ">="
288
- - !ruby/object:Gem::Version
289
- hash: 3
290
- segments:
291
- - 0
292
- version: "0"
293
- required_rubygems_version: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - ! '>='
293
+ - !ruby/object:Gem::Version
294
+ version: '0'
295
+ required_rubygems_version: !ruby/object:Gem::Requirement
294
296
  none: false
295
- requirements:
296
- - - ">="
297
- - !ruby/object:Gem::Version
298
- hash: 3
299
- segments:
300
- - 0
301
- version: "0"
297
+ requirements:
298
+ - - ! '>='
299
+ - !ruby/object:Gem::Version
300
+ version: '0'
302
301
  requirements: []
303
-
304
302
  rubyforge_project: eventmachine
305
- rubygems_version: 1.8.24
303
+ rubygems_version: 1.8.23
306
304
  signing_key:
307
305
  specification_version: 3
308
306
  summary: Ruby/EventMachine library
309
307
  test_files: []
310
-
308
+ has_rdoc: