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
@@ -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
+