careo-eventmachine 0.12.5.1

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