eventmachine-with-ipv6 1.0.0.beta.4.ipv6.0

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