eventmachine-maglev- 0.12.10 → 1.0.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/.gitignore +7 -0
  2. data/.yardopts +7 -0
  3. data/Gemfile +3 -0
  4. data/README.md +109 -0
  5. data/Rakefile +14 -368
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +521 -0
  8. data/docs/old/DEFERRABLES +246 -0
  9. data/docs/{KEYBOARD → old/KEYBOARD} +15 -11
  10. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  11. data/docs/old/SMTP +4 -0
  12. data/docs/old/SPAWNED_PROCESSES +148 -0
  13. data/eventmachine.gemspec +20 -26
  14. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  15. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  16. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  17. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  18. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  19. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  20. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  21. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  22. data/examples/{ex_channel.rb → old/ex_channel.rb} +3 -3
  23. data/examples/old/ex_tick_loop_array.rb +15 -0
  24. data/examples/old/ex_tick_loop_counter.rb +32 -0
  25. data/ext/binder.cpp +0 -1
  26. data/ext/cmain.cpp +40 -29
  27. data/ext/ed.cpp +189 -134
  28. data/ext/ed.h +34 -40
  29. data/ext/em.cpp +388 -340
  30. data/ext/em.h +29 -32
  31. data/ext/eventmachine.h +7 -6
  32. data/ext/extconf.rb +57 -48
  33. data/ext/fastfilereader/extconf.rb +5 -3
  34. data/ext/fastfilereader/mapper.cpp +1 -1
  35. data/ext/fastfilereader/rubymain.cpp +0 -1
  36. data/ext/kb.cpp +1 -3
  37. data/ext/pipe.cpp +9 -11
  38. data/ext/project.h +12 -8
  39. data/ext/rubymain.cpp +158 -112
  40. data/java/src/com/rubyeventmachine/EmReactor.java +3 -2
  41. data/lib/em/buftok.rb +35 -63
  42. data/lib/em/callback.rb +43 -11
  43. data/lib/em/channel.rb +22 -15
  44. data/lib/em/completion.rb +303 -0
  45. data/lib/em/connection.rb +341 -208
  46. data/lib/em/deferrable/pool.rb +2 -0
  47. data/lib/em/deferrable.rb +20 -2
  48. data/lib/em/file_watch.rb +37 -18
  49. data/lib/em/iterator.rb +270 -0
  50. data/lib/em/pool.rb +146 -0
  51. data/lib/em/process_watch.rb +5 -4
  52. data/lib/em/processes.rb +8 -4
  53. data/lib/em/protocols/httpclient.rb +27 -11
  54. data/lib/em/protocols/httpclient2.rb +15 -5
  55. data/lib/em/protocols/line_protocol.rb +29 -0
  56. data/lib/em/protocols/memcache.rb +17 -9
  57. data/lib/em/protocols/object_protocol.rb +2 -1
  58. data/lib/em/protocols/postgres3.rb +2 -1
  59. data/lib/em/protocols/smtpclient.rb +19 -11
  60. data/lib/em/protocols/smtpserver.rb +101 -8
  61. data/lib/em/protocols/stomp.rb +9 -7
  62. data/lib/em/protocols/tcptest.rb +3 -2
  63. data/lib/em/protocols.rb +1 -1
  64. data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +188 -205
  65. data/lib/em/queue.rb +23 -13
  66. data/lib/em/resolver.rb +192 -0
  67. data/lib/em/spawnable.rb +9 -10
  68. data/lib/em/streamer.rb +34 -46
  69. data/lib/em/threaded_resource.rb +90 -0
  70. data/lib/em/tick_loop.rb +85 -0
  71. data/lib/em/timers.rb +8 -3
  72. data/lib/em/version.rb +1 -1
  73. data/lib/eventmachine.rb +582 -686
  74. data/lib/jeventmachine.rb +25 -3
  75. data/tasks/package.rake +98 -0
  76. data/tasks/test.rake +8 -0
  77. data/tests/em_test_helper.rb +64 -0
  78. data/tests/test_attach.rb +56 -56
  79. data/tests/test_basic.rb +111 -168
  80. data/tests/test_channel.rb +5 -6
  81. data/tests/test_completion.rb +177 -0
  82. data/tests/test_connection_count.rb +1 -3
  83. data/tests/test_defer.rb +3 -32
  84. data/tests/test_deferrable.rb +35 -0
  85. data/tests/test_epoll.rb +27 -57
  86. data/tests/test_error_handler.rb +10 -7
  87. data/tests/test_exc.rb +6 -33
  88. data/tests/test_file_watch.rb +51 -35
  89. data/tests/test_futures.rb +10 -38
  90. data/tests/test_get_sock_opt.rb +27 -20
  91. data/tests/test_handler_check.rb +1 -3
  92. data/tests/test_hc.rb +49 -112
  93. data/tests/test_httpclient.rb +34 -62
  94. data/tests/test_httpclient2.rb +14 -39
  95. data/tests/test_inactivity_timeout.rb +44 -40
  96. data/tests/test_kb.rb +26 -52
  97. data/tests/test_ltp.rb +27 -71
  98. data/tests/test_ltp2.rb +1 -30
  99. data/tests/test_next_tick.rb +2 -31
  100. data/tests/test_object_protocol.rb +8 -9
  101. data/tests/test_pause.rb +45 -37
  102. data/tests/test_pending_connect_timeout.rb +42 -38
  103. data/tests/test_pool.rb +128 -0
  104. data/tests/test_process_watch.rb +37 -37
  105. data/tests/test_processes.rb +92 -110
  106. data/tests/test_proxy_connection.rb +137 -61
  107. data/tests/test_pure.rb +30 -67
  108. data/tests/test_queue.rb +10 -4
  109. data/tests/test_resolver.rb +55 -0
  110. data/tests/test_running.rb +1 -29
  111. data/tests/test_sasl.rb +8 -33
  112. data/tests/test_send_file.rb +163 -188
  113. data/tests/test_servers.rb +12 -55
  114. data/tests/test_shutdown_hooks.rb +23 -0
  115. data/tests/test_smtpclient.rb +1 -29
  116. data/tests/test_smtpserver.rb +1 -29
  117. data/tests/test_spawn.rb +2 -31
  118. data/tests/test_ssl_args.rb +9 -10
  119. data/tests/test_ssl_methods.rb +1 -3
  120. data/tests/test_ssl_verify.rb +63 -63
  121. data/tests/test_threaded_resource.rb +53 -0
  122. data/tests/test_tick_loop.rb +59 -0
  123. data/tests/test_timers.rb +52 -91
  124. data/tests/test_ud.rb +1 -29
  125. data/tests/test_unbind_reason.rb +31 -0
  126. metadata +113 -70
  127. data/README +0 -82
  128. data/docs/DEFERRABLES +0 -133
  129. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -70
  130. data/docs/SMTP +0 -2
  131. data/docs/SPAWNED_PROCESSES +0 -89
  132. data/ext/cplusplus.cpp +0 -202
  133. data/ext/emwin.cpp +0 -300
  134. data/ext/emwin.h +0 -94
  135. data/ext/epoll.cpp +0 -26
  136. data/ext/epoll.h +0 -25
  137. data/ext/eventmachine_cpp.h +0 -96
  138. data/ext/files.cpp +0 -94
  139. data/ext/files.h +0 -65
  140. data/ext/sigs.cpp +0 -89
  141. data/ext/sigs.h +0 -32
  142. data/java/src/com/rubyeventmachine/application/Application.java +0 -194
  143. data/java/src/com/rubyeventmachine/application/Connection.java +0 -74
  144. data/java/src/com/rubyeventmachine/application/ConnectionFactory.java +0 -37
  145. data/java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java +0 -46
  146. data/java/src/com/rubyeventmachine/application/PeriodicTimer.java +0 -38
  147. data/java/src/com/rubyeventmachine/application/Timer.java +0 -54
  148. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +0 -109
  149. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +0 -148
  150. data/java/src/com/rubyeventmachine/tests/EMTest.java +0 -80
  151. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +0 -53
  152. data/java/src/com/rubyeventmachine/tests/TestServers.java +0 -75
  153. data/java/src/com/rubyeventmachine/tests/TestTimers.java +0 -90
  154. data/lib/evma/callback.rb +0 -32
  155. data/lib/evma/container.rb +0 -75
  156. data/lib/evma/factory.rb +0 -77
  157. data/lib/evma/protocol.rb +0 -87
  158. data/lib/evma/reactor.rb +0 -48
  159. data/lib/evma.rb +0 -32
  160. data/setup.rb +0 -1585
  161. data/tests/test_errors.rb +0 -82
  162. data/tests/testem.rb +0 -31
  163. data/web/whatis +0 -7
  164. /data/{docs/GNU → GNU} +0 -0
  165. /data/{docs/COPYING → LICENSE} +0 -0
  166. /data/docs/{ChangeLog → old/ChangeLog} +0 -0
  167. /data/docs/{EPOLL → old/EPOLL} +0 -0
  168. /data/docs/{INSTALL → old/INSTALL} +0 -0
  169. /data/docs/{LEGAL → old/LEGAL} +0 -0
  170. /data/docs/{PURE_RUBY → old/PURE_RUBY} +0 -0
  171. /data/docs/{RELEASE_NOTES → old/RELEASE_NOTES} +0 -0
  172. /data/docs/{TODO → old/TODO} +0 -0
  173. /data/examples/{ex_queue.rb → old/ex_queue.rb} +0 -0
  174. /data/examples/{helper.rb → old/helper.rb} +0 -0
