eventmachine 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/RELEASE_NOTES +5 -1
  2. data/ext/binder.cpp +125 -0
  3. data/ext/binder.h +54 -0
  4. data/ext/ed.cpp +528 -0
  5. data/ext/ed.h +152 -0
  6. data/ext/em.cpp +475 -0
  7. data/ext/em.h +90 -0
  8. data/ext/extconf.rb +31 -0
  9. data/ext/libmain.cpp +312 -0
  10. data/ext/project.h +63 -0
  11. data/ext/sigs.cpp +60 -0
  12. data/ext/sigs.h +35 -0
  13. data/lib/eventmachine.rb +39 -1
  14. metadata +18 -80
  15. data/doc/classes/Echo.html +0 -180
  16. data/doc/classes/Echo.src/M000033.html +0 -23
  17. data/doc/classes/Echo.src/M000034.html +0 -19
  18. data/doc/classes/Echo.src/M000035.html +0 -19
  19. data/doc/classes/Echo.src/M000036.html +0 -18
  20. data/doc/classes/EventMachine.html +0 -369
  21. data/doc/classes/EventMachine.src/M000002.html +0 -24
  22. data/doc/classes/EventMachine.src/M000003.html +0 -24
  23. data/doc/classes/EventMachine.src/M000004.html +0 -26
  24. data/doc/classes/EventMachine.src/M000005.html +0 -21
  25. data/doc/classes/EventMachine.src/M000006.html +0 -23
  26. data/doc/classes/EventMachine.src/M000007.html +0 -28
  27. data/doc/classes/EventMachine.src/M000008.html +0 -20
  28. data/doc/classes/EventMachine.src/M000009.html +0 -19
  29. data/doc/classes/EventMachine.src/M000010.html +0 -18
  30. data/doc/classes/EventMachine.src/M000011.html +0 -18
  31. data/doc/classes/EventMachine/Connection.html +0 -341
  32. data/doc/classes/EventMachine/Connection.src/M000020.html +0 -19
  33. data/doc/classes/EventMachine/Connection.src/M000021.html +0 -17
  34. data/doc/classes/EventMachine/Connection.src/M000022.html +0 -18
  35. data/doc/classes/EventMachine/Connection.src/M000023.html +0 -17
  36. data/doc/classes/EventMachine/Connection.src/M000024.html +0 -18
  37. data/doc/classes/EventMachine/Connection.src/M000025.html +0 -18
  38. data/doc/classes/EventMachine/Connection.src/M000026.html +0 -18
  39. data/doc/classes/EventMachine/Connection.src/M000027.html +0 -18
  40. data/doc/classes/EventMachine/Connection.src/M000028.html +0 -17
  41. data/doc/classes/EventMachine/Connection.src/M000029.html +0 -18
  42. data/doc/classes/EventMachine/Connection.src/M000030.html +0 -18
  43. data/doc/classes/EventMachine/Connection.src/M000031.html +0 -18
  44. data/doc/classes/EventMachine/Connection.src/M000032.html +0 -18
  45. data/doc/classes/EventMachine/ConnectionAlreadyBound.html +0 -111
  46. data/doc/classes/EventMachine/ConnectionNotBound.html +0 -111
  47. data/doc/classes/EventMachine/Connections.html +0 -292
  48. data/doc/classes/EventMachine/Connections.src/M000012.html +0 -20
  49. data/doc/classes/EventMachine/Connections.src/M000013.html +0 -23
  50. data/doc/classes/EventMachine/Connections.src/M000014.html +0 -23
  51. data/doc/classes/EventMachine/Connections.src/M000015.html +0 -24
  52. data/doc/classes/EventMachine/Connections.src/M000016.html +0 -19
  53. data/doc/classes/EventMachine/Connections.src/M000017.html +0 -21
  54. data/doc/classes/EventMachine/Connections.src/M000018.html +0 -19
  55. data/doc/classes/EventMachine/Connections.src/M000019.html +0 -20
  56. data/doc/classes/EventMachine/EventCodes.html +0 -133
  57. data/doc/classes/EventMachine/NoConnectionMade.html +0 -111
  58. data/doc/classes/EventMachine/NoHandlerForAcceptedConnection.html +0 -111
  59. data/doc/classes/EventMachine/NoServerCreated.html +0 -111
  60. data/doc/classes/EventMachine/TimerNotInstalled.html +0 -111
  61. data/doc/classes/EventMachine/TooManyAcceptors.html +0 -111
  62. data/doc/classes/EventMachine/TooManyTimersPending.html +0 -111
  63. data/doc/classes/EventMachine/UnknownTimerFired.html +0 -111
  64. data/doc/classes/Zzz.html +0 -131
  65. data/doc/classes/Zzz.src/M000001.html +0 -18
  66. data/doc/created.rid +0 -1
  67. data/doc/files/binder_cpp.html +0 -101
  68. data/doc/files/ed_cpp.html +0 -101
  69. data/doc/files/em_cpp.html +0 -101
  70. data/doc/files/event_machine_rb.html +0 -118
  71. data/doc/files/g_rb.html +0 -108
  72. data/doc/files/lib/eventmachine_rb.html +0 -114
  73. data/doc/files/libmain_cpp.html +0 -101
  74. data/doc/files/sigs_cpp.html +0 -101
  75. data/doc/files/tests/testem_rb.html +0 -110
  76. data/doc/fr_class_index.html +0 -41
  77. data/doc/fr_file_index.html +0 -35
  78. data/doc/fr_method_index.html +0 -62
  79. data/doc/index.html +0 -24
  80. data/ext/libeventmachine.so +0 -0
