eventmachine 0.12.6-x86-mswin32-60

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