data/ext/ed.cpp CHANGED
@@ -54,6 +54,7 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
54
54
  bCloseNow (false),
55
55
  bCloseAfterWriting (false),
56
56
  MySocket (sd),
57
+ bWatchOnly (false),
57
58
  EventCallback (NULL),
58
59
  bCallbackUnbind (true),
59
60
  UnbindReasonCode (0),
@@ -61,7 +62,8 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
61
62
  ProxiedFrom(NULL),
62
63
  MaxOutboundBufSize(0),
63
64
  MyEventMachine (em),
64
- PendingConnectTimeout(20000000)
65
+ PendingConnectTimeout(20000000),
66
+ InactivityTimeout (0)
65
67
  {
66
68
  /* There are three ways to close a socket, all of which should
67
69
  * automatically signal to the event machine that this object
@@ -88,12 +90,13 @@ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
88
90
  throw std::runtime_error ("bad eventable descriptor");
89
91
  if (MyEventMachine == NULL)
90
92
  throw std::runtime_error ("bad em in eventable descriptor");
91
- CreatedAt = gCurrentLoopTime;
93
+ CreatedAt = MyEventMachine->GetCurrentLoopTime();
92
94
 
93
95
  #ifdef HAVE_EPOLL
94
96
  EpollEvent.events = 0;
95
97
  EpollEvent.data.ptr = this;
96
98
  #endif
99
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
97
100
  }
98
101
 
99
102
 
@@ -103,6 +106,8 @@ EventableDescriptor::~EventableDescriptor
103
106
 
104
107
  EventableDescriptor::~EventableDescriptor()
105
108
  {
109
+ if (NextHeartbeat)
110
+ MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
106
111
  if (EventCallback && bCallbackUnbind)
107
112
  (*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
108
113
  if (ProxiedFrom) {
@@ -118,7 +123,7 @@ EventableDescriptor::~EventableDescriptor()
118
123
  EventableDescriptor::SetEventCallback
119
124
  *************************************/
120
125
 
121
- void EventableDescriptor::SetEventCallback (void(*cb)(const unsigned long, int, const char*, const unsigned long))
126
+ void EventableDescriptor::SetEventCallback (EMCallback cb)
122
127
  {
123
128
  EventCallback = cb;
124
129
  }
@@ -130,10 +135,46 @@ EventableDescriptor::Close
130
135
 
131
136
  void EventableDescriptor::Close()
132
137
  {
138
+ /* EventMachine relies on the fact that when close(fd)
139
+ * is called that the fd is removed from any
140
+ * epoll event queues.
141
+ *
142
+ * However, this is not *always* the behavior of close(fd)
143
+ *
144
+ * See man 4 epoll Q6/A6 and then consider what happens
145
+ * when using pipes with eventmachine.
146
+ * (As is often done when communicating with a subprocess)
147
+ *
148
+ * The pipes end up looking like:
149
+ *
150
+ * ls -l /proc/<pid>/fd
151
+ * ...
152
+ * lr-x------ 1 root root 64 2011-08-19 21:31 3 -> pipe:[940970]
153
+ * l-wx------ 1 root root 64 2011-08-19 21:31 4 -> pipe:[940970]
154
+ *
155
+ * This meets the critera from man 4 epoll Q6/A4 for not
156
+ * removing fds from epoll event queues until all fds
157
+ * that reference the underlying file have been removed.
158
+ *
159
+ * If the EventableDescriptor associated with fd 3 is deleted,
160
+ * its dtor will call EventableDescriptor::Close(),
161
+ * which will call ::close(int fd).
162
+ *
163
+ * However, unless the EventableDescriptor associated with fd 4 is
164
+ * also deleted before the next call to epoll_wait, events may fire
165
+ * for fd 3 that were registered with an already deleted
166
+ * EventableDescriptor.
167
+ *
168
+ * Therefore, it is necessary to notify EventMachine that
169
+ * the fd associated with this EventableDescriptor is
170
+ * closing.
171
+ */
172
+
133
173
  // Close the socket right now. Intended for emergencies.
134
- if (MySocket != INVALID_SOCKET) {
174
+ if (MySocket != INVALID_SOCKET && !bWatchOnly) {
175
+ MyEventMachine->Closing (this);
135
176
  shutdown (MySocket, 1);
136
- closesocket (MySocket);
177
+ close (MySocket);
137
178
  MySocket = INVALID_SOCKET;
138
179
  }
139
180
  }
@@ -187,12 +228,13 @@ bool EventableDescriptor::IsCloseScheduled()
187
228
  EventableDescriptor::StartProxy
188
229
  *******************************/
189
230
 
190
- void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long bufsize)
231
+ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long bufsize, const unsigned long length)
191
232
  {
192
233
  EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (to));
