eventmachine 0.8.0 → 0.8.1

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