@@ -1,7 +1,11 @@
1
- $Id: RELEASE_NOTES 2259 2006-04-11 06:54:21Z francis $
1
+ $Id: RELEASE_NOTES 2283 2006-04-13 10:17:37Z francis $
2
2
 
3
3
  RUBY/EventMachine RELEASE NOTES
4
4
 
5
+ --------------------------------------------------
6
+ Version: 0.3.2, released 12Apr06
7
+ Added support for a user-supplied block in EventMachine#connect.
8
+
5
9
  --------------------------------------------------
6
10
  Version: 0.3.1, released 11Apr06
7
11
  Fixed bug that prevented EventMachine from being run multiple
@@ -0,0 +1,125 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: binder.cpp 2291 2006-04-14 03:56:18Z francis $
4
+
5
+ File: binder.cpp
6
+ Date: 07Apr06
7
+
8
+ Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat20
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation; either version 2 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ *****************************************************************************/
26
+
27
+ #include "project.h"
28
+
29
+ #define DEV_URANDOM "/dev/urandom"
30
+ #define DO_NOT_REQUIRE_UUID
31
+
32
+
33
+ map<string, Bindable_t*> Bindable_t::BindingBag;
34
+
35
+
36
+ /********************************
37
+ STATIC Bindable_t::CreateBinding
38
+ ********************************/
39
+
40
+ string Bindable_t::CreateBinding()
41
+ {
42
+ static int index = 0;
43
+ static string seed;
44
+
45
+ if ((index >= 1000000) || (seed.length() == 0)) {
46
+ #ifdef REQUIRE_UUID
47
+ uuid_t u;
48
+ uuid_generate (u);
49
+ #endif
50
+
51
+ #ifdef DO_NOT_REQUIRE_UUID
52
+ int fd = open (DEV_URANDOM, O_RDONLY);
53
+ if (fd < 0)
54
+ throw std::runtime_error ("No entropy device");
55
+
56
+ unsigned char u[16];
57
+ size_t r = read (fd, u, sizeof(u));
58
+ if (r < sizeof(u))
59
+ throw std::runtime_error ("Unable to read entropy device");
60
+ #endif
61
+
62
+ unsigned char *u1 = (unsigned char*)u;
63
+ char u2 [sizeof(u) * 2 + 1];
64
+
65
+ for (size_t i=0; i < sizeof(u); i++)
66
+ sprintf (u2 + (i * 2), "%02x", u1[i]);
67
+
68
+ seed = string (u2);
69
+ index = 0;
70
+
71
+
72
+ }
73
+
74
+ stringstream ss;
75
+ ss << seed << (++index);
76
+ return ss.str();
77
+ }
78
+
79
+
80
+ /*****************************
81
+ STATIC: Bindable_t::GetObject
82
+ *****************************/
83
+
84
+ Bindable_t *Bindable_t::GetObject (const char *binding)
85
+ {
86
+ string s (binding ? binding : "");
87
+ return GetObject (s);
88
+ }
89
+
90
+ /*****************************
91
+ STATIC: Bindable_t::GetObject
92
+ *****************************/
93
+
94
+ Bindable_t *Bindable_t::GetObject (const string &binding)
95
+ {
96
+ map<string, Bindable_t*>::const_iterator i = BindingBag.find (binding);
97
+ if (i != BindingBag.end())
98
+ return i->second;
99
+ else
100
+ return NULL;
101
+ }
102
+
103
+
104
+ /**********************
105
+ Bindable_t::Bindable_t
106
+ **********************/
107
+
108
+ Bindable_t::Bindable_t()
109
+ {
110
+ Binding = Bindable_t::CreateBinding();
111
+ BindingBag [Binding] = this;
112
+ }
113
+
114
+
115
+
116
+ /***********************
117
+ Bindable_t::~Bindable_t
118
+ ***********************/
119
+
120
+ Bindable_t::~Bindable_t()
121
+ {
122
+ BindingBag.erase (Binding);
123
+ }
124
+
125
+
@@ -0,0 +1,54 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: binder.h 2291 2006-04-14 03:56:18Z francis $
4
+
5
+ File: binder.h
6
+ Date: 07Apr06
7
+
8
+ Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat20
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation; either version 2 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ *****************************************************************************/
26
+
27
+ #ifndef __ObjectBindings__H_
28
+ #define __ObjectBindings__H_
29
+
30
+
31
+ class Bindable_t
32
+ {
33
+ public:
34
+ static string CreateBinding();
35
+ static Bindable_t *GetObject (const string&);
36
+ static Bindable_t *GetObject (const char*);
37
+ static map<string, Bindable_t*> BindingBag;
38
+
39
+ public:
40
+ Bindable_t();
41
+ virtual ~Bindable_t();
42
+
43
+ string GetBinding() {return Binding;}
44
+
45
+ private:
46
+ string Binding;
47
+ };
48
+
49
+
50
+
51
+
52
+
53
+ #endif // __ObjectBindings__H_
54
+
@@ -0,0 +1,528 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: ed.cpp 2291 2006-04-14 03:56:18Z francis $
4
+
5
+ File: ed.cpp
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat20
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation; either version 2 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program; if not, write to the Free Software
23
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+
25
+ *****************************************************************************/
26
+
27
+ #include "project.h"
28
+
29
+
30
+ /****************************************
31
+ EventableDescriptor::EventableDescriptor
32
+ ****************************************/
33
+
34
+ EventableDescriptor::EventableDescriptor (int sd):
35
+ EventCallback (NULL),
36
+ LastRead (0),
37
+ LastWritten (0),
38
+ MySocket (sd),
39
+ bCloseNow (false),
40
+ bCloseAfterWriting (false)
41
+ {
42
+ /* There are three ways to close a socket, all of which should
43
+ * automatically signal to the event machine that this object
44
+ * should be removed from the polling scheduler.
45
+ * First is a hard close, intended for bad errors or possible
46
+ * security violations. It immediately closes the connection
47
+ * and puts this object into an error state.
48
+ * Second is to set bCloseNow, which will cause the event machine
49
+ * to delete this object (and thus close the connection in our
50
+ * destructor) the next chance it gets. bCloseNow also inhibits
51
+ * the writing of new data on the socket (but not necessarily
52
+ * the reading of new data).
53
+ * The third way is to set bCloseAfterWriting, which inhibits
54
+ * the writing of new data and converts to bCloseNow as soon
55
+ * as everything in the outbound queue has been written.
56
+ * bCloseAfterWriting is really for use only by protocol handlers
57
+ * (for example, HTTP writes an HTML page and then closes the
58
+ * connection). All of the error states we generate internally
59
+ * cause an immediate close to be scheduled, which may have the
60
+ * effect of discarding outbound data.
61
+ */
62
+
63
+ if (sd == -1)
64
+ throw std::runtime_error ("bad eventable descriptor");
65
+ CreatedAt = gCurrentLoopTime;
66
+ }
67
+
68
+
69
+ /*****************************************
70
+ EventableDescriptor::~EventableDescriptor
71
+ *****************************************/
72
+
73
+ EventableDescriptor::~EventableDescriptor()
74
+ {
75
+ if (EventCallback)
76
+ (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_UNBOUND, NULL, 0);
77
+ Close();
78
+ }
79
+
80
+
81
+ /*************************************
82
+ EventableDescriptor::SetEventCallback
83
+ *************************************/
84
+
85
+ void EventableDescriptor::SetEventCallback (void(*cb)(const char*, int, const char*, int))
86
+ {
87
+ EventCallback = cb;
88
+ }
89
+
90
+
91
+ /**************************
92
+ EventableDescriptor::Close
93
+ **************************/
94
+
95
+ void EventableDescriptor::Close()
96
+ {
97
+ // Close the socket right now. Intended for emergencies.
98
+ if (MySocket != -1) {
99
+ shutdown (MySocket, 1);
100
+ close (MySocket);
101
+ MySocket = -1;
102
+ }
103
+ }
104
+
105
+
106
+ /*********************************
107
+ EventableDescriptor::ShouldDelete
108
+ *********************************/
109
+
110
+ bool EventableDescriptor::ShouldDelete()
111
+ {
112
+ /* For use by a socket manager, which needs to know if this object
113
+ * should be removed from scheduling events and deleted.
114
+ * Has an immediate close been scheduled, or are we already closed?
115
+ * If either of these are the case, return true. In theory, the manager will
116
+ * then delete us, which in turn will make sure the socket is closed.
117
+ * Note, if bCloseAfterWriting is true, we check a virtual method to see
118
+ * if there is outbound data to write, and only request a close if there is none.
119
+ */
120
+
121
+ return ((MySocket == -1) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
122
+ }
123
+
124
+
125
+ /******************************************
126
+ ConnectionDescriptor::ConnectionDescriptor
127
+ ******************************************/
128
+
129
+ ConnectionDescriptor::ConnectionDescriptor (int sd):
130
+ EventableDescriptor (sd),
131
+ bConnectPending (false),
132
+ OutboundDataSize (0)
133
+ {
134
+ }
135
+
136
+
137
+ /*******************************************
138
+ ConnectionDescriptor::~ConnectionDescriptor
139
+ *******************************************/
140
+
141
+ ConnectionDescriptor::~ConnectionDescriptor()
142
+ {
143
+ // Run down any stranded outbound data.
144
+ for (size_t i=0; i < OutboundPages.size(); i++)
145
+ OutboundPages[i].Free();
146
+ }
147
+
148
+
149
+ /**************************************************
150
+ STATIC: ConnectionDescriptor::SendDataToConnection
151
+ **************************************************/
152
+
153
+ int ConnectionDescriptor::SendDataToConnection (const char *binding, const char *data, int data_length)
154
+ {
155
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
156
+ return cd ? cd->SendOutboundData (data, data_length) : -1;
157
+ }
158
+
159
+
160
+ /*********************************************
161
+ STATIC: ConnectionDescriptor::CloseConnection
162
+ *********************************************/
163
+
164
+ void ConnectionDescriptor::CloseConnection (const char *binding, bool after_writing)
165
+ {
166
+ ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
167
+ if (cd) {
168
+ if (after_writing)
169
+ cd->bCloseAfterWriting = true;
170
+ else
171
+ cd->bCloseNow = true;
172
+ }
173
+ }
174
+
175
+
176
+
177
+ /**************************************
178
+ ConnectionDescriptor::SendOutboundData
179
+ **************************************/
180
+
181
+ int ConnectionDescriptor::SendOutboundData (const char *data, int length)
182
+ {
183
+ // Highly naive and incomplete implementation.
184
+ // There's no throttle for runaways (which should abort only this connection
185
+ // and not the whole process), and no coalescing of small pages.
186
+
187
+ if (bCloseNow || bCloseAfterWriting)
188
+ return 0;
189
+
190
+ if (!data && (length > 0))
191
+ throw std::runtime_error ("bad outbound data");
192
+ char *buffer = (char *) malloc (length + 1);
193
+ if (!buffer)
194
+ throw std::runtime_error ("no allocation for outbound data");
195
+ memcpy (buffer, data, length);
196
+ buffer [length] = 0;
197
+ OutboundPages.push_back (OutboundPage (buffer, length));
198
+ OutboundDataSize += length;
199
+ return length;
200
+ }
201
+
202
+
203
+
204
+ /***********************************
205
+ ConnectionDescriptor::SelectForRead
206
+ ***********************************/
207
+
208
+ bool ConnectionDescriptor::SelectForRead()
209
+ {
210
+ /* A connection descriptor is always scheduled for read,
211
+ * UNLESS it's in a pending-connect state.
212
+ * On Linux, unlike Unix, a nonblocking socket on which
213
+ * connect has been called, does NOT necessarily select
214
+ * both readable and writable in case of error.
215
+ * The socket will select writable when the disposition
216
+ * of the connect is known. On the other hand, a socket
217
+ * which successfully connects and selects writable may
218
+ * indeed have some data available on it, so it will
219
+ * select readable in that case, violating expectations!
220
+ * So we will not poll for readability until the socket
221
+ * is known to be in a connected state.
222
+ */
223
+
224
+ return bConnectPending ? false : true;
225
+ }
226
+
227
+
228
+ /************************************
229
+ ConnectionDescriptor::SelectForWrite
230
+ ************************************/
231
+
232
+ bool ConnectionDescriptor::SelectForWrite()
233
+ {
234
+ /* Cf the notes under SelectForRead.
235
+ * In a pending-connect state, we ALWAYS select for writable.
236
+ * In a normal state, we only select for writable when we
237
+ * have outgoing data to send.
238
+ */
239
+
240
+ if (bConnectPending)
241
+ return true;
242
+ else {
243
+ return (GetOutboundDataSize() > 0);
244
+ }
245
+ }
246
+
247
+
248
+ /**************************
249
+ ConnectionDescriptor::Read
250
+ **************************/
251
+
252
+ void ConnectionDescriptor::Read()
253
+ {
254
+ /* Read and dispatch data on a socket that has selected readable.
255
+ * It's theoretically possible to get and dispatch incoming data on
256
+ * a socket that has already been scheduled for closing or close-after-writing.
257
+ * In those cases, we'll leave it up the to protocol handler to "do the
258
+ * right thing" (which probably means to ignore the incoming data).
259
+ */
260
+
261
+ int sd = GetSocket();
262
+ assert (sd != -1);
263
+
264
+ int total_bytes_read = 0;
265
+ char readbuffer [16 * 1024];
266
+
267
+ for (int i=0; i < 10; i++) {
268
+ // Don't read just one buffer and then move on. This is faster
269
+ // if there is a lot of incoming.
270
+ // But don't read indefinitely. Give other sockets a chance to run.
271
+
272
+ int r = recv (sd, readbuffer, sizeof(readbuffer) - 1, 0);
273
+ //cerr << "<R:" << r << ">";
274
+
275
+ if (r > 0) {
276
+ total_bytes_read += r;
277
+ LastRead = gCurrentLoopTime;
278
+
279
+ readbuffer [r] = 0; // Impute a null-terminator, just for convenience.
280
+
281
+ if (EventCallback)
282
+ (*EventCallback)(GetBinding().c_str(), EventMachine_t::CONNECTION_READ, readbuffer, r);
283
+
284
+ }
285
+ else if (r == 0) {
286
+ break;
287
+ }
288
+ else {
289
+ // Basically a would-block, meaning we've everything there is to read.
290
+ break;
291
+ }
292
+
293
+ }
294
+
295
+
296
+ if (total_bytes_read == 0) {
297
+ // If we read no data on a socket that selected readable,
298
+ // it generally means the other end closed the connection gracefully.
299
+ bCloseNow = true;
300
+ }
301
+
302
+ }
303
+
304
+
305
+ /***************************
306
+ ConnectionDescriptor::Write
307
+ ***************************/
308
+
309
+ void ConnectionDescriptor::Write()
310
+ {
311
+ /* A socket which is in a pending-connect state will select
312
+ * writable when the disposition of the connect is known.
313
+ * At that point, check to be sure there are no errors,
314
+ * and if none, then promote the socket out of the pending
315
+ * state.
316
+ */
317
+
318
+ if (bConnectPending) {
319
+ int error;
320
+ socklen_t len;
321
+ len = sizeof(error);
322
+ int o = getsockopt (MySocket, SOL_SOCKET, SO_ERROR, &error, &len);
323
+ if ((o == 0) && (error == 0))
324
+ bConnectPending = false;
325
+ else
326
+ bCloseNow = true;
327
+ }
328
+ else {
329
+ _WriteOutboundData();
330
+ }
331
+ }
332
+
333
+
334
+ /****************************************
335
+ ConnectionDescriptor::_WriteOutboundData
336
+ ****************************************/
337
+
338
+ void ConnectionDescriptor::_WriteOutboundData()
339
+ {
340
+ /* This is a helper function called by ::Write.
341
+ * It's possible for a socket to select writable and then no longer
342
+ * be writable by the time we get around to writing. The kernel might
343
+ * have used up its available output buffers between the select call
344
+ * and when we get here. So this condition is not an error.
345
+ */
346
+
347
+ int sd = GetSocket();
348
+ assert (sd != -1);
349
+
350
+ char output_buffer [16 * 1024];
351
+ size_t nbytes = 0;
352
+
353
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
354
+ OutboundPage *op = &(OutboundPages[0]);
355
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
356
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
357
+ nbytes += (op->Length - op->Offset);
358
+ op->Free();
359
+ OutboundPages.pop_front();
360
+ }
361
+ else {
362
+ int len = sizeof(output_buffer) - nbytes;
363
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
364
+ op->Offset += len;
365
+ nbytes += len;
366
+ }
367
+ }
368
+
369
+ // We should never have gotten here if there were no data to write,
370
+ // so assert that as a sanity check.
371
+ // Don't bother to make sure nbytes is less than output_buffer because
372
+ // if it were we probably would have crashed already.
373
+ assert (nbytes > 0);
374
+
375
+ assert (GetSocket() != -1);
376
+ int bytes_written = send (GetSocket(), output_buffer, nbytes, 0);
377
+
378
+ if (bytes_written > 0) {
379
+ OutboundDataSize -= bytes_written;
380
+ if ((size_t)bytes_written < nbytes) {
381
+ int len = nbytes - bytes_written;
382
+ char *buffer = (char*) malloc (len + 1);
383
+ if (!buffer)
384
+ throw std::runtime_error ("bad alloc throwing back data");
385
+ memcpy (buffer, output_buffer + bytes_written, len);
386
+ buffer [len] = 0;
387
+ OutboundPages.push_front (OutboundPage (buffer, len));
388
+ }
389
+ }
390
+ else {
391
+ if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
392
+ Close();
393
+ }
394
+ }
395
+
396
+
397
+
398
+ /*******************************
399
+ ConnectionDescriptor::Heartbeat
400
+ *******************************/
401
+
402
+ void ConnectionDescriptor::Heartbeat()
403
+ {
404
+ /* Only allow a certain amount of time to go by while waiting
405
+ * for a pending connect. If it expires, then kill the socket.
406
+ */
407
+
408
+ if (bConnectPending) {
409
+ if ((gCurrentLoopTime - CreatedAt) >= PendingConnectTimeout)
410
+ bCloseNow = true;
411
+ }
412
+ }
413
+
414
+
415
+ /**************************************
416
+ AcceptorDescriptor::AcceptorDescriptor
417
+ **************************************/
418
+
419
+ AcceptorDescriptor::AcceptorDescriptor (EventMachine_t *parent_em, int sd):
420
+ EventableDescriptor (sd),
421
+ MyEventMachine (parent_em)
422
+ {
423
+ /* This is really bad and ugly. Change someday if possible.
424
+ * We have to know about an event-machine (probably the one that owns us),
425
+ * so we can pass newly-created connections to it.
426
+ */
427
+
428
+ if (!MyEventMachine)
429
+ throw std::runtime_error ("bad event-machine passed to acceptor");
430
+ }
431
+
432
+
433
+ /***************************************
434
+ AcceptorDescriptor::~AcceptorDescriptor
435
+ ***************************************/
436
+
437
+ AcceptorDescriptor::~AcceptorDescriptor()
438
+ {
439
+ }
440
+
441
+
442
+ /************************
443
+ AcceptorDescriptor::Read
444
+ ************************/
445
+
446
+ void AcceptorDescriptor::Read()
447
+ {
448
+ /* Accept up to a certain number of sockets on the listening connection.
449
+ * Don't try to accept all that are present, because this would allow a DoS attack
450
+ * in which no data were ever read or written. We should accept more than one,
451
+ * if available, to keep the partially accepted sockets from backing up in the kernel.
452
+ */
453
+
454
+ /* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
455
+ * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
456
+ * and then block when we call accept. For example, the other end resets the connection after
457
+ * the socket selects readable and before we call accept. The kernel will remove the dead
458
+ * socket from the accept queue. If the accept queue is now empty, accept will block.
459
+ */
460
+
461
+
462
+ struct sockaddr_in pin;
463
+ socklen_t addrlen = sizeof (pin);
464
+
465
+ for (int i=0; i < 10; i++) {
466
+ int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
467
+ if (sd == -1) {
468
+ // This breaks the loop when we've accepted everything on the kernel queue,
469
+ // up to 10 new connections. But what if the *first* accept fails?
470
+ // Does that mean anything serious is happening, beyond the situation
471
+ // described in the note above?
472
+ break;
473
+ }
474
+
475
+ // Set the newly-accepted socket non-blocking.
476
+ // On Windows, this may fail because, weirdly, Windows inherits the non-blocking
477
+ // attribute that we applied to the acceptor socket into the accepted one.
478
+ int val = fcntl (sd, F_GETFL, 0);
479
+ if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
480
+ shutdown (sd, 1);
481
+ close (sd);
482
+ continue;
483
+ }
484
+
485
+
486
+ // Disable slow-start (Nagle algorithm). Eventually make this configurable.
487
+ int one = 1;
488
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof(one));
489
+
490
+
491
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
492
+ if (!cd)
493
+ throw std::runtime_error ("no newly accepted connection");
494
+ if (EventCallback) {
495
+ (*EventCallback) (GetBinding().c_str(), EventMachine_t::CONNECTION_ACCEPTED, cd->GetBinding().c_str(), cd->GetBinding().size());
496
+ }
497
+ assert (MyEventMachine);
498
+ MyEventMachine->Add (cd);
499
+ }
500
+
501
+ }
502
+
503
+
504
+ /*************************
505
+ AcceptorDescriptor::Write
506
+ *************************/
507
+
508
+ void AcceptorDescriptor::Write()
509
+ {
510
+ // Why are we here?
511
+ throw std::runtime_error ("bad code path in acceptor");
512
+ }
513
+
514
+
515
+ /*****************************
516
+ AcceptorDescriptor::Heartbeat
517
+ *****************************/
518
+
519
+ void AcceptorDescriptor::Heartbeat()
520
+ {
521
+ // No-op
522
+ }
523
+
524
+
525
+
526
+
527
+
528
+