193
234
  if (ed) {
194
235
  StopProxy();
195
236
  ProxyTarget = ed;
237
+ BytesToProxy = length;
196
238
  ed->SetProxiedFrom(this, bufsize);
197
239
  return;
198
240
  }
@@ -219,6 +261,9 @@ EventableDescriptor::SetProxiedFrom
219
261
 
220
262
  void EventableDescriptor::SetProxiedFrom(EventableDescriptor *from, const unsigned long bufsize)
221
263
  {
264
+ if (from != NULL && ProxiedFrom != NULL)
265
+ throw std::runtime_error ("Tried to proxy to a busy target");
266
+
222
267
  ProxiedFrom = from;
223
268
  MaxOutboundBufSize = bufsize;
224
269
  }
@@ -232,10 +277,24 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
232
277
  {
233
278
  assert(EventCallback);
234
279
 
235
- if (ProxyTarget)
236
- ProxyTarget->SendOutboundData(buf, size);
237
- else
280
+ if (ProxyTarget) {
281
+ if (BytesToProxy > 0) {
282
+ unsigned long proxied = min(BytesToProxy, (unsigned long) size);
283
+ ProxyTarget->SendOutboundData(buf, proxied);
284
+ BytesToProxy -= proxied;
285
+ if (BytesToProxy == 0) {
286
+ StopProxy();
287
+ (*EventCallback)(GetBinding(), EM_PROXY_COMPLETED, NULL, 0);
288
+ if (proxied < size) {
289
+ (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf + proxied, size - proxied);
290
+ }
291
+ }
292
+ } else {
293
+ ProxyTarget->SendOutboundData(buf, size);
294
+ }
295
+ } else {
238
296
  (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
297
+ }
239
298
  }
240
299
 
241
300
 
@@ -243,9 +302,9 @@ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
243
302
  EventableDescriptor::GetPendingConnectTimeout
244
303
  *********************************************/
245
304
 
246
- float EventableDescriptor::GetPendingConnectTimeout()
305
+ uint64_t EventableDescriptor::GetPendingConnectTimeout()
247
306
  {
248
- return ((float)PendingConnectTimeout / 1000000);
307
+ return PendingConnectTimeout / 1000;
249
308
  }
250
309
 
251
310
 
@@ -253,16 +312,43 @@ float EventableDescriptor::GetPendingConnectTimeout()
253
312
  EventableDescriptor::SetPendingConnectTimeout
254
313
  *********************************************/
255
314
 
256
- int EventableDescriptor::SetPendingConnectTimeout (float value)
315
+ int EventableDescriptor::SetPendingConnectTimeout (uint64_t value)
257
316
  {
258
317
  if (value > 0) {
259
- PendingConnectTimeout = (Int64)(value * 1000000);
318
+ PendingConnectTimeout = value * 1000;
319
+ MyEventMachine->QueueHeartbeat(this);
260
320
  return 1;
261
321
  }
262
322
  return 0;
263
323
  }
264
324
 
265
325
 
326
+ /*************************************
327
+ EventableDescriptor::GetNextHeartbeat
328
+ *************************************/
329
+
330
+ uint64_t EventableDescriptor::GetNextHeartbeat()
331
+ {
332
+ if (NextHeartbeat)
333
+ MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
334
+
335
+ NextHeartbeat = 0;
336
+
337
+ if (!ShouldDelete()) {
338
+ uint64_t time_til_next = InactivityTimeout;
339
+ if (IsConnectPending()) {
340
+ if (time_til_next == 0 || PendingConnectTimeout < time_til_next)
341
+ time_til_next = PendingConnectTimeout;
342
+ }
343
+ if (time_til_next == 0)
344
+ return 0;
345
+ NextHeartbeat = time_til_next + MyEventMachine->GetRealTime();
346
+ }
347
+
348
+ return NextHeartbeat;
349
+ }
350
+
351
+
266
352
  /******************************************
267
353
  ConnectionDescriptor::ConnectionDescriptor
268
354
  ******************************************/
@@ -273,7 +359,6 @@ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
273
359
  bConnectPending (false),
274
360
  bNotifyReadable (false),
275
361
  bNotifyWritable (false),
276
- bWatchOnly (false),
277
362
  bReadAttemptedAfterClose (false),
278
363
  bWriteAttemptedAfterClose (false),
279
364
  OutboundDataSize (0),
@@ -286,9 +371,7 @@ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
286
371
  #ifdef HAVE_KQUEUE
287
372
  bGotExtraKqueueEvent(false),
288
373
  #endif
289
- bIsServer (false),
290
- LastIo (gCurrentLoopTime),
291
- InactivityTimeout (0)
374
+ bIsServer (false)
292
375
  {
293
376
  // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData()
294
377
  // 5May09: Moved EPOLLOUT into SetConnectPending() so it doesn't happen for attached read pipes
@@ -312,57 +395,6 @@ ConnectionDescriptor::~ConnectionDescriptor()
312
395
  }
313
396
 
314
397
 
315
- /**************************************************
316
- STATIC: ConnectionDescriptor::SendDataToConnection
317
- **************************************************/
318
-
319
- int ConnectionDescriptor::SendDataToConnection (const unsigned long binding, const char *data, int data_length)
320
- {
321
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
322
- // TODO: Poor polymorphism here. We should be calling one virtual method
323
- // instead of hacking out the runtime information of the target object.
324
- ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
325
- if (cd)
326
- return cd->SendOutboundData (data, data_length);
327
- DatagramDescriptor *ds = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
328
- if (ds)
329
- return ds->SendOutboundData (data, data_length);
330
- #ifdef OS_UNIX
331
- PipeDescriptor *ps = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
332
- if (ps)
333
- return ps->SendOutboundData (data, data_length);
334
- #endif
335
- return -1;
336
- }
337
-
338
-
339
- /*********************************************
340
- STATIC: ConnectionDescriptor::CloseConnection
341
- *********************************************/
342
-
343
- void ConnectionDescriptor::CloseConnection (const unsigned long binding, bool after_writing)
344
- {
345
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
346
- EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
347
- if (ed)
348
- ed->ScheduleClose (after_writing);
349
- }
350
-
351
- /***********************************************
352
- STATIC: ConnectionDescriptor::ReportErrorStatus
353
- ***********************************************/
354
-
355
- int ConnectionDescriptor::ReportErrorStatus (const unsigned long binding)
356
- {
357
- // TODO: This is something of a hack, or at least it's a static method of the wrong class.
358
- // TODO: Poor polymorphism here. We should be calling one virtual method
359
- // instead of hacking out the runtime information of the target object.
360
- ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
361
- if (cd)
362
- return cd->_ReportErrorStatus();
363
- return -1;
364
- }
365
-
366
398
  /***********************************
367
399
  ConnectionDescriptor::_UpdateEvents
368
400
  ************************************/
@@ -500,7 +532,7 @@ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
500
532
  if (bWatchOnly)
501
533
  throw std::runtime_error ("cannot send data on a 'watch only' connection");
502
534
 
503
- if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() + length > MaxOutboundBufSize)
535
+ if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)(GetOutboundDataSize() + length) > MaxOutboundBufSize)
504
536
  ProxiedFrom->Pause();
