eventmachine 0.12.8-x86-mswin32-60 → 0.12.10-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.gitignore +14 -13
  2. data/Rakefile +374 -264
  3. data/eventmachine.gemspec +4 -5
  4. data/ext/binder.cpp +125 -126
  5. data/ext/binder.h +46 -48
  6. data/ext/cmain.cpp +184 -42
  7. data/ext/cplusplus.cpp +202 -202
  8. data/ext/ed.cpp +242 -81
  9. data/ext/ed.h +39 -22
  10. data/ext/em.cpp +127 -108
  11. data/ext/em.h +27 -18
  12. data/ext/emwin.cpp +3 -3
  13. data/ext/eventmachine.h +49 -38
  14. data/ext/eventmachine_cpp.h +96 -96
  15. data/ext/extconf.rb +147 -132
  16. data/ext/fastfilereader/extconf.rb +82 -76
  17. data/ext/project.h +151 -140
  18. data/ext/rubymain.cpp +222 -103
  19. data/ext/ssl.cpp +460 -460
  20. data/ext/ssl.h +94 -94
  21. data/java/src/com/rubyeventmachine/EmReactor.java +570 -423
  22. data/java/src/com/rubyeventmachine/EventableChannel.java +69 -57
  23. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +189 -171
  24. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +364 -244
  25. data/java/src/com/rubyeventmachine/{Application.java → application/Application.java} +194 -200
  26. data/java/src/com/rubyeventmachine/{Connection.java → application/Connection.java} +74 -74
  27. data/java/src/com/rubyeventmachine/{ConnectionFactory.java → application/ConnectionFactory.java} +36 -36
  28. data/java/src/com/rubyeventmachine/{DefaultConnectionFactory.java → application/DefaultConnectionFactory.java} +46 -46
  29. data/java/src/com/rubyeventmachine/{PeriodicTimer.java → application/PeriodicTimer.java} +38 -38
  30. data/java/src/com/rubyeventmachine/{Timer.java → application/Timer.java} +54 -54
  31. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +109 -108
  32. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +148 -146
  33. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +53 -53
  34. data/java/src/com/rubyeventmachine/tests/TestServers.java +75 -74
  35. data/java/src/com/rubyeventmachine/tests/TestTimers.java +90 -89
  36. data/lib/em/connection.rb +71 -12
  37. data/lib/em/deferrable.rb +191 -186
  38. data/lib/em/protocols.rb +36 -35
  39. data/lib/em/protocols/httpclient2.rb +590 -582
  40. data/lib/em/protocols/line_and_text.rb +125 -126
  41. data/lib/em/protocols/linetext2.rb +161 -160
  42. data/lib/em/protocols/object_protocol.rb +45 -39
  43. data/lib/em/protocols/smtpclient.rb +357 -331
  44. data/lib/em/protocols/socks4.rb +66 -0
  45. data/lib/em/queue.rb +60 -60
  46. data/lib/em/timers.rb +56 -55
  47. data/lib/em/version.rb +1 -1
  48. data/lib/eventmachine.rb +125 -169
  49. data/lib/jeventmachine.rb +257 -142
  50. data/tasks/{cpp.rake → cpp.rake_example} +76 -76
  51. data/tests/test_attach.rb +125 -100
  52. data/tests/test_basic.rb +1 -2
  53. data/tests/test_connection_count.rb +34 -44
  54. data/tests/test_epoll.rb +0 -2
  55. data/tests/test_get_sock_opt.rb +30 -0
  56. data/tests/test_httpclient2.rb +3 -3
  57. data/tests/test_inactivity_timeout.rb +21 -1
  58. data/tests/test_ltp.rb +182 -188
  59. data/tests/test_next_tick.rb +0 -2
  60. data/tests/test_pause.rb +70 -0
  61. data/tests/test_pending_connect_timeout.rb +48 -0
  62. data/tests/test_ssl_args.rb +78 -67
  63. data/tests/test_timers.rb +162 -141
  64. metadata +13 -11
  65. data/tasks/project.rake +0 -79
  66. data/tasks/tests.rake +0 -193
