eventmachine 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +9 -5
- data/ext/autoscan.log +0 -0
- data/ext/cmain.cpp +76 -1
- data/ext/cplusplus.cpp +175 -0
- data/ext/ed.cpp +27 -2
- data/ext/ed.h +4 -1
- data/ext/eventmachine.h +3 -1
- data/ext/eventmachine_cpp.h +94 -0
- data/ext/extconf.rb +7 -1
- data/ext/project.h +9 -3
- data/ext/rubymain.cpp +44 -1
- data/lib/em/deferrable.rb +30 -5
- data/lib/em/streamer.rb +114 -0
- data/lib/eventmachine.rb +50 -2
- data/lib/eventmachine_version.rb +2 -2
- data/lib/jeventmachine.rb +106 -0
- data/lib/protocols/linetext2.rb +145 -0
- data/lib/protocols/stomp.rb +127 -0
- data/tests/test_basic.rb +10 -8
- data/tests/test_epoll.rb +8 -5
- data/tests/test_ltp.rb +7 -1
- data/tests/test_ltp2.rb +260 -0
- data/tests/test_send_file.rb +236 -0
- data/tests/test_servers.rb +87 -0
- metadata +12 -2
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
$Id: README
|
1
|
+
$Id: README 479 2007-07-27 08:51:26Z blackhedd $
|
2
2
|
|
3
3
|
= RUBY/EventMachine
|
4
4
|
|
@@ -47,9 +47,14 @@ the "C10K problem" by Dan Kegel and others.
|
|
47
47
|
|
48
48
|
EventMachine consists of an extension library written in C++ (which can be
|
49
49
|
accessed from languages other than Ruby), and a Ruby module which can be dropped
|
50
|
-
into user programs.
|
51
|
-
|
52
|
-
|
50
|
+
into user programs. On most platforms, EventMachine uses the
|
51
|
+
<tt>select(2)</tt> system call,
|
52
|
+
so it will run on a large range of Unix-like systems and on Microsoft
|
53
|
+
Windows with good performance and scalability. On Linux 2.6 kernels, EventMachine
|
54
|
+
automatically configures itself to use <tt>epoll(4)</tt> instead of
|
55
|
+
<tt>select(2),</tt> so scalability on that platform can be significantly
|
56
|
+
improved.
|
57
|
+
|
53
58
|
Here's a fully-functional echo server written with EventMachine:
|
54
59
|
|
55
60
|
require 'rubygems'
|
@@ -67,4 +72,3 @@ Here's a fully-functional echo server written with EventMachine:
|
|
67
72
|
}
|
68
73
|
|
69
74
|
|
70
|
-
# vim: sts=2 sw=2 ts=4 et ai tw=77
|
data/ext/autoscan.log
ADDED
File without changes
|
data/ext/cmain.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: cmain.cpp
|
3
|
+
$Id: cmain.cpp 476 2007-07-27 03:32:51Z blackhedd $
|
4
4
|
|
5
5
|
File: cmain.cpp
|
6
6
|
Date: 06Apr06
|
@@ -170,6 +170,17 @@ extern "C" void evma_close_connection (const char *binding, int after_writing)
|
|
170
170
|
ConnectionDescriptor::CloseConnection (binding, (after_writing ? true : false));
|
171
171
|
}
|
172
172
|
|
173
|
+
/********************
|
174
|
+
evma_stop_tcp_server
|
175
|
+
********************/
|
176
|
+
|
177
|
+
extern "C" void evma_stop_tcp_server (const char *binding)
|
178
|
+
{
|
179
|
+
if (!EventMachine)
|
180
|
+
throw std::runtime_error ("not initialized");
|
181
|
+
AcceptorDescriptor::StopAcceptor (binding);
|
182
|
+
}
|
183
|
+
|
173
184
|
|
174
185
|
/*****************
|
175
186
|
evma_stop_machine
|
@@ -355,6 +366,70 @@ extern "C" int evma_set_rlimit_nofile (int nofiles)
|
|
355
366
|
}
|
356
367
|
|
357
368
|
|
369
|
+
/*********************************
|
370
|
+
evma_send_file_data_to_connection
|
371
|
+
*********************************/
|
372
|
+
|
373
|
+
extern "C" int evma_send_file_data_to_connection (const char *binding, const char *filename)
|
374
|
+
{
|
375
|
+
/* This is a sugaring over send_data_to_connection that reads a file into a
|
376
|
+
* locally-allocated buffer, and sends the file data to the remote peer.
|
377
|
+
* Return the number of bytes written to the caller.
|
378
|
+
* TODO, needs to impose a limit on the file size. This is intended only for
|
379
|
+
* small files. (I don't know, maybe 8K or less.) For larger files, use interleaved
|
380
|
+
* I/O to avoid slowing the rest of the system down.
|
381
|
+
* TODO: we should return a code rather than barf, in case of file-not-found.
|
382
|
+
* TODO, does this compile on Windows?
|
383
|
+
* TODO, given that we want this to work only with small files, how about allocating
|
384
|
+
* the buffer on the stack rather than the heap?
|
385
|
+
*
|
386
|
+
* Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive
|
387
|
+
* errno in case of other errors.
|
388
|
+
*
|
389
|
+
/* Contributed by Kirk Haines.
|
390
|
+
*/
|
391
|
+
|
392
|
+
char data[32*1024];
|
393
|
+
int r;
|
394
|
+
|
395
|
+
if (!EventMachine)
|
396
|
+
throw std::runtime_error("not initialized");
|
397
|
+
|
398
|
+
int Fd = open (filename, O_RDONLY);
|
399
|
+
|
400
|
+
if (Fd < 0)
|
401
|
+
return errno;
|
402
|
+
// From here on, all early returns MUST close Fd.
|
403
|
+
|
404
|
+
struct stat st;
|
405
|
+
if (fstat (Fd, &st)) {
|
406
|
+
int e = errno;
|
407
|
+
close (Fd);
|
408
|
+
return e;
|
409
|
+
}
|
410
|
+
|
411
|
+
int filesize = st.st_size;
|
412
|
+
if (filesize <= 0) {
|
413
|
+
close (Fd);
|
414
|
+
return 0;
|
415
|
+
}
|
416
|
+
else if (filesize > sizeof(data)) {
|
417
|
+
close (Fd);
|
418
|
+
return -1;
|
419
|
+
}
|
420
|
+
|
421
|
+
|
422
|
+
r = read (Fd, data, filesize);
|
423
|
+
if (r != filesize) {
|
424
|
+
int e = errno;
|
425
|
+
close (Fd);
|
426
|
+
return e;
|
427
|
+
}
|
428
|
+
evma_send_data_to_connection (binding, data, r);
|
429
|
+
close (Fd);
|
430
|
+
|
431
|
+
return 0;
|
432
|
+
}
|
358
433
|
|
359
434
|
|
360
435
|
|
data/ext/cplusplus.cpp
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
/*****************************************************************************
|
2
|
+
|
3
|
+
$Id: cplusplus.cpp 474 2007-07-27 03:12:30Z blackhedd $
|
4
|
+
|
5
|
+
File: cplusplus.cpp
|
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
|
+
#include "project.h"
|
22
|
+
|
23
|
+
|
24
|
+
namespace EM {
|
25
|
+
static map<string, Eventable*> Eventables;
|
26
|
+
static map<string, void(*)()> Timers;
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
/*******
|
31
|
+
EM::Run
|
32
|
+
*******/
|
33
|
+
|
34
|
+
void EM::Run (void (*start_func)())
|
35
|
+
{
|
36
|
+
evma__epoll();
|
37
|
+
evma_initialize_library (EM::Callback);
|
38
|
+
if (start_func)
|
39
|
+
AddTimer (0, start_func);
|
40
|
+
evma_run_machine();
|
41
|
+
evma_release_library();
|
42
|
+
}
|
43
|
+
|
44
|
+
/************
|
45
|
+
EM::AddTimer
|
46
|
+
************/
|
47
|
+
|
48
|
+
void EM::AddTimer (int seconds, void (*func)())
|
49
|
+
{
|
50
|
+
if (func) {
|
51
|
+
const char *sig = evma_install_oneshot_timer (seconds);
|
52
|
+
Timers.insert (make_pair (sig, func));
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
/***************
|
58
|
+
EM::StopReactor
|
59
|
+
***************/
|
60
|
+
|
61
|
+
void EM::StopReactor()
|
62
|
+
{
|
63
|
+
evma_stop_machine();
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
/********************
|
68
|
+
EM::Acceptor::Accept
|
69
|
+
********************/
|
70
|
+
|
71
|
+
void EM::Acceptor::Accept (const char *signature)
|
72
|
+
{
|
73
|
+
Connection *c = MakeConnection();
|
74
|
+
c->Signature = signature;
|
75
|
+
Eventables.insert (make_pair (c->Signature, c));
|
76
|
+
c->PostInit();
|
77
|
+
}
|
78
|
+
|
79
|
+
/************************
|
80
|
+
EM::Connection::SendData
|
81
|
+
************************/
|
82
|
+
|
83
|
+
void EM::Connection::SendData (const char *data)
|
84
|
+
{
|
85
|
+
if (data)
|
86
|
+
SendData (data, strlen (data));
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
/************************
|
91
|
+
EM::Connection::SendData
|
92
|
+
************************/
|
93
|
+
|
94
|
+
void EM::Connection::SendData (const char *data, int length)
|
95
|
+
{
|
96
|
+
evma_send_data_to_connection (Signature.c_str(), data, length);
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
/*********************
|
101
|
+
EM::Connection::Close
|
102
|
+
*********************/
|
103
|
+
|
104
|
+
void EM::Connection::Close (bool afterWriting)
|
105
|
+
{
|
106
|
+
evma_close_connection (Signature.c_str(), afterWriting);
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
/***********************
|
111
|
+
EM::Connection::Connect
|
112
|
+
***********************/
|
113
|
+
|
114
|
+
void EM::Connection::Connect (const char *host, int port)
|
115
|
+
{
|
116
|
+
Signature = evma_connect_to_server (host, port);
|
117
|
+
Eventables.insert( make_pair (Signature, this));
|
118
|
+
}
|
119
|
+
|
120
|
+
/*******************
|
121
|
+
EM::Acceptor::Start
|
122
|
+
*******************/
|
123
|
+
|
124
|
+
void EM::Acceptor::Start (const char *host, int port)
|
125
|
+
{
|
126
|
+
Signature = evma_create_tcp_server (host, port);
|
127
|
+
Eventables.insert( make_pair (Signature, this));
|
128
|
+
}
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
/************
|
133
|
+
EM::Callback
|
134
|
+
************/
|
135
|
+
|
136
|
+
void EM::Callback (const char *sig, int ev, const char *data, int length)
|
137
|
+
{
|
138
|
+
EM::Eventable *e;
|
139
|
+
void (*f)();
|
140
|
+
|
141
|
+
switch (ev) {
|
142
|
+
case EM_TIMER_FIRED:
|
143
|
+
//(new A())->Start ("192.168.0.8", 9700);
|
144
|
+
//cerr << evma_create_tcp_server ("192.168.0.8", 9700) << " SERVER\n";
|
145
|
+
//(new M())->Connect ("www.bayshorenetworks.com", 80);
|
146
|
+
f = Timers [data];
|
147
|
+
if (f)
|
148
|
+
(*f)();
|
149
|
+
Timers.erase (sig);
|
150
|
+
break;
|
151
|
+
|
152
|
+
case EM_CONNECTION_READ:
|
153
|
+
e = EM::Eventables [sig];
|
154
|
+
e->ReceiveData (data, length);
|
155
|
+
break;
|
156
|
+
|
157
|
+
case EM_CONNECTION_COMPLETED:
|
158
|
+
e = EM::Eventables [sig];
|
159
|
+
e->ConnectionCompleted();
|
160
|
+
break;
|
161
|
+
|
162
|
+
case EM_CONNECTION_ACCEPTED:
|
163
|
+
e = EM::Eventables [sig];
|
164
|
+
e->Accept (data);
|
165
|
+
break;
|
166
|
+
|
167
|
+
case EM_CONNECTION_UNBOUND:
|
168
|
+
e = EM::Eventables [sig];
|
169
|
+
e->Unbind();
|
170
|
+
EM::Eventables.erase (sig);
|
171
|
+
delete e;
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
data/ext/ed.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: ed.cpp
|
3
|
+
$Id: ed.cpp 447 2007-07-20 16:42:06Z blackhedd $
|
4
4
|
|
5
5
|
File: ed.cpp
|
6
6
|
Date: 06Apr06
|
@@ -175,6 +175,7 @@ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
|
|
175
175
|
EventableDescriptor (sd, em),
|
176
176
|
bConnectPending (false),
|
177
177
|
bReadAttemptedAfterClose (false),
|
178
|
+
bWriteAttemptedAfterClose (false),
|
178
179
|
OutboundDataSize (0),
|
179
180
|
#ifdef WITH_SSL
|
180
181
|
SslBox (NULL),
|
@@ -537,10 +538,20 @@ void ConnectionDescriptor::_WriteOutboundData()
|
|
537
538
|
* be writable by the time we get around to writing. The kernel might
|
538
539
|
* have used up its available output buffers between the select call
|
539
540
|
* and when we get here. So this condition is not an error.
|
541
|
+
*
|
542
|
+
* 20Jul07, added the same kind of protection against an invalid socket
|
543
|
+
* that is at the top of ::Read. Not entirely how this could happen in
|
544
|
+
* real life (connection-reset from the remote peer, perhaps?), but I'm
|
545
|
+
* doing it to address some reports of crashing under heavy loads.
|
540
546
|
*/
|
541
547
|
|
542
548
|
int sd = GetSocket();
|
543
|
-
assert (sd != INVALID_SOCKET);
|
549
|
+
//assert (sd != INVALID_SOCKET);
|
550
|
+
if (sd == INVALID_SOCKET) {
|
551
|
+
assert (!bWriteAttemptedAfterClose);
|
552
|
+
bWriteAttemptedAfterClose = true;
|
553
|
+
return;
|
554
|
+
}
|
544
555
|
|
545
556
|
LastIo = gCurrentLoopTime;
|
546
557
|
char output_buffer [16 * 1024];
|
@@ -777,6 +788,20 @@ AcceptorDescriptor::~AcceptorDescriptor()
|
|
777
788
|
{
|
778
789
|
}
|
779
790
|
|
791
|
+
/****************************************
|
792
|
+
STATIC: AcceptorDescriptor::StopAcceptor
|
793
|
+
****************************************/
|
794
|
+
|
795
|
+
void AcceptorDescriptor::StopAcceptor (const char *binding)
|
796
|
+
{
|
797
|
+
// TODO: This is something of a hack, or at least it's a static method of the wrong class.
|
798
|
+
AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
|
799
|
+
if (ad)
|
800
|
+
ad->ScheduleClose (false);
|
801
|
+
else
|
802
|
+
throw std::runtime_error ("failed to close nonexistent acceptor");
|
803
|
+
}
|
804
|
+
|
780
805
|
|
781
806
|
/************************
|
782
807
|
AcceptorDescriptor::Read
|
data/ext/ed.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: ed.h
|
3
|
+
$Id: ed.h 447 2007-07-20 16:42:06Z blackhedd $
|
4
4
|
|
5
5
|
File: ed.h
|
6
6
|
Date: 06Apr06
|
@@ -167,6 +167,7 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
167
167
|
protected:
|
168
168
|
bool bConnectPending;
|
169
169
|
bool bReadAttemptedAfterClose;
|
170
|
+
bool bWriteAttemptedAfterClose;
|
170
171
|
|
171
172
|
deque<OutboundPage> OutboundPages;
|
172
173
|
int OutboundDataSize;
|
@@ -255,6 +256,8 @@ class AcceptorDescriptor: public EventableDescriptor
|
|
255
256
|
|
256
257
|
virtual bool SelectForRead() {return true;}
|
257
258
|
virtual bool SelectForWrite() {return false;}
|
259
|
+
|
260
|
+
static void StopAcceptor (const char *binding);
|
258
261
|
};
|
259
262
|
|
260
263
|
/********************
|
data/ext/eventmachine.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: eventmachine.h
|
3
|
+
$Id: eventmachine.h 426 2007-07-17 16:54:08Z blackhedd $
|
4
4
|
|
5
5
|
File: eventmachine.h
|
6
6
|
Date: 15Apr06
|
@@ -39,6 +39,7 @@ extern "C" {
|
|
39
39
|
const char *evma_install_oneshot_timer (int seconds);
|
40
40
|
const char *evma_connect_to_server (const char *server, int port);
|
41
41
|
const char *evma_connect_to_unix_server (const char *server);
|
42
|
+
void evma_stop_tcp_server (const char *signature);
|
42
43
|
const char *evma_create_tcp_server (const char *address, int port);
|
43
44
|
const char *evma_create_unix_domain_server (const char *filename);
|
44
45
|
const char *evma_open_datagram_socket (const char *server, int port);
|
@@ -50,6 +51,7 @@ extern "C" {
|
|
50
51
|
int evma_get_comm_inactivity_timeout (const char *binding, /*out*/int *value);
|
51
52
|
int evma_set_comm_inactivity_timeout (const char *binding, /*in,out*/int *value);
|
52
53
|
int evma_get_outbound_data_size (const char *binding);
|
54
|
+
int evma_send_file_data_to_connection (const char *binding, const char *filename);
|
53
55
|
|
54
56
|
void evma_close_connection (const char *binding, int after_writing);
|
55
57
|
void evma_signal_loopbreak();
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/*****************************************************************************
|
2
|
+
|
3
|
+
$Id: eventmachine_cpp.h 474 2007-07-27 03:12:30Z blackhedd $
|
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 char *sig, int event, const char *data, int 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
|
+
std::string 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 char*) {}
|
49
|
+
virtual void Unbind() {}
|
50
|
+
virtual void PostInit() {}
|
51
|
+
|
52
|
+
void StopReactor() {EM::StopReactor();}
|
53
|
+
};
|
54
|
+
|
55
|
+
/****************
|
56
|
+
class Connection
|
57
|
+
****************/
|
58
|
+
|
59
|
+
class Connection: public Eventable {
|
60
|
+
public:
|
61
|
+
Connection() {}
|
62
|
+
virtual ~Connection() {}
|
63
|
+
|
64
|
+
virtual void Connect (const char*, int);
|
65
|
+
|
66
|
+
void SendData (const char *data);
|
67
|
+
void SendData (const char *data, int length);
|
68
|
+
void Close (bool afterWriting);
|
69
|
+
};
|
70
|
+
|
71
|
+
|
72
|
+
/**************
|
73
|
+
class Acceptor
|
74
|
+
**************/
|
75
|
+
|
76
|
+
class Acceptor: public Eventable {
|
77
|
+
public:
|
78
|
+
Acceptor() {PostInit();}
|
79
|
+
virtual ~Acceptor() {}
|
80
|
+
|
81
|
+
void Start (const char*, int);
|
82
|
+
void Accept (const char*);
|
83
|
+
|
84
|
+
virtual Connection *MakeConnection() {return new Connection();}
|
85
|
+
};
|
86
|
+
|
87
|
+
|
88
|
+
};
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
#endif // __EVMA_EventmachineCpp__H_
|