505
537
 
506
538
  #ifdef WITH_SSL
@@ -541,7 +573,11 @@ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
541
573
  // (Well, not so bad, small pages are coalesced in ::Write)
542
574
 
543
575
  if (IsCloseScheduled())
544
- //if (bCloseNow || bCloseAfterWriting)
576
+ return 0;
577
+
578
+ // 25Mar10: Ignore 0 length packets as they are not meaningful in TCP (as opposed to UDP)
579
+ // and can cause the assert(nbytes>0) to fail when OutboundPages has a bunch of 0 length pages.
580
+ if (length == 0)
545
581
  return 0;
546
582
 
547
583
  if (!data && (length > 0))
@@ -688,7 +724,7 @@ void ConnectionDescriptor::Read()
688
724
  return;
689
725
  }
690
726
 
691
- LastIo = gCurrentLoopTime;
727
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
692
728
 
693
729
  int total_bytes_read = 0;
694
730
  char readbuffer [16 * 1024 + 1];
@@ -703,6 +739,7 @@ void ConnectionDescriptor::Read()
703
739
 
704
740
 
705
741
  int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
742
+ int e = errno;
706
743
  //cerr << "<R:" << r << ">";
707
744
 
708
745
  if (r > 0) {
@@ -721,8 +758,21 @@ void ConnectionDescriptor::Read()
721
758
  break;
722
759
  }