@@ -1,202 +1,202 @@
1
- /*****************************************************************************
2
-
3
- $Id$
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_set_epoll (1);
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 milliseconds, void (*func)())
49
- {
50
- if (func) {
51
- const char *sig = evma_install_oneshot_timer (milliseconds);
52
- #ifdef OS_SOLARIS8
53
- Timers.insert (map<string, void(*)()>::value_type (sig, func));
54
- #else
55
- Timers.insert (make_pair (sig, func));
56
- #endif
57
- }
58
- }
59
-
60
-
61
- /***************
62
- EM::StopReactor
63
- ***************/
64
-
65
- void EM::StopReactor()
66
- {
67
- evma_stop_machine();
68
- }
69
-
70
-
71
- /********************
72
- EM::Acceptor::Accept
73
- ********************/
74
-
75
- void EM::Acceptor::Accept (const char *signature)
76
- {
77
- Connection *c = MakeConnection();
78
- c->Signature = signature;
79
- #ifdef OS_SOLARIS8
80
- Eventables.insert (std::map<std::string,EM::Eventable*>::value_type (c->Signature, c));
81
- #else
82
- Eventables.insert (make_pair (c->Signature, c));
83
- #endif
84
- c->PostInit();
85
- }
86
-
87
- /************************
88
- EM::Connection::SendData
89
- ************************/
90
-
91
- void EM::Connection::SendData (const char *data)
92
- {
93
- if (data)
94
- SendData (data, strlen (data));
95
- }
96
-
97
-
98
- /************************
99
- EM::Connection::SendData
100
- ************************/
101
-
102
- void EM::Connection::SendData (const char *data, int length)
103
- {
104
- evma_send_data_to_connection (Signature.c_str(), data, length);
105
- }
106
-
107
-
108
- /*********************
109
- EM::Connection::Close
110
- *********************/
111
-
112
- void EM::Connection::Close (bool afterWriting)
113
- {
114
- evma_close_connection (Signature.c_str(), afterWriting);
115
- }
116
-
117
-
118
- /***************************
119
- EM::Connection::BindConnect
120
- ***************************/
121
-
122
- void EM::Connection::BindConnect (const char *bind_addr, int bind_port, const char *host, int port)
123
- {
124
- Signature = evma_connect_to_server (bind_addr, bind_port, host, port);
125
- #ifdef OS_SOLARIS8
126
- Eventables.insert( std::map<std::string,EM::Eventable*>::value_type (Signature, this));
127
- #else
128
- Eventables.insert( make_pair (Signature, this));
129
- #endif
130
- }
131
-
132
- /***********************
133
- EM::Connection::Connect
134
- ***********************/
135
-
136
- void EM::Connection::Connect (const char *host, int port)
137
- {
138
- this->BindConnect(NULL, 0, host, port);
139
- }
140
-
141
- /*******************
142
- EM::Acceptor::Start
143
- *******************/
144
-
145
- void EM::Acceptor::Start (const char *host, int port)
146
- {
147
- Signature = evma_create_tcp_server (host, port);
148
- #ifdef OS_SOLARIS8
149
- Eventables.insert( std::map<std::string,EM::Eventable*>::value_type (Signature, this));
150
- #else
151
- Eventables.insert( make_pair (Signature, this));
152
- #endif
153
- }
154
-
155
-
156
-
157
- /************
158
- EM::Callback
159
- ************/
160
-
161
- void EM::Callback (const char *sig, int ev, const char *data, int length)
162
- {
163
- EM::Eventable *e;
164
- void (*f)();
165
-
166
- switch (ev) {
167
- case EM_TIMER_FIRED:
168
- f = Timers [data];
169
- if (f)
170
- (*f)();
171
- Timers.erase (sig);
172
- break;
173
-
174
- case EM_CONNECTION_READ:
175
- e = EM::Eventables [sig];
176
- e->ReceiveData (data, length);
177
- break;
178
-
179
- case EM_CONNECTION_COMPLETED:
180
- e = EM::Eventables [sig];
181
- e->ConnectionCompleted();
182
- break;
183
-
184
- case EM_CONNECTION_ACCEPTED:
185
- e = EM::Eventables [sig];
186
- e->Accept (data);
187
- break;
188
-
189
- case EM_CONNECTION_UNBOUND:
190
- e = EM::Eventables [sig];
191
- e->Unbind();
192
- EM::Eventables.erase (sig);
193
- delete e;
194
- break;
195
-
196
- case EM_SSL_HANDSHAKE_COMPLETED:
197
- e = EM::Eventables [sig];
198
- e->SslHandshakeCompleted();
199
- break;
200
- }
201
- }
202
-
1
+ /*****************************************************************************
2
+
3
+ $Id$
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<unsigned long, Eventable*> Eventables;
26
+ static map<unsigned long, void(*)()> Timers;
27
+ }
28
+
29
+
30
+ /*******
31
+ EM::Run
32
+ *******/
33
+
34
+ void EM::Run (void (*start_func)())
35
+ {
36
+ evma_set_epoll (1);
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 milliseconds, void (*func)())
49
+ {
50
+ if (func) {
51
+ const unsigned long sig = evma_install_oneshot_timer (milliseconds);
52
+ #ifndef HAVE_MAKE_PAIR
53
+ Timers.insert (map<unsigned long, void(*)()>::value_type (sig, func));
54
+ #else
55
+ Timers.insert (make_pair (sig, func));
56
+ #endif
57
+ }
58
+ }
59
+
60
+
61
+ /***************
62
+ EM::StopReactor
63
+ ***************/
64
+
65
+ void EM::StopReactor()
66
+ {
67
+ evma_stop_machine();
68
+ }
69
+
70
+
71
+ /********************
72
+ EM::Acceptor::Accept
73
+ ********************/
74
+
75
+ void EM::Acceptor::Accept (const unsigned long signature)
76
+ {
77
+ Connection *c = MakeConnection();
78
+ c->Signature = signature;
79
+ #ifndef HAVE_MAKE_PAIR
80
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (c->Signature, c));
81
+ #else
82
+ Eventables.insert (make_pair (c->Signature, c));
83
+ #endif
84
+ c->PostInit();
85
+ }
86
+
87
+ /************************
88
+ EM::Connection::SendData
89
+ ************************/
90
+
91
+ void EM::Connection::SendData (const char *data)
92
+ {
93
+ if (data)
94
+ SendData (data, strlen (data));
95
+ }
96
+
97
+
98
+ /************************
99
+ EM::Connection::SendData
100
+ ************************/
101
+
102
+ void EM::Connection::SendData (const char *data, int length)
103
+ {
104
+ evma_send_data_to_connection (Signature, data, length);
105
+ }
106
+
107
+
108
+ /*********************
109
+ EM::Connection::Close
110
+ *********************/
111
+
112
+ void EM::Connection::Close (bool afterWriting)
113
+ {
114
+ evma_close_connection (Signature, afterWriting);
115
+ }
116
+
117
+
118
+ /***************************
119
+ EM::Connection::BindConnect
120
+ ***************************/
121
+
122
+ void EM::Connection::BindConnect (const char *bind_addr, int bind_port, const char *host, int port)
123
+ {
124
+ Signature = evma_connect_to_server (bind_addr, bind_port, host, port);
125
+ #ifndef HAVE_MAKE_PAIR
126
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
127
+ #else
128
+ Eventables.insert (make_pair (Signature, this));
129
+ #endif
130
+ }
131
+
132
+ /***********************
133
+ EM::Connection::Connect
134
+ ***********************/
135
+
136
+ void EM::Connection::Connect (const char *host, int port)
137
+ {
138
+ this->BindConnect(NULL, 0, host, port);
139
+ }
140
+
141
+ /*******************
142
+ EM::Acceptor::Start
143
+ *******************/
144
+
145
+ void EM::Acceptor::Start (const char *host, int port)
146
+ {
147
+ Signature = evma_create_tcp_server (host, port);
148
+ #ifndef HAVE_MAKE_PAIR
149
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
150
+ #else
151
+ Eventables.insert (make_pair (Signature, this));
152
+ #endif
153
+ }
154
+
155
+
156
+
157
+ /************
158
+ EM::Callback
159
+ ************/
160
+
161
+ void EM::Callback (const unsigned long sig, int ev, const char *data, const unsigned long length)
162
+ {
163
+ EM::Eventable *e;
164
+ void (*f)();
165
+
166
+ switch (ev) {
167
+ case EM_TIMER_FIRED:
168
+ f = Timers [length]; // actually a binding
169
+ if (f)
170
+ (*f)();
171
+ Timers.erase (length);
172
+ break;
173
+
174
+ case EM_CONNECTION_READ:
175
+ e = EM::Eventables [sig];
176
+ e->ReceiveData (data, length);
177
+ break;
178
+
179
+ case EM_CONNECTION_COMPLETED:
180
+ e = EM::Eventables [sig];
181
+ e->ConnectionCompleted();
182
+ break;
183
+
184
+ case EM_CONNECTION_ACCEPTED:
185
+ e = EM::Eventables [sig];
186
+ e->Accept (length); // actually a binding
187
+ break;
188
+
189
+ case EM_CONNECTION_UNBOUND:
190
+ e = EM::Eventables [sig];
191
+ e->Unbind();
192
+ EM::Eventables.erase (sig);
193
+ delete e;
194
+ break;
195
+
196
+ case EM_SSL_HANDSHAKE_COMPLETED:
197
+ e = EM::Eventables [sig];
198
+ e->SslHandshakeCompleted();
199
+ break;
200
+ }
201
+ }
202
+
data/ext/ed.cpp CHANGED
@@ -33,9 +33,16 @@ bool SetSocketNonblocking (SOCKET sd)
33
33
  #endif
