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

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