723
760
  else {
724
- // Basically a would-block, meaning we've read everything there is to read.
725
- break;
761
+ #ifdef OS_UNIX
762
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EAGAIN) && (e != EINTR)) {
763
+ #endif
764
+ #ifdef OS_WIN32
765
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
766
+ #endif
767
+ // 26Mar11: Previously, all read errors were assumed to be EWOULDBLOCK and ignored.
768
+ // Now, instead, we call Close() on errors like ECONNRESET and ENOTCONN.
769
+ UnbindReasonCode = e;
770
+ Close();
771
+ break;
772
+ } else {
773
+ // Basically a would-block, meaning we've read everything there is to read.
774
+ break;
775
+ }
726
776
  }
727
777
 
728
778
  }
@@ -831,9 +881,12 @@ void ConnectionDescriptor::Write()
831
881
  // from EventMachine_t::AttachFD as well.
832
882
  SetConnectPending (false);
833
883
  }
834
- else
884
+ else {
885
+ if (o == 0)
886
+ UnbindReasonCode = error;
835
887
  ScheduleClose (false);
836
888
  //bCloseNow = true;
889
+ }
837
890
  }
838
891
  else {
839
892
 
@@ -894,7 +947,7 @@ void ConnectionDescriptor::_WriteOutboundData()
894
947
  return;
895
948
  }