34
34
 
35
35
  #ifdef OS_WIN32
36
+ #ifdef BUILD_FOR_RUBY
37
+ // 14Jun09 Ruby provides its own wrappers for ioctlsocket. On 1.8 this is a simple wrapper,
38
+ // however, 1.9 keeps its own state about the socket.
39
+ // NOTE: F_GETFL is not supported
40
+ return (fcntl (sd, F_SETFL, O_NONBLOCK) == 0) ? true : false;
41
+ #else
36
42
  unsigned long one = 1;
37
43
  return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
38
44
  #endif
45
+ #endif
39
46
  }
40
47
 
41
48
 
@@ -51,7 +58,10 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
51
58
  bCallbackUnbind (true),
52
59
  UnbindReasonCode (0),
53
60
  ProxyTarget(NULL),
54
- MyEventMachine (em)
61
+ ProxiedFrom(NULL),
62
+ MaxOutboundBufSize(0),
63
+ MyEventMachine (em),
64
+ PendingConnectTimeout(20000000)
55
65
  {
56
66
  /* There are three ways to close a socket, all of which should
57
67
  * automatically signal to the event machine that this object
@@ -81,6 +91,7 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
81
91
  CreatedAt = gCurrentLoopTime;
82
92
 
83
93
  #ifdef HAVE_EPOLL
94
+ EpollEvent.events = 0;
84
95
  EpollEvent.data.ptr = this;
85
96
  #endif
86
97
  }
@@ -93,7 +104,11 @@ EventableDescriptor::~EventableDescriptor
93
104
  EventableDescriptor::~EventableDescriptor()
94
105
  {
95
106
  if (EventCallback && bCallbackUnbind)
96
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
107
+ (*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
108
+ if (ProxiedFrom) {
109
+ (*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
110
+ ProxiedFrom->StopProxy();
111
+ }
97
112
  StopProxy();
98
113
  Close();
99
114
  }
@@ -103,7 +118,7 @@ EventableDescriptor::~EventableDescriptor()
103
118
  EventableDescriptor::SetEventCallback
104
119
  *************************************/
105
120
 
106
- void EventableDescriptor::SetEventCallback (void(*cb)(const char*, int, const char*, int))
121
+ void EventableDescriptor::SetEventCallback (void(*cb)(const unsigned long, int, const char*, const unsigned long))
107
122
  {
108
123
  EventCallback = cb;
109
124
  }
@@ -172,12 +187,13 @@ bool EventableDescriptor::IsCloseScheduled()
172
187
  EventableDescriptor::StartProxy
173
188
  *******************************/
174
189
 
175
- void EventableDescriptor::StartProxy(const char *to)
190
+ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long bufsize)
176
191
  {
177
192
  EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (to));
