eventmachine 0.5.3 → 0.7.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.
- data/RELEASE_NOTES +14 -1
- data/TODO +10 -0
- data/ext/cmain.cpp +100 -4
- data/ext/ed.cpp +228 -44
- data/ext/ed.h +25 -2
- data/ext/em.cpp +351 -14
- data/ext/em.h +33 -8
- data/ext/emwin.h +4 -2
- data/ext/eventmachine.h +9 -1
- data/ext/files.cpp +101 -0
- data/ext/files.h +72 -0
- data/ext/project.h +3 -1
- data/ext/rubymain.cpp +113 -5
- data/lib/em/deferrable.rb +89 -0
- data/lib/em/eventable.rb +50 -0
- data/lib/eventmachine.rb +274 -9
- data/lib/eventmachine_version.rb +42 -0
- data/lib/evma/callback.rb +35 -0
- data/lib/evma/container.rb +77 -0
- data/lib/evma/factory.rb +80 -0
- data/lib/evma/protocol.rb +89 -0
- data/lib/evma/reactor.rb +50 -0
- data/lib/evma.rb +35 -0
- data/lib/pr_eventmachine.rb +714 -0
- data/lib/protocols/header_and_content.rb +134 -0
- data/lib/protocols/httpclient.rb +233 -0
- data/lib/protocols/line_and_text.rb +141 -0
- data/lib/protocols/tcptest.rb +67 -0
- data/tests/test_basic.rb +106 -0
- data/tests/test_eventables.rb +85 -0
- data/tests/test_hc.rb +207 -0
- data/tests/test_httpclient.rb +94 -0
- data/tests/test_ltp.rb +192 -0
- data/tests/test_ud.rb +52 -0
- metadata +44 -18
- data/ext/Makefile +0 -139
- data/ext/mkmf.log +0 -59
data/ext/em.cpp
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: em.cpp
|
3
|
+
$Id: em.cpp 267 2006-10-25 02:02:02Z blackhedd $
|
4
4
|
|
5
5
|
File: ed.cpp
|
6
6
|
Date: 06Apr06
|
@@ -35,6 +35,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
35
35
|
// This avoids the need for frequent expensive calls to time(NULL);
|
36
36
|
time_t gCurrentLoopTime;
|
37
37
|
|
38
|
+
#ifdef OS_WIN32
|
39
|
+
unsigned gTickCountTickover;
|
40
|
+
unsigned gLastTickCount;
|
41
|
+
#endif
|
42
|
+
|
38
43
|
|
39
44
|
/******************************
|
40
45
|
EventMachine_t::EventMachine_t
|
@@ -42,9 +47,20 @@ EventMachine_t::EventMachine_t
|
|
42
47
|
|
43
48
|
EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)):
|
44
49
|
EventCallback (event_callback),
|
45
|
-
NextHeartbeatTime (0)
|
50
|
+
NextHeartbeatTime (0),
|
51
|
+
LoopBreakerReader (-1),
|
52
|
+
LoopBreakerWriter (-1)
|
46
53
|
{
|
54
|
+
// Default time-slice is just smaller than one hundred mills.
|
55
|
+
Quantum.tv_sec = 0;
|
56
|
+
Quantum.tv_usec = 90000;
|
57
|
+
|
47
58
|
gTerminateSignalReceived = false;
|
59
|
+
// Make sure the current loop time is sane, in case we do any initializations of
|
60
|
+
// objects before we start running.
|
61
|
+
gCurrentLoopTime = time(NULL);
|
62
|
+
|
63
|
+
_InitializeLoopBreaker();
|
48
64
|
}
|
49
65
|
|
50
66
|
|
@@ -60,6 +76,9 @@ EventMachine_t::~EventMachine_t()
|
|
60
76
|
delete NewDescriptors[i];
|
61
77
|
for (i = 0; i < Descriptors.size(); i++)
|
62
78
|
delete Descriptors[i];
|
79
|
+
|
80
|
+
close (LoopBreakerReader);
|
81
|
+
close (LoopBreakerWriter);
|
63
82
|
}
|
64
83
|
|
65
84
|
|
@@ -74,12 +93,103 @@ void EventMachine_t::ScheduleHalt()
|
|
74
93
|
* This can be called by clients. Signal handlers will probably
|
75
94
|
* set the global flag.
|
76
95
|
* For now this means there can only be one EventMachine ever running at a time.
|
96
|
+
*
|
97
|
+
* IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
|
98
|
+
* because it may be called from signal handlers invoked from code that we don't
|
99
|
+
* control. At this writing (20Sep06), EM does NOT install any signal handlers of
|
100
|
+
* its own.
|
101
|
+
*
|
102
|
+
* We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
|
103
|
+
* The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
|
77
104
|
*/
|
78
105
|
gTerminateSignalReceived = true;
|
79
106
|
}
|
80
107
|
|
81
108
|
|
82
109
|
|
110
|
+
/*******************************
|
111
|
+
EventMachine_t::SetTimerQuantum
|
112
|
+
*******************************/
|
113
|
+
|
114
|
+
void EventMachine_t::SetTimerQuantum (int interval)
|
115
|
+
{
|
116
|
+
/* We get a timer-quantum expressed in milliseconds.
|
117
|
+
* Don't set a quantum smaller than 5 or larger than 2500.
|
118
|
+
*/
|
119
|
+
|
120
|
+
if ((interval < 5) || (interval > 2500))
|
121
|
+
throw std::runtime_error ("invalid timer-quantum");
|
122
|
+
|
123
|
+
Quantum.tv_sec = interval / 1000;
|
124
|
+
Quantum.tv_usec = (interval % 1000) * 1000;
|
125
|
+
}
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
/*********************************
|
130
|
+
EventMachine_t::SignalLoopBreaker
|
131
|
+
*********************************/
|
132
|
+
|
133
|
+
void EventMachine_t::SignalLoopBreaker()
|
134
|
+
{
|
135
|
+
#ifdef OS_UNIX
|
136
|
+
write (LoopBreakerWriter, "", 1);
|
137
|
+
#endif
|
138
|
+
#ifdef OS_WIN32
|
139
|
+
sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
|
140
|
+
#endif
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
/**************************************
|
145
|
+
EventMachine_t::_InitializeLoopBreaker
|
146
|
+
**************************************/
|
147
|
+
|
148
|
+
void EventMachine_t::_InitializeLoopBreaker()
|
149
|
+
{
|
150
|
+
/* A "loop-breaker" is a socket-descriptor that we can write to in order
|
151
|
+
* to break the main select loop. Primarily useful for things running on
|
152
|
+
* threads other than the main EM thread, so they can trigger processing
|
153
|
+
* of events that arise exogenously to the EM.
|
154
|
+
* Keep the loop-breaker pipe out of the main descriptor set, otherwise
|
155
|
+
* its events will get passed on to user code.
|
156
|
+
*/
|
157
|
+
|
158
|
+
#ifdef OS_UNIX
|
159
|
+
int fd[2];
|
160
|
+
if (pipe (fd))
|
161
|
+
throw std::runtime_error ("no loop breaker");
|
162
|
+
|
163
|
+
LoopBreakerWriter = fd[1];
|
164
|
+
LoopBreakerReader = fd[0];
|
165
|
+
#endif
|
166
|
+
|
167
|
+
#ifdef OS_WIN32
|
168
|
+
int sd = socket (AF_INET, SOCK_DGRAM, 0);
|
169
|
+
if (sd == INVALID_SOCKET)
|
170
|
+
throw std::runtime_error ("no loop breaker socket");
|
171
|
+
SetSocketNonblocking (sd);
|
172
|
+
|
173
|
+
memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget));
|
174
|
+
LoopBreakerTarget.sin_family = AF_INET;
|
175
|
+
LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1");
|
176
|
+
|
177
|
+
srand ((int)time(NULL));
|
178
|
+
int i;
|
179
|
+
for (i=0; i < 100; i++) {
|
180
|
+
int r = (rand() % 10000) + 20000;
|
181
|
+
LoopBreakerTarget.sin_port = htons (r);
|
182
|
+
if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0)
|
183
|
+
break;
|
184
|
+
}
|
185
|
+
|
186
|
+
if (i == 100)
|
187
|
+
throw std::runtime_error ("no loop breaker");
|
188
|
+
LoopBreakerReader = sd;
|
189
|
+
#endif
|
190
|
+
}
|
191
|
+
|
192
|
+
|
83
193
|
/*******************
|
84
194
|
EventMachine_t::Run
|
85
195
|
*******************/
|
@@ -122,18 +232,28 @@ bool EventMachine_t::_RunOnce()
|
|
122
232
|
// Return T/F to indicate whether we should continue.
|
123
233
|
// This is based on a select loop. Alternately provide epoll
|
124
234
|
// if we know we're running on a 2.6 kernel.
|
235
|
+
// epoll will be effective if we provide it as an alternative,
|
236
|
+
// however it has the same problem interoperating with Ruby
|
237
|
+
// threads that selct does.
|
125
238
|
|
126
239
|
//cerr << "X";
|
240
|
+
|
241
|
+
/* This protection is now obsolete, because we will ALWAYS
|
242
|
+
* have at least one descriptor (the loop-breaker) to read.
|
243
|
+
*/
|
244
|
+
/*
|
127
245
|
if (Descriptors.size() == 0) {
|
128
246
|
#ifdef OS_UNIX
|
129
247
|
timeval tv = {0, 200 * 1000};
|
130
248
|
EmSelect (0, NULL, NULL, NULL, &tv);
|
249
|
+
return true;
|
131
250
|
#endif
|
132
251
|
#ifdef OS_WIN32
|
133
252
|
Sleep (200);
|
134
|
-
#endif
|
135
253
|
return true;
|
254
|
+
#endif
|
136
255
|
}
|
256
|
+
*/
|
137
257
|
|
138
258
|
fd_set fdreads, fdwrites;
|
139
259
|
FD_ZERO (&fdreads);
|
@@ -141,6 +261,15 @@ bool EventMachine_t::_RunOnce()
|
|
141
261
|
|
142
262
|
int maxsocket = 0;
|
143
263
|
|
264
|
+
// Always read the loop-breaker reader.
|
265
|
+
// Changed 23Aug06, provisionally implemented for Windows with a UDP socket
|
266
|
+
// running on localhost with a randomly-chosen port. (*Puke*)
|
267
|
+
// Windows has a version of the Unix pipe() library function, but it doesn't
|
268
|
+
// give you back descriptors that are selectable.
|
269
|
+
FD_SET (LoopBreakerReader, &fdreads);
|
270
|
+
if (maxsocket < LoopBreakerReader)
|
271
|
+
maxsocket = LoopBreakerReader;
|
272
|
+
|
144
273
|
// prepare the sockets for reading and writing
|
145
274
|
size_t i;
|
146
275
|
for (i = 0; i < Descriptors.size(); i++) {
|
@@ -160,9 +289,13 @@ bool EventMachine_t::_RunOnce()
|
|
160
289
|
|
161
290
|
|
162
291
|
{ // read and write the sockets
|
163
|
-
timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
|
292
|
+
//timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
|
293
|
+
timeval tv = Quantum;
|
164
294
|
int s = EmSelect (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
|
165
295
|
if (s > 0) {
|
296
|
+
if (FD_ISSET (LoopBreakerReader, &fdreads))
|
297
|
+
_ReadLoopBreaker();
|
298
|
+
|
166
299
|
for (i=0; i < Descriptors.size(); i++) {
|
167
300
|
EventableDescriptor *ed = Descriptors[i];
|
168
301
|
assert (ed);
|
@@ -178,7 +311,7 @@ bool EventMachine_t::_RunOnce()
|
|
178
311
|
else if (s < 0) {
|
179
312
|
// select can fail on error in a handful of ways.
|
180
313
|
// If this happens, then wait for a little while to avoid busy-looping.
|
181
|
-
// If the error was EINTR, we
|
314
|
+
// If the error was EINTR, we probably caught SIGCHLD or something,
|
182
315
|
// so keep the wait short.
|
183
316
|
timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
|
184
317
|
EmSelect (0, NULL, NULL, NULL, &tv);
|
@@ -219,6 +352,23 @@ bool EventMachine_t::_RunOnce()
|
|
219
352
|
}
|
220
353
|
|
221
354
|
|
355
|
+
/********************************
|
356
|
+
EventMachine_t::_ReadLoopBreaker
|
357
|
+
********************************/
|
358
|
+
|
359
|
+
void EventMachine_t::_ReadLoopBreaker()
|
360
|
+
{
|
361
|
+
/* The loop breaker has selected readable.
|
362
|
+
* Read it ONCE (it may block if we try to read it twice)
|
363
|
+
* and send a loop-break event back to user code.
|
364
|
+
*/
|
365
|
+
char buffer [1024];
|
366
|
+
read (LoopBreakerReader, buffer, sizeof(buffer));
|
367
|
+
if (EventCallback)
|
368
|
+
(*EventCallback)("", EventMachine_t::LOOPBREAK_SIGNAL, "", 0);
|
369
|
+
}
|
370
|
+
|
371
|
+
|
222
372
|
/**************************
|
223
373
|
EventMachine_t::_RunTimers
|
224
374
|
**************************/
|
@@ -232,11 +382,25 @@ bool EventMachine_t::_RunTimers()
|
|
232
382
|
// Just keep inspecting and processing the list head until we hit
|
233
383
|
// one that hasn't expired yet.
|
234
384
|
|
385
|
+
#ifdef OS_UNIX
|
386
|
+
struct timeval tv;
|
387
|
+
gettimeofday (&tv, NULL);
|
388
|
+
Int64 now = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
|
389
|
+
#endif
|
390
|
+
|
391
|
+
#ifdef OS_WIN32
|
392
|
+
unsigned tick = GetTickCount();
|
393
|
+
if (tick < gLastTickCount)
|
394
|
+
gTickCountTickover += 1;
|
395
|
+
gLastTickCount = tick;
|
396
|
+
Int64 now = ((Int64)gTickCountTickover << 32) + (Int64)tick;
|
397
|
+
#endif
|
398
|
+
|
235
399
|
while (true) {
|
236
|
-
multimap<
|
400
|
+
multimap<Int64,Timer_t>::iterator i = Timers.begin();
|
237
401
|
if (i == Timers.end())
|
238
402
|
break;
|
239
|
-
if (i->first >
|
403
|
+
if (i->first > now)
|
240
404
|
break;
|
241
405
|
if (EventCallback)
|
242
406
|
(*EventCallback) ("", TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
|
@@ -251,17 +415,33 @@ bool EventMachine_t::_RunTimers()
|
|
251
415
|
EventMachine_t::InstallOneshotTimer
|
252
416
|
***********************************/
|
253
417
|
|
254
|
-
const char *EventMachine_t::InstallOneshotTimer (int
|
418
|
+
const char *EventMachine_t::InstallOneshotTimer (int milliseconds)
|
255
419
|
{
|
256
420
|
if (Timers.size() > MaxOutstandingTimers)
|
257
421
|
return false;
|
258
422
|
// Don't use the global loop-time variable here, because we might
|
259
423
|
// get called before the main event machine is running.
|
260
424
|
|
425
|
+
#ifdef OS_UNIX
|
426
|
+
struct timeval tv;
|
427
|
+
gettimeofday (&tv, NULL);
|
428
|
+
Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
|
429
|
+
fire_at += ((Int64)milliseconds) * 1000LL;
|
430
|
+
#endif
|
431
|
+
|
432
|
+
#ifdef OS_WIN32
|
433
|
+
unsigned tick = GetTickCount();
|
434
|
+
if (tick < gLastTickCount)
|
435
|
+
gTickCountTickover += 1;
|
436
|
+
gLastTickCount = tick;
|
437
|
+
|
438
|
+
Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick;
|
439
|
+
fire_at += (Int64)milliseconds;
|
440
|
+
#endif
|
441
|
+
|
261
442
|
Timer_t t;
|
262
|
-
multimap<
|
263
|
-
Timers.insert (make_pair (
|
264
|
-
//return t.GetBinding().c_str();
|
443
|
+
multimap<Int64,Timer_t>::iterator i =
|
444
|
+
Timers.insert (make_pair (fire_at, t));
|
265
445
|
return i->second.GetBindingChars();
|
266
446
|
}
|
267
447
|
|
@@ -304,8 +484,14 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
304
484
|
HostAddr = inet_addr (server);
|
305
485
|
if (HostAddr == INADDR_NONE) {
|
306
486
|
hostent *hp = gethostbyname ((char*)server); // Windows requires (char*)
|
307
|
-
if (!hp)
|
487
|
+
if (!hp) {
|
488
|
+
// TODO: This gives the caller a fatal error. Not good.
|
489
|
+
// They can respond by catching RuntimeError (blecch).
|
490
|
+
// Possibly we need to fire an unbind event and provide
|
491
|
+
// a status code so user code can detect the cause of the
|
492
|
+
// failure.
|
308
493
|
return NULL;
|
494
|
+
}
|
309
495
|
HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
|
310
496
|
}
|
311
497
|
|
@@ -333,7 +519,27 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
333
519
|
// never to give when the socket is nonblocking,
|
334
520
|
// even if the connection is intramachine or to
|
335
521
|
// localhost.
|
336
|
-
|
522
|
+
|
523
|
+
/* Changed this branch 08Aug06. Evidently some kernels
|
524
|
+
* (FreeBSD for example) will actually return success from
|
525
|
+
* a nonblocking connect. This is a pretty simple case,
|
526
|
+
* just set up the new connection and clear the pending flag.
|
527
|
+
* Thanks to Chris Ochs for helping track this down.
|
528
|
+
* This branch never gets taken on Linux or (oddly) OSX.
|
529
|
+
* The original behavior was to throw an unimplemented,
|
530
|
+
* which the user saw as a fatal exception. Very unfriendly.
|
531
|
+
*
|
532
|
+
* Tweaked 10Aug06. Even though the connect disposition is
|
533
|
+
* known, we still set the connect-pending flag. That way
|
534
|
+
* some needed initialization will happen in the ConnectionDescriptor.
|
535
|
+
* (To wit, the ConnectionCompleted event gets sent to the client.)
|
536
|
+
*/
|
537
|
+
ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
|
538
|
+
if (!cd)
|
539
|
+
throw std::runtime_error ("no connection allocated");
|
540
|
+
cd->SetConnectPending (true);
|
541
|
+
Add (cd);
|
542
|
+
out = cd->GetBinding().c_str();
|
337
543
|
}
|
338
544
|
else if (errno == EINPROGRESS) {
|
339
545
|
// Errno will generally always be EINPROGRESS, but on Linux
|
@@ -354,7 +560,24 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
354
560
|
out = cd->GetBinding().c_str();
|
355
561
|
}
|
356
562
|
else {
|
357
|
-
|
563
|
+
/* This could be connection refused or some such thing.
|
564
|
+
* We will come here on Linux if a localhost connection fails.
|
565
|
+
* Changed 16Jul06: Originally this branch was a no-op, and
|
566
|
+
* we'd drop down to the end of the method, close the socket,
|
567
|
+
* and return NULL, which would cause the caller to GET A
|
568
|
+
* FATAL EXCEPTION. Now we keep the socket around but schedule an
|
569
|
+
* immediate close on it, so the caller will get a close-event
|
570
|
+
* scheduled on it. This was only an issue for localhost connections
|
571
|
+
* to non-listening ports. We may eventually need to revise this
|
572
|
+
* revised behavior, in case it causes problems like making it hard
|
573
|
+
* for people to know that a failure occurred.
|
574
|
+
*/
|
575
|
+
ConnectionDescriptor *cd = new ConnectionDescriptor (sd);
|
576
|
+
if (!cd)
|
577
|
+
throw std::runtime_error ("no connection allocated");
|
578
|
+
cd->ScheduleClose (false);
|
579
|
+
Add (cd);
|
580
|
+
out = cd->GetBinding().c_str();
|
358
581
|
}
|
359
582
|
}
|
360
583
|
else {
|
@@ -574,6 +797,10 @@ void EventMachine_t::_AddNewDescriptors()
|
|
574
797
|
* Any descriptors that are added as a result of processing timers
|
575
798
|
* or acceptors should go on a temporary queue and then added
|
576
799
|
* while we're not traversing the main list.
|
800
|
+
* Also, it (rarely) happens that a newly-created descriptor
|
801
|
+
* is immediately scheduled to close. It might be a good
|
802
|
+
* idea not to bother scheduling these for I/O but if
|
803
|
+
* we do that, we might bypass some important processing.
|
577
804
|
*/
|
578
805
|
|
579
806
|
for (size_t i = 0; i < NewDescriptors.size(); i++) {
|
@@ -586,5 +813,115 @@ void EventMachine_t::_AddNewDescriptors()
|
|
586
813
|
}
|
587
814
|
|
588
815
|
|
816
|
+
/***********************************
|
817
|
+
EventMachine_t::_OpenFileForWriting
|
818
|
+
***********************************/
|
819
|
+
|
820
|
+
const char *EventMachine_t::_OpenFileForWriting (const char *filename)
|
821
|
+
{
|
822
|
+
/*
|
823
|
+
* Return the binding-text of the newly-opened file,
|
824
|
+
* or NULL if there was a problem.
|
825
|
+
*/
|
826
|
+
|
827
|
+
if (!filename || !*filename)
|
828
|
+
return NULL;
|
829
|
+
|
830
|
+
int fd = open (filename, O_CREAT|O_TRUNC|O_WRONLY|O_NONBLOCK, 0644);
|
831
|
+
|
832
|
+
FileStreamDescriptor *fsd = new FileStreamDescriptor (fd);
|
833
|
+
if (!fsd)
|
834
|
+
throw std::runtime_error ("no file-stream allocated");
|
835
|
+
Add (fsd);
|
836
|
+
return fsd->GetBinding().c_str();
|
837
|
+
|
838
|
+
}
|
839
|
+
|
840
|
+
|
841
|
+
/**************************************
|
842
|
+
EventMachine_t::CreateUnixDomainServer
|
843
|
+
**************************************/
|
844
|
+
|
845
|
+
const char *EventMachine_t::CreateUnixDomainServer (const char *filename)
|
846
|
+
{
|
847
|
+
/* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
|
848
|
+
* Return the binding of the new acceptor to the caller.
|
849
|
+
* This binding will be referenced when the new acceptor sends events
|
850
|
+
* to indicate accepted connections.
|
851
|
+
* THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
|
852
|
+
*/
|
853
|
+
|
854
|
+
#ifdef OS_WIN32
|
855
|
+
throw std::runtime_error ("unix-domain server unavailable on this platform");
|
856
|
+
#endif
|
857
|
+
|
858
|
+
// The whole rest of this function is only compiled on Unix systems.
|
859
|
+
#ifdef OS_UNIX
|
860
|
+
const char *output_binding = NULL;
|
861
|
+
|
862
|
+
struct sockaddr_un sun;
|
863
|
+
|
864
|
+
int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0);
|
865
|
+
if (sd_accept == INVALID_SOCKET) {
|
866
|
+
goto fail;
|
867
|
+
}
|
868
|
+
|
869
|
+
if (!filename || !*filename)
|
870
|
+
goto fail;
|
871
|
+
unlink (filename);
|
872
|
+
|
873
|
+
bzero (&sun, sizeof(sun));
|
874
|
+
sun.sun_family = AF_LOCAL;
|
875
|
+
strncpy (sun.sun_path, filename, sizeof(sun.sun_path)-1);
|
876
|
+
|
877
|
+
// don't bother with reuseaddr for a local socket.
|
878
|
+
|
879
|
+
{ // set CLOEXEC. Only makes sense on Unix
|
880
|
+
#ifdef OS_UNIX
|
881
|
+
int cloexec = fcntl (sd_accept, F_GETFD, 0);
|
882
|
+
assert (cloexec >= 0);
|
883
|
+
cloexec |= FD_CLOEXEC;
|
884
|
+
fcntl (sd_accept, F_SETFD, cloexec);
|
885
|
+
#endif
|
886
|
+
}
|
887
|
+
|
888
|
+
if (bind (sd_accept, (struct sockaddr*)&sun, sizeof(sun))) {
|
889
|
+
//__warning ("binding failed");
|
890
|
+
goto fail;
|
891
|
+
}
|
892
|
+
|
893
|
+
if (listen (sd_accept, 100)) {
|
894
|
+
//__warning ("listen failed");
|
895
|
+
goto fail;
|
896
|
+
}
|
897
|
+
|
898
|
+
{
|
899
|
+
// Set the acceptor non-blocking.
|
900
|
+
// THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
|
901
|
+
if (!SetSocketNonblocking (sd_accept)) {
|
902
|
+
//int val = fcntl (sd_accept, F_GETFL, 0);
|
903
|
+
//if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
|
904
|
+
goto fail;
|
905
|
+
}
|
906
|
+
}
|
907
|
+
|
908
|
+
{ // Looking good.
|
909
|
+
AcceptorDescriptor *ad = new AcceptorDescriptor (this, sd_accept);
|
910
|
+
if (!ad)
|
911
|
+
throw std::runtime_error ("unable to allocate acceptor");
|
912
|
+
Add (ad);
|
913
|
+
output_binding = ad->GetBinding().c_str();
|
914
|
+
}
|
915
|
+
|
916
|
+
return output_binding;
|
917
|
+
|
918
|
+
fail:
|
919
|
+
if (sd_accept != INVALID_SOCKET)
|
920
|
+
closesocket (sd_accept);
|
921
|
+
return NULL;
|
922
|
+
#endif // OS_UNIX
|
923
|
+
}
|
924
|
+
|
925
|
+
|
589
926
|
//#endif // OS_UNIX
|
590
927
|
|
data/ext/em.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: em.h
|
3
|
+
$Id: em.h 264 2006-10-05 16:33:22Z blackhedd $
|
4
4
|
|
5
5
|
File: ed.h
|
6
6
|
Date: 06Apr06
|
@@ -44,6 +44,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
44
44
|
#define EmSelect select
|
45
45
|
#endif
|
46
46
|
|
47
|
+
|
48
|
+
#ifdef OS_UNIX
|
49
|
+
typedef long long Int64;
|
50
|
+
#endif
|
51
|
+
#ifdef OS_WIN32
|
52
|
+
typedef __int64 Int64;
|
53
|
+
#endif
|
54
|
+
|
47
55
|
extern time_t gCurrentLoopTime;
|
48
56
|
|
49
57
|
class EventableDescriptor;
|
@@ -60,20 +68,27 @@ class EventMachine_t
|
|
60
68
|
virtual ~EventMachine_t();
|
61
69
|
|
62
70
|
void Run();
|
63
|
-
|
71
|
+
void ScheduleHalt();
|
72
|
+
void SignalLoopBreaker();
|
64
73
|
const char *InstallOneshotTimer (int);
|
65
74
|
const char *ConnectToServer (const char *, int);
|
66
75
|
const char *CreateTcpServer (const char *, int);
|
67
76
|
const char *OpenDatagramSocket (const char *, int);
|
77
|
+
const char *CreateUnixDomainServer (const char*);
|
78
|
+
const char *_OpenFileForWriting (const char*);
|
68
79
|
|
69
|
-
|
80
|
+
void Add (EventableDescriptor*);
|
70
81
|
|
71
|
-
|
82
|
+
void SetTimerQuantum (int);
|
83
|
+
|
84
|
+
public:
|
72
85
|
enum { // Event names
|
73
86
|
TIMER_FIRED = 100,
|
74
|
-
|
75
|
-
|
76
|
-
|
87
|
+
CONNECTION_READ = 101,
|
88
|
+
CONNECTION_UNBOUND = 102,
|
89
|
+
CONNECTION_ACCEPTED = 103,
|
90
|
+
CONNECTION_COMPLETED = 104,
|
91
|
+
LOOPBREAK_SIGNAL = 105
|
77
92
|
};
|
78
93
|
|
79
94
|
|
@@ -81,6 +96,8 @@ class EventMachine_t
|
|
81
96
|
bool _RunOnce();
|
82
97
|
bool _RunTimers();
|
83
98
|
void _AddNewDescriptors();
|
99
|
+
void _InitializeLoopBreaker();
|
100
|
+
void _ReadLoopBreaker();
|
84
101
|
|
85
102
|
private:
|
86
103
|
enum {
|
@@ -92,11 +109,19 @@ class EventMachine_t
|
|
92
109
|
class Timer_t: public Bindable_t {
|
93
110
|
};
|
94
111
|
|
95
|
-
multimap<
|
112
|
+
multimap<Int64, Timer_t> Timers;
|
96
113
|
vector<EventableDescriptor*> Descriptors;
|
97
114
|
vector<EventableDescriptor*> NewDescriptors;
|
98
115
|
|
99
116
|
time_t NextHeartbeatTime;
|
117
|
+
|
118
|
+
int LoopBreakerReader;
|
119
|
+
int LoopBreakerWriter;
|
120
|
+
#ifdef OS_WIN32
|
121
|
+
struct sockaddr_in LoopBreakerTarget;
|
122
|
+
#endif
|
123
|
+
|
124
|
+
timeval Quantum;
|
100
125
|
};
|
101
126
|
|
102
127
|
|
data/ext/emwin.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: emwin.h
|
3
|
+
$Id: emwin.h 209 2006-07-16 23:32:16Z blackhedd $
|
4
4
|
|
5
5
|
File: edwin.h
|
6
6
|
Date: 05May06
|
@@ -62,7 +62,9 @@ class EventMachine_t
|
|
62
62
|
TIMER_FIRED = 100,
|
63
63
|
CONNECTION_READ = 101,
|
64
64
|
CONNECTION_UNBOUND = 102,
|
65
|
-
CONNECTION_ACCEPTED = 103
|
65
|
+
CONNECTION_ACCEPTED = 103,
|
66
|
+
CONNECTION_COMPLETED = 104,
|
67
|
+
LOOPBREAK_SIGNAL = 105
|
66
68
|
};
|
67
69
|
|
68
70
|
private:
|
data/ext/eventmachine.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*****************************************************************************
|
2
2
|
|
3
|
-
$Id: eventmachine.h
|
3
|
+
$Id: eventmachine.h 265 2006-10-05 19:07:45Z blackhedd $
|
4
4
|
|
5
5
|
File: eventmachine.h
|
6
6
|
Date: 15Apr06
|
@@ -37,13 +37,21 @@ extern "C" {
|
|
37
37
|
const char *evma_install_oneshot_timer (int seconds);
|
38
38
|
const char *evma_connect_to_server (const char *server, int port);
|
39
39
|
const char *evma_create_tcp_server (const char *address, int port);
|
40
|
+
const char *evma_create_unix_domain_server (const char *filename);
|
40
41
|
const char *evma_open_datagram_socket (const char *server, int port);
|
41
42
|
void evma_start_tls (const char *binding);
|
43
|
+
int evma_get_peername (const char *binding, struct sockaddr*);
|
42
44
|
int evma_send_data_to_connection (const char *binding, const char *data, int data_length);
|
43
45
|
int evma_send_datagram (const char *binding, const char *data, int data_length, const char *address, int port);
|
46
|
+
int evma_get_comm_inactivity_timeout (const char *binding, /*out*/int *value);
|
47
|
+
int evma_set_comm_inactivity_timeout (const char *binding, /*in,out*/int *value);
|
44
48
|
void evma_close_connection (const char *binding, int after_writing);
|
49
|
+
void evma_signal_loopbreak();
|
50
|
+
void evma_set_timer_quantum (int);
|
45
51
|
void evma_stop_machine();
|
46
52
|
|
53
|
+
const char *evma__write_file (const char *filename);
|
54
|
+
|
47
55
|
#if __cplusplus
|
48
56
|
}
|
49
57
|
#endif
|