eventmachine 1.0.3-x86-mingw32 → 1.2.0.dev.2-x86-mingw32

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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +84 -1
  3. data/README.md +6 -7
  4. data/ext/binder.cpp +10 -10
  5. data/ext/binder.h +5 -5
  6. data/ext/cmain.cpp +173 -61
  7. data/ext/ed.cpp +262 -127
  8. data/ext/ed.h +50 -30
  9. data/ext/em.cpp +491 -445
  10. data/ext/em.h +101 -36
  11. data/ext/eventmachine.h +67 -51
  12. data/ext/extconf.rb +124 -31
  13. data/ext/fastfilereader/extconf.rb +9 -2
  14. data/ext/fastfilereader/mapper.cpp +3 -1
  15. data/ext/fastfilereader/rubymain.cpp +7 -7
  16. data/ext/kb.cpp +1 -1
  17. data/ext/pipe.cpp +11 -4
  18. data/ext/project.h +26 -6
  19. data/ext/rubymain.cpp +408 -201
  20. data/ext/ssl.cpp +167 -20
  21. data/ext/ssl.h +11 -2
  22. data/java/src/com/rubyeventmachine/EmReactor.java +16 -0
  23. data/java/src/com/rubyeventmachine/EventableChannel.java +2 -0
  24. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
  25. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +55 -10
  26. data/lib/1.9/fastfilereaderext.so +0 -0
  27. data/lib/1.9/rubyeventmachine.so +0 -0
  28. data/lib/2.0/fastfilereaderext.so +0 -0
  29. data/lib/2.0/rubyeventmachine.so +0 -0
  30. data/lib/2.1/fastfilereaderext.so +0 -0
  31. data/lib/2.1/rubyeventmachine.so +0 -0
  32. data/lib/2.2/fastfilereaderext.so +0 -0
  33. data/lib/2.2/rubyeventmachine.so +0 -0
  34. data/lib/2.3/fastfilereaderext.so +0 -0
  35. data/lib/2.3/rubyeventmachine.so +0 -0
  36. data/lib/em/buftok.rb +34 -85
  37. data/lib/em/channel.rb +5 -0
  38. data/lib/em/completion.rb +2 -2
  39. data/lib/em/connection.rb +62 -4
  40. data/lib/em/iterator.rb +30 -48
  41. data/lib/em/pool.rb +1 -1
  42. data/lib/em/protocols/httpclient.rb +31 -11
  43. data/lib/em/protocols/line_and_text.rb +4 -4
  44. data/lib/em/protocols/linetext2.rb +44 -39
  45. data/lib/em/protocols/smtpclient.rb +60 -31
  46. data/lib/em/protocols/smtpserver.rb +32 -9
  47. data/lib/em/pure_ruby.rb +8 -3
  48. data/lib/em/queue.rb +16 -7
  49. data/lib/em/resolver.rb +64 -24
  50. data/lib/em/threaded_resource.rb +2 -2
  51. data/lib/em/tick_loop.rb +19 -19
  52. data/lib/em/version.rb +1 -1
  53. data/lib/eventmachine.rb +96 -49
  54. data/lib/jeventmachine.rb +17 -0
  55. data/rakelib/package.rake +31 -4
  56. data/tests/dhparam.pem +13 -0
  57. data/tests/em_test_helper.rb +87 -0
  58. data/tests/test_attach.rb +25 -0
  59. data/tests/test_basic.rb +27 -38
  60. data/tests/test_channel.rb +14 -1
  61. data/tests/test_completion.rb +1 -0
  62. data/tests/test_connection_count.rb +22 -1
  63. data/tests/test_connection_write.rb +35 -0
  64. data/tests/test_defer.rb +17 -0
  65. data/tests/test_epoll.rb +26 -14
  66. data/tests/test_file_watch.rb +1 -0
  67. data/tests/test_fork.rb +75 -0
  68. data/tests/test_httpclient.rb +43 -0
  69. data/tests/test_idle_connection.rb +6 -4
  70. data/tests/test_ipv4.rb +125 -0
  71. data/tests/test_ipv6.rb +131 -0
  72. data/tests/test_iterator.rb +115 -0
  73. data/tests/test_kb.rb +19 -25
  74. data/tests/test_ltp2.rb +20 -0
  75. data/tests/test_many_fds.rb +22 -0
  76. data/tests/test_pause.rb +29 -0
  77. data/tests/test_pool.rb +2 -0
  78. data/tests/test_process_watch.rb +2 -0
  79. data/tests/test_processes.rb +7 -7
  80. data/tests/test_queue.rb +14 -0
  81. data/tests/test_resolver.rb +56 -7
  82. data/tests/test_set_sock_opt.rb +2 -0
  83. data/tests/test_smtpclient.rb +20 -0
  84. data/tests/test_ssl_args.rb +2 -2
  85. data/tests/test_ssl_dhparam.rb +83 -0
  86. data/tests/test_ssl_ecdh_curve.rb +79 -0
  87. data/tests/test_ssl_extensions.rb +49 -0
  88. data/tests/test_ssl_methods.rb +22 -5
  89. data/tests/test_ssl_protocols.rb +246 -0
  90. data/tests/test_ssl_verify.rb +103 -59
  91. data/tests/test_system.rb +4 -0
  92. data/tests/test_threaded_resource.rb +8 -0
  93. data/tests/test_unbind_reason.rb +5 -1
  94. metadata +173 -107
  95. data/.gitignore +0 -21
  96. data/.travis.yml +0 -12
  97. data/.yardopts +0 -7
  98. data/Gemfile +0 -2
  99. data/Rakefile +0 -20
  100. data/eventmachine.gemspec +0 -36
  101. data/rakelib/cpp.rake_example +0 -77
