eventmachine-eventmachine 0.12.3

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