896
949
 
897
- LastIo = gCurrentLoopTime;
950
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
898
951
  size_t nbytes = 0;
899
952
 
900
953
  #ifdef HAVE_WRITEV
@@ -902,11 +955,19 @@ void ConnectionDescriptor::_WriteOutboundData()
902
955
  // Max of 16 outbound pages at a time
903
956
  if (iovcnt > 16) iovcnt = 16;
904
957
 
958
+ #ifdef CC_SUNWspro
959
+ struct iovec iov[16];
960
+ #else
905
961
  struct iovec iov[ iovcnt ];
962
+ #endif
906
963
 
907
964
  for(int i = 0; i < iovcnt; i++){
908
965
  OutboundPage *op = &(OutboundPages[i]);
966
+ #ifdef CC_SUNWspro
967
+ iov[i].iov_base = (char *)(op->Buffer + op->Offset);
968
+ #else
909
969
  iov[i].iov_base = (void *)(op->Buffer + op->Offset);
970
+ #endif
910
971
  iov[i].iov_len = op->Length - op->Offset;
911
972
 
912
973
  nbytes += iov[i].iov_len;
@@ -945,6 +1006,7 @@ void ConnectionDescriptor::_WriteOutboundData()
945
1006
  #endif
946
1007
 
947
1008
  bool err = false;
1009
+ int e = errno;
948
1010
  if (bytes_written < 0) {
949
1011
  err = true;
950
1012
  bytes_written = 0;
@@ -953,7 +1015,7 @@ void ConnectionDescriptor::_WriteOutboundData()
953
1015
  assert (bytes_written >= 0);
954
1016
  OutboundDataSize -= bytes_written;
955
1017
 
956
- if (ProxiedFrom && MaxOutboundBufSize && GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
1018
+ if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
957
1019
  ProxiedFrom->Resume();
958
1020
 
959
1021
  #ifdef HAVE_WRITEV
@@ -995,22 +1057,28 @@ void ConnectionDescriptor::_WriteOutboundData()
995
1057
 
996
1058
  if (err) {
997
1059
  #ifdef OS_UNIX
998
- if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
1060
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
999
1061
  #endif
1000
1062
  #ifdef OS_WIN32
1001
- if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
1063
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1002
1064
  #endif
1065
+ UnbindReasonCode = e;
1003
1066
  Close();
1067
+ }
1004
1068
  }
1005
1069
  }
1006
1070
 
1007
1071
 
1008
- /****************************************
1009
- ConnectionDescriptor::_ReportErrorStatus
1010
- ****************************************/
1072
+ /***************************************
1073
+ ConnectionDescriptor::ReportErrorStatus
1074
+ ***************************************/
1011
1075
 
1012
- int ConnectionDescriptor::_ReportErrorStatus()
1076
+ int ConnectionDescriptor::ReportErrorStatus()
1013
1077
  {
1078
+ if (MySocket == INVALID_SOCKET) {
1079
+ return -1;
1080
+ }
1081
+
1014
1082
  int error;
1015
1083
  socklen_t len;
1016
1084
  len = sizeof(error);
@@ -1022,8 +1090,10 @@ int ConnectionDescriptor::_ReportErrorStatus()
1022
1090
  #endif
1023
1091
  if ((o == 0) && (error == 0))
1024
1092
  return 0;
1093
+ else if (o == 0)
1094
+ return error;
1025
1095
  else
1026
- return 1;
1096
+ return -1;
1027
1097
  }
1028
1098
 
1029
1099
 
@@ -1190,14 +1260,18 @@ void ConnectionDescriptor::Heartbeat()
1190
1260
  */
1191
1261
 
1192
1262
  if (bConnectPending) {
1193
- if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
1263
+ if ((MyEventMachine->GetCurrentLoopTime() - CreatedAt) >= PendingConnectTimeout) {
1264
+ UnbindReasonCode = ETIMEDOUT;
1194
1265
  ScheduleClose (false);
1195
1266
  //bCloseNow = true;
1267
+ }
1196
1268
  }
1197
1269
  else {
1198
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1270
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) {
1271
+ UnbindReasonCode = ETIMEDOUT;
1199
1272
  ScheduleClose (false);
1200
1273
  //bCloseNow = true;
1274
+ }
1201
1275
  }
1202
1276
  }
1203
1277
 
@@ -1328,7 +1402,7 @@ void AcceptorDescriptor::Read()
1328
1402
  //int val = fcntl (sd, F_GETFL, 0);
