jrmey-eventmachine 0.12.12

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