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 CHANGED
@@ -1,4 +1,4 @@
1
- $Id: README 317 2007-05-22 21:55:43Z blackhedd $
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. The current implementation uses the <tt>select(2)</tt> system call
51
- and may be used on a range of Unix-like systems. A future version of EventMachine
52
- for Linux will use <tt>epoll(4)</tt> and will thus require a Linux 2.6 kernel.
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
File without changes
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: cmain.cpp 377 2007-06-13 01:05:56Z blackhedd $
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
 
@@ -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 400 2007-07-11 12:10:33Z blackhedd $
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 400 2007-07-11 12:10:33Z blackhedd $
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
  /********************
@@ -1,6 +1,6 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: eventmachine.h 377 2007-06-13 01:05:56Z blackhedd $
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_