@@ -32,20 +32,20 @@ module EventMachine
32
32
  # for a version which is optimized for correctness with regard to binary text blocks
33
33
  # that can switch back to line mode.
34
34
  class LineAndTextProtocol < Connection
35
- MaxLineLength = 16*1024
36
35
  MaxBinaryLength = 32*1024*1024
37
36
 
38
37
  def initialize *args
39
38
  super
40
39
  lbp_init_line_state
41
40
  end
41
+
42
42
  def receive_data data
43
43
  if @lbp_mode == :lines
44
44
  begin
45
- @lpb_buffer.extract(data).each do |line|
45
+ @lpb_buffer.extract(data).each do |line|
46
46
  receive_line(line.chomp) if respond_to?(:receive_line)
47
47
  end
48
- rescue Exception
48
+ rescue
49
49
  receive_error('overlength line') if respond_to?(:receive_error)
50
50
  close_connection
51
51
  return
@@ -116,7 +116,7 @@ module EventMachine
116
116
  #--
117
117
  # For internal use, establish protocol baseline for handling lines.
118
118
  def lbp_init_line_state
119
- @lpb_buffer = BufferedTokenizer.new("\n", MaxLineLength)
119
+ @lpb_buffer = BufferedTokenizer.new("\n")
120
120
  @lbp_mode = :lines
121
121
  end
122
122
  private :lbp_init_line_state
@@ -37,11 +37,10 @@ module EventMachine
37
37
  # When we get around to that, call #receive_error if the user defined it, otherwise
38
38
  # throw exceptions.
39
39
 
40
- MaxLineLength = 16*1024
41
40
  MaxBinaryLength = 32*1024*1024
42
41
 
43
42
  #--
44
- # Will be called recursively until there's no data to read.
43
+ # Will loop internally until there's no data left to read.
45
44
  # That way the user-defined handlers we call can modify the
46
45
  # handling characteristics on a per-token basis.
47
46
  #
@@ -53,45 +52,51 @@ module EventMachine
53
52
  @lt2_delimiter ||= "\n"
54
53
  @lt2_linebuffer ||= []
55
54
 
