sonixlabs-eventmachine-java 1.0.0.rc.4-java

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