sensu-em 2.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +33 -0
  6. data/GNU +281 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +60 -0
  9. data/README.md +109 -0
  10. data/Rakefile +20 -0
  11. data/docs/DocumentationGuidesIndex.md +27 -0
  12. data/docs/GettingStarted.md +521 -0
  13. data/docs/old/ChangeLog +211 -0
  14. data/docs/old/DEFERRABLES +246 -0
  15. data/docs/old/EPOLL +141 -0
  16. data/docs/old/INSTALL +13 -0
  17. data/docs/old/KEYBOARD +42 -0
  18. data/docs/old/LEGAL +25 -0
  19. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  20. data/docs/old/PURE_RUBY +75 -0
  21. data/docs/old/RELEASE_NOTES +94 -0
  22. data/docs/old/SMTP +4 -0
  23. data/docs/old/SPAWNED_PROCESSES +148 -0
  24. data/docs/old/TODO +8 -0
  25. data/eventmachine.gemspec +38 -0
  26. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  27. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  28. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  29. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  30. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  31. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  32. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  33. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  34. data/examples/old/ex_channel.rb +43 -0
  35. data/examples/old/ex_queue.rb +2 -0
  36. data/examples/old/ex_tick_loop_array.rb +15 -0
  37. data/examples/old/ex_tick_loop_counter.rb +32 -0
  38. data/examples/old/helper.rb +2 -0
  39. data/ext/binder.cpp +124 -0
  40. data/ext/binder.h +46 -0
  41. data/ext/cmain.cpp +887 -0
  42. data/ext/ed.cpp +1988 -0
  43. data/ext/ed.h +422 -0
  44. data/ext/em.cpp +2352 -0
  45. data/ext/em.h +253 -0
  46. data/ext/eventmachine.h +128 -0
  47. data/ext/extconf.rb +179 -0
  48. data/ext/fastfilereader/extconf.rb +103 -0
  49. data/ext/fastfilereader/mapper.cpp +214 -0
  50. data/ext/fastfilereader/mapper.h +59 -0
  51. data/ext/fastfilereader/rubymain.cpp +127 -0
  52. data/ext/kb.cpp +79 -0
  53. data/ext/page.cpp +107 -0
  54. data/ext/page.h +51 -0
  55. data/ext/pipe.cpp +347 -0
  56. data/ext/project.h +161 -0
  57. data/ext/rubymain.cpp +1318 -0
  58. data/ext/ssl.cpp +468 -0
  59. data/ext/ssl.h +94 -0
  60. data/java/.classpath +6 -0
  61. data/java/.gitignore +1 -0
  62. data/java/.project +17 -0
  63. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  64. data/java/src/com/rubyeventmachine/EmReactor.java +529 -0
  65. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  66. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  67. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  68. data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
  69. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +180 -0
  70. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
  71. data/java/src/com/rubyeventmachine/SslBox.java +310 -0
  72. data/lib/em/buftok.rb +110 -0
  73. data/lib/em/callback.rb +58 -0
  74. data/lib/em/channel.rb +64 -0
  75. data/lib/em/completion.rb +304 -0
  76. data/lib/em/connection.rb +712 -0
  77. data/lib/em/deferrable/pool.rb +2 -0
  78. data/lib/em/deferrable.rb +210 -0
  79. data/lib/em/file_watch.rb +73 -0
  80. data/lib/em/future.rb +61 -0
  81. data/lib/em/iterator.rb +231 -0
  82. data/lib/em/messages.rb +66 -0
  83. data/lib/em/pool.rb +151 -0
  84. data/lib/em/process_watch.rb +45 -0
  85. data/lib/em/processes.rb +123 -0
  86. data/lib/em/protocols/header_and_content.rb +138 -0
  87. data/lib/em/protocols/httpclient.rb +279 -0
  88. data/lib/em/protocols/httpclient2.rb +600 -0
  89. data/lib/em/protocols/line_and_text.rb +125 -0
  90. data/lib/em/protocols/line_protocol.rb +29 -0
  91. data/lib/em/protocols/linetext2.rb +161 -0
  92. data/lib/em/protocols/memcache.rb +331 -0
  93. data/lib/em/protocols/object_protocol.rb +46 -0
  94. data/lib/em/protocols/postgres3.rb +246 -0
  95. data/lib/em/protocols/saslauth.rb +175 -0
  96. data/lib/em/protocols/smtpclient.rb +365 -0
  97. data/lib/em/protocols/smtpserver.rb +643 -0
  98. data/lib/em/protocols/socks4.rb +66 -0
  99. data/lib/em/protocols/stomp.rb +205 -0
  100. data/lib/em/protocols/tcptest.rb +54 -0
  101. data/lib/em/protocols.rb +37 -0
  102. data/lib/em/pure_ruby.rb +1017 -0
  103. data/lib/em/queue.rb +71 -0
  104. data/lib/em/resolver.rb +209 -0
  105. data/lib/em/spawnable.rb +84 -0
  106. data/lib/em/streamer.rb +118 -0
  107. data/lib/em/threaded_resource.rb +90 -0
  108. data/lib/em/tick_loop.rb +85 -0
  109. data/lib/em/timers.rb +61 -0
  110. data/lib/em/version.rb +3 -0
  111. data/lib/eventmachine.rb +1553 -0
  112. data/lib/jeventmachine.rb +321 -0
  113. data/lib/rubyeventmachine.jar +0 -0
  114. data/rakelib/cpp.rake_example +77 -0
  115. data/rakelib/package.rake +98 -0
  116. data/rakelib/test.rake +8 -0
  117. data/tests/client.crt +31 -0
  118. data/tests/client.key +51 -0
  119. data/tests/em_test_helper.rb +64 -0
  120. data/tests/server.crt +36 -0
  121. data/tests/server.key +51 -0
  122. data/tests/test_attach.rb +150 -0
  123. data/tests/test_basic.rb +294 -0
  124. data/tests/test_channel.rb +62 -0
  125. data/tests/test_completion.rb +177 -0
  126. data/tests/test_connection_count.rb +53 -0
  127. data/tests/test_defer.rb +18 -0
  128. data/tests/test_deferrable.rb +35 -0
  129. data/tests/test_epoll.rb +145 -0
  130. data/tests/test_error_handler.rb +38 -0
  131. data/tests/test_exc.rb +28 -0
  132. data/tests/test_file_watch.rb +65 -0
  133. data/tests/test_futures.rb +170 -0
  134. data/tests/test_get_sock_opt.rb +37 -0
  135. data/tests/test_handler_check.rb +35 -0
  136. data/tests/test_hc.rb +155 -0
  137. data/tests/test_httpclient.rb +190 -0
  138. data/tests/test_httpclient2.rb +133 -0
  139. data/tests/test_idle_connection.rb +25 -0
  140. data/tests/test_inactivity_timeout.rb +54 -0
  141. data/tests/test_iterator.rb +97 -0
  142. data/tests/test_kb.rb +34 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +138 -0
  145. data/tests/test_ltp2.rb +288 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +102 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +194 -0
  151. data/tests/test_process_watch.rb +48 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +88 -0
  155. data/tests/test_queue.rb +50 -0
  156. data/tests/test_resolver.rb +55 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +47 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +33 -0
  161. data/tests/test_set_sock_opt.rb +37 -0
  162. data/tests/test_shutdown_hooks.rb +23 -0
  163. data/tests/test_smtpclient.rb +55 -0
  164. data/tests/test_smtpserver.rb +57 -0
  165. data/tests/test_spawn.rb +293 -0
  166. data/tests/test_ssl_args.rb +78 -0
  167. data/tests/test_ssl_echo_data.rb +60 -0
  168. data/tests/test_ssl_methods.rb +56 -0
  169. data/tests/test_ssl_verify.rb +82 -0
  170. data/tests/test_stomp.rb +37 -0
  171. data/tests/test_system.rb +42 -0
  172. data/tests/test_threaded_resource.rb +53 -0
  173. data/tests/test_tick_loop.rb +59 -0
  174. data/tests/test_timers.rb +123 -0
  175. data/tests/test_ud.rb +8 -0
  176. data/tests/test_unbind_reason.rb +48 -0
  177. metadata +297 -0