56
- if @lt2_mode == :lines
57
- if ix = data.index( @lt2_delimiter )
58
- @lt2_linebuffer << data[0...ix]
59
- ln = @lt2_linebuffer.join
60
- @lt2_linebuffer.clear
61
- if @lt2_delimiter == "\n"
62
- ln.chomp!
55
+ remaining_data = data
56
+
57
+ while remaining_data.length > 0
58
+ if @lt2_mode == :lines
59
+ if ix = remaining_data.index( @lt2_delimiter )
60
+ @lt2_linebuffer << remaining_data[0...ix]
61
+ ln = @lt2_linebuffer.join
62
+ @lt2_linebuffer.clear
63
+ if @lt2_delimiter == "\n"
64
+ ln.chomp!
65
+ end
66
+ receive_line ln
67
+ remaining_data = remaining_data[(ix+@lt2_delimiter.length)..-1]
68
+ else
69
+ @lt2_linebuffer << remaining_data
70
+ remaining_data = ""
63
71
  end
64
- receive_line ln
65
- receive_data data[(ix+@lt2_delimiter.length)..-1]
66
- else
67
- @lt2_linebuffer << data
68
- end
69
- elsif @lt2_mode == :text
70
- if @lt2_textsize
71
- needed = @lt2_textsize - @lt2_textpos
72
- will_take = if data.length > needed
73
- needed
74
- else
75
- data.length
76
- end
77
-
78
- @lt2_textbuffer << data[0...will_take]
79
- tail = data[will_take..-1]
80
-
81
- @lt2_textpos += will_take
82
- if @lt2_textpos >= @lt2_textsize
83
- # Reset line mode (the default behavior) BEFORE calling the
84
- # receive_binary_data. This makes it possible for user code
85
- # to call set_text_mode, enabling chains of text blocks
86
- # (which can possibly be of different sizes).
87
- set_line_mode
88
- receive_binary_data @lt2_textbuffer.join
89
- receive_end_of_binary_data
72
+ elsif @lt2_mode == :text
73
+ if @lt2_textsize
74
+ needed = @lt2_textsize - @lt2_textpos
75
+ will_take = if remaining_data.length > needed
76
+ needed
77
+ else
78
+ remaining_data.length
79
+ end
80
+
81
+ @lt2_textbuffer << remaining_data[0...will_take]
82
+ tail = remaining_data[will_take..-1]
83
+
84
+ @lt2_textpos += will_take
85
+ if @lt2_textpos >= @lt2_textsize
86
+ # Reset line mode (the default behavior) BEFORE calling the
87
+ # receive_binary_data. This makes it possible for user code
88
+ # to call set_text_mode, enabling chains of text blocks
89
+ # (which can possibly be of different sizes).
90
+ set_line_mode
91
+ receive_binary_data @lt2_textbuffer.join
92
+ receive_end_of_binary_data
93
+ end
94
+
95
+ remaining_data = tail
96
+ else
97
+ receive_binary_data remaining_data
98
+ remaining_data = ""
90
99
  end
91
-
92
- receive_data tail
93
- else
94
- receive_binary_data data
95
100
  end
96
101
  end
97
102
  end
@@ -48,20 +48,20 @@ module EventMachine
48
48
  # puts 'Email failed!'
49
49
  # }
50
50
  #
51
- # Sending generated emails (using mailfactory)
51
+ # Sending generated emails (using Mail)
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 = Mail.new do
54
+ # from 'alice@example.com'
55
+ # to 'bob@example.com'
56
+ # subject 'This is a test email'
57
+ # body 'Hello, world!'
58
+ # end
59
59
  #
60
60
  # email = EM::P::SmtpClient.send(
61
- # :domain=>'site.com',
62
- # :from=>mail.from,
61
+ # :domain=>'example.com',
62
+ # :from=>mail.from.first,
63
63
  # :to=>mail.to,
64
- # :content=>"#{mail.to_s}\r\n.\r\n"
64
+ # :message=>mail.to_s
65
65
  # )
66
66
  #
67
67
  class SmtpClient < Connection
@@ -108,25 +108,29 @@ module EventMachine
108
108
  # of each requested recipient is available after the call completes. TODO, we should define
109
109
  # an overridable stub that will be called on rejection of a recipient or a sender, giving
110
110
  # user code the chance to try again or abort the connection.
