eventmachine-le 1.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/.gitignore +21 -0
  2. data/.yardopts +7 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +80 -0
  6. data/Rakefile +19 -0
  7. data/eventmachine-le.gemspec +42 -0
  8. data/ext/binder.cpp +124 -0
  9. data/ext/binder.h +46 -0
  10. data/ext/cmain.cpp +841 -0
  11. data/ext/ed.cpp +1995 -0
  12. data/ext/ed.h +424 -0
  13. data/ext/em.cpp +2377 -0
  14. data/ext/em.h +243 -0
  15. data/ext/eventmachine.h +126 -0
  16. data/ext/extconf.rb +166 -0
  17. data/ext/fastfilereader/extconf.rb +94 -0
  18. data/ext/fastfilereader/mapper.cpp +214 -0
  19. data/ext/fastfilereader/mapper.h +59 -0
  20. data/ext/fastfilereader/rubymain.cpp +127 -0
  21. data/ext/kb.cpp +79 -0
  22. data/ext/page.cpp +107 -0
  23. data/ext/page.h +51 -0
  24. data/ext/pipe.cpp +347 -0
  25. data/ext/project.h +155 -0
  26. data/ext/rubymain.cpp +1269 -0
  27. data/ext/ssl.cpp +468 -0
  28. data/ext/ssl.h +94 -0
  29. data/lib/em/buftok.rb +110 -0
  30. data/lib/em/callback.rb +58 -0
  31. data/lib/em/channel.rb +64 -0
  32. data/lib/em/completion.rb +304 -0
  33. data/lib/em/connection.rb +728 -0
  34. data/lib/em/deferrable.rb +210 -0
  35. data/lib/em/deferrable/pool.rb +2 -0
  36. data/lib/em/file_watch.rb +73 -0
  37. data/lib/em/future.rb +61 -0
  38. data/lib/em/iterator.rb +313 -0
  39. data/lib/em/messages.rb +66 -0
  40. data/lib/em/pool.rb +151 -0
  41. data/lib/em/process_watch.rb +45 -0
  42. data/lib/em/processes.rb +123 -0
  43. data/lib/em/protocols.rb +37 -0
  44. data/lib/em/protocols/header_and_content.rb +138 -0
  45. data/lib/em/protocols/httpclient.rb +279 -0
  46. data/lib/em/protocols/httpclient2.rb +600 -0
  47. data/lib/em/protocols/line_and_text.rb +125 -0
  48. data/lib/em/protocols/line_protocol.rb +29 -0
  49. data/lib/em/protocols/linetext2.rb +161 -0
  50. data/lib/em/protocols/memcache.rb +331 -0
  51. data/lib/em/protocols/object_protocol.rb +46 -0
  52. data/lib/em/protocols/postgres3.rb +246 -0
  53. data/lib/em/protocols/saslauth.rb +175 -0
  54. data/lib/em/protocols/smtpclient.rb +365 -0
  55. data/lib/em/protocols/smtpserver.rb +663 -0
  56. data/lib/em/protocols/socks4.rb +66 -0
  57. data/lib/em/protocols/stomp.rb +202 -0
  58. data/lib/em/protocols/tcptest.rb +54 -0
  59. data/lib/em/queue.rb +71 -0
  60. data/lib/em/resolver.rb +195 -0
  61. data/lib/em/spawnable.rb +84 -0
  62. data/lib/em/streamer.rb +118 -0
  63. data/lib/em/threaded_resource.rb +90 -0
  64. data/lib/em/tick_loop.rb +85 -0
  65. data/lib/em/timers.rb +106 -0
  66. data/lib/em/version.rb +3 -0
  67. data/lib/eventmachine-le.rb +10 -0
  68. data/lib/eventmachine.rb +1548 -0
  69. data/rakelib/cpp.rake_example +77 -0
  70. data/rakelib/package.rake +98 -0
  71. data/rakelib/test.rake +8 -0
  72. data/tests/client.crt +31 -0
  73. data/tests/client.key +51 -0
  74. data/tests/em_test_helper.rb +143 -0
  75. data/tests/test_attach.rb +148 -0
  76. data/tests/test_basic.rb +294 -0
  77. data/tests/test_channel.rb +62 -0
  78. data/tests/test_completion.rb +177 -0
  79. data/tests/test_connection_count.rb +33 -0
  80. data/tests/test_defer.rb +18 -0
  81. data/tests/test_deferrable.rb +35 -0
  82. data/tests/test_epoll.rb +134 -0
  83. data/tests/test_error_handler.rb +38 -0
  84. data/tests/test_exc.rb +28 -0
  85. data/tests/test_file_watch.rb +65 -0
  86. data/tests/test_futures.rb +170 -0
  87. data/tests/test_get_sock_opt.rb +37 -0
  88. data/tests/test_handler_check.rb +35 -0
  89. data/tests/test_hc.rb +155 -0
  90. data/tests/test_httpclient.rb +190 -0
  91. data/tests/test_httpclient2.rb +128 -0
  92. data/tests/test_inactivity_timeout.rb +54 -0
  93. data/tests/test_ipv4.rb +125 -0
  94. data/tests/test_ipv6.rb +131 -0
  95. data/tests/test_iterator.rb +110 -0
  96. data/tests/test_kb.rb +34 -0
  97. data/tests/test_line_protocol.rb +33 -0
  98. data/tests/test_ltp.rb +138 -0
  99. data/tests/test_ltp2.rb +288 -0
  100. data/tests/test_next_tick.rb +104 -0
  101. data/tests/test_object_protocol.rb +36 -0
  102. data/tests/test_pause.rb +78 -0
  103. data/tests/test_pending_connect_timeout.rb +52 -0
  104. data/tests/test_pool.rb +196 -0
  105. data/tests/test_process_watch.rb +48 -0
  106. data/tests/test_processes.rb +133 -0
  107. data/tests/test_proxy_connection.rb +168 -0
  108. data/tests/test_pure.rb +88 -0
  109. data/tests/test_queue.rb +50 -0
  110. data/tests/test_resolver.rb +55 -0
  111. data/tests/test_running.rb +14 -0
  112. data/tests/test_sasl.rb +47 -0
  113. data/tests/test_send_file.rb +217 -0
  114. data/tests/test_servers.rb +33 -0
  115. data/tests/test_set_sock_opt.rb +41 -0
  116. data/tests/test_shutdown_hooks.rb +23 -0
  117. data/tests/test_smtpclient.rb +55 -0
  118. data/tests/test_smtpserver.rb +120 -0
  119. data/tests/test_spawn.rb +293 -0
  120. data/tests/test_ssl_args.rb +78 -0
  121. data/tests/test_ssl_methods.rb +48 -0
  122. data/tests/test_ssl_verify.rb +82 -0
  123. data/tests/test_threaded_resource.rb +55 -0
  124. data/tests/test_tick_loop.rb +59 -0
  125. data/tests/test_timers.rb +180 -0
  126. data/tests/test_ud.rb +8 -0
  127. data/tests/test_udp46.rb +53 -0
  128. data/tests/test_unbind_reason.rb +48 -0
  129. metadata +390 -0
