eventmachine 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
@@ -0,0 +1,152 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: ed.h 2291 2006-04-14 03:56:18Z francis $
4
+
5
+ File: ed.h
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
+ #ifndef __EventableDescriptor__H_
28
+ #define __EventableDescriptor__H_
29
+
30
+
31
+ class EventMachine_t; // forward reference
32
+
33
+
34
+ /*************************
35
+ class EventableDescriptor
36
+ *************************/
37
+
38
+ class EventableDescriptor: public Bindable_t
39
+ {
40
+ public:
41
+ EventableDescriptor (int);
42
+ virtual ~EventableDescriptor();
43
+
44
+ int GetSocket() {return MySocket;}
45
+ void Close();
46
+
47
+ virtual void Read() = 0;
48
+ virtual void Write() = 0;
49
+ virtual void Heartbeat() = 0;
50
+
51
+ // These methods tell us whether the descriptor
52
+ // should be selected or polled for read/write.
53
+ virtual bool SelectForRead() = 0;
54
+ virtual bool SelectForWrite() = 0;
55
+
56
+ // are we scheduled for a close, or in an error state, or already closed?
57
+ bool ShouldDelete();
58
+ // Do we have any data to write? This is used by ShouldDelete.
59
+ virtual int GetOutboundDataSize() {return 0;}
60
+
61
+ void SetEventCallback (void (*cb)(const char*, int, const char*, int));
62
+
63
+ protected:
64
+ enum {
65
+ PendingConnectTimeout = 4 // can easily be made an instance variable
66
+ };
67
+
68
+ void (*EventCallback)(const char*, int, const char*, int);
69
+
70
+ time_t CreatedAt;
71
+ time_t LastRead;
72
+ time_t LastWritten;
73
+ int MySocket;
74
+ bool bCloseNow;
75
+ bool bCloseAfterWriting;
76
+ };
77
+
78
+
79
+
80
+ /**************************
81
+ class ConnectionDescriptor
82
+ **************************/
83
+
84
+ class ConnectionDescriptor: public EventableDescriptor
85
+ {
86
+ public:
87
+ ConnectionDescriptor (int);
88
+ virtual ~ConnectionDescriptor();
89
+
90
+ static int SendDataToConnection (const char*, const char*, int);
91
+ static void CloseConnection (const char*, bool);
92
+
93
+ int SendOutboundData (const char*, int);
94
+
95
+ void SetConnectPending (bool f) { bConnectPending = f; }
96
+
97
+ virtual void Read();
98
+ virtual void Write();
99
+ virtual void Heartbeat();
100
+
101
+ virtual bool SelectForRead();
102
+ virtual bool SelectForWrite();
103
+
104
+ // Do we have any data to write? This is used by ShouldDelete.
105
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
106
+
107
+ protected:
108
+ struct OutboundPage {
109
+ OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
110
+ void Free() {if (Buffer) free ((char*)Buffer); }
111
+ const char *Buffer;
112
+ int Length;
113
+ int Offset;
114
+ };
115
+
116
+ protected:
117
+ bool bConnectPending;
118
+
119
+ deque<OutboundPage> OutboundPages;
120
+ int OutboundDataSize;
121
+
122
+ private:
123
+ void _WriteOutboundData();
124
+ };
125
+
126
+
127
+ /************************
128
+ class AcceptorDescriptor
129
+ ************************/
130
+
131
+ class AcceptorDescriptor: public EventableDescriptor
132
+ {
133
+ public:
134
+ AcceptorDescriptor (EventMachine_t*, int);
135
+ virtual ~AcceptorDescriptor();
136
+
137
+ virtual void Read();
138
+ virtual void Write();
139
+ virtual void Heartbeat();
140
+
141
+ virtual bool SelectForRead() {return true;}
142
+ virtual bool SelectForWrite() {return false;}
143
+
144
+ protected:
145
+ EventMachine_t *MyEventMachine;
146
+ };
147
+
148
+
149
+
150
+ #endif // __EventableDescriptor__H_
151
+
152
+
@@ -0,0 +1,475 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: em.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
+ // Keep a global variable floating around
30
+ // with the current loop time as set by the Event Machine.
31
+ // This avoids the need for frequent expensive calls to time(NULL);
32
+ time_t gCurrentLoopTime;
33
+
34
+
35
+ /******************************
36
+ EventMachine_t::EventMachine_t
37
+ ******************************/
38
+
39
+ EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)):
40
+ EventCallback (event_callback),
41
+ NextHeartbeatTime (0)
42
+ {
43
+ gTerminateSignalReceived = false;
44
+ }
45
+
46
+
47
+ /*******************************
48
+ EventMachine_t::~EventMachine_t
49
+ *******************************/
50
+
51
+ EventMachine_t::~EventMachine_t()
52
+ {
53
+ // Run down descriptors
54
+ size_t i;
55
+ for (i = 0; i < NewDescriptors.size(); i++)
56
+ delete NewDescriptors[i];
57
+ for (i = 0; i < Descriptors.size(); i++)
58
+ delete Descriptors[i];
59
+ }
60
+
61
+
62
+
63
+ /****************************
64
+ EventMachine_t::ScheduleHalt
65
+ ****************************/
66
+
67
+ void EventMachine_t::ScheduleHalt()
68
+ {
69
+ /* This is how we stop the machine.
70
+ * This can be called by clients. Signal handlers will probably
71
+ * set the global flag.
72
+ * For now this means there can only be one EventMachine ever running at a time.
73
+ */
74
+ gTerminateSignalReceived = true;
75
+ }
76
+
77
+
78
+
79
+ /*******************
80
+ EventMachine_t::Run
81
+ *******************/
82
+
83
+ void EventMachine_t::Run()
84
+ {
85
+ while (true) {
86
+ gCurrentLoopTime = time(NULL);
87
+ if (!_RunTimers())
88
+ break;
89
+ _AddNewDescriptors();
90
+ if (!_RunOnce())
91
+ break;
92
+ if (gTerminateSignalReceived)
93
+ break;
94
+ }
95
+ }
96
+
97
+
98
+
99
+ /************************
100
+ EventMachine_t::_RunOnce
101
+ ************************/
102
+
103
+ bool EventMachine_t::_RunOnce()
104
+ {
105
+ // Crank the event machine once.
106
+ // If there are no descriptors to process, then sleep
107
+ // for a few hundred mills to avoid busy-looping.
108
+ // Return T/F to indicate whether we should continue.
109
+ // This is based on a select loop. Alternately provide epoll
110
+ // if we know we're running on a 2.6 kernel.
111
+
112
+ //cerr << "X";
113
+ if (Descriptors.size() == 0) {
114
+ timeval tv = {0, 200 * 1000};
115
+ select (0, NULL, NULL, NULL, &tv);
116
+ return true;
117
+ }
118
+
119
+ fd_set fdreads, fdwrites;
120
+ FD_ZERO (&fdreads);
121
+ FD_ZERO (&fdwrites);
122
+
123
+ int maxsocket = 0;
124
+
125
+ // prepare the sockets for reading and writing
126
+ size_t i;
127
+ for (i = 0; i < Descriptors.size(); i++) {
128
+ EventableDescriptor *ed = Descriptors[i];
129
+ assert (ed);
130
+ int sd = ed->GetSocket();
131
+ assert (sd != -1);
132
+
133
+ if (ed->SelectForRead())
134
+ FD_SET (sd, &fdreads);
135
+ if (ed->SelectForWrite())
136
+ FD_SET (sd, &fdwrites);
137
+
138
+ if (maxsocket < sd)
139
+ maxsocket = sd;
140
+ }
141
+
142
+
143
+ { // read and write the sockets
144
+ timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
145
+ int s = select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
146
+ if (s > 0) {
147
+ for (i=0; i < Descriptors.size(); i++) {
148
+ EventableDescriptor *ed = Descriptors[i];
149
+ assert (ed);
150
+ int sd = ed->GetSocket();
151
+ assert (sd != -1);
152
+
153
+ if (FD_ISSET (sd, &fdwrites))
154
+ ed->Write();
155
+ if (FD_ISSET (sd, &fdreads))
156
+ ed->Read();
157
+ }
158
+ }
159
+ else if (s < 0) {
160
+ // select can fail on error in a handful of ways.
161
+ // If this happens, then wait for a little while to avoid busy-looping.
162
+ // If the error was EINTR, we probaby caught SIGCHLD or something,
163
+ // so keep the wait short.
164
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
165
+ select (0, NULL, NULL, NULL, &tv);
166
+ }
167
+ }
168
+
169
+
170
+ { // dispatch heartbeats
171
+ if (gCurrentLoopTime >= NextHeartbeatTime) {
172
+ NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
173
+
174
+ for (i=0; i < Descriptors.size(); i++) {
175
+ EventableDescriptor *ed = Descriptors[i];
176
+ assert (ed);
177
+ ed->Heartbeat();
178
+ }
179
+ }
180
+ }
181
+
182
+ { // cleanup dying sockets
183
+ // vector::pop_back works in constant time.
184
+ int i, j;
185
+ int nSockets = Descriptors.size();
186
+ for (i=0, j=0; i < nSockets; i++) {
187
+ EventableDescriptor *ed = Descriptors[i];
188
+ assert (ed);
189
+ if (ed->ShouldDelete())
190
+ delete ed;
191
+ else
192
+ Descriptors [j++] = ed;
193
+ }
194
+ while ((size_t)j < Descriptors.size())
195
+ Descriptors.pop_back();
196
+
197
+ }
198
+
199
+ return true;
200
+ }
201
+
202
+
203
+ /**************************
204
+ EventMachine_t::_RunTimers
205
+ **************************/
206
+
207
+ bool EventMachine_t::_RunTimers()
208
+ {
209
+ // These are caller-defined timer handlers.
210
+ // Return T/F to indicate whether we should continue the main loop.
211
+ // We rely on the fact that multimaps sort by their keys to avoid
212
+ // inspecting the whole list every time we come here.
213
+ // Just keep inspecting and processing the list head until we hit
214
+ // one that hasn't expired yet.
215
+
216
+ while (true) {
217
+ multimap<time_t,Timer_t>::iterator i = Timers.begin();
218
+ if (i == Timers.end())
219
+ break;
220
+ if (i->first > gCurrentLoopTime)
221
+ break;
222
+ if (EventCallback)
223
+ (*EventCallback) ("", TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
224
+ Timers.erase (i);
225
+ }
226
+ return true;
227
+ }
228
+
229
+
230
+
231
+ /***********************************
232
+ EventMachine_t::InstallOneshotTimer
233
+ ***********************************/
234
+
235
+ const char *EventMachine_t::InstallOneshotTimer (int seconds)
236
+ {
237
+ if (Timers.size() > MaxOutstandingTimers)
238
+ return false;
239
+ // Don't use the global loop-time variable here, because we might
240
+ // get called before the main event machine is running.
241
+
242
+ Timer_t t;
243
+ Timers.insert (make_pair (time(NULL) + seconds, t));
244
+ return t.GetBinding().c_str();
245
+ }
246
+
247
+
248
+ /*******************************
249
+ EventMachine_t::ConnectToServer
250
+ *******************************/
251
+
252
+ const char *EventMachine_t::ConnectToServer (const char *server, int port)
253
+ {
254
+ /* We want to spend no more than a few seconds waiting for a connection
255
+ * to a remote host. So we use a nonblocking connect.
256
+ * Linux disobeys the usual rules for nonblocking connects.
257
+ * Per Stevens (UNP p.410), you expect a nonblocking connect to select
258
+ * both readable and writable on error, and not to return EINPROGRESS
259
+ * if the connect can be fulfilled immediately. Linux violates both
260
+ * of these expectations.
261
+ * Any kind of nonblocking connect on Linux returns EINPROGRESS.
262
+ * The socket will then return writable when the disposition of the
263
+ * connect is known, but it will not also be readable in case of
264
+ * error! Weirdly, it will be readable in case there is data to read!!!
265
+ * (Which can happen with protocols like SSH and SMTP.)
266
+ * I suppose if you were so inclined you could consider this logical,
267
+ * but it's not the way Unix has historically done it.
268
+ * So we ignore the readable flag and read getsockopt to see if there
269
+ * was an error connecting. A select timeout works as expected.
270
+ * In regard to getsockopt: Linux does the Berkeley-style thing,
271
+ * not the Solaris-style, and returns zero with the error code in
272
+ * the error parameter.
273
+ * Return the binding-text of the newly-created pending connection,
274
+ * or NULL if there was a problem.
275
+ */
276
+
277
+ if (!server || !*server || !port)
278
+ return NULL;
279
+
280
+ sockaddr_in pin;
281
+ unsigned long HostAddr;
282
+
283
+ HostAddr = inet_addr (server);
284
+ if (HostAddr == -1) {
285
+ hostent *hp = gethostbyname (server);
286
+ if (!hp)
287
+ return NULL;
288
+ HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
289
+ }
290
+
291
+ memset (&pin, 0, sizeof(pin));
292
+ pin.sin_family = AF_INET;
293
+ pin.sin_addr.s_addr = HostAddr;
294
+ pin.sin_port = htons (port);
295
+
296
+ int sd = socket (AF_INET, SOCK_STREAM, 0);
297
+ if (sd == -1)
298
+ return NULL;
299
+
300
+ // From here on, ALL error returns must close the socket.
301
+ // Set the new socket nonblocking.
302
+ int val = fcntl (sd, F_GETFL, 0);
303
+ if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
304
+ close (sd);
305
+ return NULL;
306
+ }
307
+
308
+ const char *out = NULL;
309
+ if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
310
+ // This is a connect success, which Linux appears
311
+ // never to give when the socket is nonblocking,
312
+ // even if the connection is intramachine or to
313
+ // localhost.
314
+ throw std::runtime_error ("unimplemented");
315
+ }
316
+ else if (errno == EINPROGRESS) {
317
+ // Errno will generally always be EINPROGRESS, but on Linux
318
+ // we have to look at getsockopt to be sure what really happened.
319
+ int error;
320
+ socklen_t len;
321
+ len = sizeof(error);
322
+ int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
323
+ if ((o == 0) && (error == 0)) {
324
+ // Here, there's no disposition.
325
+ // Put the connection on the stack and wait for it to complete
326
+ // or time out.
327
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
328
+ if (!cd)
329
+ throw std::runtime_error ("no connection allocated");
330
+ cd->SetConnectPending (true);
331
+ Add (cd);
332
+ out = cd->GetBinding().c_str();
333
+ }
334
+ else {
335
+ // This could be connection refused or something such thing.
336
+ }
337
+ }
338
+ else {
339
+ // The error from connect was something other then EINPROGRESS.
340
+ }
341
+
342
+ if (out == NULL)
343
+ close (sd);
344
+ return out;
345
+ }
346
+
347
+
348
+ /*******************************
349
+ EventMachine_t::CreateTcpServer
350
+ *******************************/
351
+
352
+ const char *EventMachine_t::CreateTcpServer (const char *server, int port)
353
+ {
354
+ /* Create a TCP-acceptor (server) socket and add it to the event machine.
355
+ * Return the binding of the new acceptor to the caller.
356
+ * This binding will be referenced when the new acceptor sends events
357
+ * to indicate accepted connections.
358
+ */
359
+
360
+ const char *output_binding = NULL;
361
+
362
+ struct sockaddr_in sin;
363
+
364
+ int sd_accept = socket (AF_INET, SOCK_STREAM, 0);
365
+ if (sd_accept == -1) {
366
+ goto fail;
367
+ }
368
+
369
+ memset (&sin, 0, sizeof(sin));
370
+ sin.sin_family = AF_INET;
371
+ sin.sin_addr.s_addr = INADDR_ANY;
372
+ sin.sin_port = htons (port);
373
+
374
+ if (server && *server) {
375
+ sin.sin_addr.s_addr = inet_addr (server);
376
+ if (sin.sin_addr.s_addr == -1) {
377
+ hostent *hp = gethostbyname (server);
378
+ if (hp == NULL) {
379
+ //__warning ("hostname not resolved: ", server);
380
+ goto fail;
381
+ }
382
+ sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
383
+ }
384
+ }
385
+
386
+ { // set reuseaddr to improve performance on restarts.
387
+ int oval = 1;
388
+ if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) {
389
+ //__warning ("setsockopt failed while creating listener","");
390
+ goto fail;
391
+ }
392
+ }
393
+
394
+ { // set CLOEXEC.
395
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
396
+ assert (cloexec >= 0);
397
+ cloexec |= FD_CLOEXEC;
398
+ fcntl (sd_accept, F_SETFD, cloexec);
399
+ }
400
+
401
+
402
+ if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
403
+ //__warning ("binding failed");
404
+ goto fail;
405
+ }
406
+
407
+ if (listen (sd_accept, 100)) {
408
+ //__warning ("listen failed");
409
+ goto fail;
410
+ }
411
+
412
+ {
413
+ // Set the acceptor non-blocking.
414
+ // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
415
+ int val = fcntl (sd_accept, F_GETFL, 0);
416
+ if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
417
+ goto fail;
418
+ }
419
+ }
420
+
421
+ { // Looking good.
422
+ AcceptorDescriptor *ad = new AcceptorDescriptor (this, sd_accept);
423
+ if (!ad)
424
+ throw std::runtime_error ("unable to allocate acceptor");
425
+ Add (ad);
426
+ output_binding = ad->GetBinding().c_str();
427
+ }
428
+
429
+ return output_binding;
430
+
431
+ fail:
432
+ if (sd_accept != -1)
433
+ close (sd_accept);
434
+ return NULL;
435
+ }
436
+
437
+
438
+
439
+
440
+ /*******************
441
+ EventMachine_t::Add
442
+ *******************/
443
+
444
+ void EventMachine_t::Add (EventableDescriptor *ed)
445
+ {
446
+ if (!ed)
447
+ throw std::runtime_error ("added bad descriptor");
448
+ ed->SetEventCallback (EventCallback);
449
+ NewDescriptors.push_back (ed);
450
+ }
451
+
452
+
453
+ /**********************************
454
+ EventMachine_t::_AddNewDescriptors
455
+ **********************************/
456
+
457
+ void EventMachine_t::_AddNewDescriptors()
458
+ {
459
+ /* Avoid adding descriptors to the main descriptor list
460
+ * while we're actually traversing the list.
461
+ * Any descriptors that are added as a result of processing timers
462
+ * or acceptors should go on a temporary queue and then added
463
+ * while we're not traversing the main list.
464
+ */
465
+
466
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
467
+ EventableDescriptor *ed = NewDescriptors[i];
468
+ if (ed == NULL)
469
+ throw std::runtime_error ("adding bad descriptor");
470
+ Descriptors.push_back (ed);
471
+ }
472
+ NewDescriptors.clear();
473
+ }
474
+
475
+