111
- # :header => Required hash of values to be transmitted in the header of the message.
112
- # The hash keys are the names of the headers (do NOT append a trailing colon), and the values are strings
113
- # containing the header values. TODO, support Arrays of header values, which would cause us to
114
- # send that specific header line more than once.
111
+ #
112
+ # One of either :message, :content, or :header and :body is required:
113
+ #
114
+ # :message => String
115
+ # A valid RFC2822 Internet Message.
116
+ # :content => String
117
+ # Raw data which MUST be in correct SMTP body format, with escaped leading dots and a trailing
118
+ # dot line.
119
+ # :header => String or Hash of values to be transmitted in the header of the message.
120
+ # The hash keys are the names of the headers (do NOT append a trailing colon), and the values
121
+ # are strings containing the header values. TODO, support Arrays of header values, which would
122
+ # cause us to send that specific header line more than once.
115
123
  #
116
124
  # @example
117
125
  # :header => {"Subject" => "Bogus", "CC" => "myboss@example.com"}
118
126
  #
119
- # :body => Optional string, defaults blank.
127
+ # :body => Optional String or Array of Strings, defaults blank.
120
128
  # This will be passed as the body of the email message.
121
129
  # TODO, this needs to be significantly beefed up. As currently written, this requires the caller
122
130
  # to properly format the input into CRLF-delimited lines of 7-bit characters in the standard
123
131
  # SMTP transmission format. We need to be able to automatically convert binary data, and add
124
- # correct line-breaks to text data. I think the :body parameter should remain as it is, and we
125
- # should add a :content parameter that contains autoconversions and/or conversion parameters.
126
- # Then we can check if either :body or :content is present and do the right thing.
127
- # :content => Optional array or string
128
- # Alternative to providing header and body, an array or string of raw data which MUST be in
129
- # correct SMTP body format, including a trailing dot line
132
+ # correct line-breaks to text data.
133
+ #
130
134
  # :verbose => Optional.
131
135
  # If true, will cause a lot of information (including the server-side of the
132
136
  # conversation) to be dumped to $>.
@@ -233,12 +237,15 @@ module EventMachine
233
237
  close_connection_after_writing
234
238
  end
235
239
 
240
+ def send_ehlo
241
+ send_data "EHLO #{@args[:domain]}\r\n"
242
+ end
243
+
236
244
  def receive_signon
237
245
  return invoke_error unless @range == 2
238
- send_data "EHLO #{@args[:domain]}\r\n"
246
+ send_ehlo
239
247
  @responder = :receive_ehlo_response
240
248
  end
241
-
242
249
  def receive_ehlo_response
243
250
  return invoke_error unless @range == 2
244
251
  @server_caps = @msg
@@ -258,6 +265,15 @@ module EventMachine
258
265
  def receive_starttls_response
259
266
  return invoke_error unless @range == 2
260
267
  start_tls
268
+ invoke_ehlo_over_tls
269
+ end
270
+
271
+ def invoke_ehlo_over_tls
272
+ send_ehlo
273
+ @responder = :receive_ehlo_over_tls_response
274
+ end
275
+ def receive_ehlo_over_tls_response
276
+ return invoke_error unless @range == 2
261
277
  invoke_auth
262
278
  end
263
279
 
@@ -316,6 +332,10 @@ module EventMachine
316
332
  invoke_rcpt_to
317
333
  end
318
334
 
335
+ def escape_leading_dots(s)
336
+ s.gsub(/^\./, '..')
337
+ end
338
+
319
339
  def invoke_data
320
340
  send_data "DATA\r\n"
321
341
  @responder = :receive_data_response
@@ -323,25 +343,34 @@ module EventMachine
323
343
  def receive_data_response
324
344
  return invoke_error unless @range == 3
325
345
 
326
- # The data to send can be given either in @args[:content] (an array or string of raw data
327
- # which MUST be in correct SMTP body format, including a trailing dot line), or a header and
328
- # body given in @args[:header] and @args[:body].
346
+ # The data to send can be given in either @args[:message], @args[:content], or the
347
+ # combination of @args[:header] and @args[:body].
348
+ #
349
+ # - @args[:message] (String) MUST be a valid RFC2822 Internet Message
329
350
  #
