├── examples
├── ex_queue.rb
├── helper.rb
└── ex_channel.rb
├── lib
├── em
│ ├── version.rb
│ ├── callback.rb
│ ├── protocols
│ │ ├── object_protocol.rb
│ │ ├── tcptest.rb
│ │ └── header_and_content.rb
│ ├── process_watch.rb
│ ├── timers.rb
│ ├── protocols.rb
│ ├── channel.rb
│ ├── test.rb
│ ├── queue.rb
│ ├── file_watch.rb
│ ├── future.rb
│ ├── server.rb
│ ├── spawnable.rb
│ ├── delegate_connection.rb
│ ├── messages.rb
│ ├── processes.rb
│ └── streamer.rb
├── evma.rb
└── evma
│ ├── callback.rb
│ ├── reactor.rb
│ ├── protocol.rb
│ ├── container.rb
│ └── factory.rb
├── .gitignore
├── docs
├── SMTP
├── TODO
├── INSTALL
├── LEGAL
├── KEYBOARD
├── COPYING
├── RELEASE_NOTES
└── PURE_RUBY
├── java
├── .classpath
├── .project
└── src
│ └── com
│ └── rubyeventmachine
│ ├── ConnectionFactory.java
│ ├── PeriodicTimer.java
│ ├── EmReactorException.java
│ ├── tests
│ ├── TestDatagrams.java
│ ├── TestServers.java
│ ├── EMTest.java
│ ├── TestTimers.java
│ ├── ApplicationTest.java
│ └── ConnectTest.java
│ ├── DefaultConnectionFactory.java
│ ├── Timer.java
│ ├── Connection.java
│ └── EventableChannel.java
├── web
└── whatis
├── tests
├── testem.rb
├── test_get_sock_opt.rb
├── test_error_handler.rb
├── test_handler_check.rb
├── test_object_protocol.rb
├── test_connection_count.rb
├── test_queue.rb
├── test_file_watch.rb
├── test_ud.rb
├── test_process_watch.rb
├── test_pending_connect_timeout.rb
├── test_ssl_methods.rb
├── test_inactivity_timeout.rb
├── test_running.rb
├── test_defer.rb
├── test_channel.rb
├── test_exc.rb
├── test_pause.rb
├── test_kb.rb
├── client.crt
├── test_sasl.rb
├── test_proxy_connection.rb
├── test_ssl_verify.rb
├── test_errors.rb
├── test_ssl_args.rb
├── test_smtpclient.rb
├── test_servers.rb
├── test_smtpserver.rb
├── test_server.rb
├── test_delegate_connection.rb
├── test_attach.rb
├── client.key
├── test_processes.rb
├── test_next_tick.rb
├── test_pure.rb
├── test_timers.rb
└── test_httpclient2.rb
├── ext
├── epoll.h
├── epoll.cpp
├── sigs.h
├── binder.h
├── page.h
├── fastfilereader
│ ├── mapper.h
│ ├── extconf.rb
│ └── rubymain.cpp
├── files.h
├── kb.cpp
├── sigs.cpp
├── ssl.h
├── page.cpp
├── files.cpp
├── emwin.h
├── eventmachine_cpp.h
├── binder.cpp
└── project.h
├── tasks
├── cpp.rake
└── project.rake
└── README
/examples/ex_queue.rb:
--------------------------------------------------------------------------------
1 | require File.dirname(__FILE__) + '/helper'
2 |
3 |
--------------------------------------------------------------------------------
/lib/em/version.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | VERSION = "0.12.9"
3 | end
4 |
--------------------------------------------------------------------------------
/examples/helper.rb:
--------------------------------------------------------------------------------
1 | $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2 | require 'eventmachine'
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | pkg
2 | rdoc
3 | Makefile
4 |
5 | *.bundle
6 | *.dll
7 | *.so
8 | *.jar
9 | *.class
10 | *.o
11 | *.log
12 | *.def
13 | *.pdb
14 | java/src/.project
15 |
--------------------------------------------------------------------------------
/docs/SMTP:
--------------------------------------------------------------------------------
1 | This note details the usage of EventMachine's built-in support for SMTP. EM supports both client and server connections, which will be described in separate sections.
2 |
3 |
--------------------------------------------------------------------------------
/docs/TODO:
--------------------------------------------------------------------------------
1 | TODO List:
2 |
3 | 12Aug06: Noticed by Don Stocks. A TCP connect-request that results
4 | in a failed DNS resolution fires a fatal error back to user code.
5 | Uuuuuugly. We should probably cause an unbind event to get fired
6 | instead, and add some parameterization so the caller can detect
7 | the nature of the failure.
8 |
9 |
--------------------------------------------------------------------------------
/java/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/java/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | em_reactor
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/INSTALL:
--------------------------------------------------------------------------------
1 | If you have obtained an EventMachine source-tarball (.tar.gz):
2 | unzip and untar the tarball, and enter the directory that is
3 | created. In that directory, say:
4 | ruby setup.rb
5 | (You may need to be root to execute this command.)
6 |
7 | To create documentation for EventMachine, simply type:
8 | rake rdoc
9 | in the distro directory. Rdocs will be created in subdirectory rdoc.
10 |
11 | If you have obtained a gem version of EventMachine, install it in the
12 | usual way (gem install eventmachine). You may need superuser privileges
13 | to execute this command.
14 |
--------------------------------------------------------------------------------
/web/whatis:
--------------------------------------------------------------------------------
1 | EventMachine is a library for Ruby, C++, and Java programs. It provides event-driven I/O using the Reactor pattern.
2 |
3 | EventMachine is designed to simultaneously meet two key needs:
4 | - Extremely high scalability, performance and stability for the most demanding production environments; and
5 | - An API that eliminates the complexities of high-performance threaded network programming, allowing engineers to concentrate on their application logic.
6 |
7 | This unique combination makes EventMachine a premier choice for designers of critical networked applications, including web servers and proxies, email and IM production systems, authentication/authorization processors, and many more.
8 |
--------------------------------------------------------------------------------
/tests/testem.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 |
3 | require 'test/unit'
4 |
5 | module EmTestRunner
6 | @em_root = File.expand_path(File.dirname(__FILE__) + '/../')
7 | @lib_dir = File.join(@em_root, 'lib')
8 | @ext_dir = File.join(@em_root, 'ext')
9 | @java_dir = File.join(@em_root, 'java')
10 |
11 | def self.run(glob = 'test_*.rb')
12 | $:.unshift(@lib_dir)
13 | $:.unshift(@ext_dir)
14 | $:.unshift(@java_dir)
15 |
16 | case glob
17 | when Array
18 | files = glob
19 | else
20 | files = Dir[File.dirname(__FILE__) + '/' + glob]
21 | end
22 |
23 | files.each do |tc|
24 | require tc
25 | end
26 | end
27 | end
28 |
29 | if __FILE__ == $0
30 | EmTestRunner.run
31 | end
32 |
--------------------------------------------------------------------------------
/ext/epoll.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: epoll.h
6 | Date: 06Jun07
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifdef HAVE_EPOLL
22 |
23 |
24 | #endif // HAVE_EPOLL
25 |
26 |
--------------------------------------------------------------------------------
/tests/test_get_sock_opt.rb:
--------------------------------------------------------------------------------
1 | $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
2 | require 'eventmachine'
3 | require 'socket'
4 | require 'test/unit'
5 |
6 | class TestGetSockOpt < Test::Unit::TestCase
7 |
8 | def setup
9 | assert(!EM.reactor_running?)
10 | end
11 |
12 | def teardown
13 | assert(!EM.reactor_running?)
14 | end
15 |
16 | #-------------------------------------
17 |
18 | def test_get_sock_opt
19 | test = self
20 | EM.run do
21 | EM.connect 'google.com', 80, Module.new {
22 | define_method :connection_completed do
23 | val = get_sock_opt Socket::SOL_SOCKET, Socket::SO_ERROR
24 | test.assert_equal "\0\0\0\0", val
25 | EM.stop
26 | end
27 | }
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/tests/test_error_handler.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestErrorHandler < Test::Unit::TestCase
6 | def test_error_handler
7 | error = nil
8 | EM.error_handler{ |e|
9 | error = e
10 | EM.error_handler(nil)
11 | EM.stop
12 | }
13 |
14 | assert_nothing_raised do
15 | EM.run{
16 | EM.add_timer(0){
17 | raise 'test'
18 | }
19 | }
20 | end
21 |
22 | assert_equal error.class, RuntimeError
23 | assert_equal error.message, 'test'
24 | end
25 |
26 | def test_without_error_handler
27 | assert_raise RuntimeError do
28 | EM.run{
29 | EM.add_timer(0){
30 | raise 'test'
31 | }
32 | }
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/ext/epoll.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: epoll.cpp
6 | Date: 06Jun07
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifdef HAVE_EPOLL
22 |
23 | #include "project.h"
24 |
25 | #endif // HAVE_EPOLL
26 |
27 |
--------------------------------------------------------------------------------
/lib/em/callback.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # Utility method for coercing arguments to an object that responds to #call
3 | # Accepts an object and a method name to send to, or a block, or an object
4 | # that responds to call.
5 | #
6 | # cb = EM.Callback{ |msg| puts(msg) }
7 | # cb.call('hello world')
8 | #
9 | # cb = EM.Callback(Object, :puts)
10 | # cb.call('hello world')
11 | #
12 | # cb = EM.Callback(proc{ |msg| puts(msg) })
13 | # cb.call('hello world')
14 | #
15 | def self.Callback(object = nil, method = nil, &blk)
16 | if object && method
17 | lambda { |*args| object.send method, *args }
18 | else
19 | if object.respond_to? :call
20 | object
21 | else
22 | blk || raise(ArgumentError)
23 | end
24 | end
25 | end
26 | end
--------------------------------------------------------------------------------
/tests/test_handler_check.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestHandlerCheck < Test::Unit::TestCase
6 |
7 | class Foo < EM::Connection; end;
8 | module TestModule; end;
9 |
10 | def test_with_correct_class
11 | assert_nothing_raised do
12 | EM.run {
13 | EM.connect("127.0.0.1", 80, Foo)
14 | EM.stop_event_loop
15 | }
16 | end
17 | end
18 |
19 | def test_with_incorrect_class
20 | assert_raise(ArgumentError) do
21 | EM.run {
22 | EM.connect("127.0.0.1", 80, String)
23 | EM.stop_event_loop
24 | }
25 | end
26 | end
27 |
28 | def test_with_module
29 | assert_nothing_raised do
30 | EM.run {
31 | EM.connect("127.0.0.1", 80, TestModule)
32 | EM.stop_event_loop
33 | }
34 | end
35 | end
36 |
37 | end
--------------------------------------------------------------------------------
/tests/test_object_protocol.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestObjectProtocol < Test::Unit::TestCase
6 | Host = "127.0.0.1"
7 | Port = 9550
8 |
9 | module Server
10 | include EM::P::ObjectProtocol
11 | def post_init
12 | send_object :hello=>'world'
13 | end
14 | def receive_object obj
15 | $server = obj
16 | EM.stop
17 | end
18 | end
19 |
20 | module Client
21 | include EM::P::ObjectProtocol
22 | def receive_object obj
23 | $client = obj
24 | send_object 'you_said'=>obj
25 | end
26 | end
27 |
28 | def test_send_receive
29 | EM.run{
30 | EM.start_server Host, Port, Server
31 | EM.connect Host, Port, Client
32 | }
33 |
34 | assert($client == {:hello=>'world'})
35 | assert($server == {'you_said'=>{:hello=>'world'}})
36 | end
37 | end
--------------------------------------------------------------------------------
/docs/LEGAL:
--------------------------------------------------------------------------------
1 | LEGAL NOTICE INFORMATION
2 | ------------------------
3 |
4 | EventMachine is Copyright (C) 2006-07 by Francis Cianfrocca.
5 |
6 | EventMachine is copyrighted software owned by Francis Cianfrocca
7 | (blackhedd ... gmail.com). You may redistribute and/or modify this
8 | software as long as you comply with either the terms of the GPL
9 | (see the file GPL), or Ruby's license (see the file COPYING).
10 |
11 | Your use of all the files in this distribution is controlled by these
12 | license terms, except for those files specifically mentioned below:
13 |
14 |
15 |
16 | setup.rb
17 | This file is Copyright (C) 2000-2005 by Minero Aoki
18 | You can distribute/modify this file under the terms of
19 | the GNU LGPL, Lesser General Public License version 2.1.
20 |
21 |
22 | lib/em/buftok.rb
23 | This file is Copyright (C) 2007 by Tony Arcieri. This file is
24 | covered by the terms of Ruby's License (see the file COPYING).
25 |
26 |
--------------------------------------------------------------------------------
/tests/test_connection_count.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestConnectionCount < Test::Unit::TestCase
6 | def test_idle_connection_count
7 | EM.run {
8 | $count = EM.connection_count
9 | EM.stop_event_loop
10 | }
11 |
12 | assert_equal(0, $count)
13 | end
14 |
15 | module Client
16 | def connection_completed
17 | $client_conns += 1
18 | EM.stop if $client_conns == 3
19 | end
20 | end
21 |
22 | def test_with_some_connections
23 | EM.run {
24 | $client_conns = 0
25 | $initial_conns = EM.connection_count
26 | EM.start_server("127.0.0.1", 9999)
27 | $server_conns = EM.connection_count
28 | 3.times { EM.connect("127.0.0.1", 9999, Client) }
29 | }
30 |
31 | assert_equal(0, $initial_conns)
32 | assert_equal(1, $server_conns)
33 | assert_equal(4, $client_conns + $server_conns)
34 | end
35 | end
--------------------------------------------------------------------------------
/ext/sigs.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: sigs.h
6 | Date: 06Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __Signals__H_
22 | #define __Signals__H_
23 |
24 | void InstallSignalHandlers();
25 | extern bool gTerminateSignalReceived;
26 |
27 | #ifdef OS_WIN32
28 | void HookControlC (bool);
29 | #endif
30 |
31 | #endif // __Signals__H_
32 |
33 |
--------------------------------------------------------------------------------
/lib/evma.rb:
--------------------------------------------------------------------------------
1 | #--
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 Apr 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 | require 'rubyeventmachine'
27 | require 'evma/reactor'
28 | require 'evma/callback'
29 | require 'evma/protocol'
30 | require 'evma/factory'
31 | require 'evma/container'
32 |
33 |
--------------------------------------------------------------------------------
/tests/test_queue.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestEventMachineQueue < Test::Unit::TestCase
6 | def test_queue_push
7 | s = 0
8 | EM.run do
9 | q = EM::Queue.new
10 | q.push(1)
11 | EM.next_tick { s = q.size; EM.stop }
12 | end
13 | assert_equal 1, s
14 | end
15 |
16 | def test_queue_pop
17 | x,y,z = nil
18 | EM.run do
19 | q = EM::Queue.new
20 | q.push(1,2,3)
21 | q.pop { |v| x = v }
22 | q.pop { |v| y = v }
23 | q.pop { |v| z = v; EM.stop }
24 | end
25 | assert_equal 1, x
26 | assert_equal 2, y
27 | assert_equal 3, z
28 | end
29 |
30 | def test_queue_reactor_thread
31 | q = EM::Queue.new
32 |
33 | Thread.new { q.push(1,2,3) }.join
34 | assert q.empty?
35 | EM.run { EM.next_tick { EM.stop } }
36 | assert_equal 3, q.size
37 |
38 | x = nil
39 | Thread.new { q.pop { |v| x = v } }.join
40 | assert_equal nil, x
41 | EM.run { EM.next_tick { EM.stop } }
42 | assert_equal 1, x
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/evma/callback.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 19 May 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 | module EventMachine
27 |
28 | def self.event_callback target, opcode, data
29 | Evma::Container.callback target, opcode, data
30 | end
31 |
32 | end # module EventMachine
33 |
--------------------------------------------------------------------------------
/tests/test_file_watch.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestFileWatch < Test::Unit::TestCase
6 | module FileWatcher
7 | def file_modified
8 | $modified = true
9 | end
10 | def file_deleted
11 | $deleted = true
12 | end
13 | def unbind
14 | $unbind = true
15 | EM.stop
16 | end
17 | end
18 |
19 | def setup
20 | EM.kqueue = true if EM.kqueue?
21 | end
22 |
23 | def teardown
24 | EM.kqueue = false if EM.kqueue?
25 | end
26 |
27 | def test_events
28 | EM.run{
29 | require 'tempfile'
30 | file = Tempfile.new('em-watch')
31 | $tmp_path = file.path
32 |
33 | # watch it
34 | watch = EM.watch_file(file.path, FileWatcher)
35 | $path = watch.path
36 |
37 | # modify it
38 | File.open(file.path, 'w'){ |f| f.puts 'hi' }
39 |
40 | # delete it
41 | EM.add_timer(0.25){ file.close; file.delete }
42 | }
43 |
44 | assert_equal($path, $tmp_path)
45 | assert($modified)
46 | assert($deleted)
47 | assert($unbind)
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/tests/test_ud.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestUserDefinedEvents < Test::Unit::TestCase
32 |
33 | def test_a
34 | end
35 |
36 | end
37 |
--------------------------------------------------------------------------------
/tests/test_process_watch.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestProcessWatch < Test::Unit::TestCase
6 | module ParentProcessWatcher
7 | def process_forked
8 | $forked = true
9 | end
10 | end
11 |
12 | module ChildProcessWatcher
13 | def process_exited
14 | $exited = true
15 | end
16 | def unbind
17 | $unbind = true
18 | EM.stop
19 | end
20 | end
21 |
22 | def setup
23 | EM.kqueue = true if EM.kqueue?
24 | end
25 |
26 | def teardown
27 | EM.kqueue = false if EM.kqueue?
28 | end
29 |
30 | def test_events
31 | EM.run{
32 | # watch ourselves for a fork notification
33 | EM.watch_process(Process.pid, ParentProcessWatcher)
34 | $fork_pid = fork{ sleep }
35 | child = EM.watch_process($fork_pid, ChildProcessWatcher)
36 | $pid = child.pid
37 |
38 | EM.add_timer(0.5){
39 | Process.kill('TERM', $fork_pid)
40 | }
41 | }
42 |
43 | assert_equal($pid, $fork_pid)
44 | assert($forked)
45 | assert($exited)
46 | assert($unbind)
47 | end
48 | end
--------------------------------------------------------------------------------
/tests/test_pending_connect_timeout.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestPendingConnectTimeout < Test::Unit::TestCase
6 |
7 | def test_default
8 | $timeout = nil
9 | EM.run {
10 | c = EM.connect("127.0.0.1", 54321)
11 | $timeout = c.pending_connect_timeout
12 | EM.stop
13 | }
14 |
15 | assert_equal(20.0, $timeout)
16 | end
17 |
18 | def test_set_and_get
19 | $timeout = nil
20 | EM.run {
21 | c = EM.connect("1.2.3.4", 54321)
22 | c.pending_connect_timeout = 2.5
23 | $timeout = c.pending_connect_timeout
24 | EM.stop
25 | }
26 |
27 | assert_equal(2.5, $timeout)
28 | end
29 |
30 | module TimeoutHandler
31 | def unbind
32 | EM.stop
33 | end
34 | end
35 |
36 | def test_for_real
37 | $timeout = nil
38 | EM.run {
39 | EM.heartbeat_interval = 0.1
40 | $start = Time.now
41 | c = EM.connect("1.2.3.4", 54321, TimeoutHandler)
42 | c.pending_connect_timeout = 5
43 | }
44 |
45 | assert_in_delta(5, (Time.now - $start), 0.3)
46 | end
47 |
48 | end
49 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/ConnectionFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 |
31 | package com.rubyeventmachine;
32 |
33 | //import com.rubyeventmachine.*;
34 |
35 | public interface ConnectionFactory {
36 | public Connection connection();
37 | }
--------------------------------------------------------------------------------
/tests/test_ssl_methods.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestSSLMethods < Test::Unit::TestCase
6 |
7 | module ServerHandler
8 |
9 | def post_init
10 | start_tls
11 | end
12 |
13 | def ssl_handshake_completed
14 | $server_called_back = true
15 | $server_cert_value = get_peer_cert
16 | end
17 |
18 | end
19 |
20 | module ClientHandler
21 |
22 | def post_init
23 | start_tls
24 | end
25 |
26 | def ssl_handshake_completed
27 | $client_called_back = true
28 | $client_cert_value = get_peer_cert
29 | EM.stop_event_loop
30 | end
31 |
32 | end
33 |
34 | def test_ssl_methods
35 | $server_called_back, $client_called_back = false, false
36 | $server_cert_value, $client_cert_value = nil, nil
37 |
38 | EM.run {
39 | EM.start_server("127.0.0.1", 9999, ServerHandler)
40 | EM.connect("127.0.0.1", 9999, ClientHandler)
41 | }
42 |
43 | assert($server_called_back)
44 | assert($client_called_back)
45 |
46 | assert($server_cert_value.is_a?(NilClass))
47 | assert($client_cert_value.is_a?(String))
48 | end
49 |
50 | end if EM.ssl?
--------------------------------------------------------------------------------
/tests/test_inactivity_timeout.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestInactivityTimeout < Test::Unit::TestCase
6 |
7 | def test_default
8 | $timeout = nil
9 | EM.run {
10 | c = EM.connect("127.0.0.1", 54321)
11 | $timeout = c.comm_inactivity_timeout
12 | EM.stop
13 | }
14 |
15 | assert_equal(0.0, $timeout)
16 | end
17 |
18 | def test_set_and_get
19 | $timeout = nil
20 | EM.run {
21 | c = EM.connect("127.0.0.1", 54321)
22 | c.comm_inactivity_timeout = 2.5
23 | $timeout = c.comm_inactivity_timeout
24 | EM.stop
25 | }
26 |
27 | assert_equal(2.5, $timeout)
28 | end
29 |
30 | module TimeoutHandler
31 | def unbind
32 | EM.stop
33 | end
34 | end
35 |
36 | def test_for_real
37 | EM.run {
38 | EM.heartbeat_interval = 0.1
39 | EM.start_server("127.0.0.1", 12345)
40 | EM.add_timer(0.2) {
41 | $start = Time.now
42 | c = EM.connect("127.0.0.1", 12345, TimeoutHandler)
43 | c.comm_inactivity_timeout = 2.5
44 | }
45 | }
46 |
47 | assert_in_delta(2.5, (Time.now - $start), 0.3)
48 | end
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/PeriodicTimer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine;
31 |
32 | public class PeriodicTimer extends Timer {
33 |
34 | public void _fire() {
35 | fire();
36 | application.addTimer(interval, this);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ext/binder.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: binder.h
6 | Date: 07Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 | #ifndef __ObjectBindings__H_
21 | #define __ObjectBindings__H_
22 |
23 |
24 | class Bindable_t
25 | {
26 | public:
27 | static unsigned long CreateBinding();
28 | static Bindable_t *GetObject (const unsigned long);
29 | static map BindingBag;
30 |
31 | public:
32 | Bindable_t();
33 | virtual ~Bindable_t();
34 |
35 | const unsigned long GetBinding() {return Binding;}
36 |
37 | private:
38 | unsigned long Binding;
39 | };
40 |
41 |
42 |
43 |
44 |
45 | #endif // __ObjectBindings__H_
46 |
47 |
--------------------------------------------------------------------------------
/lib/evma/reactor.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 18 May 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 | require 'singleton'
28 |
29 | module Evma
30 | class Reactor
31 | include Singleton
32 |
33 | #--
34 | def initialize
35 | EventMachine.initialize_event_machine
36 | end
37 |
38 | #--
39 | #
40 | def run
41 | EventMachine.run_machine
42 | end
43 |
44 | end # class Reactor
45 | end # module Evma
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/EmReactorException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 | package com.rubyeventmachine;
30 |
31 | /**
32 | * @author francis
33 | *
34 | */
35 | public class EmReactorException extends Exception {
36 | static final long serialVersionUID = 0;
37 | public EmReactorException (String msg) {
38 | super (msg);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ext/page.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: page.h
6 | Date: 30Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __PageManager__H_
22 | #define __PageManager__H_
23 |
24 |
25 | /**************
26 | class PageList
27 | **************/
28 |
29 | class PageList
30 | {
31 | struct Page {
32 | Page (const char *b, size_t s): Buffer(b), Size(s) {}
33 | const char *Buffer;
34 | size_t Size;
35 | };
36 |
37 | public:
38 | PageList();
39 | virtual ~PageList();
40 |
41 | void Push (const char*, int);
42 | bool HasPages();
43 | void Front (const char**, int*);
44 | void PopFront();
45 |
46 | private:
47 | deque Pages;
48 | };
49 |
50 |
51 | #endif // __PageManager__H_
52 |
--------------------------------------------------------------------------------
/tests/test_running.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestRunning < Test::Unit::TestCase
32 | def test_running
33 | assert_equal( false, EM::reactor_running? )
34 | r = false
35 | EM.run {
36 | r = EM::reactor_running?
37 | EM.stop
38 | }
39 | assert_equal( true, r )
40 | end
41 | end
42 |
43 |
--------------------------------------------------------------------------------
/examples/ex_channel.rb:
--------------------------------------------------------------------------------
1 | require File.dirname(__FILE__) + '/helper'
2 |
3 | EM.run do
4 |
5 | # Create a channel to push data to, this could be stocks...
6 | RandChannel = EM::Channel.new
7 |
8 | # The server simply subscribes client connections to the channel on connect,
9 | # and unsubscribes them on disconnect.
10 | class Server < EM::Connection
11 | def self.start(host = '127.0.0.1', port = 8000)
12 | EM.start_server(host, port, self)
13 | end
14 |
15 | def post_init
16 | @sid = RandChannel.subscribe { |m| send_data "#{m.inspect}\n" }
17 | end
18 |
19 | def unbind
20 | RandChannel.unsubscribe @sid
21 | end
22 | end
23 | Server.start
24 |
25 | # Two client connections, that just print what they receive.
26 | 2.times do
27 | EM.connect('127.0.0.1', 8000) do |c|
28 | c.extend EM::P::LineText2
29 | def c.receive_line(line)
30 | puts "Subscriber: #{signature} got #{line}"
31 | end
32 | EM.add_timer(2) { c.close_connection }
33 | end
34 | end
35 |
36 | # This part of the example is more fake, but imagine sleep was in fact a
37 | # long running calculation to achieve the value.
38 | 40.times do
39 | EM.defer lambda { v = sleep(rand * 2); RandChannel << [Time.now, v] }
40 | end
41 |
42 | EM.add_timer(5) { EM.stop }
43 | end
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/tests/TestDatagrams.java:
--------------------------------------------------------------------------------
1 | package com.rubyeventmachine.tests;
2 |
3 | import com.rubyeventmachine.*;
4 | import java.net.*;
5 | import java.nio.*;
6 |
7 | import org.junit.After;
8 | import org.junit.AfterClass;
9 | import org.junit.Before;
10 | import org.junit.BeforeClass;
11 | import org.junit.Test;
12 |
13 |
14 | public class TestDatagrams {
15 |
16 | @BeforeClass
17 | public static void setUpBeforeClass() throws Exception {
18 | }
19 |
20 | @AfterClass
21 | public static void tearDownAfterClass() throws Exception {
22 | }
23 |
24 | @Before
25 | public void setUp() throws Exception {
26 | }
27 |
28 | @After
29 | public void tearDown() throws Exception {
30 | }
31 |
32 | class A extends Connection {
33 | public void receiveData (ByteBuffer bb) {
34 | application.stop();
35 | }
36 | }
37 | class B extends Connection {
38 | public void postInit() {
39 | this.sendDatagram(ByteBuffer.wrap(new String("ABC").getBytes()), new InetSocketAddress ("127.0.0.1", 9550));
40 | }
41 |
42 | }
43 | @Test
44 | public final void testA() {
45 | final Application a = new Application();
46 | a.run (new Runnable() {
47 | public void run() {
48 | a.openDatagramSocket( new InetSocketAddress ("0.0.0.0", 9550), new A() );
49 | a.openDatagramSocket( new B() );
50 | }
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/docs/KEYBOARD:
--------------------------------------------------------------------------------
1 | EventMachine (EM) can respond to keyboard events. This gives your event-driven programs the ability to respond to input from local users.
2 |
3 | Programming EM to handle keyboard input in Ruby is simplicity itself. Just use EventMachine#open_keyboard, and supply the name of a Ruby module or class that will receive the input:
4 |
5 | require 'rubygems'
6 | require 'eventmachine'
7 |
8 | module MyKeyboardHandler
9 | def receive_data keystrokes
10 | puts "I received the following data from the keyboard: #{keystrokes}"
11 | end
12 | end
13 |
14 | EM.run {
15 | EM.open_keyboard(MyKeyboardHandler)
16 | }
17 |
18 |
19 | If you want EM to send line-buffered keyboard input to your program, just include the LineText2 protocol module in your handler class or module:
20 |
21 |
22 |
23 | require 'rubygems'
24 | require 'eventmachine'
25 |
26 | module MyKeyboardHandler
27 | include EM::Protocols::LineText2
28 | def receive_line data
29 | puts "I received the following line from the keyboard: #{data}"
30 | end
31 | end
32 |
33 | EM.run {
34 | EM.open_keyboard(MyKeyboardHandler)
35 | }
36 |
37 | As we said, simplicity itself. You can call EventMachine#open_keyboard at any time while the EM reactor loop is running. In other words, the method invocation may appear anywhere in an EventMachine#run block, or in any code invoked in the #run block.
38 |
39 |
--------------------------------------------------------------------------------
/lib/em/protocols/object_protocol.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | module Protocols
3 | # ObjectProtocol allows for easy communication using marshaled ruby objects
4 | #
5 | # module RubyServer
6 | # include EM::P::ObjectProtocol
7 | #
8 | # def receive_object obj
9 | # send_object({'you said' => obj})
10 | # end
11 | # end
12 | #
13 | module ObjectProtocol
14 | # By default returns Marshal, override to return JSON or YAML, or any
15 | # other serializer/deserializer responding to #dump and #load.
16 | def serializer
17 | Marshal
18 | end
19 |
20 | def receive_data data # :nodoc:
21 | (@buf ||= '') << data
22 |
23 | while @buf.size >= 4
24 | if @buf.size >= 4+(size=@buf.unpack('N').first)
25 | @buf.slice!(0,4)
26 | receive_object serializer.load(@buf.slice!(0,size))
27 | else
28 | break
29 | end
30 | end
31 | end
32 |
33 | # Invoked with ruby objects received over the network
34 | def receive_object obj
35 | # stub
36 | end
37 |
38 | # Sends a ruby object over the network
39 | def send_object obj
40 | data = serializer.dump(obj)
41 | send_data [data.respond_to?(:bytesize) ? data.bytesize : data.size, data].pack('Na*')
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/tests/test_defer.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestDeferUsage < Test::Unit::TestCase
32 |
33 | def test_defers
34 | n = 0
35 | n_times = 20
36 | EM.run {
37 | n_times.times {
38 | work_proc = proc { n += 1 }
39 | callback = proc { EM.stop if n == n_times }
40 | EM.defer work_proc, callback
41 | }
42 | }
43 | assert_equal( n, n_times )
44 | end unless RUBY_VERSION >= '1.9.0'
45 |
46 | end
47 |
48 |
--------------------------------------------------------------------------------
/ext/fastfilereader/mapper.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id: mapper.h 4529 2007-07-04 11:32:22Z francis $
4 |
5 | File: mapper.h
6 | Date: 02Jul07
7 |
8 | Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: garbagecat10
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __Mapper__H_
22 | #define __Mapper__H_
23 |
24 |
25 | /**************
26 | class Mapper_t
27 | **************/
28 |
29 | class Mapper_t
30 | {
31 | public:
32 | Mapper_t (const string&);
33 | virtual ~Mapper_t();
34 |
35 | const char *GetChunk (unsigned);
36 | void Close();
37 | size_t GetFileSize() {return FileSize;}
38 |
39 | private:
40 | size_t FileSize;
41 |
42 | #ifdef OS_UNIX
43 | private:
44 | int Fd;
45 | const char *MapPoint;
46 | #endif // OS_UNIX
47 |
48 | #ifdef OS_WIN32
49 | private:
50 | HANDLE hFile;
51 | HANDLE hMapping;
52 | char *MapPoint;
53 | #endif // OS_WIN32
54 |
55 | };
56 |
57 |
58 | #endif // __Mapper__H_
59 |
60 |
--------------------------------------------------------------------------------
/lib/em/process_watch.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 |
3 | # This is subclassed from EventMachine::Connection for use with the process monitoring API. Read the
4 | # documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_process.
5 | class ProcessWatch < Connection
6 | # :stopdoc:
7 | Cfork = 'fork'.freeze
8 | Cexit = 'exit'.freeze
9 | # :startdoc:
10 |
11 | def receive_data(data) # :nodoc:
12 | case data
13 | when Cfork
14 | process_forked
15 | when Cexit
16 | process_exited
17 | end
18 | end
19 |
20 | # Returns the pid that EventMachine::watch_process was originally called with.
21 | def pid
22 | @pid
23 | end
24 |
25 | # Should be redefined with the user's custom callback that will be fired when the prcess is forked.
26 | #
27 | # There is currently not an easy way to get the pid of the forked child.
28 | def process_forked
29 | end
30 |
31 | # Should be redefined with the user's custom callback that will be fired when the process exits.
32 | #
33 | # stop_watching is called automatically after this callback
34 | def process_exited
35 | end
36 |
37 | # Discontinue monitoring of the process.
38 | # This will be called automatically when a process dies. User code may call it as well.
39 | def stop_watching
40 | EventMachine::unwatch_pid(@signature)
41 | end
42 | end
43 |
44 | end
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/DefaultConnectionFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 |
31 | package com.rubyeventmachine;
32 |
33 | import com.rubyeventmachine.ConnectionFactory;
34 |
35 | public class DefaultConnectionFactory implements ConnectionFactory {
36 |
37 | /**
38 | * Convenience class. Its connection() method returns an instance of class
39 | * Connection, which is usually overridden. This class is probably most
40 | * useful for unit testing.
41 | */
42 | public Connection connection() {
43 | return new Connection();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/tests/test_channel.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestEventMachineChannel < Test::Unit::TestCase
6 | def test_channel_subscribe
7 | s = 0
8 | EM.run do
9 | c = EM::Channel.new
10 | c.subscribe { |v| s = v; EM.stop }
11 | c << 1
12 | end
13 | assert_equal 1, s
14 | end
15 |
16 | def test_channel_unsubscribe
17 | s = 0
18 | EM.run do
19 | c = EM::Channel.new
20 | subscription = c.subscribe { |v| s = v }
21 | c.unsubscribe(subscription)
22 | c << 1
23 | EM.next_tick { EM.stop }
24 | end
25 | assert_not_equal 1, s
26 | end
27 |
28 | def test_channel_pop
29 | s = 0
30 | EM.run do
31 | c = EM::Channel.new
32 | c.pop{ |v| s = v }
33 | c << 1
34 | c << 2
35 | EM.next_tick { EM.stop }
36 | end
37 | assert_equal 1, s
38 | end
39 |
40 | def test_channel_reactor_thread_push
41 | out = []
42 | c = EM::Channel.new
43 | c.subscribe { |v| out << v }
44 | Thread.new { c.push(1,2,3) }.join
45 | assert out.empty?
46 |
47 | EM.run { EM.next_tick { EM.stop } }
48 |
49 | assert_equal [1,2,3], out
50 | end
51 |
52 | def test_channel_reactor_thread_callback
53 | out = []
54 | c = EM::Channel.new
55 | Thread.new { c.subscribe { |v| out << v } }.join
56 | c.push(1,2,3)
57 | assert out.empty?
58 |
59 | EM.run { EM.next_tick { EM.stop } }
60 |
61 | assert_equal [1,2,3], out
62 | end
63 | end
--------------------------------------------------------------------------------
/lib/em/timers.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # Creates a one-time timer
3 | #
4 | # timer = EventMachine::Timer.new(5) do
5 | # # this will never fire because we cancel it
6 | # end
7 | # timer.cancel
8 | #
9 | class Timer
10 | # Create a new timer that fires after a given number of seconds
11 | def initialize interval, callback=nil, &block
12 | @signature = EventMachine::add_timer(interval, callback || block)
13 | end
14 |
15 | # Cancel the timer
16 | def cancel
17 | EventMachine.send :cancel_timer, @signature
18 | end
19 | end
20 |
21 | # Creates a periodic timer
22 | #
23 | # n = 0
24 | # timer = EventMachine::PeriodicTimer.new(5) do
25 | # puts "the time is #{Time.now}"
26 | # timer.cancel if (n+=1) > 5
27 | # end
28 | #
29 | class PeriodicTimer
30 | # Create a new periodic timer that executes every interval seconds
31 | def initialize interval, callback=nil, &block
32 | @interval = interval
33 | @code = callback || block
34 | @cancelled = false
35 | schedule
36 | end
37 |
38 | # Cancel the periodic timer
39 | def cancel
40 | @cancelled = true
41 | end
42 |
43 | # Fire the timer every interval seconds
44 | attr_accessor :interval
45 |
46 | def schedule # :nodoc:
47 | EventMachine::add_timer @interval, proc {self.fire}
48 | end
49 | def fire # :nodoc:
50 | unless @cancelled
51 | @code.call
52 | schedule
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/lib/em/protocols.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # This module contains various protocol implementations, including:
3 | # - HttpClient and HttpClient2
4 | # - Stomp
5 | # - Memcache
6 | # - SmtpClient and SmtpServer
7 | # - SASLauth and SASLauthclient
8 | # - LineAndTextProtocol and LineText2
9 | # - HeaderAndContentProtocol
10 | # - Postgres3
11 | # - ObjectProtocol
12 | #
13 | # The protocol implementations live in separate files in the protocols/ subdirectory,
14 | # but are auto-loaded when they are first referenced in your application.
15 | #
16 | # EventMachine::Protocols is also aliased to EM::P for easier usage.
17 | #
18 | module Protocols
19 | # TODO : various autotools are completely useless with the lack of naming
20 | # convention, we need to correct that!
21 | autoload :TcpConnectTester, 'em/protocols/tcptest'
22 | autoload :HttpClient, 'em/protocols/httpclient'
23 | autoload :HttpClient2, 'em/protocols/httpclient2'
24 | autoload :LineAndTextProtocol, 'em/protocols/line_and_text'
25 | autoload :HeaderAndContentProtocol, 'em/protocols/header_and_content'
26 | autoload :LineText2, 'em/protocols/linetext2'
27 | autoload :Stomp, 'em/protocols/stomp'
28 | autoload :SmtpClient, 'em/protocols/smtpclient'
29 | autoload :SmtpServer, 'em/protocols/smtpserver'
30 | autoload :SASLauth, 'em/protocols/saslauth'
31 | autoload :Memcache, 'em/protocols/memcache'
32 | autoload :Postgres3, 'em/protocols/postgres3'
33 | autoload :ObjectProtocol, 'em/protocols/object_protocol'
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/em/protocols/tcptest.rb:
--------------------------------------------------------------------------------
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 | class TcpConnectTester < Connection # :nodoc:
31 | include EventMachine::Deferrable
32 |
33 | def self.test( host, port )
34 | EventMachine.connect( host, port, self )
35 | end
36 |
37 | def post_init
38 | @start_time = Time.now
39 | end
40 |
41 | def connection_completed
42 | @completed = true
43 | set_deferred_status :succeeded, (Time.now - @start_time)
44 | close_connection
45 | end
46 |
47 | def unbind
48 | set_deferred_status :failed, (Time.now - @start_time) unless @completed
49 | end
50 | end
51 |
52 | end
53 | end
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/Timer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine;
31 |
32 | public class Timer {
33 | /**
34 | * User code is expected to call a method on a controlling Application,
35 | * which will fill in this field so subsequent user code can access it.
36 | */
37 | public Application application;
38 | public double interval;
39 |
40 | /**
41 | * The reactor calls here, and it may be overridden in subclasses.
42 | * User code should never call this method.
43 | */
44 | public void _fire() {
45 | fire();
46 | }
47 |
48 | /**
49 | * User code is expected to override this method.
50 | */
51 | public void fire() {
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/lib/em/channel.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # Provides a simple interface to push items to a number of subscribers. The
3 | # channel will schedule all operations on the main reactor thread for thread
4 | # safe reactor operations.
5 | #
6 | # This provides a convenient way for connections to consume messages from
7 | # long running code in defer, without threading issues.
8 | #
9 | # channel = EM::Channel.new
10 | # sid = channel.subscribe{ |msg| p [:got, msg] }
11 | # channel.push('hello world')
12 | # channel.unsubscribe(sid)
13 | #
14 | # See examples/ex_channel.rb for a detailed example.
15 | class Channel
16 | # Create a new channel
17 | def initialize
18 | @subs = {}
19 | @uid = 0
20 | end
21 |
22 | # Takes any arguments suitable for EM::Callback() and returns a subscriber
23 | # id for use when unsubscribing.
24 | def subscribe(*a, &b)
25 | name = gen_id
26 | EM.schedule { @subs[name] = EM::Callback(*a, &b) }
27 | name
28 | end
29 |
30 | # Removes this subscriber from the list.
31 | def unsubscribe(name)
32 | EM.schedule { @subs.delete name }
33 | end
34 |
35 | # Add items to the channel, which are pushed out to all subscribers.
36 | def push(*items)
37 | items = items.dup
38 | EM.schedule { @subs.values.each { |s| items.each { |i| s.call i } } }
39 | end
40 | alias << push
41 |
42 | # Receive exactly one message from the channel.
43 | def pop(*a, &b)
44 | EM.schedule {
45 | name = subscribe do |*args|
46 | unsubscribe(name)
47 | EM::Callback(*a, &b).call(*args)
48 | end
49 | }
50 | end
51 |
52 | private
53 | def gen_id # :nodoc:
54 | @uid += 1
55 | end
56 | end
57 | end
--------------------------------------------------------------------------------
/tests/test_exc.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
27 | require 'eventmachine'
28 | require 'test/unit'
29 |
30 | class TestSomeExceptions < Test::Unit::TestCase
31 |
32 | # Read the commentary in EventMachine#run.
33 | # This test exercises the ensure block in #run that makes sure
34 | # EventMachine#release_machine gets called even if an exception is
35 | # thrown within the user code. Without the ensured call to release_machine,
36 | # the second call to EventMachine#run will fail with a C++ exception
37 | # because the machine wasn't cleaned up properly.
38 |
39 | def test_a
40 | assert_raises(RuntimeError) {
41 | EventMachine.run {
42 | raise "some exception"
43 | }
44 | }
45 | end
46 |
47 | def test_b
48 | assert_raises(RuntimeError) {
49 | EventMachine.run {
50 | raise "some exception"
51 | }
52 | }
53 | end
54 |
55 | end
56 |
--------------------------------------------------------------------------------
/ext/files.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: files.h
6 | Date: 26Aug06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __FileStreamDescriptor__H_
22 | #define __FileStreamDescriptor__H_
23 |
24 |
25 |
26 | /**************************
27 | class FileStreamDescriptor
28 | **************************/
29 |
30 | class FileStreamDescriptor: public EventableDescriptor
31 | {
32 | public:
33 | FileStreamDescriptor (int, EventMachine_t*);
34 | virtual ~FileStreamDescriptor();
35 |
36 | virtual void Read();
37 | virtual void Write();
38 | virtual void Heartbeat();
39 |
40 | virtual bool SelectForRead();
41 | virtual bool SelectForWrite();
42 |
43 | // Do we have any data to write? This is used by ShouldDelete.
44 | virtual int GetOutboundDataSize() {return OutboundDataSize;}
45 |
46 | protected:
47 | struct OutboundPage {
48 | OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
49 | void Free() {if (Buffer) free ((char*)Buffer); }
50 | const char *Buffer;
51 | int Length;
52 | int Offset;
53 | };
54 |
55 | protected:
56 | deque OutboundPages;
57 | int OutboundDataSize;
58 |
59 | private:
60 |
61 | };
62 |
63 |
64 | #endif // __FileStreamDescriptor__H_
65 |
66 |
--------------------------------------------------------------------------------
/tests/test_pause.rb:
--------------------------------------------------------------------------------
1 | $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
2 | require 'eventmachine'
3 | require 'socket'
4 | require 'test/unit'
5 |
6 | class TestPause < Test::Unit::TestCase
7 | TestHost = "127.0.0.1"
8 | TestPort = 9070
9 |
10 | def setup
11 | assert(!EM.reactor_running?)
12 | end
13 |
14 | def teardown
15 | assert(!EM.reactor_running?)
16 | end
17 |
18 | #-------------------------------------
19 |
20 | def test_pause_resume
21 | test = self
22 | server = nil
23 |
24 | s_rx = c_rx = 0
25 |
26 | EM.run do
27 | EM.start_server TestHost, TestPort, Module.new {
28 | define_method :post_init do
29 | server = self
30 | end
31 |
32 | define_method :receive_data do |data|
33 | s_rx += 1
34 |
35 | EM.add_periodic_timer(0.01) { send_data 'hi' }
36 | send_data 'hi'
37 |
38 | # pause server, now no outgoing data will actually
39 | # be sent and no more incoming data will be received
40 | pause
41 | end
42 | }
43 |
44 | c = EM.connect TestHost, TestPort, Module.new {
45 | define_method :receive_data do |data|
46 | c_rx += 1
47 | end
48 | }
49 | EM.add_periodic_timer(0.01) { c.send_data 'hi' }
50 |
51 | EM.add_timer(1) do
52 | test.assert_equal 1, s_rx
53 | test.assert_equal 0, c_rx
54 | test.assert server.paused?
55 |
56 | # resume server, queued outgoing and incoming data will be flushed
57 | server.resume
58 |
59 | test.assert ! server.paused?
60 |
61 | EM.add_timer(1) do
62 | test.assert server.paused?
63 | test.assert_equal 2, s_rx
64 | test.assert c_rx >= 1
65 | EM.stop_event_loop
66 | end
67 | end
68 | end
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/lib/em/test.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # TODO : examples
3 | module Test
4 |
5 | # Calls EM.next_tick { EM.stop } when it is unbound.
6 | module UnbindStopper
7 | def unbind
8 | EM.next_tick { EM.stop }
9 | end
10 | end
11 |
12 | # Immediately closes it's connection when connection_completed is called.
13 | module ImmediateCloser
14 | def connection_completed
15 | close_connection
16 | end
17 | end
18 |
19 | # Immediately closes it's connection when connection_completed is called,
20 | # then calls EM.next_tick { EM.stop } when unbound.
21 | module ClosingStopper
22 | include ImmediateCloser
23 | include UnbindStopper
24 | end
25 |
26 | # Schedule a job to perform when the reactor is running.
27 | def job(&blk)
28 | EM.next_tick(&blk)
29 | end
30 |
31 | # For use to run a callback after a number of reactor ticks. Reactor ticks
32 | # may vary in their runtime, and as such this should not be used as a time
33 | # delay. This method is best suited to achieve relatively rapid non-sleep
34 | # based assertions "in some time", for example when calling
35 | # EM::Server#stop or EM.stop_server, which will complete asynchronously in
36 | # a short timeframe.
37 | def in_ticks(n = 3, &b)
38 | if n == 0
39 | yield
40 | else
41 | job { in_ticks(n - 1, &b) }
42 | end
43 | end
44 |
45 | # Run the reactor, the optional block will be scheduled to run after all
46 | # other scheduled jobs.
47 | def go(timeout = 1, &blk)
48 | job(&blk) if blk
49 | success = true
50 | EM.run do
51 | EM.add_timer(timeout) do
52 | EM.stop
53 | success = false
54 | end
55 | end
56 | assert success, "Timedout after #{timeout} seconds"
57 | end
58 |
59 | end
60 | end
--------------------------------------------------------------------------------
/tests/test_kb.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestKeyboardEvents < Test::Unit::TestCase
32 |
33 | def setup
34 | end
35 |
36 | def teardown
37 | end
38 |
39 | module KbHandler
40 | include EM::Protocols::LineText2
41 | def receive_line d
42 | EM::stop if d == "STOP"
43 | end
44 | end
45 |
46 | # This test doesn't actually do anything useful but is here to
47 | # illustrate the usage. If you removed the timer and ran this test
48 | # by itself on a console, and then typed into the console, it would
49 | # work.
50 | # I don't know how to get the test harness to simulate actual keystrokes.
51 | # When someone figures that out, then we can make this a real test.
52 | #
53 | def test_kb
54 | EM.run {
55 | EM.open_keyboard KbHandler
56 | EM::Timer.new(1) { EM.stop }
57 | } if $stdout.tty? # don't run the test unless it stands a chance of validity.
58 | end
59 |
60 | end
61 |
--------------------------------------------------------------------------------
/lib/em/queue.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # A cross thread, reactor scheduled, linear queue.
3 | #
4 | # This class provides a simple "Queue" like abstraction on top of the reactor
5 | # scheduler. It services two primary purposes:
6 | # * API sugar for stateful protocols
7 | # * Pushing processing onto the same thread as the reactor
8 | #
9 | # See examples/ex_queue.rb for a detailed example.
10 | #
11 | # q = EM::Queue.new
12 | # q.push('one', 'two', 'three')
13 | # 3.times do
14 | # q.pop{ |msg| puts(msg) }
15 | # end
16 | #
17 | class Queue
18 | # Create a new 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 | def pop(*a, &b)
28 | cb = EM::Callback(*a, &b)
29 | EM.schedule do
30 | if @items.empty?
31 | @popq << cb
32 | else
33 | cb.call @items.shift
34 | end
35 | end
36 | nil # Always returns nil
37 | end
38 |
39 | # Push items onto the queue in the reactor thread. The items will not appear
40 | # in the queue immediately, but will be scheduled for addition during the
41 | # next reactor tick.
42 | def push(*items)
43 | EM.schedule do
44 | @items.push(*items)
45 | @popq.shift.call @items.shift until @items.empty? || @popq.empty?
46 | end
47 | end
48 |
49 | # N.B. This is a peek, it's not thread safe, and may only tend toward
50 | # accuracy.
51 | def empty?
52 | @items.empty?
53 | end
54 |
55 | # N.B. This is a peek, it's not thread safe, and may only tend toward
56 | # accuracy.
57 | def size
58 | @items.size
59 | end
60 | end
61 | end
--------------------------------------------------------------------------------
/tests/client.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIFRDCCAywCAQEwDQYJKoZIhvcNAQEFBQAwaDELMAkGA1UEBhMCRU0xFTATBgNV
3 | BAgTDEV2ZW50TWFjaGluZTEVMBMGA1UEChMMRXZlbnRNYWNoaW5lMRQwEgYDVQQL
4 | EwtEZXZlbG9wbWVudDEVMBMGA1UEAxMMRXZlbnRNYWNoaW5lMB4XDTA5MDMyOTAy
5 | MzE0NloXDTEwMDMyOTAyMzE0NlowaDELMAkGA1UEBhMCRU0xFTATBgNVBAgTDEV2
6 | ZW50TWFjaGluZTEVMBMGA1UEChMMRXZlbnRNYWNoaW5lMRQwEgYDVQQLEwtEZXZl
7 | bG9wbWVudDEVMBMGA1UEAxMMRXZlbnRNYWNoaW5lMIICIjANBgkqhkiG9w0BAQEF
8 | AAOCAg8AMIICCgKCAgEAv1FSOIX1z7CQtVBFlrB0A3/V29T+22STKKmiRWYkKL5b
9 | +hkrp9IZ5J4phZHgUVM2VDPOO2Oc2PU6dlGGZISg+UPERunTogxQKezCV0vcE9cK
10 | OwzxCFDRvv5rK8aKMscfBLbNKocAXywuRRQmdxPiVRzbyPrl+qCr/EDLXAX3D77l
11 | S8n2AwDg19VyI+IgFUE+Dy5e1eLoY6nV+Mq+vNXdn3ttF3t+ngac5pj5Q9h+pD5p
12 | 67baDHSnf/7cy2fa/LKrLolVHQR9G2K6cEfeM99NtcsMbkoPs4iI3FA05OVTQHXg
13 | C8C8cRxrb9APl95I/ep65OIaCJgcdYxJ3QD3qOtQo6/NQsGnjbyiUxaEpjfqyT1N
14 | uzWD81Q8uXGNS8yD6dDynt/lseBjyp2nfC3uQ5fY18VdIcu0MJ9pezBUKrNuhlsy
15 | XXEZ2DXj4sY8QOvIcBqSB/zmS1nGEK55xrtkaiaNrY8fe8wRVpcPLxy+P225NFw+
16 | B69FJRA0Lj6Jt9BM4hV/3MSIEWwTVhuw4E02ywDYTzz1wq3ITf0tsbIPn0hXQMxD
17 | ohhAoKioM6u+yHtqsxD0eYaAWmHTVn5oDvOSGpvCpBfWHyA7FP5UQak0fKABEAgK
18 | iQYEnb294AXwXymJttfGTIV/Ne4tLN5dIpNma8UO8rlThlcr6xnTQDbR3gkTDRsC
19 | AwEAATANBgkqhkiG9w0BAQUFAAOCAgEAj7J8fy1LUWoVWnrXDAC9jwJ1nI/YjoSU
20 | 6ywke3o04+nZC5S+dPnuVy+HAwsU940CoNvP6RStI/bH6JL+NIqEFmwM3M8xIEWV
21 | MYVPkfvQUxxGvDnaY7vv93u+6Q77HV3qlhAQBHChyuXyO7TG3+WzsiT9AnBNtAP0
22 | 4jClt5kCAQXLO/p0SFEZQ8Ru9SM8d1i73Z0VDVzs8jYWlBhiherSgbw1xK4wBOpJ
23 | 43XmjZsBSrDpiAXd07Ak3UL2GjfT7eStgebL3UIe39ThE/s/+l43bh0M6WbOBvyQ
24 | i/rZ50kd1GvN0xnZhtv07hIJWO85FGWi7Oet8AzdUZJ17v1Md/f2vdhPVTFN9q+w
25 | mQ6LxjackqCvaJaQfBEbqsn2Tklxk4tZuDioiQbOElT2e6vljQVJWIfNx38Ny2LM
26 | aiXQPQu+4CI7meAh5gXM5nyJGbZvRPsxj89CqYzyHCYs5HBP3AsviBvn26ziOF+c
27 | 544VmHd9HkIv8UTC29hh+R64RlgMQQQdaXFaUrFPTs/do0k8n/c2bPc0iTdfi5Q2
28 | gq6Vi8q6Ay5wGgTtRRbn/mWKuCFjEh94z6pF9Xr06NX0PuEOdf+Ls9vI5vz6G0w6
29 | 0Li7devEN7EKBY+7Mcjg918yq9i5tEiMkUgT68788t3fTC+4iUQ5fDtdrHsaOlIR
30 | 8bs/XQVNE/s=
31 | -----END CERTIFICATE-----
32 |
--------------------------------------------------------------------------------
/lib/em/file_watch.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 |
3 | # This is subclassed from EventMachine::Connection for use with the file monitoring API. Read the
4 | # documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_file.
5 | class FileWatch < Connection
6 | # :stopdoc:
7 | Cmodified = 'modified'.freeze
8 | Cdeleted = 'deleted'.freeze
9 | Cmoved = 'moved'.freeze
10 | # :startdoc:
11 |
12 | def receive_data(data) #:nodoc:
13 | case data
14 | when Cmodified
15 | file_modified
16 | when Cdeleted
17 | file_deleted
18 | when Cmoved
19 | file_moved
20 | end
21 | end
22 |
23 | # Returns the path that EventMachine::watch_file was originally called with. The current implementation
24 | # does not pick up on the new filename after a rename occurs.
25 | def path
26 | @path
27 | end
28 |
29 | # Should be redefined with the user's custom callback that will be fired when the file is modified.
30 | def file_modified
31 | end
32 |
33 | # Should be redefined with the user's custom callback that will be fired when the file is deleted.
34 | # When the file is deleted, stop_watching will be called after this to make sure everything is
35 | # cleaned up correctly.
36 | #
37 | # Note that on linux (with inotify), file_deleted will not be called until all open file descriptors to
38 | # the file have been closed.
39 | def file_deleted
40 | end
41 |
42 | # Should be redefined with the user's custom callback that will be fired when the file is moved or renamed.
43 | def file_moved
44 | end
45 |
46 | # Discontinue monitoring of the file.
47 | # This involves cleaning up the underlying monitoring details with kqueue/inotify, and in turn firing unbind.
48 | # This will be called automatically when a file is deleted. User code may call it as well.
49 | def stop_watching
50 | EventMachine::unwatch_filename(@signature)
51 | end
52 | end
53 |
54 | end
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/Connection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 |
31 | package com.rubyeventmachine;
32 |
33 | //import java.io.*;
34 | import java.nio.*;
35 | import java.net.*;
36 | //import java.nio.channels.*;
37 |
38 | public class Connection {
39 |
40 | public Application application;
41 | public long signature;
42 |
43 | public void postInit() {}
44 | public void connectionCompleted() {}
45 | public void unbind() {}
46 | public void receiveData (ByteBuffer bytebuffer) {}
47 |
48 |
49 | /**
50 | * Called by user code.
51 | * @param bytebuffer
52 | */
53 | public void sendData (ByteBuffer b) {
54 | application.sendData(signature, b);
55 | }
56 |
57 | /**
58 | * This is called by user code.
59 | * TODO: don't expose the exception here.
60 | */
61 | public void close() {
62 | application.closeConnection(signature, false);
63 | }
64 | /**
65 | * This is called by user code/
66 | */
67 | public void closeAfterWriting() {
68 | application.closeConnection(signature, true);
69 | }
70 |
71 | public void sendDatagram (ByteBuffer bb, InetSocketAddress addr) {
72 | application.sendDatagram (signature, bb, addr);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/tests/TestServers.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine.tests;
31 |
32 |
33 | import com.rubyeventmachine.*;
34 | import java.net.*;
35 | import org.junit.After;
36 | import org.junit.AfterClass;
37 | import org.junit.Before;
38 | import org.junit.BeforeClass;
39 | import org.junit.Test;
40 | import org.junit.Assert;
41 |
42 | public class TestServers {
43 |
44 | @BeforeClass
45 | public static void setUpBeforeClass() throws Exception {
46 | }
47 |
48 | @AfterClass
49 | public static void tearDownAfterClass() throws Exception {
50 | }
51 |
52 | @Before
53 | public void setUp() throws Exception {
54 | }
55 |
56 | @After
57 | public void tearDown() throws Exception {
58 | }
59 |
60 |
61 | @Test
62 | public void testBadServerAddress() {
63 | final Application a = new Application();
64 | a.run (new Runnable() {
65 | public void run() {
66 | try {
67 | a.startServer(new InetSocketAddress ("100.100.100.100", 100), new DefaultConnectionFactory());
68 | Assert.fail ("was supposed to throw a reactor exception");
69 | } catch (EmReactorException e) {}
70 | a.stop();
71 | }
72 | });
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/EventableChannel.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine;
31 |
32 | import java.nio.ByteBuffer;
33 | import java.io.IOException;
34 | import java.nio.channels.ClosedChannelException;
35 |
36 | public interface EventableChannel {
37 |
38 | public void scheduleOutboundData (ByteBuffer bb);
39 |
40 | public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort);
41 |
42 | public boolean scheduleClose (boolean afterWriting);
43 |
44 | public void startTls();
45 |
46 | public long getBinding();
47 |
48 | public void readInboundData (ByteBuffer dst) throws IOException;
49 |
50 | public void register() throws ClosedChannelException;
51 |
52 | /**
53 | * This is called by the reactor after it finishes running.
54 | * The idea is to free network resources.
55 | */
56 | public void close();
57 |
58 | public boolean writeOutboundData() throws IOException;
59 |
60 | public void setCommInactivityTimeout (long seconds);
61 |
62 | public Object[] getPeerName();
63 |
64 | public boolean isWatchOnly();
65 |
66 | public boolean isNotifyReadable();
67 | public boolean isNotifyWritable();
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/lib/em/future.rb:
--------------------------------------------------------------------------------
1 | #--
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 16 Jul 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 | # This defines EventMachine::Deferrable#future, which requires
28 | # that the rest of EventMachine::Deferrable has already been seen.
29 | # (It's in deferrable.rb.)
30 |
31 | module EventMachine
32 | module Deferrable
33 |
34 | # A future is a sugaring of a typical deferrable usage.
35 | #--
36 | # Evaluate arg (which may be an expression or a block).
37 | # What's the class of arg?
38 | # If arg is an ordinary expression, then return it.
39 | # If arg is deferrable (responds to :set_deferred_status),
40 | # then look at the arguments. If either callback or errback
41 | # are defined, then use them. If neither are defined, then
42 | # use the supplied block (if any) as the callback.
43 | # Then return arg.
44 | def self.future arg, cb=nil, eb=nil, &blk
45 | arg = arg.call if arg.respond_to?(:call)
46 |
47 | if arg.respond_to?(:set_deferred_status)
48 | if cb || eb
49 | arg.callback(&cb) if cb
50 | arg.errback(&eb) if eb
51 | else
52 | arg.callback(&blk) if blk
53 | end
54 | end
55 |
56 | arg
57 | end
58 |
59 | end
60 | end
61 |
62 |
--------------------------------------------------------------------------------
/tests/test_sasl.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 |
32 | class TestSASL < Test::Unit::TestCase
33 |
34 | # SASL authentication is usually done with UNIX-domain sockets, but
35 | # we'll use TCP so this test will work on Windows. As far as the
36 | # protocol handlers are concerned, there's no difference.
37 |
38 | Host,Port = "127.0.0.1",9560
39 | TestUser,TestPsw = "someone", "password"
40 |
41 | class SaslServer < EM::Connection
42 | include EM::Protocols::SASLauth
43 | def validate usr, psw, sys, realm
44 | usr == TestUser and psw == TestPsw
45 | end
46 | end
47 |
48 | class SaslClient < EM::Connection
49 | include EM::Protocols::SASLauthclient
50 | end
51 |
52 | def test_sasl
53 | resp = nil
54 | EM.run {
55 | EM.start_server( Host, Port, SaslServer )
56 |
57 | c = EM.connect( Host, Port, SaslClient )
58 | d = c.validate?( TestUser, TestPsw )
59 | d.timeout 2
60 | d.callback {
61 | resp = true
62 | EM.stop
63 | }
64 | d.errback {
65 | resp = false
66 | EM.stop
67 | }
68 | }
69 | assert_equal( true, resp )
70 | end
71 |
72 | end
73 |
--------------------------------------------------------------------------------
/ext/kb.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: kb.cpp
6 | Date: 24Aug07
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 | #include "project.h"
21 |
22 |
23 | /**************************************
24 | KeyboardDescriptor::KeyboardDescriptor
25 | **************************************/
26 |
27 | KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em):
28 | EventableDescriptor (0, parent_em),
29 | bReadAttemptedAfterClose (false),
30 | LastIo (gCurrentLoopTime),
31 | InactivityTimeout (0)
32 | {
33 | #ifdef HAVE_EPOLL
34 | EpollEvent.events = EPOLLIN;
35 | #endif
36 | #ifdef HAVE_KQUEUE
37 | MyEventMachine->ArmKqueueReader (this);
38 | #endif
39 | }
40 |
41 |
42 | /***************************************
43 | KeyboardDescriptor::~KeyboardDescriptor
44 | ***************************************/
45 |
46 | KeyboardDescriptor::~KeyboardDescriptor()
47 | {
48 | }
49 |
50 |
51 | /*************************
52 | KeyboardDescriptor::Write
53 | *************************/
54 |
55 | void KeyboardDescriptor::Write()
56 | {
57 | // Why are we here?
58 | throw std::runtime_error ("bad code path in keyboard handler");
59 | }
60 |
61 |
62 | /*****************************
63 | KeyboardDescriptor::Heartbeat
64 | *****************************/
65 |
66 | void KeyboardDescriptor::Heartbeat()
67 | {
68 | // no-op
69 | }
70 |
71 |
72 | /************************
73 | KeyboardDescriptor::Read
74 | ************************/
75 |
76 | void KeyboardDescriptor::Read()
77 | {
78 | char c;
79 | read (GetSocket(), &c, 1);
80 | _GenericInboundDispatch(&c, 1);
81 | }
82 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/tests/EMTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine.tests;
31 |
32 | //import static org.junit.Assert.*;
33 |
34 | import org.junit.After;
35 | import org.junit.AfterClass;
36 | import org.junit.Before;
37 | import org.junit.BeforeClass;
38 | import org.junit.Test;
39 |
40 | import com.rubyeventmachine.EmReactor;
41 |
42 | import java.io.*;
43 | import java.nio.*;
44 |
45 |
46 | public class EMTest {
47 |
48 | class ShortTimer extends EmReactor {
49 | public void eventCallback (String sig, int eventCode, ByteBuffer data) {
50 | System.out.println ("Short Callback "+sig+" "+eventCode+" "+data);
51 | this.stop();
52 | }
53 | }
54 |
55 | @BeforeClass
56 | public static void setUpBeforeClass() throws Exception {
57 | }
58 |
59 | @AfterClass
60 | public static void tearDownAfterClass() throws Exception {
61 | }
62 |
63 | @Before
64 | public void setUp() throws Exception {
65 | }
66 |
67 | @After
68 | public void tearDown() throws Exception {
69 | }
70 |
71 |
72 | @Test
73 | public final void testOneShort() throws IOException {
74 | EmReactor em = new ShortTimer();
75 | em.installOneshotTimer(1050);
76 | em.run();
77 | }
78 |
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/tests/test_proxy_connection.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestProxyConnection < Test::Unit::TestCase
6 |
7 | module ProxyConnection
8 | def initialize(client, request)
9 | @client, @request = client, request
10 | end
11 |
12 | def post_init
13 | EM::enable_proxy(self, @client)
14 | end
15 |
16 | def connection_completed
17 | EM.next_tick {
18 | send_data @request
19 | }
20 | end
21 |
22 | def proxy_target_unbound
23 | $unbound_early = true
24 | EM.stop
25 | end
26 |
27 | def unbind
28 | @client.close_connection_after_writing
29 | end
30 | end
31 |
32 | module Client
33 | def connection_completed
34 | send_data "EventMachine rocks!"
35 | end
36 |
37 | def receive_data(data)
38 | $client_data = data
39 | end
40 |
41 | def unbind
42 | EM.stop
43 | end
44 | end
45 |
46 | module Client2
47 | include Client
48 | def unbind; end
49 | end
50 |
51 | module Server
52 | def receive_data(data)
53 | send_data "I know!" if data == "EventMachine rocks!"
54 | close_connection_after_writing
55 | end
56 | end
57 |
58 | module ProxyServer
59 | def receive_data(data)
60 | EM.connect("127.0.0.1", 54321, ProxyConnection, self, data)
61 | end
62 | end
63 |
64 | module EarlyClosingProxy
65 | def receive_data(data)
66 | EM.connect("127.0.0.1", 54321, ProxyConnection, self, data)
67 | close_connection
68 | end
69 | end
70 |
71 | def test_proxy_connection
72 | EM.run {
73 | EM.start_server("127.0.0.1", 54321, Server)
74 | EM.start_server("127.0.0.1", 12345, ProxyServer)
75 | EM.connect("127.0.0.1", 12345, Client)
76 | }
77 |
78 | assert_equal("I know!", $client_data)
79 | end
80 |
81 | def test_early_close
82 | $client_data = nil
83 | EM.run {
84 | EM.start_server("127.0.0.1", 54321, Server)
85 | EM.start_server("127.0.0.1", 12345, EarlyClosingProxy)
86 | EM.connect("127.0.0.1", 12345, Client2)
87 | }
88 |
89 | assert($unbound_early)
90 | end
91 |
92 | end
93 |
--------------------------------------------------------------------------------
/lib/evma/protocol.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 19 May 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 | module Evma
27 | class Protocol
28 |
29 | attr_reader :signature
30 |
31 | def initialize sig
32 | @signature = sig
33 | end
34 |
35 | def unbind
36 | end
37 |
38 | def close
39 | Evma::Reactor.instance # ensure initialized
40 | EventMachine.close_connection signature, false
41 | end
42 |
43 | def close_after_writing
44 | Evma::Reactor.instance # ensure initialized
45 | EventMachine.close_connection signature, true
46 | end
47 |
48 | end # class Protocol
49 | end # module Evma
50 |
51 |
52 | ###########################################
53 |
54 | module Evma
55 | class StreamProtocol < Protocol
56 |
57 | def initialize sig
58 | super
59 | end
60 |
61 | def send_data data
62 | Evma::Reactor.instance # ensure initialized
63 | EventMachine.send_data signature, data, data.length
64 | end
65 |
66 | end # class Protocol
67 | end # module Evma
68 |
69 |
70 | ###########################################
71 |
72 | module Evma
73 | class DatagramProtocol < Protocol
74 |
75 | def initialize sig
76 | super
77 | end
78 |
79 | def send_message data
80 | Evma::Reactor.instance # ensure initialized
81 | raise "unimplemented"
82 | end
83 |
84 | end # class Protocol
85 | end # module Evma
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/evma/container.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 19 May 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 | require 'singleton'
28 |
29 | module Evma
30 |
31 | class ContainerHasObject < Exception; end
32 | class UnsupportedCallback < Exception; end
33 | class UnknownTarget < Exception; end
34 |
35 | class Container
36 | include Singleton
37 |
38 | def initialize
39 | @objects = {}
40 | end
41 |
42 | def self.store obj
43 | instance.store obj
44 | end
45 |
46 | def self.callback target, opcode, data
47 | instance.callback target, opcode, data
48 | end
49 |
50 | def store obj
51 | sig = obj.signature
52 | raise ContainerHasObject.new(sig) if @objects.has_key?(sig)
53 | @objects[sig] = obj
54 | end
55 |
56 | def callback target, opcode, data
57 | case opcode
58 | when 101 # received data
59 | obj = @objects[target] or raise UnknownTarget.new( target )
60 | obj.receive_data data
61 | when 102 # unbind
62 | obj = @objects[target] or raise UnknownTarget.new( target )
63 | obj.unbind
64 | @objects.delete obj.signature
65 | when 103 # accept
66 | obj = @objects[target] or raise UnknownTarget.new( target )
67 | obj.accept data
68 | else
69 | raise UnsupportedCallback.new( opcode.to_s )
70 | end
71 | end
72 |
73 | end # class Container
74 | end # module Evma
75 |
76 |
--------------------------------------------------------------------------------
/ext/sigs.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: sigs.cpp
6 | Date: 06Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 | #include "project.h"
21 |
22 |
23 | bool gTerminateSignalReceived;
24 |
25 |
26 | /**************
27 | SigtermHandler
28 | **************/
29 |
30 | void SigtermHandler (int sig)
31 | {
32 | // This is a signal-handler, don't do anything frisky. Interrupts are disabled.
33 | // Set the terminate flag WITHOUT trying to lock a mutex- otherwise we can easily
34 | // self-deadlock, especially if the event machine is looping quickly.
35 | gTerminateSignalReceived = true;
36 | }
37 |
38 |
39 | /*********************
40 | InstallSignalHandlers
41 | *********************/
42 |
43 | void InstallSignalHandlers()
44 | {
45 | #ifdef OS_UNIX
46 | static bool bInstalled = false;
47 | if (!bInstalled) {
48 | bInstalled = true;
49 | signal (SIGINT, SigtermHandler);
50 | signal (SIGTERM, SigtermHandler);
51 | signal (SIGPIPE, SIG_IGN);
52 | }
53 | #endif
54 | }
55 |
56 |
57 |
58 | /*******************
59 | WintelSignalHandler
60 | *******************/
61 |
62 | #ifdef OS_WIN32
63 | BOOL WINAPI WintelSignalHandler (DWORD control)
64 | {
65 | if (control == CTRL_C_EVENT)
66 | gTerminateSignalReceived = true;
67 | return TRUE;
68 | }
69 | #endif
70 |
71 | /************
72 | HookControlC
73 | ************/
74 |
75 | #ifdef OS_WIN32
76 | void HookControlC (bool hook)
77 | {
78 | if (hook) {
79 | // INSTALL hook
80 | SetConsoleCtrlHandler (WintelSignalHandler, TRUE);
81 | }
82 | else {
83 | // UNINSTALL hook
84 | SetConsoleCtrlHandler (WintelSignalHandler, FALSE);
85 | }
86 | }
87 | #endif
88 |
89 |
90 |
--------------------------------------------------------------------------------
/ext/ssl.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: ssl.h
6 | Date: 30Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __SslBox__H_
22 | #define __SslBox__H_
23 |
24 |
25 |
26 |
27 | #ifdef WITH_SSL
28 |
29 | /******************
30 | class SslContext_t
31 | ******************/
32 |
33 | class SslContext_t
34 | {
35 | public:
36 | SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
37 | virtual ~SslContext_t();
38 |
39 | private:
40 | static bool bLibraryInitialized;
41 |
42 | private:
43 | bool bIsServer;
44 | SSL_CTX *pCtx;
45 |
46 | EVP_PKEY *PrivateKey;
47 | X509 *Certificate;
48 |
49 | friend class SslBox_t;
50 | };
51 |
52 |
53 | /**************
54 | class SslBox_t
55 | **************/
56 |
57 | class SslBox_t
58 | {
59 | public:
60 | SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, const unsigned long binding);
61 | virtual ~SslBox_t();
62 |
63 | int PutPlaintext (const char*, int);
64 | int GetPlaintext (char*, int);
65 |
66 | bool PutCiphertext (const char*, int);
67 | bool CanGetCiphertext();
68 | int GetCiphertext (char*, int);
69 | bool IsHandshakeCompleted() {return bHandshakeCompleted;}
70 |
71 | X509 *GetPeerCert();
72 |
73 | void Shutdown();
74 |
75 | protected:
76 | SslContext_t *Context;
77 |
78 | bool bIsServer;
79 | bool bHandshakeCompleted;
80 | bool bVerifyPeer;
81 | SSL *pSSL;
82 | BIO *pbioRead;
83 | BIO *pbioWrite;
84 |
85 | PageList OutboundQ;
86 | };
87 |
88 | extern "C" int ssl_verify_wrapper(int, X509_STORE_CTX*);
89 |
90 | #endif // WITH_SSL
91 |
92 |
93 | #endif // __SslBox__H_
94 |
95 |
--------------------------------------------------------------------------------
/lib/em/server.rb:
--------------------------------------------------------------------------------
1 | module EventMachine
2 | # An object oriented approach at EventMachine servers. This server class
3 | # provides a convenient handle to EventMachine server bindings. The delegate
4 | # parameter defines the connection module, or class that will be used to
5 | # process connections. Optionally, users may pass a block which will be used
6 | # as if it were passed to Module.new and passed in. The delegate paramenter
7 | # will also accept an already constructed object to which it will delegate
8 | # the callbacks for all connections to that object using
9 | # EventMachine::DelegateConnection.
10 | class Server
11 |
12 | # The host and port parameters define the listen side of a server binding.
13 | # The delegate parameter defines the object, module, or class that will be
14 | # utilised. Users may also pass a block instead of a delegate object which
15 | # will define a module for the connections.
16 | def initialize(host, port, delegate = nil, *delegate_args, &blk)
17 | @host, @port = host, port
18 | set_delegate(delegate || blk)
19 | @delegate_args = delegate_args
20 | end
21 |
22 | # Schedule the start of the server listener. If the reactor is not yet
23 | # running, then this method will simply schedule listening for the reactor
24 | # start.
25 | def listen
26 | args = @delegate + @delegate_args
27 | EM.schedule { @signature = EM.start_server(@host, @port, *args) }
28 | self
29 | end
30 |
31 | # Schedule the asynchronous shutdown of the server binding.
32 | def stop
33 | EM.schedule { EM.stop_server(@signature) if @signature }
34 | self
35 | end
36 |
37 | # Start the reactor. If the reactor is not already running, calling this
38 | # method will block until EM.stop is called.
39 | def run
40 | EM.run
41 | end
42 |
43 | private
44 | def set_delegate(delegate)
45 | @delegate = case delegate
46 | when Class
47 | [delegate]
48 | when Module
49 | [Class.new(EM::Connection) { include delegate }]
50 | when Proc
51 | [Module.new(&delegate)]
52 | # when nil # TODO
53 | # LoggerConnection
54 | else
55 | [DelegateConnection, delegate]
56 | end
57 | end
58 | end
59 | end
--------------------------------------------------------------------------------
/tests/test_ssl_verify.rb:
--------------------------------------------------------------------------------
1 | $:.unshift "../lib"
2 | require 'eventmachine'
3 | require 'test/unit'
4 |
5 | class TestSslVerify < Test::Unit::TestCase
6 |
7 | def setup
8 | $dir = File.dirname(File.expand_path(__FILE__)) + '/'
9 | $cert_from_file = File.read($dir+'client.crt')
10 | end
11 |
12 | module Client
13 | def connection_completed
14 | start_tls(:private_key_file => $dir+'client.key', :cert_chain_file => $dir+'client.crt')
15 | end
16 |
17 | def ssl_handshake_completed
18 | $client_handshake_completed = true
19 | close_connection
20 | end
21 |
22 | def unbind
23 | EM.stop_event_loop
24 | end
25 | end
26 |
27 | module AcceptServer
28 | def post_init
29 | start_tls(:verify_peer => true)
30 | end
31 |
32 | def ssl_verify_peer(cert)
33 | $cert_from_server = cert
34 | true
35 | end
36 |
37 | def ssl_handshake_completed
38 | $server_handshake_completed = true
39 | end
40 | end
41 |
42 | module DenyServer
43 | def post_init
44 | start_tls(:verify_peer => true)
45 | end
46 |
47 | def ssl_verify_peer(cert)
48 | $cert_from_server = cert
49 | # Do not accept the peer. This should now cause the connection to shut down without the SSL handshake being completed.
50 | false
51 | end
52 |
53 | def ssl_handshake_completed
54 | $server_handshake_completed = true
55 | end
56 | end
57 |
58 | def test_accept_server
59 | $client_handshake_completed, $server_handshake_completed = false, false
60 | EM.run {
61 | EM.start_server("127.0.0.1", 16784, AcceptServer)
62 | EM.connect("127.0.0.1", 16784, Client).instance_variable_get("@signature")
63 | }
64 |
65 | assert_equal($cert_from_file, $cert_from_server)
66 | assert($client_handshake_completed)
67 | assert($server_handshake_completed)
68 | end
69 |
70 | def test_deny_server
71 | $client_handshake_completed, $server_handshake_completed = false, false
72 | EM.run {
73 | EM.start_server("127.0.0.1", 16784, DenyServer)
74 | EM.connect("127.0.0.1", 16784, Client)
75 | }
76 |
77 | assert_equal($cert_from_file, $cert_from_server)
78 | assert(!$client_handshake_completed)
79 | assert(!$server_handshake_completed)
80 | end
81 |
82 | end
83 |
--------------------------------------------------------------------------------
/tests/test_errors.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 |
28 | ###### THIS TEST IS NOW OBSOLETE.
29 | ###### As of 27Dec07, the hookable error handling is obsolete because
30 | ###### of its performance impact.
31 |
32 |
33 | $:.unshift "../lib"
34 | require 'eventmachine'
35 | require 'test/unit'
36 |
37 | class TestErrors < Test::Unit::TestCase
38 |
39 | Localhost = "127.0.0.1"
40 | Localport = 9801
41 |
42 | def setup
43 | end
44 |
45 | def obsolete_teardown
46 | # Calling #set_runtime_error_hook with no block restores the
47 | # default handling of runtime_errors.
48 | #
49 | EM.set_runtime_error_hook
50 | end
51 |
52 | def test_no_tests_stub
53 | end
54 |
55 | # EM has a default handler for RuntimeErrors that are emitted from
56 | # user written code. You can override the handler if you wish, but it's
57 | # easier to call #set_runtime_error_hook.
58 | # Ordinarily, an error in user code invoked by the reactor aborts the
59 | # run.
60 | #
61 | def obsolete_test_unhandled_error
62 | assert_raises( RuntimeError ) {
63 | EM.run {
64 | EM.add_timer(0) {raise "AAA"}
65 | }
66 | }
67 |
68 | end
69 |
70 | def obsolete_test_handled_error
71 | err = nil
72 | EM.run {
73 | EM.set_runtime_error_hook {
74 | err = true
75 | EM.stop
76 | }
77 | EM.add_timer(0) {raise "AAA"}
78 | }
79 | assert err
80 | end
81 | end
82 |
83 |
--------------------------------------------------------------------------------
/ext/page.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: page.cpp
6 | Date: 30Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #include "project.h"
22 |
23 |
24 | /******************
25 | PageList::PageList
26 | ******************/
27 |
28 | PageList::PageList()
29 | {
30 | }
31 |
32 |
33 | /*******************
34 | PageList::~PageList
35 | *******************/
36 |
37 | PageList::~PageList()
38 | {
39 | while (HasPages())
40 | PopFront();
41 | }
42 |
43 |
44 | /***************
45 | PageList::Front
46 | ***************/
47 |
48 | void PageList::Front (const char **page, int *length)
49 | {
50 | assert (page && length);
51 |
52 | if (HasPages()) {
53 | Page p = Pages.front();
54 | *page = p.Buffer;
55 | *length = p.Size;
56 | }
57 | else {
58 | *page = NULL;
59 | *length = 0;
60 | }
61 | }
62 |
63 |
64 | /******************
65 | PageList::PopFront
66 | ******************/
67 |
68 | void PageList::PopFront()
69 | {
70 | if (HasPages()) {
71 | Page p = Pages.front();
72 | Pages.pop_front();
73 | if (p.Buffer)
74 | free ((void*)p.Buffer);
75 | }
76 | }
77 |
78 |
79 | /******************
80 | PageList::HasPages
81 | ******************/
82 |
83 | bool PageList::HasPages()
84 | {
85 | return (Pages.size() > 0) ? true : false;
86 | }
87 |
88 |
89 | /**************
90 | PageList::Push
91 | **************/
92 |
93 | void PageList::Push (const char *buf, int size)
94 | {
95 | if (buf && (size > 0)) {
96 | char *copy = (char*) malloc (size);
97 | if (!copy)
98 | throw runtime_error ("no memory in pagelist");
99 | memcpy (copy, buf, size);
100 | Pages.push_back (Page (copy, size));
101 | }
102 | }
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/tests/TestTimers.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 | package com.rubyeventmachine.tests;
31 |
32 | import com.rubyeventmachine.*;
33 | import java.io.*;
34 |
35 | import org.junit.Assert;
36 | import org.junit.After;
37 | import org.junit.AfterClass;
38 | import org.junit.Before;
39 | import org.junit.BeforeClass;
40 | import org.junit.Test;
41 |
42 |
43 | public class TestTimers {
44 |
45 | @BeforeClass
46 | public static void setUpBeforeClass() throws Exception {
47 | }
48 |
49 | @AfterClass
50 | public static void tearDownAfterClass() throws Exception {
51 | }
52 |
53 | @Before
54 | public void setUp() throws Exception {
55 | }
56 |
57 | @After
58 | public void tearDown() throws Exception {
59 | }
60 |
61 |
62 |
63 | @Test
64 | public final void test2() throws IOException {
65 | Application a = new Application();
66 | a.addTimer(0, new Timer() {
67 | public void fire() {
68 | application.stop();
69 | }
70 | });
71 | a.run();
72 | Assert.assertEquals (1, 1); // just to make sure the reactor halts.
73 | }
74 |
75 | @Test
76 | public final void test3() throws IOException {
77 | Application a = new Application();
78 | a.addTimer (0.1, new PeriodicTimer() {
79 | int n = 0;
80 | public void fire() {
81 | n++;
82 | if (n == 5)
83 | application.stop();
84 | }
85 | });
86 | a.run();
87 | Assert.assertEquals(1, 1);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/tests/test_ssl_args.rb:
--------------------------------------------------------------------------------
1 | require "test/unit"
2 | require 'tempfile'
3 |
4 | $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
5 | require "eventmachine"
6 |
7 | module EventMachine
8 | def self._set_mocks
9 | class < priv_file)
57 | end
58 | assert_raises(EventMachine::FileNotFoundException) do
59 | conn.start_tls(:cert_chain_file => cert_file)
60 | end
61 | assert_raises(EventMachine::FileNotFoundException) do
62 | conn.start_tls(:private_key_file => priv_file, :cert_chain_file => cert_file)
63 | end
64 | end
65 |
66 | def test_tls_params_file_does_exist
67 | priv_file = Tempfile.new('em_test')
68 | cert_file = Tempfile.new('em_test')
69 | priv_file_path = priv_file.path
70 | cert_file_path = cert_file.path
71 | conn = EventMachine::Connection.new('foo')
72 | params = {:private_key_file => priv_file_path, :cert_chain_file => cert_file_path}
73 | begin
74 | conn.start_tls params
75 | rescue Object
76 | assert(false, 'should not have raised an exception')
77 | end
78 | end
79 | end if EM.ssl?
--------------------------------------------------------------------------------
/ext/files.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: files.cpp
6 | Date: 26Aug06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 | #include "project.h"
21 |
22 |
23 | /******************************************
24 | FileStreamDescriptor::FileStreamDescriptor
25 | ******************************************/
26 |
27 | FileStreamDescriptor::FileStreamDescriptor (int fd, EventMachine_t *em):
28 | EventableDescriptor (fd, em),
29 | OutboundDataSize (0)
30 | {
31 | cerr << "#####";
32 | }
33 |
34 |
35 | /*******************************************
36 | FileStreamDescriptor::~FileStreamDescriptor
37 | *******************************************/
38 |
39 | FileStreamDescriptor::~FileStreamDescriptor()
40 | {
41 | // Run down any stranded outbound data.
42 | for (size_t i=0; i < OutboundPages.size(); i++)
43 | OutboundPages[i].Free();
44 | }
45 |
46 |
47 | /**************************
48 | FileStreamDescriptor::Read
49 | **************************/
50 |
51 | void FileStreamDescriptor::Read()
52 | {
53 | }
54 |
55 | /***************************
56 | FileStreamDescriptor::Write
57 | ***************************/
58 |
59 | void FileStreamDescriptor::Write()
60 | {
61 | }
62 |
63 |
64 | /*******************************
65 | FileStreamDescriptor::Heartbeat
66 | *******************************/
67 |
68 | void FileStreamDescriptor::Heartbeat()
69 | {
70 | }
71 |
72 |
73 | /***********************************
74 | FileStreamDescriptor::SelectForRead
75 | ***********************************/
76 |
77 | bool FileStreamDescriptor::SelectForRead()
78 | {
79 | cerr << "R?";
80 | return false;
81 | }
82 |
83 |
84 | /************************************
85 | FileStreamDescriptor::SelectForWrite
86 | ************************************/
87 |
88 | bool FileStreamDescriptor::SelectForWrite()
89 | {
90 | cerr << "W?";
91 | return false;
92 | }
93 |
94 |
95 |
--------------------------------------------------------------------------------
/ext/fastfilereader/extconf.rb:
--------------------------------------------------------------------------------
1 | require 'mkmf'
2 |
3 | def check_libs libs = [], fatal = false
4 | libs.all? { |lib| have_library(lib) || (abort("could not find library: #{lib}") if fatal) }
5 | end
6 |
7 | def check_heads heads = [], fatal = false
8 | heads.all? { |head| have_header(head) || (abort("could not find header: #{head}") if fatal)}
9 | end
10 |
11 | def add_define(name)
12 | $defs.push("-D#{name}")
13 | end
14 |
15 | add_define 'BUILD_FOR_RUBY'
16 |
17 | # Minor platform details between *nix and Windows:
18 |
19 | if RUBY_PLATFORM =~ /(mswin|mingw|bccwin)/
20 | GNU_CHAIN = $1 == 'mingw'
21 | OS_WIN32 = true
22 | add_define "OS_WIN32"
23 | else
24 | GNU_CHAIN = true
25 | OS_UNIX = true
26 | add_define 'OS_UNIX'
27 | end
28 |
29 | # Main platform invariances:
30 |
31 | case RUBY_PLATFORM
32 | when /mswin32/, /mingw32/, /bccwin32/
33 | check_heads(%w[windows.h winsock.h], true)
34 | check_libs(%w[kernel32 rpcrt4 gdi32], true)
35 |
36 | if GNU_CHAIN
37 | CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
38 | else
39 | $defs.push "-EHs"
40 | $defs.push "-GR"
41 | end
42 |
43 | when /solaris/
44 | check_libs(%w[nsl socket], true)
45 |
46 | add_define 'OS_SOLARIS8'
47 |
48 | # Patch by Tim Pease, fixes SUNWspro compile problems.
49 | if CONFIG['CC'] == 'cc'
50 | # SUN CHAIN
51 | $CFLAGS = CONFIG['CFLAGS'] = "-KPIC -G"
52 | CONFIG['CCDLFLAGS'] = "-KPIC"
53 | else
54 | # GNU CHAIN
55 | # on Unix we need a g++ link, not gcc.
56 | CONFIG['LDSHARED'] = "$(CXX) -shared"
57 | end
58 |
59 | when /openbsd/
60 | # OpenBSD branch contributed by Guillaume Sellier.
61 |
62 | # on Unix we need a g++ link, not gcc. On OpenBSD, linking against libstdc++ have to be explicitly done for shared libs
63 | CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++ -fPIC"
64 | CONFIG['LDSHAREDXX'] = "$(CXX) -shared -lstdc++ -fPIC"
65 |
66 | when /darwin/
67 | # on Unix we need a g++ link, not gcc.
68 | # Ff line contributed by Daniel Harple.
69 | CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
70 |
71 | when /linux/
72 | # on Unix we need a g++ link, not gcc.
73 | CONFIG['LDSHARED'] = "$(CXX) -shared"
74 |
75 | when /aix/
76 | # on Unix we need a g++ link, not gcc.
77 | CONFIG['LDSHARED'] = "$(CXX) -shared -Wl,-G"
78 |
79 | else
80 | # on Unix we need a g++ link, not gcc.
81 | CONFIG['LDSHARED'] = "$(CXX) -shared"
82 | end
83 |
84 | create_makefile "fastfilereaderext"
--------------------------------------------------------------------------------
/tests/test_smtpclient.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestSmtpClient < Test::Unit::TestCase
32 |
33 | Localhost = "127.0.0.1"
34 | Localport = 9801
35 |
36 | def setup
37 | end
38 |
39 | def teardown
40 | end
41 |
42 | def test_a
43 | # No real tests until we have a server implementation to test against.
44 | # This is what the call looks like, though:
45 | err = nil
46 | EM.run {
47 | d = EM::Protocols::SmtpClient.send :domain=>"example.com",
48 | :host=>Localhost,
49 | :port=>Localport, # optional, defaults 25
50 | :starttls=>true,
51 | :from=>"sender@example.com",
52 | :to=> ["to_1@example.com", "to_2@example.com"],
53 | :header=> {"Subject" => "This is a subject line"},
54 | :body=> "This is the body of the email",
55 | :verbose=>true
56 | d.errback {|e|
57 | err = e
58 | EM.stop
59 | }
60 | }
61 | assert(err)
62 | end
63 |
64 | def test_content
65 | err = nil
66 | EM.run {
67 | d = EM::Protocols::SmtpClient.send :domain=>"example.com",
68 | :host=>Localhost,
69 | :port=>Localport, # optional, defaults 25
70 | :starttls=>true,
71 | :from=>"sender@example.com",
72 | :to=> ["to_1@example.com", "to_2@example.com"],
73 | :content => ["Subject: xxx\r\n\r\ndata\r\n.\r\n"],
74 | :verbose=>true
75 | d.errback {|e|
76 | err = e
77 | EM.stop
78 | }
79 | }
80 | assert(err)
81 | end
82 |
83 | end
84 |
--------------------------------------------------------------------------------
/lib/evma/factory.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 19 May 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 | module Evma
27 | class ProtocolFactory < Protocol
28 |
29 | #--
30 | # default implementation raises an exception.
31 | # we expect subclasses to override this.
32 | # we can't do anything reasonable here because
33 | def accept new_object
34 | # don't bother calling Evma::Reactor.instance, since only Reactor can call accept
35 | Evma::Container.store Evma::Protocol.new( new_object )
36 | EventMachine.close_connection new_object, false
37 | end
38 |
39 |
40 | end # class ProtocolFactory
41 | end # module Evma
42 |
43 | ######################################
44 |
45 | module Evma
46 | class TcpSocket
47 |
48 | def self.connect server, port, protocol_handler = Evma::Protocol
49 | Evma::Reactor.instance # ensure initialization
50 | sig = EventMachine.connect_server server, port
51 | Evma::Container.store protocol_handler.new( sig )
52 | end
53 |
54 | end
55 | end # module Evma
56 |
57 | ######################################
58 |
59 | module Evma
60 | class TcpServerFactory < Evma::ProtocolFactory
61 |
62 | def initialize server, port, protocol_handler = Evma::Protocol
63 | Evma::Reactor.instance # ensure initialization
64 | sig = EventMachine.start_tcp_server server, port
65 | super sig
66 | @protocol_handler = protocol_handler
67 | Evma::Container.store self
68 | end
69 |
70 | def accept new_obj
71 | # don't bother calling Evma::Reactor.instance, since only Reactor can call accept
72 | Evma::Container.store @protocol_handler.new( new_obj )
73 | end
74 |
75 | end
76 | end # module Evma
77 |
78 |
--------------------------------------------------------------------------------
/ext/emwin.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: emwin.h
6 | Date: 05May06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | // THIS ENTIRE FILE IS FOR WINDOWS BUILDS ONLY.
22 | // INCOMPLETE AND DISABLED FOR NOW.
23 | #ifdef xOS_WIN32
24 |
25 | #ifndef __EventMachine__H_
26 | #define __EventMachine__H_
27 |
28 |
29 | extern time_t gCurrentLoopTime;
30 |
31 | class EventableDescriptor;
32 |
33 |
34 | /********************
35 | class EventMachine_t
36 | ********************/
37 |
38 | class EventMachine_t
39 | {
40 | public:
41 | EventMachine_t (void(*event_callback)(const char*, int, const char*, int));
42 | virtual ~EventMachine_t();
43 |
44 | void Run();
45 | void ScheduleHalt();
46 | const char *InstallOneshotTimer (int);
47 | const char *ConnectToServer (const char *, int);
48 | const char *CreateTcpServer (const char *, int);
49 | const char *OpenDatagramSocket (const char *, int);
50 |
51 | void Add (EventableDescriptor*);
52 |
53 | public:
54 | enum { // Event names
55 | TIMER_FIRED = 100,
56 | CONNECTION_READ = 101,
57 | CONNECTION_UNBOUND = 102,
58 | CONNECTION_ACCEPTED = 103,
59 | CONNECTION_COMPLETED = 104,
60 | LOOPBREAK_SIGNAL = 105
61 | };
62 |
63 | private:
64 | HANDLE Iocp;
65 |
66 | private:
67 | bool _RunOnce();
68 | bool _RunTimers();
69 | void _AddNewDescriptors();
70 |
71 | private:
72 | enum {
73 | MaxOutstandingTimers = 40,
74 | HeartbeatInterval = 2
75 | };
76 | void (*EventCallback)(const char*, int, const char*, int);
77 |
78 | class Timer_t: public Bindable_t {
79 | };
80 |
81 | multimap Timers;
82 | vector Descriptors;
83 | vector NewDescriptors;
84 |
85 | time_t NextHeartbeatTime;
86 | };
87 |
88 |
89 |
90 |
91 | #endif // __EventMachine__H_
92 |
93 | #endif // OS_WIN32
94 |
95 |
--------------------------------------------------------------------------------
/tests/test_servers.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'socket'
30 | require 'test/unit'
31 |
32 | class TestServers < Test::Unit::TestCase
33 |
34 | Host = "127.0.0.1"
35 | Port = 9555
36 |
37 | module NetstatHelper
38 | GlobalUdp4Rexp = /udp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
39 | GlobalTcp4Rexp = /tcp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
40 | LocalUdpRexp = /udp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
41 | LocalTcpRexp = /tcp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
42 | def grep_netstat(pattern)
43 | `netstat -an`.scan(/^.*$/).grep(pattern)
44 | end
45 | end
46 | include NetstatHelper
47 |
48 | class TestStopServer < EM::Connection
49 | def initialize *args
50 | super
51 | end
52 | def post_init
53 | # TODO,sucks that this isn't OOPy enough.
54 | EM.stop_server @server_instance
55 | end
56 | end
57 |
58 | def run_test_stop_server
59 | EM.run {
60 | sig = EM.start_server(Host, Port)
61 | assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).size >= 1, "Server didn't start")
62 | EM.stop_server sig
63 | # Give the server some time to shutdown.
64 | EM.add_timer(0.1) {
65 | assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
66 | EM.stop
67 | }
68 | }
69 | end
70 | def test_stop_server
71 | assert(grep_netstat(LocalTcpRexp).grep(Port).empty?, "Port already in use")
72 | 5.times {run_test_stop_server}
73 | assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
74 | end
75 |
76 | end
77 |
--------------------------------------------------------------------------------
/tasks/cpp.rake:
--------------------------------------------------------------------------------
1 | # EventMachine C++ Rakefile Stab Case
2 | # TODO : track header files as a build dependency...
3 | # TODO : cross platform support
4 | # TODO : configure style functionality
5 | namespace :cpp do
6 |
7 | require 'rake/clean'
8 |
9 | # *nix only atm...
10 | module Cpp
11 | class < [proc { |targ|
39 | targ.sub(%r{^#{EmConfig::Path}/(.*)\.o$}, "#{EmConfig::Path}/\\1.cpp")
40 | }] do |t|
41 | Cpp.compile t.source, t.name, EmConfig::Includes, EmConfig::Flags
42 | end
43 |
44 | file "#{EmConfig::Path}/libeventmachine.a" => EmConfig::Compiled do |t|
45 | Cpp.static t.name, EmConfig::Compiled
46 | end
47 | CLEAN.include("#{EmConfig::Path}/libeventmachine.a")
48 |
49 | module AppConfig
50 | Appname = 'echo_em'
51 | Sources = FileList['*.cpp']
52 | Compiled = Sources.sub(%r{^(.*)\.cpp}, '\\1.o')
53 |
54 | Flags = ["", EmConfig::Flags].join(' ')
55 | Includes = ["-I. -I#{EmConfig::Path}", EmConfig::Includes].join(' ')
56 | Libs = ["-L#{EmConfig::Path} -leventmachine", EmConfig::Libs].join(' ')
57 | end
58 | CLEAN.include(AppConfig::Compiled)
59 | CLEAN.include(AppConfig::Appname)
60 |
61 | rule %r{^.*\.o$} => [proc { |targ|
62 | targ.sub(%r{^(.*)\.o$}, '\\1.cpp')
63 | }] do |t|
64 | Cpp.compile t.source, t.name, AppConfig::Includes, AppConfig::Flags
65 | end
66 |
67 | file AppConfig::Appname => ["#{EmConfig::Path}/libeventmachine.a", AppConfig::Compiled] do |t|
68 | Cpp.link AppConfig::Compiled, t.name, AppConfig::Libs, AppConfig::Flags
69 | end
70 |
71 | task :build => AppConfig::Appname
72 |
73 | task :run => AppConfig::Appname do
74 | sh "./#{AppConfig::Appname}"
75 | end
76 |
77 | end
--------------------------------------------------------------------------------
/ext/eventmachine_cpp.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: eventmachine_cpp.h
6 | Date: 27Jul07
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __EVMA_EventmachineCpp__H_
22 | #define __EVMA_EventmachineCpp__H_
23 |
24 |
25 | // This material is only for directly integrating EM into C++ programs.
26 |
27 | namespace EM {
28 |
29 | void Callback (const unsigned long sig, int event, const char *data, const unsigned long length);
30 | void Run (void(*)(void));
31 | void AddTimer (int, void(*)());
32 | void StopReactor();
33 |
34 | /***************
35 | class Eventable
36 | ***************/
37 |
38 | class Eventable {
39 | public:
40 | Eventable() {}
41 | virtual ~Eventable() {}
42 |
43 | unsigned long Signature;
44 |
45 | // Called by the framework
46 | virtual void ReceiveData (const char *data, int length) {}
47 | virtual void ConnectionCompleted() {}
48 | virtual void Accept (const unsigned long) {}
49 | virtual void Unbind() {}
50 | virtual void PostInit() {}
51 | virtual void SslHandshakeCompleted() {}
52 |
53 | void StopReactor() {EM::StopReactor();}
54 | };
55 |
56 | /****************
57 | class Connection
58 | ****************/
59 |
60 | class Connection: public Eventable {
61 | public:
62 | Connection() {}
63 | virtual ~Connection() {}
64 |
65 | virtual void Connect (const char*, int);
66 | virtual void BindConnect (const char *, int, const char*, int);
67 |
68 | void SendData (const char *data);
69 | void SendData (const char *data, int length);
70 | void Close (bool afterWriting);
71 | };
72 |
73 |
74 | /**************
75 | class Acceptor
76 | **************/
77 |
78 | class Acceptor: public Eventable {
79 | public:
80 | Acceptor() {PostInit();}
81 | virtual ~Acceptor() {}
82 |
83 | void Start (const char*, int);
84 | void Accept (const unsigned long);
85 |
86 | virtual Connection *MakeConnection() {return new Connection();}
87 | };
88 |
89 |
90 | };
91 |
92 |
93 |
94 |
95 |
96 | #endif // __EVMA_EventmachineCpp__H_
97 |
--------------------------------------------------------------------------------
/lib/em/spawnable.rb:
--------------------------------------------------------------------------------
1 | #--
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 25 Aug 2007
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 | module EventMachine
27 | # Support for Erlang-style processes.
28 | #
29 | class SpawnedProcess
30 | # Send a message to the spawned process
31 | def notify *x
32 | me = self
33 | EM.next_tick {
34 | # A notification executes in the context of this
35 | # SpawnedProcess object. That makes self and notify
36 | # work as one would expect.
37 | #
38 | y = me.call(*x)
39 | if y and y.respond_to?(:pull_out_yield_block)
40 | a,b = y.pull_out_yield_block
41 | set_receiver a
42 | self.notify if b
43 | end
44 | }
45 | end
46 | alias_method :resume, :notify
47 | alias_method :run, :notify # for formulations like (EM.spawn {xxx}).run
48 | #attr_accessor :receiver
49 |
50 | #--
51 | # I know I'm missing something stupid, but the inside of class << s
52 | # can't see locally-bound values. It can see globals, though.
53 | def set_receiver blk
54 | $em______tmpglobal = blk
55 | class << self
56 | define_method :call, $em______tmpglobal.dup
57 | end
58 | end
59 |
60 | end
61 |
62 | class YieldBlockFromSpawnedProcess # :nodoc:
63 | def initialize block, notify
64 | @block = [block,notify]
65 | end
66 | def pull_out_yield_block
67 | @block
68 | end
69 | end
70 |
71 | # Spawn an erlang-style process
72 | def self.spawn &block
73 | s = SpawnedProcess.new
74 | s.set_receiver block
75 | s
76 | end
77 |
78 | def self.yield &block # :nodoc:
79 | return YieldBlockFromSpawnedProcess.new( block, false )
80 | end
81 |
82 | def self.yield_and_notify &block # :nodoc:
83 | return YieldBlockFromSpawnedProcess.new( block, true )
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/lib/em/delegate_connection.rb:
--------------------------------------------------------------------------------
1 | require 'socket'
2 |
3 | module EventMachine
4 | # A simple delegate provider that will pass on all callbacks the connection
5 | # receives to the given delegate object, prepended with a reference to
6 | # itself.
7 | #
8 | # Example Usage:
9 | #
10 | # The following is an example of a central logging delegate. Only one
11 | # instance of this delegate needs to exist, as such users may more easily
12 | # aggregate less stated connection events.
13 | #
14 | # my_delegate = Class.new do
15 | # def method_missing(name, connection, *args)
16 | # puts [
17 | # Time.now, connection.signature, connection.ip_port, name, *args
18 | # ].inspect
19 | # end
20 | # end
21 | # EM.connect(host, port, DelegateConnection, my_delegate)
22 | #
23 | # A Note on the Init Callback:
24 | #
25 | # Delegates must respond to the callback methods or an error will be
26 | # raised at runtime. One additional callback has been added from initialize,
27 | # in order to not clobber the API from normal ruby class construction, when
28 | # a new connection is initialized #init will be called on the delegate.
29 | class DelegateConnection < Connection
30 |
31 | # The given delegate will be used, init will be called each time a new
32 | # connection is opened, passing in the connection object.
33 | def initialize(delegate)
34 | @delegate = delegate
35 | @delegate.init(self)
36 | @ip, @port = nil, nil
37 | end
38 |
39 | # Retreive the connections ip and port from the reactor.
40 | def address_tuple
41 | @port, @ip = Socket.unpack_sockaddr_in(get_peername)
42 | end
43 |
44 | # The remote IP.
45 | def ip
46 | @ip || address_tuple && @ip
47 | end
48 |
49 | # The remote Port.
50 | def port
51 | @port || address_tuple && @port
52 | end
53 |
54 | # A consistent, frozen string containing ip:port, well suited for a hash
55 | # key.
56 | def ip_port
57 | @ip_port ||= "#{@ip}:#{@port}".freeze
58 | end
59 |
60 | def post_init
61 | # TODO pass in connection details
62 | @delegate.post_init(self)
63 | end
64 |
65 | def receive_data(data)
66 | @delegate.receive_data(self, data)
67 | end
68 |
69 | def ssl_handshake_completed
70 | @delegate.ssl_handshake_completed(self)
71 | end
72 |
73 | def ssl_verify_peer(cert)
74 | @delegate.ssl_verify_peer(self, cert)
75 | end
76 |
77 | def unbind
78 | @delegate.unbind(self)
79 | end
80 |
81 | def proxy_target_unbound
82 | @delegate.proxy_target_unbound(self)
83 | end
84 |
85 | def connection_completed
86 | @delegate.connection_completed(self)
87 | end
88 | end
89 | end
--------------------------------------------------------------------------------
/tests/test_smtpserver.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestSmtpServer < Test::Unit::TestCase
32 |
33 | # Don't test on port 25. It requires superuser and there's probably
34 | # a mail server already running there anyway.
35 | Localhost = "127.0.0.1"
36 | Localport = 25001
37 |
38 | # This class is an example of what you need to write in order
39 | # to implement a mail server. You override the methods you are
40 | # interested in. Some, but not all, of these are illustrated here.
41 | #
42 | class Mailserver < EM::Protocols::SmtpServer
43 |
44 | attr_reader :my_msg_body, :my_sender, :my_recipients
45 |
46 | def initialize *args
47 | super
48 | end
49 | def receive_sender sender
50 | @my_sender = sender
51 | #p sender
52 | true
53 | end
54 | def receive_recipient rcpt
55 | @my_recipients ||= []
56 | @my_recipients << rcpt
57 | true
58 | end
59 | def receive_data_chunk c
60 | @my_msg_body = c.last
61 | end
62 | def connection_ended
63 | EM.stop
64 | end
65 | end
66 |
67 | def test_mail
68 | c = nil
69 | EM.run {
70 | EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
71 | EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
72 | EM::Protocols::SmtpClient.send :host=>Localhost,
73 | :port=>Localport,
74 | :domain=>"bogus",
75 | :from=>"me@example.com",
76 | :to=>"you@example.com",
77 | :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
78 | :body=>"Not much of interest here."
79 |
80 | }
81 | assert_equal( "Not much of interest here.", c.my_msg_body )
82 | assert_equal( "", c.my_sender )
83 | assert_equal( [""], c.my_recipients )
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/tests/test_server.rb:
--------------------------------------------------------------------------------
1 | require "test/unit"
2 |
3 | require "eventmachine"
4 |
5 | class TestEventmachineServer < Test::Unit::TestCase
6 | include EM::Test
7 |
8 | attr_reader :localhost, :port
9 |
10 | def setup
11 | @localhost, @port = '127.0.0.1', 10000 + rand(1000)
12 | end
13 |
14 | def test_initialize
15 | assert EM::Server.new(localhost, port)
16 | end
17 |
18 | def test_listen_with_module
19 | go do
20 | EM::Server.new(localhost, port, UnbindStopper).listen
21 | EM.connect localhost, port, ImmediateCloser
22 | end
23 | end
24 |
25 | def test_listen_with_class
26 | klass = Class.new(EM::Connection) { include UnbindStopper }
27 | go do
28 | EM::Server.new(localhost, port, klass).listen
29 | EM.connect localhost, port, ImmediateCloser
30 | end
31 | end
32 |
33 | def test_listen_with_block
34 | go do
35 | server = EM::Server.new(localhost, port) { include UnbindStopper }
36 | server.listen
37 | EM.connect localhost, port, ImmediateCloser
38 | end
39 | end
40 |
41 | def test_listen_without_reactor_running_schedules
42 | EM::Server.new(localhost, port, UnbindStopper).listen
43 | go { EM.connect localhost, port, ImmediateCloser }
44 | end
45 |
46 | def test_run
47 | server = EM::Server.new(localhost, port, UnbindStopper).listen
48 | job { EM.connect localhost, port, ImmediateCloser }
49 | server.run
50 | end
51 |
52 | def test_stop
53 | server = EM::Server.new(localhost, port, EM::Connection).listen.stop
54 | # We have to belay this a few ticks to allow the machine to asynchronously
55 | # complete the closing of the listen socket
56 | go { in_ticks(5) { EM.connect(localhost, port, UnbindStopper) } }
57 | end
58 |
59 | class Aggregator
60 | attr_reader :table
61 |
62 | def initialize
63 | @table = Hash.new { |h,k| h[k] = [] }
64 | end
65 |
66 | def method_missing(name, *args)
67 | @table[name] << args
68 | end
69 | end
70 |
71 | def test_delegate_connection
72 | aggregator = Aggregator.new
73 | server = EM::Server.new(localhost, port, aggregator).listen
74 | 2.times do
75 | job { EM.connect localhost, port, ImmediateCloser }
76 | end
77 | go { EM.connect localhost, port, ClosingStopper }
78 | assert_equal 3, aggregator.table[:init].size
79 | assert_equal 3, aggregator.table[:unbind].size
80 | end
81 |
82 | module ArgCaller
83 | def initialize(*args)
84 | args.each { |a| a.call }
85 | end
86 | end
87 |
88 | def test_delegate_arguments
89 | arg1_ran, arg2_ran = false, false
90 | arg1, arg2 = lambda { arg1_ran = true }, lambda { arg2_ran = true }
91 | server = EM::Server.new(localhost, port, EM::DelegateConnection, arg1, arg2)
92 | go { EM.connect localhost, port, ClosingStopper }
93 | end
94 | end
--------------------------------------------------------------------------------
/docs/COPYING:
--------------------------------------------------------------------------------
1 | EventMachine is copyrighted free software owned by Francis Cianfrocca
2 | (blackhedd ... gmail.com). The Owner of this software permits you to
3 | redistribute and/or modify the software under either the terms of the GPL
4 | version 2 (see the file GPL), or the conditions below ("Ruby License"):
5 |
6 | 1. You may make and give away verbatim copies of the source form of this
7 | software without restriction, provided that you retain ALL of the
8 | original copyright notices and associated disclaimers.
9 |
10 | 2. You may modify your copy of the software in any way, provided that
11 | you do at least ONE of the following:
12 |
13 | a) place your modifications in the Public Domain or otherwise
14 | make them Freely Available, such as by posting said
15 | modifications to Usenet or an equivalent medium, or by allowing
16 | the author to include your modifications in the software.
17 |
18 | b) use the modified software only within your corporation or
19 | organization.
20 |
21 | c) give non-standard binaries non-standard names, with
22 | instructions on where to get the original software distribution.
23 |
24 | d) make other distribution arrangements with the Owner.
25 |
26 | 3. You may distribute the software in object code or binary form,
27 | provided that you do at least ONE of the following:
28 |
29 | a) distribute the binaries and library files of the software,
30 | together with instructions (in a manual page or equivalent)
31 | on where to get the original distribution.
32 |
33 | b) accompany the distribution with the machine-readable source of
34 | the software.
35 |
36 | c) give non-standard binaries non-standard names, with
37 | instructions on where to get the original software distribution.
38 |
39 | d) make other distribution arrangements with the Owner.
40 |
41 | 4. You may modify and include parts of the software into any other
42 | software (possibly commercial), provided you comply with the terms in
43 | Sections 1, 2, and 3 above. But some files in the distribution
44 | are not written by the Owner, so they may be made available to you
45 | under different terms.
46 |
47 | For the list of those files and their copying conditions, see the
48 | file LEGAL.
49 |
50 | 5. The scripts and library files supplied as input to or produced as
51 | output from the software do not automatically fall under the
52 | copyright of the software, but belong to whoever generated them,
53 | and may be sold commercially, and may be aggregated with this
54 | software.
55 |
56 | 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
57 | IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
58 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59 | PURPOSE.
60 |
61 |
--------------------------------------------------------------------------------
/java/src/com/rubyeventmachine/tests/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * $Id$
3 | *
4 | * Author:: Francis Cianfrocca (gmail: blackhedd)
5 | * Homepage:: http://rubyeventmachine.com
6 | * Date:: 15 Jul 2007
7 | *
8 | * See EventMachine and EventMachine::Connection for documentation and
9 | * usage examples.
10 | *
11 | *
12 | *----------------------------------------------------------------------------
13 | *
14 | * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15 | * Gmail: blackhedd
16 | *
17 | * This program is free software; you can redistribute it and/or modify
18 | * it under the terms of either: 1) the GNU General Public License
19 | * as published by the Free Software Foundation; either version 2 of the
20 | * License, or (at your option) any later version; or 2) Ruby's License.
21 | *
22 | * See the file COPYING for complete licensing information.
23 | *
24 | *---------------------------------------------------------------------------
25 | *
26 | *
27 | */
28 |
29 |
30 |
31 | package com.rubyeventmachine.tests;
32 |
33 |
34 | import org.junit.After;
35 | import org.junit.AfterClass;
36 | import org.junit.Before;
37 | import org.junit.BeforeClass;
38 | import org.junit.Test;
39 | import org.junit.Assert;
40 | import java.net.*;
41 | import java.io.*;
42 | import java.nio.*;
43 |
44 | import com.rubyeventmachine.*;
45 |
46 | public class ApplicationTest {
47 |
48 | @BeforeClass
49 | public static void setUpBeforeClass() throws Exception {
50 | }
51 |
52 | @AfterClass
53 | public static void tearDownAfterClass() throws Exception {
54 | }
55 |
56 | @Before
57 | public void setUp() throws Exception {
58 | }
59 |
60 | @After
61 | public void tearDown() throws Exception {
62 | }
63 |
64 | @Test
65 | public void testRunnableArgument() {
66 | final Application a = new Application();
67 | a.run (new Runnable() {
68 | public void run() {
69 | a.stop();
70 | }
71 | });
72 | }
73 |
74 |
75 |
76 | class F implements ConnectionFactory {
77 | public Connection connection() {
78 | return new Connection() {
79 | public void receiveData (ByteBuffer bb) {
80 | application.stop();
81 | }
82 | };
83 | }
84 |
85 | };
86 |
87 | @Test
88 | public void testTcpServer() throws EmReactorException {
89 | final Application a = new Application();
90 | final SocketAddress saddr = new InetSocketAddress ("127.0.0.1", 9008);
91 | a.run (new Runnable() {
92 | public void run() {
93 | try {
94 | a.startServer (saddr, new F());
95 | } catch (EmReactorException e) { Assert.fail(); }
96 | new Thread() {
97 | public void run() {
98 | try {
99 | Socket s = new Socket ("127.0.0.1", 9008);
100 | s.getOutputStream().write(new String ("boo").getBytes());
101 | } catch (UnknownHostException e) {
102 | } catch (IOException e) {}
103 | }
104 | }.start();
105 | }
106 | });
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/tasks/project.rake:
--------------------------------------------------------------------------------
1 | require 'rake/gempackagetask'
2 | require 'rake/rdoctask'
3 | require 'rake/clean'
4 |
5 | # monkey bitchin' for windows stuffs...
6 | module FileUtils
7 | # If any of these methods ever clobber, try removing them.
8 | # Hopefully they'll do something semantically similar.
9 | abort "Err: #{__FILE__}:#{__LINE__} monkey patch windows? clobbers!" unless instance_methods.grep(/windows\?/).empty?
10 | abort "Err: #{__FILE__}:#{__LINE__} monkey patch sudo clobbers!" unless instance_methods.grep(/sudo/).empty?
11 | abort "Err: #{__FILE__}:#{__LINE__} monkey patch gem_cmd clobbers!" unless instance_methods.grep(/gem_cmd/).empty?
12 | def windows?; RUBY_PLATFORM =~ /mswin|mingw/; end
13 | def sudo(cmd)
14 | if windows? || (require 'etc'; Etc.getpwuid.uid == 0)
15 | sh cmd
16 | else
17 | sh "sudo #{cmd}"
18 | end
19 | end
20 | def gem_cmd(action, name, *args)
21 | rb = Gem.ruby rescue nil
22 | rb ||= (require 'rbconfig'; File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']))
23 | sudo "#{rb} -r rubygems -e 'require %{rubygems/gem_runner}; Gem::GemRunner.new.run(%w{#{action} #{name} #{args.join(' ')}})'"
24 | end
25 | end
26 |
27 |
28 | # Setup our packaging tasks, we're just jacking the builtins.
29 | Rake::GemPackageTask.new(Spec) do |pkg|
30 | pkg.need_tar, pkg.need_tar_gz, pkg.need_zip = true, true, true if Package
31 | pkg.gem_spec = Spec
32 | end
33 | Rake::Task[:clean].enhance [:clobber_package]
34 |
35 | # Only generate rdoc if the spec says so, again, jack the builtins.
36 | if Spec.has_rdoc
37 | Rake::RDocTask.new do |rd|
38 | rd.title = Spec.name
39 | rd.rdoc_dir = 'rdoc'
40 | rd.main = "README"
41 | rd.rdoc_files.include("lib/**/*.rb", *Spec.extra_rdoc_files)
42 | rd.rdoc_files.exclude(*%w(lib/em/version lib/emva lib/evma/ lib/pr_eventmachine lib/jeventmachine))
43 | end
44 | Rake::Task[:clean].enhance [:clobber_rdoc]
45 |
46 | desc 'Generate and open documentation'
47 | task :docs => :rdoc do
48 | case RUBY_PLATFORM
49 | when /darwin/ ; sh 'open rdoc/index.html'
50 | when /mswin|mingw/ ; sh 'start rdoc\index.html'
51 | else
52 | sh 'firefox rdoc/index.html'
53 | end
54 | end
55 | end
56 |
57 | if Spec.default_executable
58 | desc "Run #{Spec.default_executable}"
59 | task :run do ruby File.join(Spec.bindir, Spec.default_executable) end
60 | end
61 |
62 | require 'rubygems'
63 |
64 | desc 'Install gem (and sudo if required)'
65 | task :install => :package do
66 | gem_cmd(:install, "pkg/#{Spec.name}-#{Spec.version}.gem")
67 | end
68 |
69 | desc 'Uninstall gem (and sudo if required)'
70 | task :uninstall do
71 | gem_cmd(:uninstall, "#{Spec.name}", "-v=#{Spec.version}")
72 | end
73 |
74 | # Find an scm's store directory, if we do, make a task to commit to it only
75 | # after running all the tests (successfully).
76 | if scm = %w(git svn bzr hg).find { |d| File.directory? ".#{d}" }
77 | desc "Run tests then commit to #{scm}"
78 | task :commit => :test do sh "#{scm} commit" end
79 | end
--------------------------------------------------------------------------------
/tests/test_delegate_connection.rb:
--------------------------------------------------------------------------------
1 | require "test/unit"
2 | require "eventmachine"
3 |
4 | class TestDelegateConnection < Test::Unit::TestCase
5 | include EM::Test
6 |
7 | class Aggregator
8 | attr_reader :table
9 |
10 | def initialize
11 | @table = Hash.new { |h,k| h[k] = [] }
12 | end
13 |
14 | def method_missing(name, *args)
15 | @table[name] << args
16 | end
17 | end
18 |
19 | def test_delegate_connection_with_server
20 | localhost, port = '127.0.0.1', 10000+rand(500)
21 | aggregator = Aggregator.new
22 | server = EM::Server.new(localhost, port, aggregator).listen
23 | 2.times do
24 | job { EM.connect localhost, port, ImmediateCloser }
25 | end
26 | go { EM.connect localhost, port, ClosingStopper }
27 | assert_equal 3, aggregator.table[:init].size
28 | assert_equal 3, aggregator.table[:unbind].size
29 | end
30 |
31 | def test_parameterless_callbacks
32 | signature = '12345678'
33 |
34 | tracker = Aggregator.new
35 |
36 | # EM::Connection.new overrides new, and requires a signature parameter
37 | conn = EM::DelegateConnection.new(signature, tracker)
38 |
39 | assert_equal 1, tracker.table[:init].size
40 |
41 | # Automatically called by EM::Connection.new
42 | assert_equal 1, tracker.table[:post_init].size
43 |
44 | parameterless_callbacks = %w(
45 | ssl_handshake_completed unbind proxy_target_unbound connection_completed
46 | )
47 | parameterless_callbacks.each do |method|
48 | conn.__send__ method
49 | assert_equal 1, tracker.table[method.to_sym].size
50 | end
51 |
52 | end
53 |
54 | def test_parametered_callbacks
55 | signature = '12345678'
56 |
57 | tracker = Aggregator.new
58 |
59 | # EM::Connection.new overrides new, and requires a signature parameter
60 | conn = EM::DelegateConnection.new(signature, tracker)
61 |
62 | conn.receive_data("rubyfoo")
63 | assert_equal "rubyfoo", tracker.table[:receive_data].first.last
64 |
65 | conn.ssl_verify_peer("some cert")
66 | assert_equal "some cert", tracker.table[:ssl_verify_peer].first.last
67 | end
68 |
69 | def test_ip_port
70 | localhost, port = '127.0.0.1', 10000+rand(500)
71 | aggregator = Aggregator.new
72 | server = EM::Server.new(localhost, port, aggregator).listen
73 |
74 | assertions = lambda {
75 | assert_equal localhost, aggregator.table[:init].first.first.ip
76 | assert_kind_of Integer, aggregator.table[:init].first.first.port
77 | ip = localhost
78 | prt = aggregator.table[:init].first.first.port
79 | assert_equal "#{ip}:#{prt}", aggregator.table[:init].first.first.ip_port
80 | }
81 |
82 | go do
83 | EM.connect localhost, port, Module.new {
84 | define_method(:connection_completed) do
85 | # Allow reactor callbacks for server side of connection by waiting
86 | # another tick.
87 | EM.next_tick {
88 | assertions.call
89 | EM.stop
90 | }
91 | end
92 | }
93 | end
94 | end
95 | end
--------------------------------------------------------------------------------
/lib/em/messages.rb:
--------------------------------------------------------------------------------
1 | #--
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 16 Jul 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 | =begin
27 |
28 | Message Routing in EventMachine.
29 |
30 | The goal here is to enable "routing points," objects that can send and receive
31 | "messages," which are delimited streams of bytes. The boundaries of a message
32 | are preserved as it passes through the reactor system.
33 |
34 | There will be several module methods defined in EventMachine to create route-point
35 | objects (which will probably have a base class of EventMachine::MessageRouter
36 | until someone suggests a better name).
37 |
38 | As with I/O objects, routing objects will receive events by having the router
39 | core call methods on them. And of course user code can and will define handlers
40 | to deal with events of interest.
41 |
42 | The message router base class only really needs a receive_message method. There will
43 | be an EM module-method to send messages, in addition to the module methods to create
44 | the various kinds of message receivers.
45 |
46 | The simplest kind of message receiver object can receive messages by being named
47 | explicitly in a parameter to EM#send_message. More sophisticated receivers can define
48 | pub-sub selectors and message-queue names. And they can also define channels for
49 | route-points in other processes or even on other machines.
50 |
51 | A message is NOT a marshallable entity. Rather, it's a chunk of flat content more like
52 | an Erlang message. Initially, all content submitted for transmission as a message will
53 | have the to_s method called on it. Eventually, we'll be able to transmit certain structured
54 | data types (XML and YAML documents, Structs within limits) and have them reconstructed
55 | on the other end.
56 |
57 | A fundamental goal of the message-routing capability is to interoperate seamlessly with
58 | external systems, including non-Ruby systems like ActiveMQ. We will define various protocol
59 | handlers for things like Stomp and possibly AMQP, but these will be wrapped up and hidden
60 | from the users of the basic routing capability.
61 |
62 | As with Erlang, a critical goal is for programs that are built to use message-passing to work
63 | WITHOUT CHANGE when the code is re-based on a multi-process system.
64 |
65 | =end
66 |
67 |
--------------------------------------------------------------------------------
/tests/test_attach.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | #----------------------------------------------------------------------------
4 | #
5 | # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
6 | # Gmail: blackhedd
7 | #
8 | # This program is free software; you can redistribute it and/or modify
9 | # it under the terms of either: 1) the GNU General Public License
10 | # as published by the Free Software Foundation; either version 2 of the
11 | # License, or (at your option) any later version; or 2) Ruby's License.
12 | #
13 | # See the file COPYING for complete licensing information.
14 | #
15 | #---------------------------------------------------------------------------
16 | #
17 |
18 | $:.unshift "../lib"
19 | require 'eventmachine'
20 | require 'socket'
21 | require 'test/unit'
22 |
23 |
24 | class TestAttach < Test::Unit::TestCase
25 |
26 | Host = "127.0.0.1"
27 | Port = 9550
28 |
29 | class EchoServer < EM::Connection
30 | def receive_data data
31 | send_data data
32 | end
33 | end
34 |
35 | class EchoClient < EM::Connection
36 | def initialize
37 | self.notify_readable = true
38 | $sock.write("abc\n")
39 | end
40 |
41 | def notify_readable
42 | $read = $sock.readline
43 | $fd = detach
44 | end
45 |
46 | def unbind
47 | EM.next_tick do
48 | $sock.write("def\n")
49 | EM.add_timer(0.5){ EM.stop }
50 | end
51 | end
52 | end
53 |
54 | def test_attach
55 | EM.run{
56 | EM.start_server Host, Port, EchoServer
57 | $sock = TCPSocket.new Host, Port
58 | EM.watch $sock, EchoClient
59 | }
60 |
61 | assert_equal $read, "abc\n"
62 | unless defined? JRuby # jruby filenos are not real
63 | assert_equal $fd, $sock.fileno
64 | end
65 | assert_equal false, $sock.closed?
66 | assert_equal $sock.readline, "def\n"
67 | end
68 |
69 | module PipeWatch
70 | def notify_readable
71 | $read = $r.readline
72 | EM.stop
73 | end
74 | end
75 |
76 | def test_attach_pipe
77 | EM.run{
78 | $r, $w = IO.pipe
79 | EM.watch $r, PipeWatch do |c|
80 | c.notify_readable = true
81 | end
82 | $w.write("ghi\n")
83 | }
84 |
85 | assert_equal $read, "ghi\n"
86 | end
87 |
88 | def test_set_readable
89 | EM.run{
90 | $r, $w = IO.pipe
91 | c = EM.watch $r, PipeWatch do |c|
92 | c.notify_readable = false
93 | end
94 |
95 | EM.next_tick{
96 | $before = c.notify_readable?
97 | c.notify_readable = true
98 | $after = c.notify_readable?
99 | }
100 |
101 | $w.write("jkl\n")
102 | }
103 |
104 | assert !$before
105 | assert $after
106 | assert_equal $read, "jkl\n"
107 | end
108 |
109 | module PipeReader
110 | def receive_data data
111 | $read = data
112 | EM.stop
113 | end
114 | end
115 |
116 | def test_read_write_pipe
117 | EM.run{
118 | $r, $w = IO.pipe
119 | EM.attach $r, PipeReader
120 | writer = EM.attach($w)
121 | writer.send_data 'ghi'
122 | }
123 |
124 | assert_equal $read, "ghi"
125 | end
126 | end
--------------------------------------------------------------------------------
/ext/binder.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: binder.cpp
6 | Date: 07Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 | #include "project.h"
21 |
22 | #define DEV_URANDOM "/dev/urandom"
23 |
24 |
25 | map Bindable_t::BindingBag;
26 |
27 |
28 | /********************************
29 | STATIC Bindable_t::CreateBinding
30 | ********************************/
31 |
32 | unsigned long Bindable_t::CreateBinding()
33 | {
34 | // XXX use atomic_t to prevent thread-safety issues
35 | static unsigned long num = 0;
36 | while(BindingBag[++num]);
37 | return num;
38 | }
39 |
40 | #if 0
41 | string Bindable_t::CreateBinding()
42 | {
43 | static int index = 0;
44 | static string seed;
45 |
46 | if ((index >= 1000000) || (seed.length() == 0)) {
47 | #ifdef OS_UNIX
48 | int fd = open (DEV_URANDOM, O_RDONLY);
49 | if (fd < 0)
50 | throw std::runtime_error ("No entropy device");
51 |
52 | unsigned char u[16];
53 | size_t r = read (fd, u, sizeof(u));
54 | if (r < sizeof(u))
55 | throw std::runtime_error ("Unable to read entropy device");
56 |
57 | unsigned char *u1 = (unsigned char*)u;
58 | char u2 [sizeof(u) * 2 + 1];
59 |
60 | for (size_t i=0; i < sizeof(u); i++)
61 | sprintf (u2 + (i * 2), "%02x", u1[i]);
62 |
63 | seed = string (u2);
64 | #endif
65 |
66 |
67 | #ifdef OS_WIN32
68 | UUID uuid;
69 | UuidCreate (&uuid);
70 | unsigned char *uuidstring = NULL;
71 | UuidToString (&uuid, &uuidstring);
72 | if (!uuidstring)
73 | throw std::runtime_error ("Unable to read uuid");
74 | seed = string ((const char*)uuidstring);
75 |
76 | RpcStringFree (&uuidstring);
77 | #endif
78 |
79 | index = 0;
80 |
81 |
82 | }
83 |
84 | stringstream ss;
85 | ss << seed << (++index);
86 | return ss.str();
87 | }
88 | #endif
89 |
90 | /*****************************
91 | STATIC: Bindable_t::GetObject
92 | *****************************/
93 |
94 | Bindable_t *Bindable_t::GetObject (const unsigned long binding)
95 | {
96 | map::const_iterator i = BindingBag.find (binding);
97 | if (i != BindingBag.end())
98 | return i->second;
99 | else
100 | return NULL;
101 | }
102 |
103 |
104 | /**********************
105 | Bindable_t::Bindable_t
106 | **********************/
107 |
108 | Bindable_t::Bindable_t()
109 | {
110 | Binding = Bindable_t::CreateBinding();
111 | BindingBag [Binding] = this;
112 | }
113 |
114 |
115 |
116 | /***********************
117 | Bindable_t::~Bindable_t
118 | ***********************/
119 |
120 | Bindable_t::~Bindable_t()
121 | {
122 | BindingBag.erase (Binding);
123 | }
124 |
125 |
126 |
--------------------------------------------------------------------------------
/tests/client.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIJKAIBAAKCAgEAv1FSOIX1z7CQtVBFlrB0A3/V29T+22STKKmiRWYkKL5b+hkr
3 | p9IZ5J4phZHgUVM2VDPOO2Oc2PU6dlGGZISg+UPERunTogxQKezCV0vcE9cKOwzx
4 | CFDRvv5rK8aKMscfBLbNKocAXywuRRQmdxPiVRzbyPrl+qCr/EDLXAX3D77lS8n2
5 | AwDg19VyI+IgFUE+Dy5e1eLoY6nV+Mq+vNXdn3ttF3t+ngac5pj5Q9h+pD5p67ba
6 | DHSnf/7cy2fa/LKrLolVHQR9G2K6cEfeM99NtcsMbkoPs4iI3FA05OVTQHXgC8C8
7 | cRxrb9APl95I/ep65OIaCJgcdYxJ3QD3qOtQo6/NQsGnjbyiUxaEpjfqyT1NuzWD
8 | 81Q8uXGNS8yD6dDynt/lseBjyp2nfC3uQ5fY18VdIcu0MJ9pezBUKrNuhlsyXXEZ
9 | 2DXj4sY8QOvIcBqSB/zmS1nGEK55xrtkaiaNrY8fe8wRVpcPLxy+P225NFw+B69F
10 | JRA0Lj6Jt9BM4hV/3MSIEWwTVhuw4E02ywDYTzz1wq3ITf0tsbIPn0hXQMxDohhA
11 | oKioM6u+yHtqsxD0eYaAWmHTVn5oDvOSGpvCpBfWHyA7FP5UQak0fKABEAgKiQYE
12 | nb294AXwXymJttfGTIV/Ne4tLN5dIpNma8UO8rlThlcr6xnTQDbR3gkTDRsCAwEA
13 | AQKCAgB495RDRQB9x6hX3F+DviI8rDGug+h5FAiwJ0IBG2o1kNdbNVsTC5dvpEmg
14 | uPHaugCaEP+PMZbU34mNklKlb+7QbPbH18UGqz5so9TlmYOXz9oaKD6nAWL9nqRo
15 | 02pCXQDR3DuxbhbgFnFTIECJ/jqXkl2toGaVp83W+6kZkHP8srkMyLASihWgosc+
16 | xRWAGvaAZtNz7br+eT5fxuH/SEKPOl1qAZ23kXrXm1XQfizk8MnMTptkUMYv+hfl
17 | TM98BASUsiTs6g+opy43HFn09naOQcqkWZO/8s6Gbvhi2lVfZqi5Ba6g3lVYJ3gU
18 | kGoako4N9qB7WqJz+LYjVR9C4TbkkJ9OD6ArwGAx5IIzC3XKSxCyY/pUn4YumPhY
19 | fjvY/km54TBtx/isS1TAgjSgDUxbzrfbkh7afOXSOniy9bWJMgNqHF61dqxWxmUg
20 | F5Tch9zH3qFFVkXpYzDU/R8ZV+CRouCvhn0eZYDh8IqIAwjH0VjkxjPyQtrdrMd3
21 | gDKMVKoY31EOMLZzv8a0prjpr15A+uw30tT336qb3fofks4pZKUJw8ru9jJVir2p
22 | +RML6iUHCmIeceF7/N1meooSMLPJe0xgKeMb9M4Wtd/et2UNVtP8nCDG622rf2a0
23 | F/EudXuFgc3FB8nXRw9TCkw9xKQff38edG5xPFUEgqObbVl5YQKCAQEA5DDKGOmp
24 | EO5Zuf/kZfG6/AMMYwAuv1HrYTV2w/HnI3tyQ34Xkeqo+I/OqmRk68Ztxw4Kx1So
25 | SRavkotrlWhhDpl2+Yn1BjkHktSoOdf9gJ9z9llkLmbOkBjmupig1NUB7fq/4y2k
26 | MdqJXDy3uVKHJ97gxdIheMTyHiKuMJPnuT5lZtlT210Ig82P7sLQb/sgCfKVFTr0
27 | Z3haQ5/tBNKjq+igT4nMBWupOTD1q2GeZLIZACnmnUIhvu+3/bm0l+wiCB0DqF0T
28 | Wy9tlL3fqQSCqzevL7/k5Lg6tJTaP/XYePB73TsOtAXgIaoltXgRBsBUeE1eaODx
29 | kMT6E1PPtn7EqQKCAQEA1qImmTWGqhKICrwje40awPufFtZ/qXKVCN/V+zYsrJV1
30 | EnZpUDM+zfitlQCugnrQVHSpgfekI6mmVkmogO3fkNjUFTq+neg7IHOUHnqotx+3
31 | NMqIsyFInGstu9mfPd26fzZjUtx5wKF38LDTIJJAEJ83U3UpPBfpwKmiOGDXOa54
32 | 2i4em/bb/hrQR6JySruZYLi0fXnGI5ZOfpkHgC/KOFkKNKAg2oh4B9qo7ACyiSNk
33 | yojb2mmn6g1OLPxi7wGUSrkS1HQq4an6RZ+eUO0HXVWag0QStdQ91M9IrIHgSBBG
34 | 0e86Ar6jtD579gqsbz4ySpI/FqEI9obTC+E1/b0aIwKCAQAGz334qGCnZLXA22ZR
35 | tJlEFEM2YTcD9snzqMjWqE2hvXl3kjfZ3wsUABbG9yAb+VwlaMHhmSE8rTSoRwj6
36 | +JaM/P+UCw4JFYKoWzh6IXwrbpbjb1+SEvdvTY71WsDSGVlpZOZ9PUt9QWyAGD/T
37 | hCcMhZZn0RG2rQoc5CQWxxNPcBFOtIXQMkKizGvTUHUwImqeYWMZsxzASdNH2WoV
38 | jsPbyaGfPhmcv83ZKyDp8IvtrXMZkiaT4vlm3Xi8VeKR9jY9z7/gMob1XcEDg3c9
39 | cCkGOy87WZrXSLhX02mAJzJCycqom66gqNw7pPxjIiY/8VWUEZsTvkL3cymTkhjM
40 | 9ZOhAoIBAGUaNqJe01NTrV+ZJgGyAxM6s8LXQYV5IvjuL2bJKxwUvvP2cT9FFGWD
41 | qYiRrKJr5ayS07IUC+58oIzu33/0DSa27JgfduD9HrT3nKMK1mSEfRFSAjiXChQc
42 | bIubRGapBoub/AdxMazqoovvT1R9b84kobQfcVAMV6DYh0CVZWyXYfgsV2DSVOiK
43 | iufjfoDzg5lLCEI+1XW3/LunrB/W4yPN1X/amf8234ublYyt+2ucD4NUGnP05xLa
44 | N6P7M0MwdEEKkvMe0YBBSFH5kWK/dIOjqkgBDes20fVnuuz/tL1dZW7IiIP4dzaV
45 | ZGEOwBEatCfqYetv6b/u3IUxDfS7Wg8CggEBALoOwkn5LGdQg+bpdZAKJspGnJWL
46 | Kyr9Al2tvgc69rxfpZqS5eDLkYYCzWPpspSt0Axm1O7xOUDQDt42luaLNGJzHZ2Q
47 | Hn0ZNMhyHpe8d8mIQngRjD+nuLI/uFUglPzabDOCOln2aycjg1mA6ecXP1XMEVbu
48 | 0RB/0IE36XTMfZ+u9+TRjkBLpmUaX1FdIQQWfwUou/LfaXotoQlhSGAcprLrncuJ
49 | T44UATYEgO/q9pMM33bdE3eBYZHoT9mSvqoLCN4s0LuwOYItIxLKUj0GulL0VQOI
50 | SZi+0A1c8cVDXgApkBrWPDQIR9JS4de0gW4hnDoUvHtUc2TYPRnz6N9MtFY=
51 | -----END RSA PRIVATE KEY-----
52 |
--------------------------------------------------------------------------------
/ext/fastfilereader/rubymain.cpp:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id: rubymain.cpp 4529 2007-07-04 11:32:22Z francis $
4 |
5 | File: rubymain.cpp
6 | Date: 02Jul07
7 |
8 | Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: garbagecat10
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 |
22 | #include
23 | #include
24 | using namespace std;
25 |
26 | #include
27 | #include "mapper.h"
28 |
29 | static VALUE EmModule;
30 | static VALUE FastFileReader;
31 | static VALUE Mapper;
32 |
33 |
34 |
35 | /*********
36 | mapper_dt
37 | *********/
38 |
39 | static void mapper_dt (void *ptr)
40 | {
41 | if (ptr)
42 | delete (Mapper_t*) ptr;
43 | }
44 |
45 | /**********
46 | mapper_new
47 | **********/
48 |
49 | static VALUE mapper_new (VALUE self, VALUE filename)
50 | {
51 | Mapper_t *m = new Mapper_t (StringValuePtr (filename));
52 | if (!m)
53 | rb_raise (rb_eException, "No Mapper Object");
54 | VALUE v = Data_Wrap_Struct (Mapper, 0, mapper_dt, (void*)m);
55 | return v;
56 | }
57 |
58 |
59 | /****************
60 | mapper_get_chunk
61 | ****************/
62 |
63 | static VALUE mapper_get_chunk (VALUE self, VALUE start, VALUE length)
64 | {
65 | Mapper_t *m = NULL;
66 | Data_Get_Struct (self, Mapper_t, m);
67 | if (!m)
68 | rb_raise (rb_eException, "No Mapper Object");
69 |
70 | // TODO, what if some moron sends us a negative start value?
71 | unsigned _start = NUM2INT (start);
72 | unsigned _length = NUM2INT (length);
73 | if ((_start + _length) > m->GetFileSize())
74 | rb_raise (rb_eException, "Mapper Range Error");
75 |
76 | const char *chunk = m->GetChunk (_start);
77 | if (!chunk)
78 | rb_raise (rb_eException, "No Mapper Chunk");
79 | return rb_str_new (chunk, _length);
80 | }
81 |
82 | /************
83 | mapper_close
84 | ************/
85 |
86 | static VALUE mapper_close (VALUE self)
87 | {
88 | Mapper_t *m = NULL;
89 | Data_Get_Struct (self, Mapper_t, m);
90 | if (!m)
91 | rb_raise (rb_eException, "No Mapper Object");
92 | m->Close();
93 | return Qnil;
94 | }
95 |
96 | /***********
97 | mapper_size
98 | ***********/
99 |
100 | static VALUE mapper_size (VALUE self)
101 | {
102 | Mapper_t *m = NULL;
103 | Data_Get_Struct (self, Mapper_t, m);
104 | if (!m)
105 | rb_raise (rb_eException, "No Mapper Object");
106 | return INT2NUM (m->GetFileSize());
107 | }
108 |
109 |
110 | /**********************
111 | Init_fastfilereaderext
112 | **********************/
113 |
114 | extern "C" void Init_fastfilereaderext()
115 | {
116 | EmModule = rb_define_module ("EventMachine");
117 | FastFileReader = rb_define_class_under (EmModule, "FastFileReader", rb_cObject);
118 | Mapper = rb_define_class_under (FastFileReader, "Mapper", rb_cObject);
119 |
120 | rb_define_module_function (Mapper, "new", (VALUE(*)(...))mapper_new, 1);
121 | rb_define_method (Mapper, "size", (VALUE(*)(...))mapper_size, 0);
122 | rb_define_method (Mapper, "close", (VALUE(*)(...))mapper_close, 0);
123 | rb_define_method (Mapper, "get_chunk", (VALUE(*)(...))mapper_get_chunk, 2);
124 | }
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/docs/RELEASE_NOTES:
--------------------------------------------------------------------------------
1 | RUBY/EventMachine RELEASE NOTES
2 |
3 | --------------------------------------------------
4 | Version: 0.9.0, released xxXXX07
5 | Added Erlang-like distributed-computing features
6 |
7 | --------------------------------------------------
8 | Version: 0.8.0, released 23Jun07
9 | Added an epoll implementation for Linux 2.6 kernels.
10 | Added evented #popen.
11 |
12 | --------------------------------------------------
13 | Version: 0.7.3, released 22May07
14 | Added a large variety of small features. See the ChangeLog.
15 |
16 | --------------------------------------------------
17 | Version: 0.7.1, released xxNov06
18 | Added protocol handlers for line-oriented protocols.
19 | Various bug fixes.
20 |
21 | --------------------------------------------------
22 | Version: 0.7.0, released 20Nov06
23 | Added a fix in em.cpp/ConnectToServer to fix a fatal exception that
24 | occurred in FreeBSD when connecting successfully to a remote server.
25 |
26 | --------------------------------------------------
27 | Version: 0.6.0, released xxJul06
28 | Added deferred operations, suggested by Don Stocks, amillionhitpoints@yahoo.com.
29 |
30 | --------------------------------------------------
31 | Version: 0.5.4, released xxJun06
32 | Added get_peername support for streams and datagrams.
33 |
34 | --------------------------------------------------
35 | Version: 0.5.3, released 17May06
36 | Fixed bugs in extconf.rb, thanks to Daniel Harple, dharple@generalconsumption.org.
37 | Added proper setup.rb and rake tasks, thanks to Austin Ziegler.
38 | Fixed a handful of reported problems with builds on various platforms.
39 |
40 | --------------------------------------------------
41 | Version: 0.5.2, released 05May06
42 | Made several nonvisible improvements to the Windows
43 | implementation.
44 | Added an exception-handling patch contributed by Jeff Rose, jeff@rosejn.net.
45 | Added a dir-config patch contributed anonymously.
46 | Supported builds on Solaris.
47 |
48 | --------------------------------------------------
49 | Version: 0.5.1, released 05May06
50 | Made it possible to pass a Class rather than a Module
51 | to a protocol handler.
52 | Added Windows port.
53 |
54 | --------------------------------------------------
55 | Version: 0.5.0, released 30Apr06
56 | Added a preliminary SSL/TLS extension. This will probably
57 | change over the next few releases.
58 |
59 | --------------------------------------------------
60 | Version: 0.4.5, released 29Apr06
61 | Changed ext files so the ruby.h is installed after unistd.h
62 | otherwise it doesn't compile on gcc 4.1
63 |
64 | --------------------------------------------------
65 | Version: 0.4.2, released 19Apr06
66 | Changed the Ruby-glue so the extension will play nicer
67 | in the sandbox with Ruby threads.
68 | Added an EventMachine::run_without_threads API to
69 | switch off the thread-awareness for better performance
70 | in programs that do not spin any Ruby threads.
71 |
72 | --------------------------------------------------
73 | Version: 0.4.1, released 15Apr06
74 | Reworked the shared-object interface to make it easier to
75 | use EventMachine from languages other than Ruby.
76 |
77 | --------------------------------------------------
78 | Version: 0.3.2, released 12Apr06
79 | Added support for a user-supplied block in EventMachine#connect.
80 |
81 | --------------------------------------------------
82 | Version: 0.3.1, released 11Apr06
83 | Fixed bug that prevented EventMachine from being run multiple
84 | times in a single process.
85 |
86 | --------------------------------------------------
87 | Version: 0.3.0, released 10Apr06
88 | Added method EventHandler::Connection::post_init
89 |
90 | --------------------------------------------------
91 | Version: 0.2.0, released 10Apr06
92 | Added method EventHandler::stop
93 |
94 |
95 |
--------------------------------------------------------------------------------
/tests/test_processes.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 | $:.unshift "../lib"
28 | require 'eventmachine'
29 | require 'test/unit'
30 |
31 | class TestProcesses < Test::Unit::TestCase
32 |
33 | # EM::DeferrableChildProcess is a sugaring of a common use-case
34 | # involving EM::popen.
35 | # Call the #open method on EM::DeferrableChildProcess, passing
36 | # a command-string. #open immediately returns an EM::Deferrable
37 | # object. It also schedules the forking of a child process, which
38 | # will execute the command passed to #open.
39 | # When the forked child terminates, the Deferrable will be signalled
40 | # and execute its callbacks, passing the data that the child process
41 | # wrote to stdout.
42 | #
43 | def test_deferrable_child_process
44 | ls = ""
45 | EM.run {
46 | d = EM::DeferrableChildProcess.open( "ls -ltr" )
47 | d.callback {|data_from_child|
48 | ls = data_from_child
49 | EM.stop
50 | }
51 | }
52 | assert( ls.length > 0)
53 | end
54 |
55 | def setup
56 | $out = nil
57 | $status = nil
58 | end
59 |
60 | def test_em_system
61 | EM.run{
62 | EM.system('ls'){ |out,status| $out, $status = out, status; EM.stop }
63 | }
64 |
65 | assert( $out.length > 0 )
66 | assert_equal($status.exitstatus, 0)
67 | assert_equal($status.class, Process::Status)
68 | end
69 |
70 | def test_em_system_pid
71 | $pids = []
72 |
73 | EM.run{
74 | $pids << EM.system('echo hi', proc{ |out,status|$pids << status.pid; EM.stop })
75 | }
76 |
77 | assert_equal $pids[0], $pids[1]
78 | end
79 |
80 | def test_em_system_with_proc
81 | EM.run{
82 | EM.system('ls', proc{ |out,status| $out, $status = out, status; EM.stop })
83 | }
84 |
85 | assert( $out.length > 0 )
86 | assert_equal($status.exitstatus, 0)
87 | assert_equal($status.class, Process::Status)
88 | end
89 |
90 | def test_em_system_with_two_procs
91 | EM.run{
92 | EM.system('sh', proc{ |process|
93 | process.send_data("echo hello\n")
94 | process.send_data("exit\n")
95 | }, proc{ |out,status|
96 | $out = out
97 | $status = status
98 | EM.stop
99 | })
100 | }
101 |
102 | assert_equal("hello\n", $out)
103 | end
104 |
105 | def test_em_system_cmd_arguments
106 | EM.run{
107 | EM.system('sh', '--version', proc{ |process|
108 | }, proc{ |out,status|
109 | $out = out
110 | $status = status
111 | EM.stop
112 | })
113 | }
114 |
115 | assert_match(/version/i, $out)
116 | end
117 |
118 | def test_em_system_spaced_arguments
119 | EM.run{
120 | EM.system('ruby', '-e', 'puts "hello"', proc{ |out,status|
121 | $out = out
122 | EM.stop
123 | })
124 | }
125 |
126 | assert_equal("hello\n", $out)
127 | end
128 | end
129 |
--------------------------------------------------------------------------------
/tests/test_next_tick.rb:
--------------------------------------------------------------------------------
1 | # $Id$
2 | #
3 | # Author:: Francis Cianfrocca (gmail: blackhedd)
4 | # Homepage:: http://rubyeventmachine.com
5 | # Date:: 8 April 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 |
28 | $:.unshift "../lib"
29 | require 'eventmachine'
30 | require 'test/unit'
31 |
32 | class TestNextTick < Test::Unit::TestCase
33 |
34 | def test_tick_arg
35 | pr = proc {EM.stop}
36 | EM.run {
37 | EM.next_tick pr
38 | }
39 | assert true
40 | end
41 |
42 | def test_tick_block
43 | EM.run {
44 | EM.next_tick {EM.stop}
45 | }
46 | assert true
47 | end
48 |
49 | # This illustrates the solution to a long-standing problem.
50 | # It's now possible to correctly nest calls to EM#run.
51 | # See the source code commentary for EM#run for more info.
52 | #
53 | def test_run_run
54 | EM.run {
55 | EM.run {
56 | EM.next_tick {EM.stop}
57 | }
58 | }
59 | end
60 |
61 | def test_pre_run_queue
62 | x = false
63 | EM.next_tick { EM.stop; x = true }
64 | EM.run { EM.add_timer(0.2) { EM.stop } }
65 | assert x
66 | end
67 |
68 | def test_cleanup_after_stop
69 | x = true
70 | EM.run{
71 | EM.next_tick{
72 | EM.stop
73 | EM.next_tick{ x=false }
74 | }
75 | }
76 | EM.run{
77 | EM.next_tick{ EM.stop }
78 | }
79 | assert x
80 | end
81 |
82 | # We now support an additional parameter for EM#run.
83 | # You can pass two procs to EM#run now. The first is executed as the normal
84 | # run block. The second (if given) is scheduled for execution after the
85 | # reactor loop completes.
86 | # The reason for supporting this is subtle. There has always been an expectation
87 | # that EM#run doesn't return until after the reactor loop ends. But now it's
88 | # possible to nest calls to EM#run, which means that a nested call WILL
89 | # RETURN. In order to write code that will run correctly either way, it's
90 | # recommended to put any code which must execute after the reactor completes
91 | # in the second parameter.
92 | #
93 | def test_run_run_2
94 | a = proc {EM.stop}
95 | b = proc {assert true}
96 | EM.run a, b
97 | end
98 |
99 |
100 | # This illustrates that EM#run returns when it's called nested.
101 | # This isn't a feature, rather it's something to be wary of when writing code
102 | # that must run correctly even if EM#run is called while a reactor is already
103 | # running.
104 | def test_run_run_3
105 | a = []
106 | EM.run {
107 | EM.run proc {EM.stop}, proc {a << 2}
108 | a << 1
109 | }
110 | assert_equal( [1,2], a )
111 | end
112 |
113 |
114 | def test_schedule_on_reactor_thread
115 | x = false
116 | EM.run do
117 | EM.schedule { x = true }
118 | EM.stop
119 | end
120 | assert x
121 | end
122 |
123 | def test_schedule_from_thread
124 | x = false
125 | EM.run do
126 | Thread.new { EM.schedule { x = true } }.join
127 | assert !x
128 | EM.next_tick { EM.stop }
129 | end
130 | assert x
131 | end
132 |
133 | end
134 |
--------------------------------------------------------------------------------
/docs/PURE_RUBY:
--------------------------------------------------------------------------------
1 | EventMachine is supplied in three alternative versions.
2 |
3 | 1) A version that includes a Ruby extension written in C++. This version requires compilation;
4 | 2) A version for JRuby that contains a precompiled JAR file written in Java;
5 | 3) A pure Ruby version that has no external dependencies and can run in any Ruby environment.
6 |
7 | The Java version of EventMachine is packaged in a distinct manner and must be installed using a
8 | special procedure. This version is described fully in a different document, and not considered
9 | further here.
10 |
11 | The C++ and pure-Ruby versions, however, are shipped in the same distribution. You use the same
12 | files (either tarball or Ruby gem) to install both of these versions.
13 |
14 | If you intend to use the C++ version, you must successfully compile EventMachine after you install it.
15 | (The gem installation attempts to perform this step automatically.)
16 |
17 | If you choose not to compile the EventMachine C++ extension, or if your compilation fails for any
18 | reason, you still have a fully-functional installation of the pure-Ruby version of EM.
19 |
20 | However, for technical reasons, a default EM installation (whether or not the compilation succeeds)
21 | will always assume that the compiled ("extension") implementation should be used.
22 |
23 | If you want your EM program to use the pure Ruby version, you must specifically request it. There
24 | are two ways to do this: by setting either a Ruby global variable, or an environment string.
25 |
26 | The following code will invoke the pure-Ruby implementation of EM:
27 |
28 | $eventmachine_library = :pure_ruby
29 | require 'eventmachine'
30 |
31 | EM.library_type #=> "pure_ruby"
32 |
33 | Notice that this requires a code change and is not the preferred way to select pure Ruby, unless
34 | for some reason you are absolutely sure you will never want the compiled implementation.
35 |
36 | Setting the following environment string has the same effect:
37 |
38 | export EVENTMACHINE_LIBRARY="pure_ruby"
39 |
40 | This technique gives you the flexibility to select either version at runtime with no code changes.
41 |
42 | Support
43 |
44 | The EventMachine development team has committed to support precisely the same APIs for all the
45 | various implementations of EM.
46 |
47 | This means that you can expect any EM program to behave identically, whether you use pure Ruby,
48 | the compiled C++ extension, or JRuby. Deviations from this behavior are to be considered bugs
49 | and should be reported as such.
50 |
51 | There is a small number of exceptions to this rule, which arise from underlying platform
52 | distinctions. Notably, EM#epoll is a silent no-op in the pure Ruby implementation.
53 |
54 |
55 | When Should You Use the Pure-Ruby Implementation of EM?
56 |
57 |
58 | Use the pure Ruby implementation of EM when you must support a platform for which no C++ compiler
59 | is available, or on which the standard EM C++ code can't be compiled.
60 |
61 | Keep in mind that you don't need a C++ compiler in order to deploy EM applications that rely on
62 | the compiled version, so long as appropriate C++ runtime libraries are available on the target platform.
63 |
64 | In extreme cases, you may find that you can develop software with the compiled EM version, but are
65 | not allowed to install required runtime libraries on the deployment system(s). This would be another
66 | case in which the pure Ruby implementation can be useful.
67 |
68 | In general you should avoid the pure Ruby version of EM when performance and scalability are important.
69 | EM in pure Ruby will necessarily run slower than the compiled version. Depending on your application
70 | this may or may not be a key issue.
71 |
72 | Also, since EPOLL is not supported in pure Ruby, your applications will be affected by Ruby's built-in
73 | limit of 1024 file and socket descriptors that may be open in a single process. For maximum scalability
74 | and performance, always use EPOLL if possible.
75 |
76 |
--------------------------------------------------------------------------------
/ext/project.h:
--------------------------------------------------------------------------------
1 | /*****************************************************************************
2 |
3 | $Id$
4 |
5 | File: project.h
6 | Date: 06Apr06
7 |
8 | Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9 | Gmail: blackhedd
10 |
11 | This program is free software; you can redistribute it and/or modify
12 | it under the terms of either: 1) the GNU General Public License
13 | as published by the Free Software Foundation; either version 2 of the
14 | License, or (at your option) any later version; or 2) Ruby's License.
15 |
16 | See the file COPYING for complete licensing information.
17 |
18 | *****************************************************************************/
19 |
20 |
21 | #ifndef __Project__H_
22 | #define __Project__H_
23 |
24 |
25 | #ifdef OS_WIN32
26 | #pragma warning(disable:4786)
27 | #endif
28 |
29 | #include
30 | #include