@@ -0,0 +1,66 @@
1
+ module EventMachine
2
+ module Protocols
3
+ # Basic SOCKS v4 client implementation
4
+ #
5
+ # Use as you would any regular connection:
6
+ #
7
+ # class MyConn < EM::P::Socks4
8
+ # def post_init
9
+ # send_data("sup")
10
+ # end
11
+ #
12
+ # def receive_data(data)
13
+ # send_data("you said: #{data}")
14
+ # end
15
+ # end
16
+ #
17
+ # EM.connect socks_host, socks_port, MyConn, host, port
18
+ #
19
+ class Socks4 < Connection
20
+ def initialize(host, port)
21
+ @host = Socket.gethostbyname(host).last
22
+ @port = port
23
+ @socks_error_code = nil
24
+ @buffer = ''
25
+ setup_methods
26
+ end
27
+
28
+ def setup_methods
29
+ class << self
30
+ def post_init; socks_post_init; end
31
+ def receive_data(*a); socks_receive_data(*a); end
32
+ end
33
+ end
34
+
35
+ def restore_methods
36
+ class << self
37
+ remove_method :post_init
38
+ remove_method :receive_data
39
+ end
40
+ end
41
+
42
+ def socks_post_init
43
+ header = [4, 1, @port, @host, 0].flatten.pack("CCnA4C")
44
+ send_data(header)
45
+ end
46
+
47
+ def socks_receive_data(data)
48
+ @buffer << data
49
+ return if @buffer.size < 8
50
+
51
+ header_resp = @buffer.slice! 0, 8
52
+ _, r = header_resp.unpack("cc")
53
+ if r != 90
54
+ @socks_error_code = r
55
+ close_connection
56
+ return
57
+ end
58
+
59
+ restore_methods
60
+
61
+ post_init
62
+ receive_data(@buffer) unless @buffer.empty?
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,202 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 15 November 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ # Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol).
31
+ #
32
+ # == Usage example
33
+ #
34
+ # module StompClient
35
+ # include EM::Protocols::Stomp
36
+ #
37
+ # def connection_completed
38
+ # connect :login => 'guest', :passcode => 'guest'
39
+ # end
40
+ #
41
+ # def receive_msg msg
42
+ # if msg.command == "CONNECTED"
43
+ # subscribe '/some/topic'
44
+ # else
45
+ # p ['got a message', msg]
46
+ # puts msg.body
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # EM.run{
52
+ # EM.connect 'localhost', 61613, StompClient
53
+ # }
54
+ #
55
+ module Stomp
56
+ include LineText2
57
+
58
+ class Message
59
+ # The command associated with the message, usually 'CONNECTED' or 'MESSAGE'
60
+ attr_accessor :command
61
+ # Hash containing headers such as destination and message-id
62
+ attr_accessor :header
63
+ alias :headers :header
64
+ # Body of the message
65
+ attr_accessor :body
66
+
67
+ # @private
68
+ def initialize
69
+ @header = {}
70
+ @state = :precommand
71
+ @content_length = nil
72
+ end
73
+ # @private
74
+ def consume_line line
75
+ if @state == :precommand
76
+ unless line =~ /\A\s*\Z/
77
+ @command = line
78
+ @state = :headers
79
+ end
80
+ elsif @state == :headers
81
+ if line == ""
82
+ if @content_length
83
+ yield( [:sized_text, @content_length+1] )
84
+ else
85
+ @state = :body
86
+ yield( [:unsized_text] )
87
+ end
88
+ elsif line =~ /\A([^:]+):(.+)\Z/
89
+ k = $1.dup.strip
90
+ v = $2.dup.strip
91
+ @header[k] = v
92
+ if k == "content-length"
93
+ @content_length = v.to_i
94
+ end
95
+ else
96
+ # This is a protocol error. How to signal it?
97
+ end
98
+ elsif @state == :body
99
+ @body = line
100
+ yield( [:dispatch] )
101
+ end
102
+ end
103
+ end
104
+
105
+ # @private
106
+ def send_frame verb, headers={}, body=""
107
+ ary = [verb, "\n"]
108
+ headers.each {|k,v| ary << "#{k}:#{v}\n" }
109
+ ary << "content-length: #{body.to_s.length}\n"
110
+ ary << "content-type: text/plain; charset=UTF-8\n" unless headers.has_key? 'content-type'
111
+ ary << "\n"
112
+ ary << body.to_s
113
+ ary << "\0"
114
+ send_data ary.join
115
+ end
116
+
117
+ # @private
118
+ def receive_line line
119
+ @stomp_initialized || init_message_reader
120
+ @stomp_message.consume_line(line) {|outcome|
121
+ if outcome.first == :sized_text
122
+ set_text_mode outcome[1]
123
+ elsif outcome.first == :unsized_text
124
+ set_delimiter "\0"
125
+ elsif outcome.first == :dispatch
126
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
127
+ init_message_reader
128
+ end
129
+ }
130
+ end
131
+
132
+ # @private
133
+ def receive_binary_data data
134
+ @stomp_message.body = data[0..-2]
135
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
136
+ init_message_reader
137
+ end
138
+
139
+ # @private
140
+ def init_message_reader
141
+ @stomp_initialized = true
142
+ set_delimiter "\n"
143
+ set_line_mode
144
+ @stomp_message = Message.new
145
+ end
146
+
147
+ # Invoked with an incoming Stomp::Message received from the STOMP server
148
+ def receive_msg msg
149
+ # stub, overwrite this in your handler
150
+ end
151
+
152
+ # CONNECT command, for authentication
153
+ #
154
+ # connect :login => 'guest', :passcode => 'guest'
155
+ #
156
+ def connect parms={}
157
+ send_frame "CONNECT", parms
158
+ end
159
+
160
+ # SEND command, for publishing messages to a topic
161
+ #
162
+ # send '/topic/name', 'some message here'
163
+ #
164
+ def send destination, body, parms={}
165
+ send_frame "SEND", parms.merge( :destination=>destination ), body.to_s
166
+ end
167
+
168
+ # SUBSCRIBE command, for subscribing to topics
169
+ #
170
+ # subscribe '/topic/name', false
171
+ #
172
+ def subscribe dest, ack=false
173
+ send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")}
174
+ end
175
+
176
+ # ACK command, for acknowledging receipt of messages
177
+ #
178
+ # module StompClient
179
+ # include EM::P::Stomp
180
+ #
181
+ # def connection_completed
182
+ # connect :login => 'guest', :passcode => 'guest'
183
+ # # subscribe with ack mode
184
+ # subscribe '/some/topic', true
185
+ # end
186
+ #
187
+ # def receive_msg msg
188
+ # if msg.command == "MESSAGE"
189
+ # ack msg.headers['message-id']
190
+ # puts msg.body
191
+ # end
192
+ # end
193
+ # end
194
+ #
195
+ def ack msgid
196
+ send_frame "ACK", 'message-id'=> msgid
197
+ end
198
+
199
+ end
200
+ end
201
+ end
202
+
@@ -0,0 +1,54 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ # @private
31
+ class TcpConnectTester < Connection
32
+ include EventMachine::Deferrable
33
+
34
+ def self.test( host, port )
35
+ EventMachine.connect( host, port, self )
36
+ end
37
+
38
+ def post_init
39
+ @start_time = Time.now
40
+ end
41
+
42
+ def connection_completed
43
+ @completed = true
44
+ set_deferred_status :succeeded, (Time.now - @start_time)
45
+ close_connection
46
+ end
47
+
48
+ def unbind
49
+ set_deferred_status :failed, (Time.now - @start_time) unless @completed
50
+ end
51
+ end
52
+
53
+ end
54
+ end
data/lib/em/queue.rb ADDED
@@ -0,0 +1,71 @@
1
+ module EventMachine
2
+ # A cross thread, reactor scheduled, linear queue.
3
+ #
4
+ # This class provides a simple queue abstraction on top of the reactor
5
+ # scheduler. It services two primary purposes:
6
+ #
7
+ # * API sugar for stateful protocols
8
+ # * Pushing processing onto the reactor thread
9
+ #
10
+ # @example
11
+ #
12
+ # q = EM::Queue.new
13
+ # q.push('one', 'two', 'three')
14
+ # 3.times do
15
+ # q.pop { |msg| puts(msg) }
16
+ # end
17
+ #
18
+ class Queue
19
+ def initialize
20
+ @items = []
21
+ @popq = []
22
+ end
23
+
24
+ # Pop items off the queue, running the block on the reactor thread. The pop
25
+ # will not happen immediately, but at some point in the future, either in
26
+ # the next tick, if the queue has data, or when the queue is populated.
27
+ #
28
+ # @return [NilClass] nil
29
+ def pop(*a, &b)
30
+ cb = EM::Callback(*a, &b)
31
+ EM.schedule do
32
+ if @items.empty?
33
+ @popq << cb
34
+ else
35
+ cb.call @items.shift
36
+ end
37
+ end
38
+ nil # Always returns nil
39
+ end
40
+
41
+ # Push items onto the queue in the reactor thread. The items will not appear
42
+ # in the queue immediately, but will be scheduled for addition during the
43
+ # next reactor tick.
44
+ def push(*items)
45
+ EM.schedule do
46
+ @items.push(*items)
47
+ @popq.shift.call @items.shift until @items.empty? || @popq.empty?
48
+ end
49
+ end
50
+ alias :<< :push
51
+
52
+ # @return [Boolean]
53
+ # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
54
+ def empty?
55
+ @items.empty?
56
+ end
57
+
58
+ # @return [Integer] Queue size
59
+ # @note This is a peek, it's not thread safe, and may only tend toward accuracy.
60
+ def size
61
+ @items.size
62
+ end
63
+
64
+ # @return [Integer] Waiting size
65
+ # @note This is a peek at the number of jobs that are currently waiting on the Queue
66
+ def num_waiting
67
+ @popq.size
68
+ end
69
+
70
+ end # Queue
71
+ end # EventMachine
@@ -0,0 +1,195 @@
1
+ module EventMachine
2
+ module DNS
3
+ class Resolver
4
+
5
+ def self.resolve(hostname)
6
+ Request.new(socket, hostname)
7
+ end
8
+
9
+ @socket = @nameservers = nil
10
+
11
+ def self.socket
12
+ if !@socket || (@socket && @socket.error?)
13
+ @socket = Socket.open
14
+
15
+ @hosts = {}
16
+ IO.readlines('/etc/hosts').each do |line|
17
+ next if line =~ /^#/
18
+ addr, host = line.split(/\s+/)
19
+
20
+ if @hosts[host]
21
+ @hosts[host] << addr
22
+ else
23
+ @hosts[host] = [addr]
24
+ end
25
+ end
26
+ end
27
+
28
+ @socket
29
+ end
30
+
31
+ def self.nameservers=(ns)
32
+ @nameservers = ns
33
+ end
34
+
35
+ def self.nameservers
36
+ if !@nameservers
37
+ @nameservers = []
38
+ IO.readlines('/etc/resolv.conf').each do |line|
39
+ if line =~ /^nameserver (.+)$/
40
+ nscandidate = $1.split(/\s+/).first
41
+ @nameservers << nscandidate unless nscandidate =~ /:/ # stick with IPv4 for now
42
+ end
43
+ end
44
+ end
45
+ @nameservers
46
+ end
47
+
48
+ def self.nameserver
49
+ nameservers.shuffle.first
50
+ end
51
+
52
+ def self.hosts
53
+ @hosts
54
+ end
55
+ end
56
+
57
+ class RequestIdAlreadyUsed < RuntimeError; end
58
+
59
+ class Socket < EventMachine::Connection
60
+ def self.open
61
+ s = EventMachine::open_datagram_socket('0.0.0.0', 0, self) # FIXME: this is IPv4 only
62
+ s.send_error_handling = :ERRORHANDLING_REPORT
63
+ s
64
+ end
65
+
66
+ def initialize
67
+ @nameserver = nil
68
+ end
69
+
70
+ def post_init
71
+ @requests = {}
72
+ EM.add_periodic_timer(0.1, &method(:tick))
73
+ end
74
+
75
+ def unbind
76
+ end
77
+
78
+ def tick
79
+ @requests.each do |id,req|
80
+ req.tick
81
+ end
82
+ end
83
+
84
+ def register_request(id, req)
85
+ if @requests.has_key?(id)
86
+ raise RequestIdAlreadyUsed
87
+ else
88
+ @requests[id] = req
89
+ end
90
+ end
91
+
92
+ def send_packet(pkt)
93
+ send_datagram(pkt, nameserver, 53)
94
+ end
95
+
96
+ def nameserver=(ns)
97
+ @nameserver = ns
98
+ end
99
+
100
+ def nameserver
101
+ @nameserver || Resolver.nameserver
102
+ end
103
+
104
+ # Decodes the packet, looks for the request and passes the
105
+ # response over to the requester
106
+ def receive_data(data)
107
+ msg = nil
108
+ begin
109
+ msg = Resolv::DNS::Message.decode data
110
+ rescue
111
+ else
112
+ req = @requests[msg.id]
113
+ if req
114
+ @requests.delete(msg.id)
115
+ req.receive_answer(msg)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ class Request
122
+ include Deferrable
123
+ attr_accessor :retry_interval, :max_tries
124
+
125
+ def initialize(socket, hostname)
126
+ @socket = socket
127
+ @hostname = hostname
128
+ @tries = 0
129
+ @last_send = Time.at(0)
130
+ @retry_interval = 3
131
+ @max_tries = 5
132
+
133
+ if addrs = Resolver.hosts[hostname]
134
+ succeed addrs
135
+ else
136
+ EM.next_tick { tick }
137
+ end
138
+ end
139
+
140
+ def tick
141
+ # Break early if nothing to do
142
+ return if @last_send + @retry_interval > Time.now
143
+ if @tries < @max_tries
144
+ send
145
+ else
146
+ fail 'retries exceeded'
147
+ end
148
+ end
149
+
150
+ def receive_answer(msg)
151
+ addrs = []
152
+ msg.each_answer do |name,ttl,data|
153
+ if data.kind_of?(Resolv::DNS::Resource::IN::A) ||
154
+ data.kind_of?(Resolv::DNS::Resource::IN::AAAA)
155
+ addrs << data.address.to_s
156
+ end
157
+ end
158
+
159
+ if addrs.empty?
160
+ fail "rcode=#{msg.rcode}"
161
+ else
162
+ succeed addrs
163
+ end
164
+ end
165
+
166
+ private
167
+
168
+ def send
169
+ @tries += 1
170
+ @last_send = Time.now
171
+ @socket.send_packet(packet.encode)
172
+ end
173
+
174
+ def id
175
+ begin
176
+ @id = rand(65535)
177
+ @socket.register_request(@id, self)
178
+ rescue RequestIdAlreadyUsed
179
+ retry
180
+ end unless defined?(@id)
181
+
182
+ @id
183
+ end
184
+
185
+ def packet
186
+ msg = Resolv::DNS::Message.new
187
+ msg.id = id
188
+ msg.rd = 1
189
+ msg.add_question @hostname, Resolv::DNS::Resource::IN::A
190
+ msg
191
+ end
192
+
193
+ end
194
+ end
195
+ end