330
- if @args[:content]
351
+ # - @args[:content] (String) MUST be in correct SMTP body format, with escaped
352
+ # leading dots and a trailing dot line
353
+ #
354
+ # - @args[:header] (Hash or String)
355
+ # - @args[:body] (Array or String)
356
+ if @args[:message]
357
+ send_data escape_leading_dots(@args[:message].to_s)
358
+ send_data "\r\n.\r\n"
359
+ elsif @args[:content]
331
360
  send_data @args[:content].to_s
332
361
  else
333
362
  # The header can be a hash or an array.
334
363
  if @args[:header].is_a?(Hash)
335
- (@args[:header] || {}).each {|k,v| send_data "#{k}: #{v}\r\n" }
364
+ (@args[:header] || {}).each {|k,v| send_data escape_leading_dots("#{k}: #{v}\r\n") }
336
365
  else
337
- send_data @args[:header].to_s
366
+ send_data escape_leading_dots(@args[:header].to_s)
338
367
  end
339
368
  send_data "\r\n"
340
369
 
341
370
  if @args[:body].is_a?(Array)
342
- @args[:body].each {|e| send_data e}
371
+ @args[:body].each {|e| send_data escape_leading_dots(e)}
343
372
  else
344
- send_data @args[:body].to_s
373
+ send_data escape_leading_dots(@args[:body].to_s)
345
374
  end
346
375
 
347
376
  send_data "\r\n.\r\n"
@@ -227,18 +227,26 @@ module EventMachine
227
227
  process_unknown
228
228
  end
229
229
  end
230
-
230
+
231
231
  # TODO - implement this properly, the implementation is a stub!
232
- def process_vrfy
232
+ def process_help
233
233
  send_data "250 Ok, but unimplemented\r\n"
234
234
  end
235
+
236
+ # RFC2821, 3.5.3 Meaning of VRFY or EXPN Success Response:
237
+ # A server MUST NOT return a 250 code in response to a VRFY or EXPN
238
+ # command unless it has actually verified the address. In particular,
239
+ # a server MUST NOT return 250 if all it has done is to verify that the
240
+ # syntax given is valid. In that case, 502 (Command not implemented)
241
+ # or 500 (Syntax error, command unrecognized) SHOULD be returned.
242
+ #
235
243
  # TODO - implement this properly, the implementation is a stub!
236
- def process_help
237
- send_data "250 Ok, but unimplemented\r\n"
244
+ def process_vrfy
245
+ send_data "502 Command not implemented\r\n"
238
246
  end
239
247
  # TODO - implement this properly, the implementation is a stub!
240
248
  def process_expn
241
- send_data "250 Ok, but unimplemented\r\n"
249
+ send_data "502 Command not implemented\r\n"
242
250
  end
243
251
 
244
252
  #--
@@ -358,12 +366,23 @@ module EventMachine
358
366
  def process_auth_line(line)
359
367
  plain = line.unpack("m").first
360
368
  _,user,psw = plain.split("\000")
361
- if receive_plain_auth user,psw
369
+
370
+ succeeded = proc {
362
371
  send_data "235 authentication ok\r\n"
363
372
  @state << :auth
364
- else
373
+ }
374
+ failed = proc {
365
375
  send_data "535 invalid authentication\r\n"
376
+ }
377
+ auth = receive_plain_auth user,psw
378
+
379
+ if auth.respond_to?(:callback)
380
+ auth.callback(&succeeded)
381
+ auth.errback(&failed)
382
+ else
383
+ (auth ? succeeded : failed).call
366
384
  end
385
+
367
386
  @state.delete :auth_incomplete
368
387
  end
369
388
 
@@ -409,8 +428,12 @@ module EventMachine
409
428
  #--
410
429
  # STARTTLS may not be issued before EHLO, or unless the user has chosen
411
430
  # to support it.
412
- # TODO, must support user-supplied certificates.
413
431
  #