1329
1403
  //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
1330
1404
  shutdown (sd, 1);
1331
- closesocket (sd);
1405
+ close (sd);
1332
1406
  continue;
1333
1407
  }
1334
1408
 
@@ -1385,12 +1459,11 @@ void AcceptorDescriptor::Heartbeat()
1385
1459
  AcceptorDescriptor::GetSockname
1386
1460
  *******************************/
1387
1461
 
1388
- bool AcceptorDescriptor::GetSockname (struct sockaddr *s)
1462
+ bool AcceptorDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1389
1463
  {
1390
1464
  bool ok = false;
1391
1465
  if (s) {
1392
- socklen_t len = sizeof(*s);
1393
- int gp = getsockname (GetSocket(), s, &len);
1466
+ int gp = getsockname (GetSocket(), s, len);
1394
1467
  if (gp == 0)
1395
1468
  ok = true;
1396
1469
  }
@@ -1405,9 +1478,7 @@ DatagramDescriptor::DatagramDescriptor
1405
1478
 
1406
1479
  DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1407
1480
  EventableDescriptor (sd, parent_em),
1408
- OutboundDataSize (0),
1409
- LastIo (gCurrentLoopTime),
1410
- InactivityTimeout (0)
1481
+ OutboundDataSize (0)
1411
1482
  {
1412
1483
  memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1413
1484
 
@@ -1461,7 +1532,7 @@ void DatagramDescriptor::Heartbeat()
1461
1532
  {
1462
1533
  // Close it if its inactivity timer has expired.
1463
1534
 
1464
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
1535
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout))
1465
1536
  ScheduleClose (false);
1466
1537
  //bCloseNow = true;
1467
1538
  }
@@ -1475,7 +1546,7 @@ void DatagramDescriptor::Read()
1475
1546
  {
1476
1547
  int sd = GetSocket();
1477
1548
  assert (sd != INVALID_SOCKET);
1478
- LastIo = gCurrentLoopTime;
1549
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
1479
1550
 
1480
1551
  // This is an extremely large read buffer.
1481
1552
  // In many cases you wouldn't expect to get any more than 4K.
@@ -1552,7 +1623,7 @@ void DatagramDescriptor::Write()
1552
1623
 
1553
1624
  int sd = GetSocket();
1554
1625
  assert (sd != INVALID_SOCKET);
1555
- LastIo = gCurrentLoopTime;
1626
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
1556
1627
 
1557
1628
  assert (OutboundPages.size() > 0);
1558
1629
 
@@ -1577,6 +1648,7 @@ void DatagramDescriptor::Write()
1577
1648
  #ifdef OS_WIN32
1578
1649
  if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1579
1650
  #endif
1651
+ UnbindReasonCode = e;
1580
1652
  Close();
1581
1653
  break;
1582
1654
  }
@@ -1618,11 +1690,11 @@ DatagramDescriptor::SendOutboundData
1618
1690
 
1619
1691
  int DatagramDescriptor::SendOutboundData (const char *data, int length)
1620
1692
  {
1621
- // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1622
- // That means it needs to move to a common ancestor.
1693
+ // This is almost an exact clone of ConnectionDescriptor::_SendRawOutboundData.
1694
+ // That means most of it could be factored to a common ancestor. Note that
1695
+ // empty datagrams are meaningful, which isn't the case for TCP streams.
1623
1696
 
1624
1697
  if (IsCloseScheduled())
1625
- //if (bCloseNow || bCloseAfterWriting)
1626
1698
  return 0;
1627
1699
 
1628
1700
  if (!data && (length > 0))
@@ -1706,30 +1778,15 @@ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, cons
1706
1778
  }
1707
1779
 
1708
1780
 
1709
- /****************************************
1710
- STATIC: DatagramDescriptor::SendDatagram
1711
- ****************************************/
1712
-
1713
- int DatagramDescriptor::SendDatagram (const unsigned long binding, const char *data, int length, const char *address, int port)
1714
- {
1715
- DatagramDescriptor *dd = dynamic_cast <DatagramDescriptor*> (Bindable_t::GetObject (binding));
1716
- if (dd)
1717
- return dd->SendOutboundDatagram (data, length, address, port);
1718
- else
1719
- return -1;
1720
- }
1721
-
1722
-
1723
1781
  /*********************************
1724
1782
  ConnectionDescriptor::GetPeername
1725
1783
  *********************************/
1726
1784
 
