eventmachine 0.12.0-i386-mswin32

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