432
+ # If :starttls_options is present and :starttls is set in the parms
433
+ # pass the options in :starttls_options to start_tls. Do this if you want to use
434
+ # your own certificate
435
+ # e.g. {:cert_chain_file => "/etc/ssl/cert.pem", :private_key_file => "/etc/ssl/private/cert.key"}
436
+
414
437
  def process_starttls
415
438
  if @@parms[:starttls]
416
439
  if @state.include?(:starttls)
@@ -419,7 +442,7 @@ module EventMachine
419
442
  send_data "503 EHLO required before STARTTLS\r\n"
420
443
  else
421
444
  send_data "220 Start TLS negotiation\r\n"
422
- start_tls
445
+ start_tls(@@parms[:starttls_options] || {})
423
446
  @state << :starttls
424
447
  end
425
448
  else
@@ -66,6 +66,11 @@ module EventMachine
66
66
  def release_machine
67
67
  end
68
68
 
69
+
70
+ def stopping?
71
+ return Reactor.instance.stop_scheduled
72
+ end
73
+
69
74
  # @private
70
75
  def stop
71
76
  Reactor.instance.stop
@@ -273,7 +278,7 @@ module EventMachine
273
278
 
274
279
  HeartbeatInterval = 2
275
280
 
276
- attr_reader :current_loop_time
281
+ attr_reader :current_loop_time, :stop_scheduled
277
282
 
278
283
  def initialize
279
284
  initialize_for_run
@@ -393,7 +398,7 @@ module EventMachine
393
398
  100.times {
394
399
  @loopbreak_port = rand(10000) + 40000
395
400
  begin
396
- @loopbreak_reader.bind "localhost", @loopbreak_port
401
+ @loopbreak_reader.bind "127.0.0.1", @loopbreak_port
397
402
  bound = true
398
403
  break
399
404
  rescue
@@ -410,7 +415,7 @@ module EventMachine
410
415
 
411
416
  def signal_loopbreak
412
417
  #@loopbreak_writer.write '+' if @loopbreak_writer
413
- @loopbreak_writer.send('+',0,"localhost",@loopbreak_port) if @loopbreak_writer
418
+ @loopbreak_writer.send('+',0,"127.0.0.1",@loopbreak_port) if @loopbreak_writer
414
419
  end
415
420
 
416
421
  def set_timer_quantum interval_in_seconds
@@ -17,7 +17,8 @@ module EventMachine
17
17
  #
18
18
  class Queue
19
19
  def initialize
20
- @items = []
20
+ @sink = []
21
+ @drain = []
21
22
  @popq = []
22
23
  end
23
24
 
@@ -29,10 +30,14 @@ module EventMachine
29
30
  def pop(*a, &b)
30
31
  cb = EM::Callback(*a, &b)
31
32
  EM.schedule do
32
- if @items.empty?
33
+ if @drain.empty?
34
+ @drain = @sink
35
+ @sink = []
36
+ end
37
+ if @drain.empty?
33
38
  @popq << cb
34
39
  else
35
- cb.call @items.shift
40
+ cb.call @drain.shift
36
41
  end
37
42
  end
38
43
  nil # Always returns nil
@@ -43,8 +48,12 @@ module EventMachine
43
48
  # next reactor tick.
44
49
  def push(*items)
45
50
  EM.schedule do
46
- @items.push(*items)
47
- @popq.shift.call @items.shift until @items.empty? || @popq.empty?
51
+ @sink.push(*items)
52
+ unless @popq.empty?
53
+ @drain = @sink
54
+ @sink = []
55
+ @popq.shift.call @drain.shift until @drain.empty? || @popq.empty?
56
+ end
48
57
  end
49
58
  end
50
59
  alias :<< :push
@@ -52,13 +61,13 @@ module EventMachine
52
61
  # @return [Boolean]
53
62
  # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
54
63
  def empty?
55
- @items.empty?
64
+ @drain.empty? && @sink.empty?
56
65
  end
57
66
 
58
67
  # @return [Integer] Queue size
59
68
  # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
60
69
  def size
61
- @items.size
70
+ @drain.size + @sink.size
62
71
  end
63
72
 
64
73
  # @return [Integer] Waiting size