eventmachine 0.12.8 → 0.12.10

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 +2 -1
  2. data/Rakefile +155 -45
  3. data/eventmachine.gemspec +4 -5
  4. data/ext/binder.cpp +13 -14
  5. data/ext/binder.h +5 -7
  6. data/ext/cmain.cpp +184 -42
  7. data/ext/cplusplus.cpp +20 -20
  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 +4 -4
  15. data/ext/extconf.rb +28 -13
  16. data/ext/fastfilereader/extconf.rb +11 -5
  17. data/ext/project.h +12 -1
  18. data/ext/rubymain.cpp +222 -103
  19. data/ext/ssl.cpp +3 -3
  20. data/ext/ssl.h +2 -2
  21. data/java/src/com/rubyeventmachine/EmReactor.java +396 -249
  22. data/java/src/com/rubyeventmachine/EventableChannel.java +16 -4
  23. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +23 -5
  24. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +181 -61
  25. data/java/src/com/rubyeventmachine/{Application.java → application/Application.java} +25 -31
  26. data/java/src/com/rubyeventmachine/{Connection.java → application/Connection.java} +2 -2
  27. data/java/src/com/rubyeventmachine/{ConnectionFactory.java → application/ConnectionFactory.java} +1 -1
  28. data/java/src/com/rubyeventmachine/{DefaultConnectionFactory.java → application/DefaultConnectionFactory.java} +2 -2
  29. data/java/src/com/rubyeventmachine/{PeriodicTimer.java → application/PeriodicTimer.java} +1 -1
  30. data/java/src/com/rubyeventmachine/{Timer.java → application/Timer.java} +1 -1
  31. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +1 -0
  32. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +4 -2
  33. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +1 -1
  34. data/java/src/com/rubyeventmachine/tests/TestServers.java +1 -0
  35. data/java/src/com/rubyeventmachine/tests/TestTimers.java +1 -0
  36. data/lib/em/connection.rb +71 -12
  37. data/lib/em/deferrable.rb +5 -0
  38. data/lib/em/protocols.rb +1 -0
  39. data/lib/em/protocols/httpclient2.rb +8 -0
  40. data/lib/em/protocols/line_and_text.rb +0 -1
  41. data/lib/em/protocols/linetext2.rb +1 -0
  42. data/lib/em/protocols/object_protocol.rb +8 -2
  43. data/lib/em/protocols/smtpclient.rb +42 -16
  44. data/lib/em/protocols/socks4.rb +66 -0
  45. data/lib/em/queue.rb +1 -1
  46. data/lib/em/timers.rb +2 -1
  47. data/lib/em/version.rb +1 -1
  48. data/lib/eventmachine.rb +125 -169
  49. data/lib/jeventmachine.rb +124 -9
  50. data/tasks/{cpp.rake → cpp.rake_example} +0 -0
  51. data/tests/test_attach.rb +29 -4
  52. data/tests/test_basic.rb +1 -2
  53. data/tests/test_connection_count.rb +10 -20
  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 +0 -6
  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 +16 -5
  63. data/tests/test_timers.rb +22 -1
  64. metadata +14 -12
  65. data/tasks/project.rake +0 -79
  66. data/tasks/tests.rake +0 -193
@@ -22,8 +22,8 @@ See the file COPYING for complete licensing information.
22
22
 
23
23
 
24
24
  namespace EM {
25
- static map<string, Eventable*> Eventables;
26
- static map<string, void(*)()> Timers;
25
+ static map<unsigned long, Eventable*> Eventables;
26
+ static map<unsigned long, void(*)()> Timers;
27
27
  }
28
28
 
29
29
 
@@ -48,9 +48,9 @@ EM::AddTimer
48
48
  void EM::AddTimer (int milliseconds, void (*func)())
49
49
  {
50
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));
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
54
  #else
55
55
  Timers.insert (make_pair (sig, func));
56
56
  #endif
@@ -72,12 +72,12 @@ void EM::StopReactor()
72
72
  EM::Acceptor::Accept
73
73
  ********************/
74
74
 
75
- void EM::Acceptor::Accept (const char *signature)
75
+ void EM::Acceptor::Accept (const unsigned long signature)
76
76
  {
77
77
  Connection *c = MakeConnection();
78
78
  c->Signature = signature;
79
- #ifdef OS_SOLARIS8
80
- Eventables.insert (std::map<std::string,EM::Eventable*>::value_type (c->Signature, c));
79
+ #ifndef HAVE_MAKE_PAIR
80
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (c->Signature, c));
81
81
  #else
82
82
  Eventables.insert (make_pair (c->Signature, c));
83
83
  #endif
@@ -101,7 +101,7 @@ EM::Connection::SendData
101
101
 
102
102
  void EM::Connection::SendData (const char *data, int length)
103
103
  {
104
- evma_send_data_to_connection (Signature.c_str(), data, length);
104
+ evma_send_data_to_connection (Signature, data, length);
105
105
  }
106
106
 
107
107
 
@@ -111,7 +111,7 @@ EM::Connection::Close
111
111
 
112
112
  void EM::Connection::Close (bool afterWriting)
113
113
  {
114
- evma_close_connection (Signature.c_str(), afterWriting);
114
+ evma_close_connection (Signature, afterWriting);
115
115
  }
116
116
 
117
117
 
@@ -122,10 +122,10 @@ EM::Connection::BindConnect
122
122
  void EM::Connection::BindConnect (const char *bind_addr, int bind_port, const char *host, int port)
123
123
  {
124
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));
125
+ #ifndef HAVE_MAKE_PAIR
126
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
127
127
  #else
128
- Eventables.insert( make_pair (Signature, this));
128
+ Eventables.insert (make_pair (Signature, this));
129
129
  #endif
130
130
  }
131
131
 
@@ -145,10 +145,10 @@ EM::Acceptor::Start
145
145
  void EM::Acceptor::Start (const char *host, int port)
146
146
  {
147
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));
148
+ #ifndef HAVE_MAKE_PAIR
149
+ Eventables.insert (std::map<unsigned long,EM::Eventable*>::value_type (Signature, this));
150
150
  #else
151
- Eventables.insert( make_pair (Signature, this));
151
+ Eventables.insert (make_pair (Signature, this));
152
152
  #endif
153
153
  }
154
154
 
@@ -158,17 +158,17 @@ void EM::Acceptor::Start (const char *host, int port)
158
158
  EM::Callback
159
159
  ************/
160
160
 
161
- void EM::Callback (const char *sig, int ev, const char *data, int length)
161
+ void EM::Callback (const unsigned long sig, int ev, const char *data, const unsigned long length)
162
162
  {
163
163
  EM::Eventable *e;
164
164
  void (*f)();
165
165
 
166
166
  switch (ev) {
167
167
  case EM_TIMER_FIRED:
168
- f = Timers [data];
168
+ f = Timers [length]; // actually a binding
169
169
  if (f)
170
170
  (*f)();
171
- Timers.erase (sig);
171
+ Timers.erase (length);
172
172
  break;
173
173
 
174
174
  case EM_CONNECTION_READ:
@@ -183,7 +183,7 @@ void EM::Callback (const char *sig, int ev, const char *data, int length)
183
183
 
184
184
  case EM_CONNECTION_ACCEPTED:
185
185
  e = EM::Eventables [sig];
186
- e->Accept (data);
186
+ e->Accept (length); // actually a binding
187
187
  break;
188
188
 
189
189
  case EM_CONNECTION_UNBOUND:
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)