178
193
  if (ed) {
179
194
  StopProxy();
180
- ProxyTarget = strdup(to);
195
+ ProxyTarget = ed;
196
+ ed->SetProxiedFrom(this, bufsize);
181
197
  return;
182
198
  }
183
199
  throw std::runtime_error ("Tried to proxy to an invalid descriptor");
@@ -191,12 +207,23 @@ EventableDescriptor::StopProxy
191
207
  void EventableDescriptor::StopProxy()
192
208
  {
193
209
  if (ProxyTarget) {
194
- free(ProxyTarget);
210
+ ProxyTarget->SetProxiedFrom(NULL, 0);
195
211
  ProxyTarget = NULL;
196
212
  }
197
213
  }
198
214
 
199
215
 
216
+ /***********************************
217
+ EventableDescriptor::SetProxiedFrom
218
+ ***********************************/
219
+
220
+ void EventableDescriptor::SetProxiedFrom(EventableDescriptor *from, const unsigned long bufsize)
221
+ {
222
+ ProxiedFrom = from;
223
+ MaxOutboundBufSize = bufsize;
224
+ }
225
+
226
+
200
227
  /********************************************
201
228
  EventableDescriptor::_GenericInboundDispatch
202
229
  ********************************************/
@@ -205,12 +232,34 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
205
232
  {
206
233
  assert(EventCallback);
207
234
 
208
- if (!ProxyTarget)
209
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, buf, size);
210
- else if (ConnectionDescriptor::SendDataToConnection(ProxyTarget, buf, size) == -1) {
211
- (*EventCallback)(GetBinding().c_str(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
212
- StopProxy();
235
+ if (ProxyTarget)
236
+ ProxyTarget->SendOutboundData(buf, size);
237
+ else
238
+ (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
239
+ }
240
+
241
+
242
+ /*********************************************
243
+ EventableDescriptor::GetPendingConnectTimeout
244
+ *********************************************/
245
+
246
+ float EventableDescriptor::GetPendingConnectTimeout()
247
+ {
248
+ return ((float)PendingConnectTimeout / 1000000);
249
+ }
250
+
251
+
252
+ /*********************************************
253
+ EventableDescriptor::SetPendingConnectTimeout
254
+ *********************************************/
255
+
256
+ int EventableDescriptor::SetPendingConnectTimeout (float value)
257
+ {
258
+ if (value > 0) {
259
+ PendingConnectTimeout = (Int64)(value * 1000000);
260
+ return 1;
213
261
  }
262
+ return 0;
214
263
  }
215
264
 
216
265
 
@@ -220,9 +269,11 @@ ConnectionDescriptor::ConnectionDescriptor
220
269
 
221
270
  ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
222
271
  EventableDescriptor (sd, em),
272
+ bPaused (false),
223
273
  bConnectPending (false),
224
274
  bNotifyReadable (false),
225
275
  bNotifyWritable (false),
276
+ bWatchOnly (false),
226
277
  bReadAttemptedAfterClose (false),
227
278
  bWriteAttemptedAfterClose (false),
228
279
  OutboundDataSize (0),
@@ -265,7 +316,7 @@ ConnectionDescriptor::~ConnectionDescriptor()
265
316
  STATIC: ConnectionDescriptor::SendDataToConnection
266
317
  **************************************************/
267
318
 
268
- int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length)
319
+ int ConnectionDescriptor::SendDataToConnection (const unsigned long binding, const char *data, int data_length)
269
320
  {
270
321
  // TODO: This is something of a hack, or at least it's a static method of the wrong class.
271
322
  // TODO: Poor polymorphism here. We should be calling one virtual method
@@ -289,7 +340,7 @@ int ConnectionDescriptor::SendDataToConnection (const char *binding, const char
289
340
  STATIC: ConnectionDescriptor::CloseConnection
290
341
  *********************************************/
291
342
 
292
- void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writing)
343
+ void ConnectionDescriptor::CloseConnection (const unsigned long binding, bool after_writing)
293
344
  {
294
345
  // TODO: This is something of a hack, or at least it's a static method of the wrong class.
295
346
  EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
@@ -301,7 +352,7 @@ void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writ
301
352
  STATIC: ConnectionDescriptor::ReportErrorStatus
302
353
  ***********************************************/
303
354
 
304
- int ConnectionDescriptor::ReportErrorStatus (const char *binding)
355
+ int ConnectionDescriptor::ReportErrorStatus (const unsigned long binding)
305
356
  {
306
357
  // TODO: This is something of a hack, or at least it's a static method of the wrong class.
307
358
  // TODO: Poor polymorphism here. We should be calling one virtual method
@@ -312,6 +363,49 @@ int ConnectionDescriptor::ReportErrorStatus (const char *binding)
312
363
  return -1;
313
364
  }
314
365
 
366
+ /***********************************
367
+ ConnectionDescriptor::_UpdateEvents
368
+ ************************************/
369
+
370
+ void ConnectionDescriptor::_UpdateEvents()
371
+ {
372
+ _UpdateEvents(true, true);
373
+ }
374
+
375
+ void ConnectionDescriptor::_UpdateEvents(bool read, bool write)
376
+ {
377
+ if (MySocket == INVALID_SOCKET)
378
+ return;
379
+
380
+ #ifdef HAVE_EPOLL
381
+ unsigned int old = EpollEvent.events;
382
+
383
+ if (read) {
384
+ if (SelectForRead())
385
+ EpollEvent.events |= EPOLLIN;
386
+ else
387
+ EpollEvent.events &= ~EPOLLIN;
388
+ }
389
+
390
+ if (write) {
391
+ if (SelectForWrite())
392
+ EpollEvent.events |= EPOLLOUT;
393
+ else
394
+ EpollEvent.events &= ~EPOLLOUT;
395
+ }
396
+
397
+ if (old != EpollEvent.events)
398
+ MyEventMachine->Modify (this);
399
+ #endif
400
+
401
+ #ifdef HAVE_KQUEUE
402
+ if (read && SelectForRead())
403
+ MyEventMachine->ArmKqueueReader (this);
404
+ if (write && SelectForWrite())
405
+ MyEventMachine->ArmKqueueWriter (this);
406
+ #endif
407
+ }
408
+
315
409
  /***************************************
316
410
  ConnectionDescriptor::SetConnectPending
317
411
  ****************************************/
@@ -319,42 +413,67 @@ ConnectionDescriptor::SetConnectPending
319
413
  void ConnectionDescriptor::SetConnectPending(bool f)
320
414
  {
321
415
  bConnectPending = f;
416
+ _UpdateEvents();
417
+ }
322
418
 
323
- if (bConnectPending) { // not yet connected, select for writability
324
- #ifdef HAVE_EPOLL
325
- EpollEvent.events = EPOLLOUT;
326
- #endif
327
- #ifdef HAVE_KQUEUE
328
- MyEventMachine->ArmKqueueWriter (this);
329
- #endif
330
- } else { // connected, wait for incoming data and write out any pending outgoing data
331
- #ifdef HAVE_EPOLL
332
- EpollEvent.events = EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0);
333
- #endif
334
- #ifdef HAVE_KQUEUE
335
- MyEventMachine->ArmKqueueReader (this);
336
- if (SelectForWrite())
337
- MyEventMachine->ArmKqueueWriter (this);
338
- #endif
419
+
420
+ /**********************************
421
+ ConnectionDescriptor::SetWatchOnly
422
+ ***********************************/
423
+
424
+ void ConnectionDescriptor::SetWatchOnly(bool watching)
425
+ {
426
+ bWatchOnly = watching;
427
+ _UpdateEvents();
428
+ }
429
+
430
+
431
+ /*********************************
432
+ ConnectionDescriptor::HandleError
433
+ *********************************/
434
+
435
+ void ConnectionDescriptor::HandleError()
436
+ {
437
+ if (bWatchOnly) {
438
+ // An EPOLLHUP | EPOLLIN condition will call Read() before HandleError(), in which case the
439
+ // socket is already detached and invalid, so we don't need to do anything.
440
+ if (MySocket == INVALID_SOCKET) return;
441
+
442
+ // HandleError() is called on WatchOnly descriptors by the epoll reactor
443
+ // when it gets a EPOLLERR | EPOLLHUP. Usually this would show up as a readable and
444
+ // writable event on other reactors, so we have to fire those events ourselves.
445
+ if (bNotifyReadable) Read();
446
+ if (bNotifyWritable) Write();
447
+ } else {
448
+ ScheduleClose (false);
339
449
  }
340
450
  }
341
451
 
342
452
 
453
+ /***********************************
454
+ ConnectionDescriptor::ScheduleClose
455
+ ***********************************/
456
+
457
+ void ConnectionDescriptor::ScheduleClose (bool after_writing)
458
+ {
459
+ if (bWatchOnly)
460
+ throw std::runtime_error ("cannot close 'watch only' connections");
461
+
462
+ EventableDescriptor::ScheduleClose(after_writing);
463
+ }
464
+
465
+
343
466
  /***************************************
344
467
  ConnectionDescriptor::SetNotifyReadable
345
468
  ****************************************/
346
469
 
347
470
  void ConnectionDescriptor::SetNotifyReadable(bool readable)
348
471
  {
472
+ if (!bWatchOnly)
473
+ throw std::runtime_error ("notify_readable must be on 'watch only' connections");
474
+
349
475
  bNotifyReadable = readable;
350
- if (bNotifyReadable) {
351
- #ifdef HAVE_EPOLL
352
- EpollEvent.events |= EPOLLIN;
353
- #endif
354
- #ifdef HAVE_KQUEUE
355
- MyEventMachine->ArmKqueueReader (this);
356
- #endif
357
- }
476
+ _UpdateEvents(true, false);
358
477
  }
359
478
 
360
479
 
@@ -364,15 +483,11 @@ ConnectionDescriptor::SetNotifyWritable
364
483
 
365
484
  void ConnectionDescriptor::SetNotifyWritable(bool writable)
366
485
  {
486
+ if (!bWatchOnly)
487
+ throw std::runtime_error ("notify_writable must be on 'watch only' connections");
488
+
367
489
  bNotifyWritable = writable;
368
- if (bNotifyWritable) {
369
- #ifdef HAVE_EPOLL
370
- EpollEvent.events |= EPOLLOUT;
371
- #endif
372
- #ifdef HAVE_KQUEUE
373
- MyEventMachine->ArmKqueueWriter (this);
374
- #endif
375
- }
490
+ _UpdateEvents(false, true);
376
491
  }
377
492
 
378
493
 
@@ -382,6 +497,12 @@ ConnectionDescriptor::SendOutboundData
382
497
 
383
498
  int ConnectionDescriptor::SendOutboundData (const char *data, int length)
384
499
  {
500
+ if (bWatchOnly)
501
+ throw std::runtime_error ("cannot send data on a 'watch only' connection");
502
+
503
+ if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() + length > MaxOutboundBufSize)
504
+ ProxiedFrom->Pause();
505
+
385
506
  #ifdef WITH_SSL
386
507
  if (SslBox) {
387
508
  if (length > 0) {
@@ -434,14 +555,7 @@ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
434
555
  OutboundPages.push_back (OutboundPage (buffer, length));
435
556
  OutboundDataSize += length;
436
557
 
437
- #ifdef HAVE_EPOLL
438
- EpollEvent.events = (EPOLLIN | EPOLLOUT);
439
- assert (MyEventMachine);
440
- MyEventMachine->Modify (this);
441
- #endif
442
- #ifdef HAVE_KQUEUE
443
- MyEventMachine->ArmKqueueWriter (this);
444
- #endif
558
+ _UpdateEvents(false, true);
445
559
 
446
560
  return length;
447
561
  }
@@ -468,7 +582,14 @@ bool ConnectionDescriptor::SelectForRead()
468
582
  * is known to be in a connected state.
469
583
  */
470
584
 
471
- return bConnectPending ? false : true;
585
+ if (bPaused)
586
+ return false;
587
+ else if (bConnectPending)
588
+ return false;
589
+ else if (bWatchOnly)
590
+ return bNotifyReadable ? true : false;
591
+ else
592
+ return true;
472
593
  }
473
594
 
474
595
 
@@ -484,13 +605,45 @@ bool ConnectionDescriptor::SelectForWrite()
484
605
  * have outgoing data to send.
485
606
  */
486
607
 
487
- if (bConnectPending || bNotifyWritable)
608
+ if (bPaused)
609
+ return false;
610
+ else if (bConnectPending)
488
611
  return true;
489
- else {
612
+ else if (bWatchOnly)
613
+ return bNotifyWritable ? true : false;
614
+ else
490
615
  return (GetOutboundDataSize() > 0);
491
- }
492
616
  }
493
617
 
618
+ /***************************
619
+ ConnectionDescriptor::Pause
620
+ ***************************/
621
+
622
+ bool ConnectionDescriptor::Pause()
623
+ {
624
+ if (bWatchOnly)
625
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
626
+
627
+ bool old = bPaused;
628
+ bPaused = true;
629
+ _UpdateEvents();
630
+ return old == false;
631
+ }
632
+
633
+ /****************************
634
+ ConnectionDescriptor::Resume
635
+ ****************************/
636
+
637
+ bool ConnectionDescriptor::Resume()
638
+ {
639
+ if (bWatchOnly)
640
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
641
+
642
+ bool old = bPaused;
643
+ bPaused = false;
644
+ _UpdateEvents();
645
+ return old == true;
646
+ }
494
647
 
495
648
  /**************************
496
649
  ConnectionDescriptor::Read
@@ -529,9 +682,9 @@ void ConnectionDescriptor::Read()
529
682
  return;
530
683
  }
531
684
 
532
- if (bNotifyReadable) {
533
- if (EventCallback)
534
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
685
+ if (bWatchOnly) {
686
+ if (bNotifyReadable && EventCallback)
687
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
535
688
  return;
536
689
  }
537
690
 
@@ -635,7 +788,7 @@ void ConnectionDescriptor::_CheckHandshakeStatus()
635
788
  if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
636
789
  bHandshakeSignaled = true;
637
790
  if (EventCallback)
638
- (*EventCallback)(GetBinding().c_str(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
791
+ (*EventCallback)(GetBinding(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
639
792
  }
640
793
  #endif
641
794
  }
@@ -672,7 +825,7 @@ void ConnectionDescriptor::Write()
672
825
  #endif
673
826
  if ((o == 0) && (error == 0)) {
674
827
  if (EventCallback)
675
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_COMPLETED, "", 0);
828
+ (*EventCallback)(GetBinding(), EM_CONNECTION_COMPLETED, "", 0);
676
829
 
677
830
  // 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called
678
831
  // from EventMachine_t::AttachFD as well.
@@ -686,10 +839,14 @@ void ConnectionDescriptor::Write()
686
839
 
687
840
  if (bNotifyWritable) {
688
841
  if (EventCallback)
689
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
842
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
843
+
844
+ _UpdateEvents(false, true);
690
845
  return;
691
846
  }
692
847
 
848
+ assert(!bWatchOnly);
849
+
693
850
  /* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using
694
851
  EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again,
695
852
  we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause
@@ -796,9 +953,12 @@ void ConnectionDescriptor::_WriteOutboundData()
796
953
  assert (bytes_written >= 0);
797
954
  OutboundDataSize -= bytes_written;
798
955
 
956
+ if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
957
+ ProxiedFrom->Resume();
958
+
799
959
  #ifdef HAVE_WRITEV
800
960
  if (!err) {
801
- int sent = bytes_written;
961
+ unsigned int sent = bytes_written;
802
962
  deque<OutboundPage>::iterator op = OutboundPages.begin();
803
963
 
804
964
  for (int i = 0; i < iovcnt; i++) {
@@ -831,16 +991,7 @@ void ConnectionDescriptor::_WriteOutboundData()
831
991
  }
832
992
  #endif
833
993
 
834
- #ifdef HAVE_EPOLL
835
- EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
836
- assert (MyEventMachine);
837
- MyEventMachine->Modify (this);
838
- #endif
839
- #ifdef HAVE_KQUEUE
840
- if (SelectForWrite())
841
- MyEventMachine->ArmKqueueWriter (this);
842
- #endif
843
-
994
+ _UpdateEvents(false, true);
844
995
 
845
996
  if (err) {
846
997
  #ifdef OS_UNIX
@@ -886,7 +1037,7 @@ void ConnectionDescriptor::StartTls()
886
1037
  if (SslBox)
887
1038
  throw std::runtime_error ("SSL/TLS already running on connection");
888
1039
 
889
- SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding().c_str());
1040
+ SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding());
890
1041
  _DispatchCiphertext();
891
1042
  #endif
892
1043
 
@@ -942,7 +1093,7 @@ bool ConnectionDescriptor::VerifySslPeer(const char *cert)
942
1093
  bSslPeerAccepted = false;
943
1094
 
944
1095
  if (EventCallback)
945
- (*EventCallback)(GetBinding().c_str(), EM_SSL_VERIFY, cert, strlen(cert));
1096
+ (*EventCallback)(GetBinding(), EM_SSL_VERIFY, cert, strlen(cert));
946
1097
 
947
1098
  return bSslPeerAccepted;
948
1099
  }
@@ -1126,7 +1277,7 @@ AcceptorDescriptor::~AcceptorDescriptor()
1126
1277
  STATIC: AcceptorDescriptor::StopAcceptor
1127
1278
  ****************************************/
1128
1279
 
1129
- void AcceptorDescriptor::StopAcceptor (const char *binding)
1280
+ void AcceptorDescriptor::StopAcceptor (const unsigned long binding)
1130
1281
  {
1131
1282
  // TODO: This is something of a hack, or at least it's a static method of the wrong class.
1132
1283
  AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
@@ -1192,7 +1343,7 @@ void AcceptorDescriptor::Read()
1192
1343
  throw std::runtime_error ("no newly accepted connection");
1193
1344
  cd->SetServerMode();
1194
1345
  if (EventCallback) {
1195
- (*EventCallback) (GetBinding().c_str(), EM_CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
1346
+ (*EventCallback) (GetBinding(), EM_CONNECTION_ACCEPTED, NULL, cd->GetBinding());
1196
1347
  }
1197
1348
  #ifdef HAVE_EPOLL
1198
1349
  cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
@@ -1279,7 +1430,7 @@ DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1279
1430
  */
1280
1431
 
1281
1432
  int oval = 1;
1282
- int sob = setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1433
+ setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1283
1434
 
1284
1435
  #ifdef HAVE_EPOLL
1285
1436
  EpollEvent.events = EPOLLIN;
@@ -1437,6 +1588,10 @@ void DatagramDescriptor::Write()
1437
1588
  assert (MyEventMachine);
1438
1589
  MyEventMachine->Modify (this);
1439
1590
  #endif
1591
+ #ifdef HAVE_KQUEUE
1592
+ if (SelectForWrite())
1593
+ MyEventMachine->ArmKqueueWriter (this);
1594
+ #endif
1440
1595
  }
1441
1596
 
1442
1597
 
@@ -1485,6 +1640,9 @@ int DatagramDescriptor::SendOutboundData (const char *data, int length)
1485
1640
  assert (MyEventMachine);
1486
1641
  MyEventMachine->Modify (this);
1487
1642
  #endif
1643
+ #ifdef HAVE_KQUEUE
1644
+ MyEventMachine->ArmKqueueWriter (this);
1645
+ #endif
1488
1646
 
1489
1647
  return length;
1490
1648
  }
@@ -1540,6 +1698,9 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
1540
1698
  assert (MyEventMachine);
1541
1699
  MyEventMachine->Modify (this);
1542
1700
  #endif
1701
+ #ifdef HAVE_KQUEUE
1702
+ MyEventMachine->ArmKqueueWriter (this);
1703
+ #endif
1543
1704
 
1544
1705
  return length;
1545
1706
  }
@@ -1549,7 +1710,7 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
1549
1710
  STATIC: DatagramDescriptor::SendDatagram
1550
1711
  ****************************************/
1551
1712
 
1552
- int DatagramDescriptor::SendDatagram (const char *binding, const char *data, int length, const char *address, int port)
1713
+ int DatagramDescriptor::SendDatagram (const unsigned long binding, const char *data, int length, const char *address, int port)
1553
1714
  {
1554
1715
  DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
1555
1716
  if (dd)