1727
- bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1785
+ bool ConnectionDescriptor::GetPeername (struct sockaddr *s, socklen_t *len)
1728
1786
  {
1729
1787
  bool ok = false;
1730
1788
  if (s) {
1731
- socklen_t len = sizeof(*s);
1732
- int gp = getpeername (GetSocket(), s, &len);
1789
+ int gp = getpeername (GetSocket(), s, len);
1733
1790
  if (gp == 0)
1734
1791
  ok = true;
1735
1792
  }
@@ -1740,12 +1797,11 @@ bool ConnectionDescriptor::GetPeername (struct sockaddr *s)
1740
1797
  ConnectionDescriptor::GetSockname
1741
1798
  *********************************/
1742
1799
 
1743
- bool ConnectionDescriptor::GetSockname (struct sockaddr *s)
1800
+ bool ConnectionDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1744
1801
  {
1745
1802
  bool ok = false;
1746
1803
  if (s) {
1747
- socklen_t len = sizeof(*s);
1748
- int gp = getsockname (GetSocket(), s, &len);
1804
+ int gp = getsockname (GetSocket(), s, len);
1749
1805
  if (gp == 0)
1750
1806
  ok = true;
1751
1807
  }
@@ -1757,9 +1813,9 @@ bool ConnectionDescriptor::GetSockname (struct sockaddr *s)
1757
1813
  ConnectionDescriptor::GetCommInactivityTimeout
1758
1814
  **********************************************/
1759
1815
 
1760
- float ConnectionDescriptor::GetCommInactivityTimeout()
1816
+ uint64_t ConnectionDescriptor::GetCommInactivityTimeout()
1761
1817
  {
1762
- return ((float)InactivityTimeout / 1000000);
1818
+ return InactivityTimeout / 1000;
1763
1819
  }
1764
1820
 
1765
1821
 
@@ -1767,23 +1823,22 @@ float ConnectionDescriptor::GetCommInactivityTimeout()
1767
1823
  ConnectionDescriptor::SetCommInactivityTimeout
1768
1824
  **********************************************/
1769
1825
 
1770
- int ConnectionDescriptor::SetCommInactivityTimeout (float value)
1826
+ int ConnectionDescriptor::SetCommInactivityTimeout (uint64_t value)
1771
1827
  {
1772
- if (value > 0) {
1773
- InactivityTimeout = (Int64)(value * 1000000);
1774
- return 1;
1775
- }
1776
- return 0;
1828
+ InactivityTimeout = value * 1000;
1829
+ MyEventMachine->QueueHeartbeat(this);
1830
+ return 1;
1777
1831
  }
1778
1832
 
1779
1833
  /*******************************
1780
1834
  DatagramDescriptor::GetPeername
1781
1835
  *******************************/
1782
1836
 
1783
- bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1837
+ bool DatagramDescriptor::GetPeername (struct sockaddr *s, socklen_t *len)
1784
1838
  {
1785
1839
  bool ok = false;
1786
1840
  if (s) {
1841
+ *len = sizeof(struct sockaddr);
1787
1842
  memset (s, 0, sizeof(struct sockaddr));
1788
1843
  memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1789
1844
  ok = true;
@@ -1795,12 +1850,11 @@ bool DatagramDescriptor::GetPeername (struct sockaddr *s)
1795
1850
  DatagramDescriptor::GetSockname
1796
1851
  *******************************/
1797
1852
 
1798
- bool DatagramDescriptor::GetSockname (struct sockaddr *s)
1853
+ bool DatagramDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1799
1854
  {
1800
1855
  bool ok = false;
1801
1856
  if (s) {
1802
- socklen_t len = sizeof(*s);
1803
- int gp = getsockname (GetSocket(), s, &len);
1857
+ int gp = getsockname (GetSocket(), s, len);
1804
1858
  if (gp == 0)
1805
1859
  ok = true;
1806
1860
  }
@@ -1813,19 +1867,20 @@ bool DatagramDescriptor::GetSockname (struct sockaddr *s)
1813
1867
  DatagramDescriptor::GetCommInactivityTimeout
1814
1868
  ********************************************/
1815
1869
 
1816
- float DatagramDescriptor::GetCommInactivityTimeout()
1870
+ uint64_t DatagramDescriptor::GetCommInactivityTimeout()
1817
1871
  {
1818
- return ((float)InactivityTimeout / 1000000);
1872
+ return InactivityTimeout / 1000;
1819
1873
  }
1820
1874
 
1821
1875
  /********************************************
1822
1876
  DatagramDescriptor::SetCommInactivityTimeout
1823
1877
  ********************************************/
1824
1878
 
1825
- int DatagramDescriptor::SetCommInactivityTimeout (float value)
1879
+ int DatagramDescriptor::SetCommInactivityTimeout (uint64_t value)
1826
1880
  {
1827
1881
  if (value > 0) {
1828
- InactivityTimeout = (Int64)(value * 1000000);
1882
+ InactivityTimeout = value * 1000;
1883
+ MyEventMachine->QueueHeartbeat(this);
1829
1884
  return 1;
1830
1885
  }
1831
1886
  return 0;