data/ext/ed.cpp ADDED
@@ -0,0 +1,1988 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: ed.cpp
6
+ Date: 06Apr06
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
+ #include "project.h"
21
+
22
+
23
+
24
+ /********************
25
+ SetSocketNonblocking
26
+ ********************/
27
+
28
+ bool SetSocketNonblocking (SOCKET sd)
29
+ {
30
+ #ifdef OS_UNIX
31
+ int val = fcntl (sd, F_GETFL, 0);
32
+ return (fcntl (sd, F_SETFL, val | O_NONBLOCK) != SOCKET_ERROR) ? true : false;
33
+ #endif
34
+
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
42
+ unsigned long one = 1;
43
+ return (ioctlsocket (sd, FIONBIO, &one) == 0) ? true : false;
44
+ #endif
45
+ #endif
46
+ }
47
+
48
+
49
+ /****************************************
50
+ EventableDescriptor::EventableDescriptor
51
+ ****************************************/
52
+
53
+ EventableDescriptor::EventableDescriptor (int sd, EventMachine_t *em):
54
+ bCloseNow (false),
55
+ bCloseAfterWriting (false),
56
+ MySocket (sd),
57
+ bAttached (false),
58
+ bWatchOnly (false),
59
+ EventCallback (NULL),
60
+ bCallbackUnbind (true),
61
+ UnbindReasonCode (0),
62
+ ProxyTarget(NULL),
63
+ ProxiedFrom(NULL),
64
+ ProxiedBytes(0),
65
+ MaxOutboundBufSize(0),
66
+ MyEventMachine (em),
67
+ PendingConnectTimeout(20000000),
68
+ InactivityTimeout (0),
69
+ bPaused (false)
70
+ {
71
+ /* There are three ways to close a socket, all of which should
72
+ * automatically signal to the event machine that this object
73
+ * should be removed from the polling scheduler.
74
+ * First is a hard close, intended for bad errors or possible
75
+ * security violations. It immediately closes the connection
76
+ * and puts this object into an error state.
77
+ * Second is to set bCloseNow, which will cause the event machine
78
+ * to delete this object (and thus close the connection in our
79
+ * destructor) the next chance it gets. bCloseNow also inhibits
80
+ * the writing of new data on the socket (but not necessarily
81
+ * the reading of new data).
82
+ * The third way is to set bCloseAfterWriting, which inhibits
83
+ * the writing of new data and converts to bCloseNow as soon
84
+ * as everything in the outbound queue has been written.
85
+ * bCloseAfterWriting is really for use only by protocol handlers
86
+ * (for example, HTTP writes an HTML page and then closes the
87
+ * connection). All of the error states we generate internally
88
+ * cause an immediate close to be scheduled, which may have the
89
+ * effect of discarding outbound data.
90
+ */
91
+
92
+ if (sd == INVALID_SOCKET)
93
+ throw std::runtime_error ("bad eventable descriptor");
94
+ if (MyEventMachine == NULL)
95
+ throw std::runtime_error ("bad em in eventable descriptor");
96
+ CreatedAt = MyEventMachine->GetCurrentLoopTime();
97
+
98
+ #ifdef HAVE_EPOLL
99
+ EpollEvent.events = 0;
100
+ EpollEvent.data.ptr = this;
101
+ #endif
102
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
103
+ }
104
+
105
+
106
+ /*****************************************
107
+ EventableDescriptor::~EventableDescriptor
108
+ *****************************************/
109
+
110
+ EventableDescriptor::~EventableDescriptor()
111
+ {
112
+ if (NextHeartbeat)
113
+ MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
114
+ if (EventCallback && bCallbackUnbind)
115
+ (*EventCallback)(GetBinding(), EM_CONNECTION_UNBOUND, NULL, UnbindReasonCode);
116
+ if (ProxiedFrom) {
117
+ (*EventCallback)(ProxiedFrom->GetBinding(), EM_PROXY_TARGET_UNBOUND, NULL, 0);
118
+ ProxiedFrom->StopProxy();
119
+ }
120
+ MyEventMachine->NumCloseScheduled--;
121
+ StopProxy();
122
+ Close();
123
+ }
124
+
125
+
126
+ /*************************************
127
+ EventableDescriptor::SetEventCallback
128
+ *************************************/
129
+
130
+ void EventableDescriptor::SetEventCallback (EMCallback cb)
131
+ {
132
+ EventCallback = cb;
133
+ }
134
+
135
+
136
+ /**************************
137
+ EventableDescriptor::Close
138
+ **************************/
139
+
140
+ void EventableDescriptor::Close()
141
+ {
142
+ /* EventMachine relies on the fact that when close(fd)
143
+ * is called that the fd is removed from any
144
+ * epoll event queues.
145
+ *
146
+ * However, this is not *always* the behavior of close(fd)
147
+ *
148
+ * See man 4 epoll Q6/A6 and then consider what happens
149
+ * when using pipes with eventmachine.
150
+ * (As is often done when communicating with a subprocess)
151
+ *
152
+ * The pipes end up looking like:
153
+ *
154
+ * ls -l /proc/<pid>/fd
155
+ * ...
156
+ * lr-x------ 1 root root 64 2011-08-19 21:31 3 -> pipe:[940970]
157
+ * l-wx------ 1 root root 64 2011-08-19 21:31 4 -> pipe:[940970]
158
+ *
159
+ * This meets the critera from man 4 epoll Q6/A4 for not
160
+ * removing fds from epoll event queues until all fds
161
+ * that reference the underlying file have been removed.
162
+ *
163
+ * If the EventableDescriptor associated with fd 3 is deleted,
164
+ * its dtor will call EventableDescriptor::Close(),
165
+ * which will call ::close(int fd).
166
+ *
167
+ * However, unless the EventableDescriptor associated with fd 4 is
168
+ * also deleted before the next call to epoll_wait, events may fire
169
+ * for fd 3 that were registered with an already deleted
170
+ * EventableDescriptor.
171
+ *
172
+ * Therefore, it is necessary to notify EventMachine that
173
+ * the fd associated with this EventableDescriptor is
174
+ * closing.
175
+ *
176
+ * EventMachine also never closes fds for STDIN, STDOUT and
177
+ * STDERR (0, 1 & 2)
178
+ */
179
+
180
+ // Close the socket right now. Intended for emergencies.
181
+ if (MySocket != INVALID_SOCKET) {
182
+ MyEventMachine->Deregister (this);
183
+
184
+ // Do not close STDIN, STDOUT, STDERR
185
+ if (MySocket > 2 && !bAttached) {
186
+ shutdown (MySocket, 1);
187
+ close (MySocket);
188
+ }
189
+
190
+ MySocket = INVALID_SOCKET;
191
+ }
192
+ }
193
+
194
+
195
+ /*********************************
196
+ EventableDescriptor::ShouldDelete
197
+ *********************************/
198
+
199
+ bool EventableDescriptor::ShouldDelete()
200
+ {
201
+ /* For use by a socket manager, which needs to know if this object
202
+ * should be removed from scheduling events and deleted.
203
+ * Has an immediate close been scheduled, or are we already closed?
204
+ * If either of these are the case, return true. In theory, the manager will
205
+ * then delete us, which in turn will make sure the socket is closed.
206
+ * Note, if bCloseAfterWriting is true, we check a virtual method to see
207
+ * if there is outbound data to write, and only request a close if there is none.
208
+ */
209
+
210
+ return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
211
+ }
212
+
213
+
214
+ /**********************************
215
+ EventableDescriptor::ScheduleClose
216
+ **********************************/
217
+
218
+ void EventableDescriptor::ScheduleClose (bool after_writing)
219
+ {
220
+ if (IsCloseScheduled())
221
+ return;
222
+ MyEventMachine->NumCloseScheduled++;
223
+ // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
224
+ if (after_writing)
225
+ bCloseAfterWriting = true;
226
+ else
227
+ bCloseNow = true;
228
+ }
229
+
230
+
231
+ /*************************************
232
+ EventableDescriptor::IsCloseScheduled
233
+ *************************************/
234
+
235
+ bool EventableDescriptor::IsCloseScheduled()
236
+ {
237
+ // KEEP THIS SYNCHRONIZED WITH ::ScheduleClose.
238
+ return (bCloseNow || bCloseAfterWriting);
239
+ }
240
+
241
+
242
+ /*******************************
243
+ EventableDescriptor::StartProxy
244
+ *******************************/
245
+
246
+ void EventableDescriptor::StartProxy(const unsigned long to, const unsigned long bufsize, const unsigned long length)
247
+ {
248
+ EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (to));
249
+ if (ed) {
250
+ StopProxy();
251
+ ProxyTarget = ed;
252
+ BytesToProxy = length;
253
+ ProxiedBytes = 0;
254
+ ed->SetProxiedFrom(this, bufsize);
255
+ return;
256
+ }
257
+ throw std::runtime_error ("Tried to proxy to an invalid descriptor");
258
+ }
259
+
260
+
261
+ /******************************
262
+ EventableDescriptor::StopProxy
263
+ ******************************/
264
+
265
+ void EventableDescriptor::StopProxy()
266
+ {
267
+ if (ProxyTarget) {
268
+ ProxyTarget->SetProxiedFrom(NULL, 0);
269
+ ProxyTarget = NULL;
270
+ }
271
+ }
272
+
273
+
274
+ /***********************************
275
+ EventableDescriptor::SetProxiedFrom
276
+ ***********************************/
277
+
278
+ void EventableDescriptor::SetProxiedFrom(EventableDescriptor *from, const unsigned long bufsize)
279
+ {
280
+ if (from != NULL && ProxiedFrom != NULL)
281
+ throw std::runtime_error ("Tried to proxy to a busy target");
282
+
283
+ ProxiedFrom = from;
284
+ MaxOutboundBufSize = bufsize;
285
+ }
286
+
287
+
288
+ /********************************************
289
+ EventableDescriptor::_GenericInboundDispatch
290
+ ********************************************/
291
+
292
+ void EventableDescriptor::_GenericInboundDispatch(const char *buf, int size)
293
+ {
294
+ assert(EventCallback);
295
+
296
+ if (ProxyTarget) {
297
+ if (BytesToProxy > 0) {
298
+ unsigned long proxied = min(BytesToProxy, (unsigned long) size);
299
+ ProxyTarget->SendOutboundData(buf, proxied);
300
+ ProxiedBytes += (unsigned long) proxied;
301
+ BytesToProxy -= proxied;
302
+ if (BytesToProxy == 0) {
303
+ StopProxy();
304
+ (*EventCallback)(GetBinding(), EM_PROXY_COMPLETED, NULL, 0);
305
+ if (proxied < size) {
306
+ (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf + proxied, size - proxied);
307
+ }
308
+ }
309
+ } else {
310
+ ProxyTarget->SendOutboundData(buf, size);
311
+ ProxiedBytes += (unsigned long) size;
312
+ }
313
+ } else {
314
+ (*EventCallback)(GetBinding(), EM_CONNECTION_READ, buf, size);
315
+ }
316
+ }
317
+
318
+
319
+ /*********************************************
320
+ EventableDescriptor::GetPendingConnectTimeout
321
+ *********************************************/
322
+
323
+ uint64_t EventableDescriptor::GetPendingConnectTimeout()
324
+ {
325
+ return PendingConnectTimeout / 1000;
326
+ }
327
+
328
+
329
+ /*********************************************
330
+ EventableDescriptor::SetPendingConnectTimeout
331
+ *********************************************/
332
+
333
+ int EventableDescriptor::SetPendingConnectTimeout (uint64_t value)
334
+ {
335
+ if (value > 0) {
336
+ PendingConnectTimeout = value * 1000;
337
+ MyEventMachine->QueueHeartbeat(this);
338
+ return 1;
339
+ }
340
+ return 0;
341
+ }
342
+
343
+
344
+ /*************************************
345
+ EventableDescriptor::GetNextHeartbeat
346
+ *************************************/
347
+
348
+ uint64_t EventableDescriptor::GetNextHeartbeat()
349
+ {
350
+ if (NextHeartbeat)
351
+ MyEventMachine->ClearHeartbeat(NextHeartbeat, this);
352
+
353
+ NextHeartbeat = 0;
354
+
355
+ if (!ShouldDelete()) {
356
+ uint64_t time_til_next = InactivityTimeout;
357
+ if (IsConnectPending()) {
358
+ if (time_til_next == 0 || PendingConnectTimeout < time_til_next)
359
+ time_til_next = PendingConnectTimeout;
360
+ }
361
+ if (time_til_next == 0)
362
+ return 0;
363
+ NextHeartbeat = time_til_next + MyEventMachine->GetRealTime();
364
+ }
365
+
366
+ return NextHeartbeat;
367
+ }
368
+
369
+
370
+ /******************************************
371
+ ConnectionDescriptor::ConnectionDescriptor
372
+ ******************************************/
373
+
374
+ ConnectionDescriptor::ConnectionDescriptor (int sd, EventMachine_t *em):
375
+ EventableDescriptor (sd, em),
376
+ bConnectPending (false),
377
+ bNotifyReadable (false),
378
+ bNotifyWritable (false),
379
+ bReadAttemptedAfterClose (false),
380
+ bWriteAttemptedAfterClose (false),
381
+ OutboundDataSize (0),
382
+ #ifdef WITH_SSL
383
+ SslBox (NULL),
384
+ bHandshakeSignaled (false),
385
+ bSslVerifyPeer (false),
386
+ bSslPeerAccepted(false),
387
+ #endif
388
+ #ifdef HAVE_KQUEUE
389
+ bGotExtraKqueueEvent(false),
390
+ #endif
391
+ bIsServer (false)
392
+ {
393
+ // 22Jan09: Moved ArmKqueueWriter into SetConnectPending() to fix assertion failure in _WriteOutboundData()
394
+ // 5May09: Moved EPOLLOUT into SetConnectPending() so it doesn't happen for attached read pipes
395
+ }
396
+
397
+
398
+ /*******************************************
399
+ ConnectionDescriptor::~ConnectionDescriptor
400
+ *******************************************/
401
+
402
+ ConnectionDescriptor::~ConnectionDescriptor()
403
+ {
404
+ // Run down any stranded outbound data.
405
+ for (size_t i=0; i < OutboundPages.size(); i++)
406
+ OutboundPages[i].Free();
407
+
408
+ #ifdef WITH_SSL
409
+ if (SslBox)
410
+ delete SslBox;
411
+ #endif
412
+ }
413
+
414
+
415
+ /***********************************
416
+ ConnectionDescriptor::_UpdateEvents
417
+ ************************************/
418
+
419
+ void ConnectionDescriptor::_UpdateEvents()
420
+ {
421
+ _UpdateEvents(true, true);
422
+ }
423
+
424
+ void ConnectionDescriptor::_UpdateEvents(bool read, bool write)
425
+ {
426
+ if (MySocket == INVALID_SOCKET)
427
+ return;
428
+
429
+ #ifdef HAVE_EPOLL
430
+ unsigned int old = EpollEvent.events;
431
+
432
+ if (read) {
433
+ if (SelectForRead())
434
+ EpollEvent.events |= EPOLLIN;
435
+ else
436
+ EpollEvent.events &= ~EPOLLIN;
437
+ }
438
+
439
+ if (write) {
440
+ if (SelectForWrite())
441
+ EpollEvent.events |= EPOLLOUT;
442
+ else
443
+ EpollEvent.events &= ~EPOLLOUT;
444
+ }
445
+
446
+ if (old != EpollEvent.events)
447
+ MyEventMachine->Modify (this);
448
+ #endif
449
+
450
+ #ifdef HAVE_KQUEUE
451
+ if (read && SelectForRead())
452
+ MyEventMachine->ArmKqueueReader (this);
453
+ if (write && SelectForWrite())
454
+ MyEventMachine->ArmKqueueWriter (this);
455
+ #endif
456
+ }
457
+
458
+ /***************************************
459
+ ConnectionDescriptor::SetConnectPending
460
+ ****************************************/
461
+
462
+ void ConnectionDescriptor::SetConnectPending(bool f)
463
+ {
464
+ bConnectPending = f;
465
+ MyEventMachine->QueueHeartbeat(this);
466
+ _UpdateEvents();
467
+ }
468
+
469
+
470
+ /**********************************
471
+ ConnectionDescriptor::SetAttached
472
+ ***********************************/
473
+
474
+ void ConnectionDescriptor::SetAttached(bool state)
475
+ {
476
+ bAttached = state;
477
+ }
478
+
479
+
480
+ /**********************************
481
+ ConnectionDescriptor::SetWatchOnly
482
+ ***********************************/
483
+
484
+ void ConnectionDescriptor::SetWatchOnly(bool watching)
485
+ {
486
+ bWatchOnly = watching;
487
+ _UpdateEvents();
488
+ }
489
+
490
+
491
+ /*********************************
492
+ ConnectionDescriptor::HandleError
493
+ *********************************/
494
+
495
+ void ConnectionDescriptor::HandleError()
496
+ {
497
+ if (bWatchOnly) {
498
+ // An EPOLLHUP | EPOLLIN condition will call Read() before HandleError(), in which case the
499
+ // socket is already detached and invalid, so we don't need to do anything.
500
+ if (MySocket == INVALID_SOCKET) return;
501
+
502
+ // HandleError() is called on WatchOnly descriptors by the epoll reactor
503
+ // when it gets a EPOLLERR | EPOLLHUP. Usually this would show up as a readable and
504
+ // writable event on other reactors, so we have to fire those events ourselves.
505
+ if (bNotifyReadable) Read();
506
+ if (bNotifyWritable) Write();
507
+ } else {
508
+ ScheduleClose (false);
509
+ }
510
+ }
511
+
512
+
513
+ /***********************************
514
+ ConnectionDescriptor::ScheduleClose
515
+ ***********************************/
516
+
517
+ void ConnectionDescriptor::ScheduleClose (bool after_writing)
518
+ {
519
+ if (bWatchOnly)
520
+ throw std::runtime_error ("cannot close 'watch only' connections");
521
+
522
+ EventableDescriptor::ScheduleClose(after_writing);
523
+ }
524
+
525
+
526
+ /***************************************
527
+ ConnectionDescriptor::SetNotifyReadable
528
+ ****************************************/
529
+
530
+ void ConnectionDescriptor::SetNotifyReadable(bool readable)
531
+ {
532
+ if (!bWatchOnly)
533
+ throw std::runtime_error ("notify_readable must be on 'watch only' connections");
534
+
535
+ bNotifyReadable = readable;
536
+ _UpdateEvents(true, false);
537
+ }
538
+
539
+
540
+ /***************************************
541
+ ConnectionDescriptor::SetNotifyWritable
542
+ ****************************************/
543
+
544
+ void ConnectionDescriptor::SetNotifyWritable(bool writable)
545
+ {
546
+ if (!bWatchOnly)
547
+ throw std::runtime_error ("notify_writable must be on 'watch only' connections");
548
+
549
+ bNotifyWritable = writable;
550
+ _UpdateEvents(false, true);
551
+ }
552
+
553
+
554
+ /**************************************
555
+ ConnectionDescriptor::SendOutboundData
556
+ **************************************/
557
+
558
+ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
559
+ {
560
+ if (bWatchOnly)
561
+ throw std::runtime_error ("cannot send data on a 'watch only' connection");
562
+
563
+ if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)(GetOutboundDataSize() + length) > MaxOutboundBufSize)
564
+ ProxiedFrom->Pause();
565
+
566
+ #ifdef WITH_SSL
567
+ if (SslBox) {
568
+ if (length > 0) {
569
+ int w = SslBox->PutPlaintext (data, length);
570
+ if (w < 0)
571
+ ScheduleClose (false);
572
+ else
573
+ _DispatchCiphertext();
574
+ }
575
+ // TODO: What's the correct return value?
576
+ return 1; // That's a wild guess, almost certainly wrong.
577
+ }
578
+ else
579
+ #endif
580
+ return _SendRawOutboundData (data, length);
581
+ }
582
+
583
+
584
+
585
+ /******************************************
586
+ ConnectionDescriptor::_SendRawOutboundData
587
+ ******************************************/
588
+
589
+ int ConnectionDescriptor::_SendRawOutboundData (const char *data, int length)
590
+ {
591
+ /* This internal method is called to schedule bytes that
592
+ * will be sent out to the remote peer.
593
+ * It's not directly accessed by the caller, who hits ::SendOutboundData,
594
+ * which may or may not filter or encrypt the caller's data before
595
+ * sending it here.
596
+ */
597
+
598
+ // Highly naive and incomplete implementation.
599
+ // There's no throttle for runaways (which should abort only this connection
600
+ // and not the whole process), and no coalescing of small pages.
601
+ // (Well, not so bad, small pages are coalesced in ::Write)
602
+
603
+ if (IsCloseScheduled())
604
+ return 0;
605
+
606
+ // 25Mar10: Ignore 0 length packets as they are not meaningful in TCP (as opposed to UDP)
607
+ // and can cause the assert(nbytes>0) to fail when OutboundPages has a bunch of 0 length pages.
608
+ if (length == 0)
609
+ return 0;
610
+
611
+ if (!data && (length > 0))
612
+ throw std::runtime_error ("bad outbound data");
613
+ char *buffer = (char *) malloc (length + 1);
614
+ if (!buffer)
615
+ throw std::runtime_error ("no allocation for outbound data");
616
+
617
+ memcpy (buffer, data, length);
618
+ buffer [length] = 0;
619
+ OutboundPages.push_back (OutboundPage (buffer, length));
620
+ OutboundDataSize += length;
621
+
622
+ _UpdateEvents(false, true);
623
+
624
+ return length;
625
+ }
626
+
627
+
628
+
629
+ /***********************************
630
+ ConnectionDescriptor::SelectForRead
631
+ ***********************************/
632
+
633
+ bool ConnectionDescriptor::SelectForRead()
634
+ {
635
+ /* A connection descriptor is always scheduled for read,
636
+ * UNLESS it's in a pending-connect state.
637
+ * On Linux, unlike Unix, a nonblocking socket on which
638
+ * connect has been called, does NOT necessarily select
639
+ * both readable and writable in case of error.
640
+ * The socket will select writable when the disposition
641
+ * of the connect is known. On the other hand, a socket
642
+ * which successfully connects and selects writable may
643
+ * indeed have some data available on it, so it will
644
+ * select readable in that case, violating expectations!
645
+ * So we will not poll for readability until the socket
646
+ * is known to be in a connected state.
647
+ */
648
+
649
+ if (bPaused)
650
+ return false;
651
+ else if (bConnectPending)
652
+ return false;
653
+ else if (bWatchOnly)
654
+ return bNotifyReadable ? true : false;
655
+ else
656
+ return true;
657
+ }
658
+
659
+
660
+ /************************************
661
+ ConnectionDescriptor::SelectForWrite
662
+ ************************************/
663
+
664
+ bool ConnectionDescriptor::SelectForWrite()
665
+ {
666
+ /* Cf the notes under SelectForRead.
667
+ * In a pending-connect state, we ALWAYS select for writable.
668
+ * In a normal state, we only select for writable when we
669
+ * have outgoing data to send.
670
+ */
671
+
672
+ if (bPaused)
673
+ return false;
674
+ else if (bConnectPending)
675
+ return true;
676
+ else if (bWatchOnly)
677
+ return bNotifyWritable ? true : false;
678
+ else
679
+ return (GetOutboundDataSize() > 0);
680
+ }
681
+
682
+ /***************************
683
+ ConnectionDescriptor::Pause
684
+ ***************************/
685
+
686
+ bool ConnectionDescriptor::Pause()
687
+ {
688
+ if (bWatchOnly)
689
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
690
+
691
+ bool old = bPaused;
692
+ bPaused = true;
693
+ _UpdateEvents();
694
+ return old == false;
695
+ }
696
+
697
+ /****************************
698
+ ConnectionDescriptor::Resume
699
+ ****************************/
700
+
701
+ bool ConnectionDescriptor::Resume()
702
+ {
703
+ if (bWatchOnly)
704
+ throw std::runtime_error ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
705
+
706
+ bool old = bPaused;
707
+ bPaused = false;
708
+ _UpdateEvents();
709
+ return old == true;
710
+ }
711
+
712
+ /**************************
713
+ ConnectionDescriptor::Read
714
+ **************************/
715
+
716
+ void ConnectionDescriptor::Read()
717
+ {
718
+ /* Read and dispatch data on a socket that has selected readable.
719
+ * It's theoretically possible to get and dispatch incoming data on
720
+ * a socket that has already been scheduled for closing or close-after-writing.
721
+ * In those cases, we'll leave it up the to protocol handler to "do the
722
+ * right thing" (which probably means to ignore the incoming data).
723
+ *
724
+ * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
725
+ * here with the socket already closed, after the process receives
726
+ * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
727
+ * was one in which network connections were doing a lot of interleaved reads
728
+ * and writes.
729
+ * Since we always write before reading (in order to keep the outbound queues
730
+ * as light as possible), I think what happened is that an interrupt caused
731
+ * the socket to be closed in ConnectionDescriptor::Write. We'll then
732
+ * come here in the same pass through the main event loop, and won't get
733
+ * cleaned up until immediately after.
734
+ * We originally asserted that the socket was valid when we got here.
735
+ * To deal properly with the possibility that we are closed when we get here,
736
+ * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
737
+ * so even though this is really clunky, I added a flag to assert that we never
738
+ * come here more than once after being closed. (FCianfrocca)
739
+ */
740
+
741
+ int sd = GetSocket();
742
+ //assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
743
+ if (sd == INVALID_SOCKET) {
744
+ assert (!bReadAttemptedAfterClose);
745
+ bReadAttemptedAfterClose = true;
746
+ return;
747
+ }
748
+
749
+ if (bWatchOnly) {
750
+ if (bNotifyReadable && EventCallback)
751
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
752
+ return;
753
+ }
754
+
755
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
756
+
757
+ int total_bytes_read = 0;
758
+ char readbuffer [16 * 1024 + 1];
759
+
760
+ for (int i=0; i < 10; i++) {
761
+ // Don't read just one buffer and then move on. This is faster
762
+ // if there is a lot of incoming.
763
+ // But don't read indefinitely. Give other sockets a chance to run.
764
+ // NOTICE, we're reading one less than the buffer size.
765
+ // That's so we can put a guard byte at the end of what we send
766
+ // to user code.
767
+
768
+
769
+ int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
770
+ #ifdef OS_WIN32
771
+ int e = WSAGetLastError();
772
+ #else
773
+ int e = errno;
774
+ #endif
775
+ //cerr << "<R:" << r << ">";
776
+
777
+ if (r > 0) {
778
+ total_bytes_read += r;
779
+
780
+ // Add a null-terminator at the the end of the buffer
781
+ // that we will send to the callback.
782
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
783
+ // to be able to depend on this behavior, so they will have
784
+ // the option to do some things faster. Additionally it's
785
+ // a security guard against buffer overflows.
786
+ readbuffer [r] = 0;
787
+ _DispatchInboundData (readbuffer, r);
788
+ if (bPaused)
789
+ break;
790
+ }
791
+ else if (r == 0) {
792
+ break;
793
+ }
794
+ else {
795
+ #ifdef OS_UNIX
796
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EAGAIN) && (e != EINTR)) {
797
+ #endif
798
+ #ifdef OS_WIN32
799
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
800
+ #endif
801
+ // 26Mar11: Previously, all read errors were assumed to be EWOULDBLOCK and ignored.
802
+ // Now, instead, we call Close() on errors like ECONNRESET and ENOTCONN.
803
+ UnbindReasonCode = e;
804
+ Close();
805
+ break;
806
+ } else {
807
+ // Basically a would-block, meaning we've read everything there is to read.
808
+ break;
809
+ }
810
+ }
811
+
812
+ }
813
+
814
+
815
+ if (total_bytes_read == 0) {
816
+ // If we read no data on a socket that selected readable,
817
+ // it generally means the other end closed the connection gracefully.
818
+ ScheduleClose (false);
819
+ //bCloseNow = true;
820
+ }
821
+
822
+ }
823
+
824
+
825
+
826
+ /******************************************
827
+ ConnectionDescriptor::_DispatchInboundData
828
+ ******************************************/
829
+
830
+ void ConnectionDescriptor::_DispatchInboundData (const char *buffer, int size)
831
+ {
832
+ #ifdef WITH_SSL
833
+ if (SslBox) {
834
+ SslBox->PutCiphertext (buffer, size);
835
+
836
+ int s;
837
+ char B [2048];
838
+ while ((s = SslBox->GetPlaintext (B, sizeof(B) - 1)) > 0) {
839
+ _CheckHandshakeStatus();
840
+ B [s] = 0;
841
+ _GenericInboundDispatch(B, s);
842
+ }
843
+
844
+ // If our SSL handshake had a problem, shut down the connection.
845
+ if (s == -2) {
846
+ ScheduleClose(false);
847
+ return;
848
+ }
849
+
850
+ _CheckHandshakeStatus();
851
+ _DispatchCiphertext();
852
+ }
853
+ else {
854
+ _GenericInboundDispatch(buffer, size);
855
+ }
856
+ #endif
857
+
858
+ #ifdef WITHOUT_SSL
859
+ _GenericInboundDispatch(buffer, size);
860
+ #endif
861
+ }
862
+
863
+
864
+
865
+ /*******************************************
866
+ ConnectionDescriptor::_CheckHandshakeStatus
867
+ *******************************************/
868
+
869
+ void ConnectionDescriptor::_CheckHandshakeStatus()
870
+ {
871
+ #ifdef WITH_SSL
872
+ if (SslBox && (!bHandshakeSignaled) && SslBox->IsHandshakeCompleted()) {
873
+ bHandshakeSignaled = true;
874
+ if (EventCallback)
875
+ (*EventCallback)(GetBinding(), EM_SSL_HANDSHAKE_COMPLETED, NULL, 0);
876
+ }
877
+ #endif
878
+ }
879
+
880
+
881
+
882
+ /***************************
883
+ ConnectionDescriptor::Write
884
+ ***************************/
885
+
886
+ void ConnectionDescriptor::Write()
887
+ {
888
+ /* A socket which is in a pending-connect state will select
889
+ * writable when the disposition of the connect is known.
890
+ * At that point, check to be sure there are no errors,
891
+ * and if none, then promote the socket out of the pending
892
+ * state.
893
+ * TODO: I haven't figured out how Windows signals errors on
894
+ * unconnected sockets. Maybe it does the untraditional but
895
+ * logical thing and makes the socket selectable for error.
896
+ * If so, it's unsupported here for the time being, and connect
897
+ * errors will have to be caught by the timeout mechanism.
898
+ */
899
+
900
+ if (bConnectPending) {
901
+ int error;
902
+ socklen_t len;
903
+ len = sizeof(error);
904
+ #ifdef OS_UNIX
905
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
906
+ #endif
907
+ #ifdef OS_WIN32
908
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
909
+ #endif
910
+ if ((o == 0) && (error == 0)) {
911
+ if (EventCallback)
912
+ (*EventCallback)(GetBinding(), EM_CONNECTION_COMPLETED, "", 0);
913
+
914
+ // 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called
915
+ // from EventMachine_t::AttachFD as well.
916
+ SetConnectPending (false);
917
+ }
918
+ else {
919
+ if (o == 0)
920
+ UnbindReasonCode = error;
921
+ ScheduleClose (false);
922
+ //bCloseNow = true;
923
+ }
924
+ }
925
+ else {
926
+
927
+ if (bNotifyWritable) {
928
+ if (EventCallback)
929
+ (*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);
930
+
931
+ _UpdateEvents(false, true);
932
+ return;
933
+ }
934
+
935
+ assert(!bWatchOnly);
936
+
937
+ /* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using
938
+ EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again,
939
+ we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause
940
+ ::Write to be called in a busy-loop.
941
+ */
942
+ #ifdef HAVE_KQUEUE
943
+ if (MyEventMachine->UsingKqueue()) {
944
+ if (OutboundDataSize == 0 && !bGotExtraKqueueEvent) {
945
+ bGotExtraKqueueEvent = true;
946
+ return;
947
+ } else if (OutboundDataSize > 0) {
948
+ bGotExtraKqueueEvent = false;
949
+ }
950
+ }
951
+ #endif
952
+
953
+ _WriteOutboundData();
954
+ }
955
+ }
956
+
957
+
958
+ /****************************************
959
+ ConnectionDescriptor::_WriteOutboundData
960
+ ****************************************/
961
+
962
+ void ConnectionDescriptor::_WriteOutboundData()
963
+ {
964
+ /* This is a helper function called by ::Write.
965
+ * It's possible for a socket to select writable and then no longer
966
+ * be writable by the time we get around to writing. The kernel might
967
+ * have used up its available output buffers between the select call
968
+ * and when we get here. So this condition is not an error.
969
+ *
970
+ * 20Jul07, added the same kind of protection against an invalid socket
971
+ * that is at the top of ::Read. Not entirely how this could happen in
972
+ * real life (connection-reset from the remote peer, perhaps?), but I'm
973
+ * doing it to address some reports of crashing under heavy loads.
974
+ */
975
+
976
+ int sd = GetSocket();
977
+ //assert (sd != INVALID_SOCKET);
978
+ if (sd == INVALID_SOCKET) {
979
+ assert (!bWriteAttemptedAfterClose);
980
+ bWriteAttemptedAfterClose = true;
981
+ return;
982
+ }
983
+
984
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
985
+ size_t nbytes = 0;
986
+
987
+ #ifdef HAVE_WRITEV
988
+ int iovcnt = OutboundPages.size();
989
+ // Max of 16 outbound pages at a time
990
+ if (iovcnt > 16) iovcnt = 16;
991
+
992
+ iovec iov[16];
993
+
994
+ for(int i = 0; i < iovcnt; i++){
995
+ OutboundPage *op = &(OutboundPages[i]);
996
+ #ifdef CC_SUNWspro
997
+ iov[i].iov_base = (char *)(op->Buffer + op->Offset);
998
+ #else
999
+ iov[i].iov_base = (void *)(op->Buffer + op->Offset);
1000
+ #endif
1001
+ iov[i].iov_len = op->Length - op->Offset;
1002
+
1003
+ nbytes += iov[i].iov_len;
1004
+ }
1005
+ #else
1006
+ char output_buffer [16 * 1024];
1007
+
1008
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
1009
+ OutboundPage *op = &(OutboundPages[0]);
1010
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
1011
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
1012
+ nbytes += (op->Length - op->Offset);
1013
+ op->Free();
1014
+ OutboundPages.pop_front();
1015
+ }
1016
+ else {
1017
+ int len = sizeof(output_buffer) - nbytes;
1018
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
1019
+ op->Offset += len;
1020
+ nbytes += len;
1021
+ }
1022
+ }
1023
+ #endif
1024
+
1025
+ // We should never have gotten here if there were no data to write,
1026
+ // so assert that as a sanity check.
1027
+ // Don't bother to make sure nbytes is less than output_buffer because
1028
+ // if it were we probably would have crashed already.
1029
+ assert (nbytes > 0);
1030
+
1031
+ assert (GetSocket() != INVALID_SOCKET);
1032
+ #ifdef HAVE_WRITEV
1033
+ int bytes_written = writev (GetSocket(), iov, iovcnt);
1034
+ #else
1035
+ int bytes_written = write (GetSocket(), output_buffer, nbytes);
1036
+ #endif
1037
+
1038
+ bool err = false;
1039
+ #ifdef OS_WIN32
1040
+ int e = WSAGetLastError();
1041
+ #else
1042
+ int e = errno;
1043
+ #endif
1044
+ if (bytes_written < 0) {
1045
+ err = true;
1046
+ bytes_written = 0;
1047
+ }
1048
+
1049
+ assert (bytes_written >= 0);
1050
+ OutboundDataSize -= bytes_written;
1051
+
1052
+ if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
1053
+ ProxiedFrom->Resume();
1054
+
1055
+ #ifdef HAVE_WRITEV
1056
+ if (!err) {
1057
+ unsigned int sent = bytes_written;
1058
+ deque<OutboundPage>::iterator op = OutboundPages.begin();
1059
+
1060
+ for (int i = 0; i < iovcnt; i++) {
1061
+ if (iov[i].iov_len <= sent) {
1062
+ // Sent this page in full, free it.
1063
+ op->Free();
1064
+ OutboundPages.pop_front();
1065
+
1066
+ sent -= iov[i].iov_len;
1067
+ } else {
1068
+ // Sent part (or none) of this page, increment offset to send the remainder
1069
+ op->Offset += sent;
1070
+ break;
1071
+ }
1072
+
1073
+ // Shouldn't be possible run out of pages before the loop ends
1074
+ assert(op != OutboundPages.end());
1075
+ *op++;
1076
+ }
1077
+ }
1078
+ #else
1079
+ if ((size_t)bytes_written < nbytes) {
1080
+ int len = nbytes - bytes_written;
1081
+ char *buffer = (char*) malloc (len + 1);
1082
+ if (!buffer)
1083
+ throw std::runtime_error ("bad alloc throwing back data");
1084
+ memcpy (buffer, output_buffer + bytes_written, len);
1085
+ buffer [len] = 0;
1086
+ OutboundPages.push_front (OutboundPage (buffer, len));
1087
+ }
1088
+ #endif
1089
+
1090
+ _UpdateEvents(false, true);
1091
+
1092
+ if (err) {
1093
+ #ifdef OS_UNIX
1094
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
1095
+ #endif
1096
+ #ifdef OS_WIN32
1097
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1098
+ #endif
1099
+ UnbindReasonCode = e;
1100
+ Close();
1101
+ }
1102
+ }
1103
+ }
1104
+
1105
+
1106
+ /***************************************
1107
+ ConnectionDescriptor::ReportErrorStatus
1108
+ ***************************************/
1109
+
1110
+ int ConnectionDescriptor::ReportErrorStatus()
1111
+ {
1112
+ if (MySocket == INVALID_SOCKET) {
1113
+ return -1;
1114
+ }
1115
+
1116
+ int error;
1117
+ socklen_t len;
1118
+ len = sizeof(error);
1119
+ #ifdef OS_UNIX
1120
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
1121
+ #endif
1122
+ #ifdef OS_WIN32
1123
+ int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
1124
+ #endif
1125
+ if ((o == 0) && (error == 0))
1126
+ return 0;
1127
+ else if (o == 0)
1128
+ return error;
1129
+ else
1130
+ return -1;
1131
+ }
1132
+
1133
+
1134
+ /******************************
1135
+ ConnectionDescriptor::StartTls
1136
+ ******************************/
1137
+
1138
+ void ConnectionDescriptor::StartTls()
1139
+ {
1140
+ #ifdef WITH_SSL
1141
+ if (SslBox)
1142
+ throw std::runtime_error ("SSL/TLS already running on connection");
1143
+
1144
+ SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding());
1145
+ _DispatchCiphertext();
1146
+ #endif
1147
+
1148
+ #ifdef WITHOUT_SSL
1149
+ throw std::runtime_error ("Encryption not available on this event-machine");
1150
+ #endif
1151
+ }
1152
+
1153
+
1154
+ /*********************************
1155
+ ConnectionDescriptor::SetTlsParms
1156
+ *********************************/
1157
+
1158
+ void ConnectionDescriptor::SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer)
1159
+ {
1160
+ #ifdef WITH_SSL
1161
+ if (SslBox)
1162
+ throw std::runtime_error ("call SetTlsParms before calling StartTls");
1163
+ if (privkey_filename && *privkey_filename)
1164
+ PrivateKeyFilename = privkey_filename;
1165
+ if (certchain_filename && *certchain_filename)
1166
+ CertChainFilename = certchain_filename;
1167
+ bSslVerifyPeer = verify_peer;
1168
+ #endif
1169
+
1170
+ #ifdef WITHOUT_SSL
1171
+ throw std::runtime_error ("Encryption not available on this event-machine");
1172
+ #endif
1173
+ }
1174
+
1175
+
1176
+ /*********************************
1177
+ ConnectionDescriptor::GetPeerCert
1178
+ *********************************/
1179
+
1180
+ #ifdef WITH_SSL
1181
+ X509 *ConnectionDescriptor::GetPeerCert()
1182
+ {
1183
+ if (!SslBox)
1184
+ throw std::runtime_error ("SSL/TLS not running on this connection");
1185
+ return SslBox->GetPeerCert();
1186
+ }
1187
+ #endif
1188
+
1189
+
1190
+ /***********************************
1191
+ ConnectionDescriptor::VerifySslPeer
1192
+ ***********************************/
1193
+
1194
+ #ifdef WITH_SSL
1195
+ bool ConnectionDescriptor::VerifySslPeer(const char *cert)
1196
+ {
1197
+ bSslPeerAccepted = false;
1198
+
1199
+ if (EventCallback)
1200
+ (*EventCallback)(GetBinding(), EM_SSL_VERIFY, cert, strlen(cert));
1201
+
1202
+ return bSslPeerAccepted;
1203
+ }
1204
+ #endif
1205
+
1206
+
1207
+ /***********************************
1208
+ ConnectionDescriptor::AcceptSslPeer
1209
+ ***********************************/
1210
+
1211
+ #ifdef WITH_SSL
1212
+ void ConnectionDescriptor::AcceptSslPeer()
1213
+ {
1214
+ bSslPeerAccepted = true;
1215
+ }
1216
+ #endif
1217
+
1218
+
1219
+ /*****************************************
1220
+ ConnectionDescriptor::_DispatchCiphertext
1221
+ *****************************************/
1222
+
1223
+ #ifdef WITH_SSL
1224
+ void ConnectionDescriptor::_DispatchCiphertext()
1225
+ {
1226
+ assert (SslBox);
1227
+
1228
+
1229
+ char BigBuf [2048];
1230
+ bool did_work;
1231
+
1232
+ do {
1233
+ did_work = false;
1234
+
1235
+ // try to drain ciphertext
1236
+ while (SslBox->CanGetCiphertext()) {
1237
+ int r = SslBox->GetCiphertext (BigBuf, sizeof(BigBuf));
1238
+ assert (r > 0);
1239
+ _SendRawOutboundData (BigBuf, r);
1240
+ did_work = true;
1241
+ }
1242
+
1243
+ // Pump the SslBox, in case it has queued outgoing plaintext
1244
+ // This will return >0 if data was written,
1245
+ // 0 if no data was written, and <0 if there was a fatal error.
1246
+ bool pump;
1247
+ do {
1248
+ pump = false;
1249
+ int w = SslBox->PutPlaintext (NULL, 0);
1250
+ if (w > 0) {
1251
+ did_work = true;
1252
+ pump = true;
1253
+ }
1254
+ else if (w < 0)
1255
+ ScheduleClose (false);
1256
+ } while (pump);
1257
+
1258
+ // try to put plaintext. INCOMPLETE, doesn't belong here?
1259
+ // In SendOutboundData, we're spooling plaintext directly
1260
+ // into SslBox. That may be wrong, we may need to buffer it
1261
+ // up here!
1262
+ /*
1263
+ const char *ptr;
1264
+ int ptr_length;
1265
+ while (OutboundPlaintext.GetPage (&ptr, &ptr_length)) {
1266
+ assert (ptr && (ptr_length > 0));
1267
+ int w = SslMachine.PutPlaintext (ptr, ptr_length);
1268
+ if (w > 0) {
1269
+ OutboundPlaintext.DiscardBytes (w);
1270
+ did_work = true;
1271
+ }
1272
+ else
1273
+ break;
1274
+ }
1275
+ */
1276
+
1277
+ } while (did_work);
1278
+
1279
+ }
1280
+ #endif
1281
+
1282
+
1283
+
1284
+ /*******************************
1285
+ ConnectionDescriptor::Heartbeat
1286
+ *******************************/
1287
+
1288
+ void ConnectionDescriptor::Heartbeat()
1289
+ {
1290
+ /* Only allow a certain amount of time to go by while waiting
1291
+ * for a pending connect. If it expires, then kill the socket.
1292
+ * For a connected socket, close it if its inactivity timer
1293
+ * has expired.
1294
+ */
1295
+
1296
+ if (bConnectPending) {
1297
+ if ((MyEventMachine->GetCurrentLoopTime() - CreatedAt) >= PendingConnectTimeout) {
1298
+ UnbindReasonCode = ETIMEDOUT;
1299
+ ScheduleClose (false);
1300
+ //bCloseNow = true;
1301
+ }
1302
+ }
1303
+ else {
1304
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout)) {
1305
+ UnbindReasonCode = ETIMEDOUT;
1306
+ ScheduleClose (false);
1307
+ //bCloseNow = true;
1308
+ }
1309
+ }
1310
+ }
1311
+
1312
+
1313
+ /****************************************
1314
+ LoopbreakDescriptor::LoopbreakDescriptor
1315
+ ****************************************/
1316
+
1317
+ LoopbreakDescriptor::LoopbreakDescriptor (int sd, EventMachine_t *parent_em):
1318
+ EventableDescriptor (sd, parent_em)
1319
+ {
1320
+ /* This is really bad and ugly. Change someday if possible.
1321
+ * We have to know about an event-machine (probably the one that owns us),
1322
+ * so we can pass newly-created connections to it.
1323
+ */
1324
+
1325
+ bCallbackUnbind = false;
1326
+
1327
+ #ifdef HAVE_EPOLL
1328
+ EpollEvent.events = EPOLLIN;
1329
+ #endif
1330
+ #ifdef HAVE_KQUEUE
1331
+ MyEventMachine->ArmKqueueReader (this);
1332
+ #endif
1333
+ }
1334
+
1335
+
1336
+
1337
+
1338
+ /*************************
1339
+ LoopbreakDescriptor::Read
1340
+ *************************/
1341
+
1342
+ void LoopbreakDescriptor::Read()
1343
+ {
1344
+ // TODO, refactor, this code is probably in the wrong place.
1345
+ assert (MyEventMachine);
1346
+ MyEventMachine->_ReadLoopBreaker();
1347
+ }
1348
+
1349
+
1350
+ /**************************
1351
+ LoopbreakDescriptor::Write
1352
+ **************************/
1353
+
1354
+ void LoopbreakDescriptor::Write()
1355
+ {
1356
+ // Why are we here?
1357
+ throw std::runtime_error ("bad code path in loopbreak");
1358
+ }
1359
+
1360
+ /**************************************
1361
+ AcceptorDescriptor::AcceptorDescriptor
1362
+ **************************************/
1363
+
1364
+ AcceptorDescriptor::AcceptorDescriptor (int sd, EventMachine_t *parent_em):
1365
+ EventableDescriptor (sd, parent_em)
1366
+ {
1367
+ #ifdef HAVE_EPOLL
1368
+ EpollEvent.events = EPOLLIN;
1369
+ #endif
1370
+ #ifdef HAVE_KQUEUE
1371
+ MyEventMachine->ArmKqueueReader (this);
1372
+ #endif
1373
+ }
1374
+
1375
+
1376
+ /***************************************
1377
+ AcceptorDescriptor::~AcceptorDescriptor
1378
+ ***************************************/
1379
+
1380
+ AcceptorDescriptor::~AcceptorDescriptor()
1381
+ {
1382
+ }
1383
+
1384
+ /****************************************
1385
+ STATIC: AcceptorDescriptor::StopAcceptor
1386
+ ****************************************/
1387
+
1388
+ void AcceptorDescriptor::StopAcceptor (const unsigned long binding)
1389
+ {
1390
+ // TODO: This is something of a hack, or at least it's a static method of the wrong class.
1391
+ AcceptorDescriptor *ad = dynamic_cast <AcceptorDescriptor*> (Bindable_t::GetObject (binding));
1392
+ if (ad)
1393
+ ad->ScheduleClose (false);
1394
+ else
1395
+ throw std::runtime_error ("failed to close nonexistent acceptor");
1396
+ }
1397
+
1398
+
1399
+ /************************
1400
+ AcceptorDescriptor::Read
1401
+ ************************/
1402
+
1403
+ void AcceptorDescriptor::Read()
1404
+ {
1405
+ /* Accept up to a certain number of sockets on the listening connection.
1406
+ * Don't try to accept all that are present, because this would allow a DoS attack
1407
+ * in which no data were ever read or written. We should accept more than one,
1408
+ * if available, to keep the partially accepted sockets from backing up in the kernel.
1409
+ */
1410
+
1411
+ /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
1412
+ * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
1413
+ * and then block when we call accept. For example, the other end resets the connection after
1414
+ * the socket selects readable and before we call accept. The kernel will remove the dead
1415
+ * socket from the accept queue. If the accept queue is now empty, accept will block.
1416
+ */
1417
+
1418
+
1419
+ struct sockaddr_in pin;
1420
+ socklen_t addrlen = sizeof (pin);
1421
+
1422
+ for (int i=0; i < 10; i++) {
1423
+ int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
1424
+ if (sd == INVALID_SOCKET) {
1425
+ // This breaks the loop when we've accepted everything on the kernel queue,
1426
+ // up to 10 new connections. But what if the *first* accept fails?
1427
+ // Does that mean anything serious is happening, beyond the situation
1428
+ // described in the note above?
1429
+ break;
1430
+ }
1431
+
1432
+ // Set the newly-accepted socket non-blocking.
1433
+ // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
1434
+ // attribute that we applied to the acceptor socket into the accepted one.
1435
+ if (!SetSocketNonblocking (sd)) {
1436
+ //int val = fcntl (sd, F_GETFL, 0);
1437
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
1438
+ shutdown (sd, 1);
1439
+ close (sd);
1440
+ continue;
1441
+ }
1442
+
1443
+
1444
+ // Disable slow-start (Nagle algorithm). Eventually make this configurable.
1445
+ int one = 1;
1446
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
1447
+
1448
+
1449
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
1450
+ if (!cd)
1451
+ throw std::runtime_error ("no newly accepted connection");
1452
+ cd->SetServerMode();
1453
+ if (EventCallback) {
1454
+ (*EventCallback) (GetBinding(), EM_CONNECTION_ACCEPTED, NULL, cd->GetBinding());
1455
+ }
1456
+ #ifdef HAVE_EPOLL
1457
+ cd->GetEpollEvent()->events =
1458
+ (cd->SelectForRead() ? EPOLLIN : 0) | (cd->SelectForWrite() ? EPOLLOUT : 0);
1459
+ #endif
1460
+ assert (MyEventMachine);
1461
+ MyEventMachine->Add (cd);
1462
+ #ifdef HAVE_KQUEUE
1463
+ if (cd->SelectForWrite())
1464
+ MyEventMachine->ArmKqueueWriter (cd);
1465
+ if (cd->SelectForRead())
1466
+ MyEventMachine->ArmKqueueReader (cd);
1467
+ #endif
1468
+ }
1469
+
1470
+ }
1471
+
1472
+
1473
+ /*************************
1474
+ AcceptorDescriptor::Write
1475
+ *************************/
1476
+
1477
+ void AcceptorDescriptor::Write()
1478
+ {
1479
+ // Why are we here?
1480
+ throw std::runtime_error ("bad code path in acceptor");
1481
+ }
1482
+
1483
+
1484
+ /*****************************
1485
+ AcceptorDescriptor::Heartbeat
1486
+ *****************************/
1487
+
1488
+ void AcceptorDescriptor::Heartbeat()
1489
+ {
1490
+ // No-op
1491
+ }
1492
+
1493
+
1494
+ /*******************************
1495
+ AcceptorDescriptor::GetSockname
1496
+ *******************************/
1497
+
1498
+ bool AcceptorDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1499
+ {
1500
+ bool ok = false;
1501
+ if (s) {
1502
+ int gp = getsockname (GetSocket(), s, len);
1503
+ if (gp == 0)
1504
+ ok = true;
1505
+ }
1506
+ return ok;
1507
+ }
1508
+
1509
+
1510
+
1511
+ /**************************************
1512
+ DatagramDescriptor::DatagramDescriptor
1513
+ **************************************/
1514
+
1515
+ DatagramDescriptor::DatagramDescriptor (int sd, EventMachine_t *parent_em):
1516
+ EventableDescriptor (sd, parent_em),
1517
+ OutboundDataSize (0)
1518
+ {
1519
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1520
+
1521
+ /* Provisionally added 19Oct07. All datagram sockets support broadcasting.
1522
+ * Until now, sending to a broadcast address would give EACCES (permission denied)
1523
+ * on systems like Linux and BSD that require the SO_BROADCAST socket-option in order
1524
+ * to accept a packet to a broadcast address. Solaris doesn't require it. I think
1525
+ * Windows DOES require it but I'm not sure.
1526
+ *
1527
+ * Ruby does NOT do what we're doing here. In Ruby, you have to explicitly set SO_BROADCAST
1528
+ * on a UDP socket in order to enable broadcasting. The reason for requiring the option
1529
+ * in the first place is so that applications don't send broadcast datagrams by mistake.
1530
+ * I imagine that could happen if a user of an application typed in an address that happened
1531
+ * to be a broadcast address on that particular subnet.
1532
+ *
1533
+ * This is provisional because someone may eventually come up with a good reason not to
1534
+ * do it for all UDP sockets. If that happens, then we'll need to add a usercode-level API
1535
+ * to set the socket option, just like Ruby does. AND WE'LL ALSO BREAK CODE THAT DOESN'T
1536
+ * EXPLICITLY SET THE OPTION.
1537
+ */
1538
+
1539
+ int oval = 1;
1540
+ setsockopt (GetSocket(), SOL_SOCKET, SO_BROADCAST, (char*)&oval, sizeof(oval));
1541
+
1542
+ #ifdef HAVE_EPOLL
1543
+ EpollEvent.events = EPOLLIN;
1544
+ #endif
1545
+ #ifdef HAVE_KQUEUE
1546
+ MyEventMachine->ArmKqueueReader (this);
1547
+ #endif
1548
+ }
1549
+
1550
+
1551
+ /***************************************
1552
+ DatagramDescriptor::~DatagramDescriptor
1553
+ ***************************************/
1554
+
1555
+ DatagramDescriptor::~DatagramDescriptor()
1556
+ {
1557
+ // Run down any stranded outbound data.
1558
+ for (size_t i=0; i < OutboundPages.size(); i++)
1559
+ OutboundPages[i].Free();
1560
+ }
1561
+
1562
+
1563
+ /*****************************
1564
+ DatagramDescriptor::Heartbeat
1565
+ *****************************/
1566
+
1567
+ void DatagramDescriptor::Heartbeat()
1568
+ {
1569
+ // Close it if its inactivity timer has expired.
1570
+
1571
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout))
1572
+ ScheduleClose (false);
1573
+ //bCloseNow = true;
1574
+ }
1575
+
1576
+
1577
+ /************************
1578
+ DatagramDescriptor::Read
1579
+ ************************/
1580
+
1581
+ void DatagramDescriptor::Read()
1582
+ {
1583
+ int sd = GetSocket();
1584
+ assert (sd != INVALID_SOCKET);
1585
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
1586
+
1587
+ // This is an extremely large read buffer.
1588
+ // In many cases you wouldn't expect to get any more than 4K.
1589
+ char readbuffer [16 * 1024];
1590
+
1591
+ for (int i=0; i < 10; i++) {
1592
+ // Don't read just one buffer and then move on. This is faster
1593
+ // if there is a lot of incoming.
1594
+ // But don't read indefinitely. Give other sockets a chance to run.
1595
+ // NOTICE, we're reading one less than the buffer size.
1596
+ // That's so we can put a guard byte at the end of what we send
1597
+ // to user code.
1598
+
1599
+ struct sockaddr_in sin;
1600
+ socklen_t slen = sizeof (sin);
1601
+ memset (&sin, 0, slen);
1602
+
1603
+ int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
1604
+ //cerr << "<R:" << r << ">";
1605
+
1606
+ // In UDP, a zero-length packet is perfectly legal.
1607
+ if (r >= 0) {
1608
+
1609
+ // Add a null-terminator at the the end of the buffer
1610
+ // that we will send to the callback.
1611
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
1612
+ // to be able to depend on this behavior, so they will have
1613
+ // the option to do some things faster. Additionally it's
1614
+ // a security guard against buffer overflows.
1615
+ readbuffer [r] = 0;
1616
+
1617
+
1618
+ // Set up a "temporary" return address so that callers can "reply" to us
1619
+ // from within the callback we are about to invoke. That means that ordinary
1620
+ // calls to "send_data_to_connection" (which is of course misnamed in this
1621
+ // case) will result in packets being sent back to the same place that sent
1622
+ // us this one.
1623
+ // There is a different call (evma_send_datagram) for cases where the caller
1624
+ // actually wants to send a packet somewhere else.
1625
+
1626
+ memset (&ReturnAddress, 0, sizeof(ReturnAddress));
1627
+ memcpy (&ReturnAddress, &sin, slen);
1628
+
1629
+ _GenericInboundDispatch(readbuffer, r);
1630
+
1631
+ }
1632
+ else {
1633
+ // Basically a would-block, meaning we've read everything there is to read.
1634
+ break;
1635
+ }
1636
+
1637
+ }
1638
+
1639
+
1640
+ }
1641
+
1642
+
1643
+ /*************************
1644
+ DatagramDescriptor::Write
1645
+ *************************/
1646
+
1647
+ void DatagramDescriptor::Write()
1648
+ {
1649
+ /* It's possible for a socket to select writable and then no longer
1650
+ * be writable by the time we get around to writing. The kernel might
1651
+ * have used up its available output buffers between the select call
1652
+ * and when we get here. So this condition is not an error.
1653
+ * This code is very reminiscent of ConnectionDescriptor::_WriteOutboundData,
1654
+ * but differs in the that the outbound data pages (received from the
1655
+ * user) are _message-structured._ That is, we send each of them out
1656
+ * one message at a time.
1657
+ * TODO, we are currently suppressing the EMSGSIZE error!!!
1658
+ */
1659
+
1660
+ int sd = GetSocket();
1661
+ assert (sd != INVALID_SOCKET);
1662
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
1663
+
1664
+ assert (OutboundPages.size() > 0);
1665
+
1666
+ // Send out up to 10 packets, then cycle the machine.
1667
+ for (int i = 0; i < 10; i++) {
1668
+ if (OutboundPages.size() <= 0)
1669
+ break;
1670
+ OutboundPage *op = &(OutboundPages[0]);
1671
+
1672
+ // The nasty cast to (char*) is needed because Windows is brain-dead.
1673
+ int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1674
+ #ifdef OS_WIN32
1675
+ int e = WSAGetLastError();
1676
+ #else
1677
+ int e = errno;
1678
+ #endif
1679
+
1680
+ OutboundDataSize -= op->Length;
1681
+ op->Free();
1682
+ OutboundPages.pop_front();
1683
+
1684
+ if (s == SOCKET_ERROR) {
1685
+ #ifdef OS_UNIX
1686
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR)) {
1687
+ #endif
1688
+ #ifdef OS_WIN32
1689
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK)) {
1690
+ #endif
1691
+ UnbindReasonCode = e;
1692
+ Close();
1693
+ break;
1694
+ }
1695
+ }
1696
+ }
1697
+
1698
+ #ifdef HAVE_EPOLL
1699
+ EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
1700
+ assert (MyEventMachine);
1701
+ MyEventMachine->Modify (this);
1702
+ #endif
1703
+ #ifdef HAVE_KQUEUE
1704
+ if (SelectForWrite())
1705
+ MyEventMachine->ArmKqueueWriter (this);
1706
+ #endif
1707
+ }
1708
+
1709
+
1710
+ /**********************************
1711
+ DatagramDescriptor::SelectForWrite
1712
+ **********************************/
1713
+
1714
+ bool DatagramDescriptor::SelectForWrite()
1715
+ {
1716
+ /* Changed 15Nov07, per bug report by Mark Zvillius.
1717
+ * The outbound data size will be zero if there are zero-length outbound packets,
1718
+ * so we now select writable in case the outbound page buffer is not empty.
1719
+ * Note that the superclass ShouldDelete method still checks for outbound data size,
1720
+ * which may be wrong.
1721
+ */
1722
+ //return (GetOutboundDataSize() > 0); (Original)
1723
+ return (OutboundPages.size() > 0);
1724
+ }
1725
+
1726
+
1727
+ /************************************
1728
+ DatagramDescriptor::SendOutboundData
1729
+ ************************************/
1730
+
1731
+ int DatagramDescriptor::SendOutboundData (const char *data, int length)
1732
+ {
1733
+ // This is almost an exact clone of ConnectionDescriptor::_SendRawOutboundData.
1734
+ // That means most of it could be factored to a common ancestor. Note that
1735
+ // empty datagrams are meaningful, which isn't the case for TCP streams.
1736
+
1737
+ if (IsCloseScheduled())
1738
+ return 0;
1739
+
1740
+ if (!data && (length > 0))
1741
+ throw std::runtime_error ("bad outbound data");
1742
+ char *buffer = (char *) malloc (length + 1);
1743
+ if (!buffer)
1744
+ throw std::runtime_error ("no allocation for outbound data");
1745
+ memcpy (buffer, data, length);
1746
+ buffer [length] = 0;
1747
+ OutboundPages.push_back (OutboundPage (buffer, length, ReturnAddress));
1748
+ OutboundDataSize += length;
1749
+
1750
+ #ifdef HAVE_EPOLL
1751
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1752
+ assert (MyEventMachine);
1753
+ MyEventMachine->Modify (this);
1754
+ #endif
1755
+ #ifdef HAVE_KQUEUE
1756
+ MyEventMachine->ArmKqueueWriter (this);
1757
+ #endif
1758
+
1759
+ return length;
1760
+ }
1761
+
1762
+
1763
+ /****************************************
1764
+ DatagramDescriptor::SendOutboundDatagram
1765
+ ****************************************/
1766
+
1767
+ int DatagramDescriptor::SendOutboundDatagram (const char *data, int length, const char *address, int port)
1768
+ {
1769
+ // This is an exact clone of ConnectionDescriptor::SendOutboundData.
1770
+ // That means it needs to move to a common ancestor.
1771
+ // TODO: Refactor this so there's no overlap with SendOutboundData.
1772
+
1773
+ if (IsCloseScheduled())
1774
+ //if (bCloseNow || bCloseAfterWriting)
1775
+ return 0;
1776
+
1777
+ if (!address || !*address || !port)
1778
+ return 0;
1779
+
1780
+ sockaddr_in pin;
1781
+ unsigned long HostAddr;
1782
+
1783
+ HostAddr = inet_addr (address);
1784
+ if (HostAddr == INADDR_NONE) {
1785
+ // The nasty cast to (char*) is because Windows is brain-dead.
1786
+ hostent *hp = gethostbyname ((char*)address);
1787
+ if (!hp)
1788
+ return 0;
1789
+ HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
1790
+ }
1791
+
1792
+ memset (&pin, 0, sizeof(pin));
1793
+ pin.sin_family = AF_INET;
1794
+ pin.sin_addr.s_addr = HostAddr;
1795
+ pin.sin_port = htons (port);
1796
+
1797
+
1798
+ if (!data && (length > 0))
1799
+ throw std::runtime_error ("bad outbound data");
1800
+ char *buffer = (char *) malloc (length + 1);
1801
+ if (!buffer)
1802
+ throw std::runtime_error ("no allocation for outbound data");
1803
+ memcpy (buffer, data, length);
1804
+ buffer [length] = 0;
1805
+ OutboundPages.push_back (OutboundPage (buffer, length, pin));
1806
+ OutboundDataSize += length;
1807
+
1808
+ #ifdef HAVE_EPOLL
1809
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
1810
+ assert (MyEventMachine);
1811
+ MyEventMachine->Modify (this);
1812
+ #endif
1813
+ #ifdef HAVE_KQUEUE
1814
+ MyEventMachine->ArmKqueueWriter (this);
1815
+ #endif
1816
+
1817
+ return length;
1818
+ }
1819
+
1820
+
1821
+ /*********************************
1822
+ ConnectionDescriptor::GetPeername
1823
+ *********************************/
1824
+
1825
+ bool ConnectionDescriptor::GetPeername (struct sockaddr *s, socklen_t *len)
1826
+ {
1827
+ bool ok = false;
1828
+ if (s) {
1829
+ int gp = getpeername (GetSocket(), s, len);
1830
+ if (gp == 0)
1831
+ ok = true;
1832
+ }
1833
+ return ok;
1834
+ }
1835
+
1836
+ /*********************************
1837
+ ConnectionDescriptor::GetSockname
1838
+ *********************************/
1839
+
1840
+ bool ConnectionDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1841
+ {
1842
+ bool ok = false;
1843
+ if (s) {
1844
+ int gp = getsockname (GetSocket(), s, len);
1845
+ if (gp == 0)
1846
+ ok = true;
1847
+ }
1848
+ return ok;
1849
+ }
1850
+
1851
+
1852
+ /**********************************************
1853
+ ConnectionDescriptor::GetCommInactivityTimeout
1854
+ **********************************************/
1855
+
1856
+ uint64_t ConnectionDescriptor::GetCommInactivityTimeout()
1857
+ {
1858
+ return InactivityTimeout / 1000;
1859
+ }
1860
+
1861
+
1862
+ /**********************************************
1863
+ ConnectionDescriptor::SetCommInactivityTimeout
1864
+ **********************************************/
1865
+
1866
+ int ConnectionDescriptor::SetCommInactivityTimeout (uint64_t value)
1867
+ {
1868
+ InactivityTimeout = value * 1000;
1869
+ MyEventMachine->QueueHeartbeat(this);
1870
+ return 1;
1871
+ }
1872
+
1873
+ /*******************************
1874
+ DatagramDescriptor::GetPeername
1875
+ *******************************/
1876
+
1877
+ bool DatagramDescriptor::GetPeername (struct sockaddr *s, socklen_t *len)
1878
+ {
1879
+ bool ok = false;
1880
+ if (s) {
1881
+ *len = sizeof(struct sockaddr);
1882
+ memset (s, 0, sizeof(struct sockaddr));
1883
+ memcpy (s, &ReturnAddress, sizeof(ReturnAddress));
1884
+ ok = true;
1885
+ }
1886
+ return ok;
1887
+ }
1888
+
1889
+ /*******************************
1890
+ DatagramDescriptor::GetSockname
1891
+ *******************************/
1892
+
1893
+ bool DatagramDescriptor::GetSockname (struct sockaddr *s, socklen_t *len)
1894
+ {
1895
+ bool ok = false;
1896
+ if (s) {
1897
+ int gp = getsockname (GetSocket(), s, len);
1898
+ if (gp == 0)
1899
+ ok = true;
1900
+ }
1901
+ return ok;
1902
+ }
1903
+
1904
+
1905
+
1906
+ /********************************************
1907
+ DatagramDescriptor::GetCommInactivityTimeout
1908
+ ********************************************/
1909
+
1910
+ uint64_t DatagramDescriptor::GetCommInactivityTimeout()
1911
+ {
1912
+ return InactivityTimeout / 1000;
1913
+ }
1914
+
1915
+ /********************************************
1916
+ DatagramDescriptor::SetCommInactivityTimeout
1917
+ ********************************************/
1918
+
1919
+ int DatagramDescriptor::SetCommInactivityTimeout (uint64_t value)
1920
+ {
1921
+ if (value > 0) {
1922
+ InactivityTimeout = value * 1000;
1923
+ MyEventMachine->QueueHeartbeat(this);
1924
+ return 1;
1925
+ }
1926
+ return 0;
1927
+ }
1928
+
1929
+
1930
+ /************************************
1931
+ InotifyDescriptor::InotifyDescriptor
1932
+ *************************************/
1933
+
1934
+ InotifyDescriptor::InotifyDescriptor (EventMachine_t *em):
1935
+ EventableDescriptor(0, em)
1936
+ {
1937
+ bCallbackUnbind = false;
1938
+
1939
+ #ifndef HAVE_INOTIFY
1940
+ throw std::runtime_error("no inotify support on this system");
1941
+ #else
1942
+
1943
+ int fd = inotify_init();
1944
+ if (fd == -1) {
1945
+ char buf[200];
1946
+ snprintf (buf, sizeof(buf)-1, "unable to create inotify descriptor: %s", strerror(errno));
1947
+ throw std::runtime_error (buf);
1948
+ }
1949
+
1950
+ MySocket = fd;
1951
+ SetSocketNonblocking(MySocket);
1952
+ #ifdef HAVE_EPOLL
1953
+ EpollEvent.events = EPOLLIN;
1954
+ #endif
1955
+
1956
+ #endif
1957
+ }
1958
+
1959
+
1960
+ /*************************************
1961
+ InotifyDescriptor::~InotifyDescriptor
1962
+ **************************************/
1963
+
1964
+ InotifyDescriptor::~InotifyDescriptor()
1965
+ {
1966
+ close(MySocket);
1967
+ MySocket = INVALID_SOCKET;
1968
+ }
1969
+
1970
+ /***********************
1971
+ InotifyDescriptor::Read
1972
+ ************************/
1973
+
1974
+ void InotifyDescriptor::Read()
1975
+ {
1976
+ assert (MyEventMachine);
1977
+ MyEventMachine->_ReadInotifyEvents();
1978
+ }
1979
+
1980
+
1981
+ /************************
1982
+ InotifyDescriptor::Write
1983
+ *************************/
1984
+
1985
+ void InotifyDescriptor::Write()
1986
+ {
1987
+ throw std::runtime_error("bad code path in inotify");
1988
+ }