eventmachine 0.12.6-java → 0.12.8-java
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/{docs/README → README} +21 -13
- data/Rakefile +5 -3
- data/docs/DEFERRABLES +0 -5
- data/docs/INSTALL +2 -4
- data/docs/LEGAL +1 -1
- data/docs/LIGHTWEIGHT_CONCURRENCY +0 -2
- data/docs/PURE_RUBY +0 -2
- data/docs/RELEASE_NOTES +0 -2
- data/docs/SMTP +0 -7
- data/docs/SPAWNED_PROCESSES +0 -4
- data/docs/TODO +0 -2
- data/eventmachine.gemspec +17 -8
- data/examples/ex_channel.rb +43 -0
- data/examples/ex_queue.rb +2 -0
- data/examples/helper.rb +2 -0
- data/ext/cmain.cpp +119 -20
- data/ext/cplusplus.cpp +15 -6
- data/ext/ed.cpp +303 -93
- data/ext/ed.h +49 -22
- data/ext/em.cpp +368 -42
- data/ext/em.h +43 -6
- data/ext/eventmachine.h +21 -8
- data/ext/eventmachine_cpp.h +1 -0
- data/ext/extconf.rb +4 -0
- data/ext/kb.cpp +1 -2
- data/ext/pipe.cpp +1 -3
- data/ext/project.h +21 -0
- data/ext/rubymain.cpp +232 -32
- data/ext/ssl.cpp +38 -1
- data/ext/ssl.h +5 -1
- data/java/src/com/rubyeventmachine/Application.java +7 -3
- data/java/src/com/rubyeventmachine/EmReactor.java +16 -1
- data/java/src/com/rubyeventmachine/tests/ConnectTest.java +25 -3
- data/lib/{protocols → em}/buftok.rb +16 -5
- data/lib/em/callback.rb +26 -0
- data/lib/em/channel.rb +57 -0
- data/lib/em/connection.rb +505 -0
- data/lib/em/deferrable.rb +144 -165
- data/lib/em/file_watch.rb +54 -0
- data/lib/em/future.rb +24 -25
- data/lib/em/messages.rb +1 -1
- data/lib/em/process_watch.rb +44 -0
- data/lib/em/processes.rb +58 -52
- data/lib/em/protocols.rb +35 -0
- data/lib/em/protocols/header_and_content.rb +138 -0
- data/lib/em/protocols/httpclient.rb +263 -0
- data/lib/em/protocols/httpclient2.rb +582 -0
- data/lib/{protocols → em/protocols}/line_and_text.rb +2 -2
- data/lib/em/protocols/linetext2.rb +160 -0
- data/lib/{protocols → em/protocols}/memcache.rb +37 -7
- data/lib/em/protocols/object_protocol.rb +39 -0
- data/lib/em/protocols/postgres3.rb +247 -0
- data/lib/em/protocols/saslauth.rb +175 -0
- data/lib/em/protocols/smtpclient.rb +331 -0
- data/lib/em/protocols/smtpserver.rb +547 -0
- data/lib/em/protocols/stomp.rb +200 -0
- data/lib/{protocols → em/protocols}/tcptest.rb +21 -25
- data/lib/em/queue.rb +61 -0
- data/lib/em/spawnable.rb +53 -56
- data/lib/em/streamer.rb +92 -74
- data/lib/em/timers.rb +55 -0
- data/lib/em/version.rb +3 -0
- data/lib/eventmachine.rb +1008 -1298
- data/lib/evma.rb +1 -1
- data/lib/jeventmachine.rb +106 -101
- data/lib/pr_eventmachine.rb +47 -36
- data/tasks/project.rake +2 -1
- data/tests/client.crt +31 -0
- data/tests/client.key +51 -0
- data/tests/test_attach.rb +18 -0
- data/tests/test_basic.rb +108 -54
- data/tests/test_channel.rb +63 -0
- data/tests/test_connection_count.rb +2 -2
- data/tests/test_epoll.rb +109 -110
- data/tests/test_errors.rb +36 -36
- data/tests/test_exc.rb +22 -25
- data/tests/test_file_watch.rb +49 -0
- data/tests/test_futures.rb +77 -93
- data/tests/test_hc.rb +2 -2
- data/tests/test_httpclient.rb +55 -52
- data/tests/test_httpclient2.rb +110 -112
- data/tests/test_inactivity_timeout.rb +30 -0
- data/tests/test_kb.rb +8 -9
- data/tests/test_ltp2.rb +274 -277
- data/tests/test_next_tick.rb +91 -65
- data/tests/test_object_protocol.rb +37 -0
- data/tests/test_process_watch.rb +48 -0
- data/tests/test_processes.rb +56 -23
- data/tests/test_proxy_connection.rb +92 -0
- data/tests/test_pure.rb +1 -5
- data/tests/test_queue.rb +44 -0
- data/tests/test_running.rb +9 -14
- data/tests/test_sasl.rb +32 -34
- data/tests/test_send_file.rb +175 -176
- data/tests/test_servers.rb +37 -41
- data/tests/test_smtpserver.rb +47 -55
- data/tests/test_spawn.rb +284 -291
- data/tests/test_ssl_args.rb +1 -1
- data/tests/test_ssl_methods.rb +1 -1
- data/tests/test_ssl_verify.rb +82 -0
- data/tests/test_timers.rb +81 -88
- data/tests/test_ud.rb +0 -7
- data/tests/testem.rb +1 -1
- metadata +52 -36
- data/lib/em/eventable.rb +0 -39
- data/lib/eventmachine_version.rb +0 -31
- data/lib/protocols/header_and_content.rb +0 -129
- data/lib/protocols/httpcli2.rb +0 -803
- data/lib/protocols/httpclient.rb +0 -270
- data/lib/protocols/linetext2.rb +0 -161
- data/lib/protocols/postgres.rb +0 -261
- data/lib/protocols/saslauth.rb +0 -179
- data/lib/protocols/smtpclient.rb +0 -308
- data/lib/protocols/smtpserver.rb +0 -556
- data/lib/protocols/stomp.rb +0 -153
- data/tests/test_eventables.rb +0 -77
data/ext/ed.h
CHANGED
|
@@ -67,27 +67,28 @@ class EventableDescriptor: public Bindable_t
|
|
|
67
67
|
virtual bool GetSubprocessPid (pid_t*) {return false;}
|
|
68
68
|
|
|
69
69
|
virtual void StartTls() {}
|
|
70
|
-
virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename) {}
|
|
70
|
+
virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer) {}
|
|
71
71
|
|
|
72
72
|
#ifdef WITH_SSL
|
|
73
73
|
virtual X509 *GetPeerCert() {return NULL;}
|
|
74
74
|
#endif
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
virtual int GetCommInactivityTimeout (int *value) {return 0;}
|
|
79
|
-
virtual int SetCommInactivityTimeout (int *value) {return 0;}
|
|
76
|
+
virtual float GetCommInactivityTimeout() {return 0.0;}
|
|
77
|
+
virtual int SetCommInactivityTimeout (float value) {return 0;}
|
|
80
78
|
|
|
81
79
|
#ifdef HAVE_EPOLL
|
|
82
80
|
struct epoll_event *GetEpollEvent() { return &EpollEvent; }
|
|
83
81
|
#endif
|
|
84
82
|
|
|
83
|
+
virtual void StartProxy(const char*);
|
|
84
|
+
virtual void StopProxy();
|
|
85
|
+
|
|
85
86
|
private:
|
|
86
87
|
bool bCloseNow;
|
|
87
88
|
bool bCloseAfterWriting;
|
|
88
|
-
int MySocket;
|
|
89
89
|
|
|
90
90
|
protected:
|
|
91
|
+
int MySocket;
|
|
91
92
|
enum {
|
|
92
93
|
// 4 seconds is too short, most other libraries default to OS settings
|
|
93
94
|
// which in 2.6 kernel defaults to a 60 second connect timeout.
|
|
@@ -96,16 +97,17 @@ class EventableDescriptor: public Bindable_t
|
|
|
96
97
|
//
|
|
97
98
|
// updating to 50 seconds, so we catch it before the OS does
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
// can easily be made an instance variable
|
|
101
|
+
PendingConnectTimeout = 50000000 // now in usec
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
void (*EventCallback)(const char*, int, const char*, int);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
time_t LastWritten;
|
|
105
|
+
void _GenericInboundDispatch(const char*, int);
|
|
106
|
+
|
|
107
|
+
Int64 CreatedAt;
|
|
107
108
|
bool bCallbackUnbind;
|
|
108
109
|
int UnbindReasonCode;
|
|
110
|
+
char *ProxyTarget;
|
|
109
111
|
|
|
110
112
|
#ifdef HAVE_EPOLL
|
|
111
113
|
struct epoll_event EpollEvent;
|
|
@@ -153,8 +155,8 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
|
153
155
|
|
|
154
156
|
void SetConnectPending (bool f);
|
|
155
157
|
|
|
156
|
-
void SetNotifyReadable (bool
|
|
157
|
-
void SetNotifyWritable (bool
|
|
158
|
+
void SetNotifyReadable (bool);
|
|
159
|
+
void SetNotifyWritable (bool);
|
|
158
160
|
|
|
159
161
|
virtual void Read();
|
|
160
162
|
virtual void Write();
|
|
@@ -167,10 +169,12 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
|
167
169
|
virtual int GetOutboundDataSize() {return OutboundDataSize;}
|
|
168
170
|
|
|
169
171
|
virtual void StartTls();
|
|
170
|
-
virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename);
|
|
172
|
+
virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer);
|
|
171
173
|
|
|
172
174
|
#ifdef WITH_SSL
|
|
173
175
|
virtual X509 *GetPeerCert();
|
|
176
|
+
virtual bool VerifySslPeer(const char*);
|
|
177
|
+
virtual void AcceptSslPeer();
|
|
174
178
|
#endif
|
|
175
179
|
|
|
176
180
|
void SetServerMode() {bIsServer = true;}
|
|
@@ -178,8 +182,8 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
|
178
182
|
virtual bool GetPeername (struct sockaddr*);
|
|
179
183
|
virtual bool GetSockname (struct sockaddr*);
|
|
180
184
|
|
|
181
|
-
virtual
|
|
182
|
-
virtual int SetCommInactivityTimeout (
|
|
185
|
+
virtual float GetCommInactivityTimeout();
|
|
186
|
+
virtual int SetCommInactivityTimeout (float value);
|
|
183
187
|
|
|
184
188
|
|
|
185
189
|
protected:
|
|
@@ -208,10 +212,16 @@ class ConnectionDescriptor: public EventableDescriptor
|
|
|
208
212
|
std::string CertChainFilename;
|
|
209
213
|
std::string PrivateKeyFilename;
|
|
210
214
|
bool bHandshakeSignaled;
|
|
215
|
+
bool bSslVerifyPeer;
|
|
216
|
+
bool bSslPeerAccepted;
|
|
211
217
|
#endif
|
|
212
218
|
bool bIsServer;
|
|
213
219
|
|
|
214
|
-
|
|
220
|
+
#ifdef HAVE_KQUEUE
|
|
221
|
+
bool bGotExtraKqueueEvent;
|
|
222
|
+
#endif
|
|
223
|
+
|
|
224
|
+
Int64 LastIo;
|
|
215
225
|
int InactivityTimeout;
|
|
216
226
|
|
|
217
227
|
private:
|
|
@@ -251,8 +261,8 @@ class DatagramDescriptor: public EventableDescriptor
|
|
|
251
261
|
virtual bool GetPeername (struct sockaddr*);
|
|
252
262
|
virtual bool GetSockname (struct sockaddr*);
|
|
253
263
|
|
|
254
|
-
virtual
|
|
255
|
-
virtual int SetCommInactivityTimeout (
|
|
264
|
+
virtual float GetCommInactivityTimeout();
|
|
265
|
+
virtual int SetCommInactivityTimeout (float value);
|
|
256
266
|
|
|
257
267
|
static int SendDatagram (const char*, const char*, int, const char*, int);
|
|
258
268
|
|
|
@@ -272,7 +282,7 @@ class DatagramDescriptor: public EventableDescriptor
|
|
|
272
282
|
|
|
273
283
|
struct sockaddr_in ReturnAddress;
|
|
274
284
|
|
|
275
|
-
|
|
285
|
+
Int64 LastIo;
|
|
276
286
|
int InactivityTimeout;
|
|
277
287
|
};
|
|
278
288
|
|
|
@@ -333,7 +343,7 @@ class PipeDescriptor: public EventableDescriptor
|
|
|
333
343
|
|
|
334
344
|
protected:
|
|
335
345
|
bool bReadAttemptedAfterClose;
|
|
336
|
-
|
|
346
|
+
Int64 LastIo;
|
|
337
347
|
int InactivityTimeout;
|
|
338
348
|
|
|
339
349
|
deque<OutboundPage> OutboundPages;
|
|
@@ -366,7 +376,7 @@ class KeyboardDescriptor: public EventableDescriptor
|
|
|
366
376
|
|
|
367
377
|
protected:
|
|
368
378
|
bool bReadAttemptedAfterClose;
|
|
369
|
-
|
|
379
|
+
Int64 LastIo;
|
|
370
380
|
int InactivityTimeout;
|
|
371
381
|
|
|
372
382
|
private:
|
|
@@ -374,6 +384,23 @@ class KeyboardDescriptor: public EventableDescriptor
|
|
|
374
384
|
};
|
|
375
385
|
|
|
376
386
|
|
|
387
|
+
/***********************
|
|
388
|
+
class InotifyDescriptor
|
|
389
|
+
************************/
|
|
390
|
+
|
|
391
|
+
class InotifyDescriptor: public EventableDescriptor
|
|
392
|
+
{
|
|
393
|
+
public:
|
|
394
|
+
InotifyDescriptor (EventMachine_t*);
|
|
395
|
+
virtual ~InotifyDescriptor();
|
|
396
|
+
|
|
397
|
+
void Read();
|
|
398
|
+
void Write();
|
|
399
|
+
|
|
400
|
+
virtual void Heartbeat() {}
|
|
401
|
+
virtual bool SelectForRead() {return true;}
|
|
402
|
+
virtual bool SelectForWrite() {return false;}
|
|
403
|
+
};
|
|
377
404
|
|
|
378
405
|
#endif // __EventableDescriptor__H_
|
|
379
406
|
|
data/ext/em.cpp
CHANGED
|
@@ -26,7 +26,7 @@ See the file COPYING for complete licensing information.
|
|
|
26
26
|
// Keep a global variable floating around
|
|
27
27
|
// with the current loop time as set by the Event Machine.
|
|
28
28
|
// This avoids the need for frequent expensive calls to time(NULL);
|
|
29
|
-
|
|
29
|
+
Int64 gCurrentLoopTime;
|
|
30
30
|
|
|
31
31
|
#ifdef OS_WIN32
|
|
32
32
|
unsigned gTickCountTickover;
|
|
@@ -87,7 +87,9 @@ EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const c
|
|
|
87
87
|
bEpoll (false),
|
|
88
88
|
bKqueue (false),
|
|
89
89
|
kqfd (-1),
|
|
90
|
-
epfd (-1)
|
|
90
|
+
epfd (-1),
|
|
91
|
+
inotify (NULL),
|
|
92
|
+
HeartbeatInterval(2)
|
|
91
93
|
{
|
|
92
94
|
// Default time-slice is just smaller than one hundred mills.
|
|
93
95
|
Quantum.tv_sec = 0;
|
|
@@ -96,7 +98,7 @@ EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const c
|
|
|
96
98
|
gTerminateSignalReceived = false;
|
|
97
99
|
// Make sure the current loop time is sane, in case we do any initializations of
|
|
98
100
|
// objects before we start running.
|
|
99
|
-
|
|
101
|
+
_UpdateTime();
|
|
100
102
|
|
|
101
103
|
/* We initialize the network library here (only on Windows of course)
|
|
102
104
|
* and initialize "loop breakers." Our destructor also does some network-level
|
|
@@ -129,6 +131,10 @@ EventMachine_t::~EventMachine_t()
|
|
|
129
131
|
close (LoopBreakerReader);
|
|
130
132
|
close (LoopBreakerWriter);
|
|
131
133
|
|
|
134
|
+
// Remove any file watch descriptors
|
|
135
|
+
for(map<int, Bindable_t*>::iterator f=Files.begin(); f != Files.end(); f++)
|
|
136
|
+
UnwatchFile (f->first);
|
|
137
|
+
|
|
132
138
|
if (epfd != -1)
|
|
133
139
|
close (epfd);
|
|
134
140
|
if (kqfd != -1)
|
|
@@ -339,6 +345,28 @@ void EventMachine_t::_InitializeLoopBreaker()
|
|
|
339
345
|
#endif
|
|
340
346
|
}
|
|
341
347
|
|
|
348
|
+
/***************************
|
|
349
|
+
EventMachine_t::_UpdateTime
|
|
350
|
+
***************************/
|
|
351
|
+
|
|
352
|
+
void EventMachine_t::_UpdateTime()
|
|
353
|
+
{
|
|
354
|
+
#if defined(OS_UNIX)
|
|
355
|
+
struct timeval tv;
|
|
356
|
+
gettimeofday (&tv, NULL);
|
|
357
|
+
gCurrentLoopTime = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
|
|
358
|
+
|
|
359
|
+
#elif defined(OS_WIN32)
|
|
360
|
+
unsigned tick = GetTickCount();
|
|
361
|
+
if (tick < gLastTickCount)
|
|
362
|
+
gTickCountTickover += 1;
|
|
363
|
+
gLastTickCount = tick;
|
|
364
|
+
gCurrentLoopTime = ((Int64)gTickCountTickover << 32) + (Int64)tick;
|
|
365
|
+
|
|
366
|
+
#else
|
|
367
|
+
gCurrentLoopTime = (Int64)time(NULL) * 1000000LL;
|
|
368
|
+
#endif
|
|
369
|
+
}
|
|
342
370
|
|
|
343
371
|
/*******************
|
|
344
372
|
EventMachine_t::Run
|
|
@@ -388,7 +416,7 @@ void EventMachine_t::Run()
|
|
|
388
416
|
#endif
|
|
389
417
|
|
|
390
418
|
while (true) {
|
|
391
|
-
|
|
419
|
+
_UpdateTime();
|
|
392
420
|
if (!_RunTimers())
|
|
393
421
|
break;
|
|
394
422
|
|
|
@@ -435,26 +463,25 @@ bool EventMachine_t::_RunEpollOnce()
|
|
|
435
463
|
{
|
|
436
464
|
#ifdef HAVE_EPOLL
|
|
437
465
|
assert (epfd != -1);
|
|
438
|
-
struct epoll_event ev [MaxEpollDescriptors];
|
|
439
466
|
int s;
|
|
440
467
|
|
|
441
468
|
#ifdef BUILD_FOR_RUBY
|
|
442
469
|
TRAP_BEG;
|
|
443
470
|
#endif
|
|
444
|
-
s = epoll_wait (epfd,
|
|
471
|
+
s = epoll_wait (epfd, epoll_events, MaxEvents, 50);
|
|
445
472
|
#ifdef BUILD_FOR_RUBY
|
|
446
473
|
TRAP_END;
|
|
447
474
|
#endif
|
|
448
475
|
|
|
449
476
|
if (s > 0) {
|
|
450
477
|
for (int i=0; i < s; i++) {
|
|
451
|
-
EventableDescriptor *ed = (EventableDescriptor*)
|
|
478
|
+
EventableDescriptor *ed = (EventableDescriptor*) epoll_events[i].data.ptr;
|
|
452
479
|
|
|
453
|
-
if (
|
|
480
|
+
if (epoll_events[i].events & (EPOLLERR | EPOLLHUP))
|
|
454
481
|
ed->ScheduleClose (false);
|
|
455
|
-
if (
|
|
482
|
+
if (epoll_events[i].events & EPOLLIN)
|
|
456
483
|
ed->Read();
|
|
457
|
-
if (
|
|
484
|
+
if (epoll_events[i].events & EPOLLOUT) {
|
|
458
485
|
ed->Write();
|
|
459
486
|
epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent());
|
|
460
487
|
// Ignoring return value
|
|
@@ -551,29 +578,43 @@ bool EventMachine_t::_RunKqueueOnce()
|
|
|
551
578
|
{
|
|
552
579
|
#ifdef HAVE_KQUEUE
|
|
553
580
|
assert (kqfd != -1);
|
|
554
|
-
const int maxKevents = 2000;
|
|
555
|
-
struct kevent Karray [maxKevents];
|
|
556
581
|
struct timespec ts = {0, 10000000}; // Too frequent. Use blocking_region
|
|
557
582
|
|
|
558
583
|
int k;
|
|
559
584
|
#ifdef BUILD_FOR_RUBY
|
|
560
585
|
TRAP_BEG;
|
|
561
586
|
#endif
|
|
562
|
-
k = kevent (kqfd, NULL, 0, Karray,
|
|
587
|
+
k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
|
|
563
588
|
#ifdef BUILD_FOR_RUBY
|
|
564
589
|
TRAP_END;
|
|
565
590
|
#endif
|
|
591
|
+
|
|
566
592
|
struct kevent *ke = Karray;
|
|
567
593
|
while (k > 0) {
|
|
568
|
-
|
|
569
|
-
|
|
594
|
+
switch (ke->filter)
|
|
595
|
+
{
|
|
596
|
+
case EVFILT_VNODE:
|
|
597
|
+
_HandleKqueueFileEvent (ke);
|
|
598
|
+
break;
|
|
599
|
+
|
|
600
|
+
case EVFILT_PROC:
|
|
601
|
+
_HandleKqueuePidEvent (ke);
|
|
602
|
+
break;
|
|
603
|
+
|
|
604
|
+
case EVFILT_READ:
|
|
605
|
+
case EVFILT_WRITE:
|
|
606
|
+
EventableDescriptor *ed = (EventableDescriptor*) (ke->udata);
|
|
607
|
+
assert (ed);
|
|
570
608
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
609
|
+
if (ke->filter == EVFILT_READ)
|
|
610
|
+
ed->Read();
|
|
611
|
+
else if (ke->filter == EVFILT_WRITE)
|
|
612
|
+
ed->Write();
|
|
613
|
+
else
|
|
614
|
+
cerr << "Discarding unknown kqueue event " << ke->filter << endl;
|
|
615
|
+
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
577
618
|
|
|
578
619
|
--k;
|
|
579
620
|
++ke;
|
|
@@ -875,25 +916,11 @@ bool EventMachine_t::_RunTimers()
|
|
|
875
916
|
// Just keep inspecting and processing the list head until we hit
|
|
876
917
|
// one that hasn't expired yet.
|
|
877
918
|
|
|
878
|
-
#ifdef OS_UNIX
|
|
879
|
-
struct timeval tv;
|
|
880
|
-
gettimeofday (&tv, NULL);
|
|
881
|
-
Int64 now = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
|
|
882
|
-
#endif
|
|
883
|
-
|
|
884
|
-
#ifdef OS_WIN32
|
|
885
|
-
unsigned tick = GetTickCount();
|
|
886
|
-
if (tick < gLastTickCount)
|
|
887
|
-
gTickCountTickover += 1;
|
|
888
|
-
gLastTickCount = tick;
|
|
889
|
-
Int64 now = ((Int64)gTickCountTickover << 32) + (Int64)tick;
|
|
890
|
-
#endif
|
|
891
|
-
|
|
892
919
|
while (true) {
|
|
893
920
|
multimap<Int64,Timer_t>::iterator i = Timers.begin();
|
|
894
921
|
if (i == Timers.end())
|
|
895
922
|
break;
|
|
896
|
-
if (i->first >
|
|
923
|
+
if (i->first > gCurrentLoopTime)
|
|
897
924
|
break;
|
|
898
925
|
if (EventCallback)
|
|
899
926
|
(*EventCallback) ("", EM_TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
|
|
@@ -946,7 +973,7 @@ const char *EventMachine_t::InstallOneshotTimer (int milliseconds)
|
|
|
946
973
|
EventMachine_t::ConnectToServer
|
|
947
974
|
*******************************/
|
|
948
975
|
|
|
949
|
-
const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
976
|
+
const char *EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port)
|
|
950
977
|
{
|
|
951
978
|
/* We want to spend no more than a few seconds waiting for a connection
|
|
952
979
|
* to a remote host. So we use a nonblocking connect.
|
|
@@ -975,9 +1002,10 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
|
975
1002
|
return NULL;
|
|
976
1003
|
|
|
977
1004
|
int family, bind_size;
|
|
978
|
-
struct sockaddr
|
|
979
|
-
if (!
|
|
1005
|
+
struct sockaddr bind_as, *bind_as_ptr = name2address (server, port, &family, &bind_size);
|
|
1006
|
+
if (!bind_as_ptr)
|
|
980
1007
|
return NULL;
|
|
1008
|
+
bind_as = *bind_as_ptr; // copy because name2address points to a static
|
|
981
1009
|
|
|
982
1010
|
int sd = socket (family, SOCK_STREAM, 0);
|
|
983
1011
|
if (sd == INVALID_SOCKET)
|
|
@@ -1020,12 +1048,27 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
|
1020
1048
|
// Disable slow-start (Nagle algorithm).
|
|
1021
1049
|
int one = 1;
|
|
1022
1050
|
setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
|
|
1051
|
+
// Set reuseaddr to improve performance on restarts
|
|
1052
|
+
setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
|
|
1053
|
+
|
|
1054
|
+
if (bind_addr) {
|
|
1055
|
+
int bind_to_size, bind_to_family;
|
|
1056
|
+
struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
|
|
1057
|
+
if (!bind_to) {
|
|
1058
|
+
closesocket (sd);
|
|
1059
|
+
throw std::runtime_error ("bad bind address");
|
|
1060
|
+
}
|
|
1061
|
+
if (bind (sd, bind_to, bind_to_size) < 0) {
|
|
1062
|
+
closesocket (sd);
|
|
1063
|
+
throw std::runtime_error ("couldn't bind to address");
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1023
1066
|
|
|
1024
1067
|
const char *out = NULL;
|
|
1025
1068
|
|
|
1026
1069
|
#ifdef OS_UNIX
|
|
1027
1070
|
//if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
|
|
1028
|
-
if (connect (sd, bind_as, bind_size) == 0) {
|
|
1071
|
+
if (connect (sd, &bind_as, bind_size) == 0) {
|
|
1029
1072
|
// This is a connect success, which Linux appears
|
|
1030
1073
|
// never to give when the socket is nonblocking,
|
|
1031
1074
|
// even if the connection is intramachine or to
|
|
@@ -1098,7 +1141,7 @@ const char *EventMachine_t::ConnectToServer (const char *server, int port)
|
|
|
1098
1141
|
|
|
1099
1142
|
#ifdef OS_WIN32
|
|
1100
1143
|
//if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
|
|
1101
|
-
if (connect (sd, bind_as, bind_size) == 0) {
|
|
1144
|
+
if (connect (sd, &bind_as, bind_size) == 0) {
|
|
1102
1145
|
// This is a connect success, which Windows appears
|
|
1103
1146
|
// never to give when the socket is nonblocking,
|
|
1104
1147
|
// even if the connection is intramachine or to
|
|
@@ -1236,6 +1279,8 @@ const char *EventMachine_t::AttachFD (int fd, bool notify_readable, bool notify_
|
|
|
1236
1279
|
}
|
|
1237
1280
|
}
|
|
1238
1281
|
|
|
1282
|
+
SetSocketNonblocking(fd);
|
|
1283
|
+
|
|
1239
1284
|
ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this);
|
|
1240
1285
|
if (!cd)
|
|
1241
1286
|
throw std::runtime_error ("no connection allocated");
|
|
@@ -1929,9 +1974,290 @@ EventMachine_t::GetConnectionCount
|
|
|
1929
1974
|
|
|
1930
1975
|
int EventMachine_t::GetConnectionCount ()
|
|
1931
1976
|
{
|
|
1932
|
-
return Descriptors.size();
|
|
1977
|
+
return Descriptors.size() + NewDescriptors.size();
|
|
1933
1978
|
}
|
|
1934
1979
|
|
|
1935
1980
|
|
|
1981
|
+
/************************
|
|
1982
|
+
EventMachine_t::WatchPid
|
|
1983
|
+
************************/
|
|
1984
|
+
|
|
1985
|
+
const char *EventMachine_t::WatchPid (int pid)
|
|
1986
|
+
{
|
|
1987
|
+
#ifdef HAVE_KQUEUE
|
|
1988
|
+
if (!bKqueue)
|
|
1989
|
+
throw std::runtime_error("must enable kqueue");
|
|
1990
|
+
|
|
1991
|
+
struct kevent event;
|
|
1992
|
+
int kqres;
|
|
1993
|
+
|
|
1994
|
+
EV_SET(&event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT | NOTE_FORK, 0, 0);
|
|
1995
|
+
|
|
1996
|
+
// Attempt to register the event
|
|
1997
|
+
kqres = kevent(kqfd, &event, 1, NULL, 0, NULL);
|
|
1998
|
+
if (kqres == -1) {
|
|
1999
|
+
char errbuf[200];
|
|
2000
|
+
sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
|
|
2001
|
+
throw std::runtime_error(errbuf);
|
|
2002
|
+
}
|
|
2003
|
+
#endif
|
|
2004
|
+
|
|
2005
|
+
#ifdef HAVE_KQUEUE
|
|
2006
|
+
Bindable_t* b = new Bindable_t();
|
|
2007
|
+
Pids.insert(make_pair (pid, b));
|
|
2008
|
+
|
|
2009
|
+
return b->GetBinding().c_str();
|
|
2010
|
+
#endif
|
|
2011
|
+
|
|
2012
|
+
throw std::runtime_error("no pid watching support on this system");
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
/**************************
|
|
2016
|
+
EventMachine_t::UnwatchPid
|
|
2017
|
+
**************************/
|
|
2018
|
+
|
|
2019
|
+
void EventMachine_t::UnwatchPid (int pid)
|
|
2020
|
+
{
|
|
2021
|
+
Bindable_t *b = Pids[pid];
|
|
2022
|
+
assert(b);
|
|
2023
|
+
Pids.erase(pid);
|
|
2024
|
+
|
|
2025
|
+
#ifdef HAVE_KQUEUE
|
|
2026
|
+
struct kevent k;
|
|
2027
|
+
|
|
2028
|
+
EV_SET(&k, pid, EVFILT_PROC, EV_DELETE, 0, 0, 0);
|
|
2029
|
+
int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
|
|
2030
|
+
// t==-1 if the process already exited; ignore this for now
|
|
2031
|
+
#endif
|
|
2032
|
+
|
|
2033
|
+
if (EventCallback)
|
|
2034
|
+
(*EventCallback)(b->GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, 0);
|
|
2035
|
+
|
|
2036
|
+
delete b;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
void EventMachine_t::UnwatchPid (const char *sig)
|
|
2040
|
+
{
|
|
2041
|
+
for(map<int, Bindable_t*>::iterator i=Pids.begin(); i != Pids.end(); i++)
|
|
2042
|
+
{
|
|
2043
|
+
if (strncmp(i->second->GetBinding().c_str(), sig, strlen(sig)) == 0) {
|
|
2044
|
+
UnwatchPid (i->first);
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
throw std::runtime_error("attempted to remove invalid pid signature");
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
/*************************
|
|
2054
|
+
EventMachine_t::WatchFile
|
|
2055
|
+
*************************/
|
|
2056
|
+
|
|
2057
|
+
const char *EventMachine_t::WatchFile (const char *fpath)
|
|
2058
|
+
{
|
|
2059
|
+
struct stat sb;
|
|
2060
|
+
int sres;
|
|
2061
|
+
int wd = -1;
|
|
2062
|
+
|
|
2063
|
+
sres = stat(fpath, &sb);
|
|
2064
|
+
|
|
2065
|
+
if (sres == -1) {
|
|
2066
|
+
char errbuf[300];
|
|
2067
|
+
sprintf(errbuf, "error registering file %s for watching: %s", fpath, strerror(errno));
|
|
2068
|
+
throw std::runtime_error(errbuf);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
#ifdef HAVE_INOTIFY
|
|
2072
|
+
if (!inotify) {
|
|
2073
|
+
inotify = new InotifyDescriptor(this);
|
|
2074
|
+
assert (inotify);
|
|
2075
|
+
Add(inotify);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
wd = inotify_add_watch(inotify->GetSocket(), fpath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF);
|
|
2079
|
+
if (wd == -1) {
|
|
2080
|
+
char errbuf[300];
|
|
2081
|
+
sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno));
|
|
2082
|
+
throw std::runtime_error(errbuf);
|
|
2083
|
+
}
|
|
2084
|
+
#endif
|
|
2085
|
+
|
|
2086
|
+
#ifdef HAVE_KQUEUE
|
|
2087
|
+
if (!bKqueue)
|
|
2088
|
+
throw std::runtime_error("must enable kqueue");
|
|
2089
|
+
|
|
2090
|
+
// With kqueue we have to open the file first and use the resulting fd to register for events
|
|
2091
|
+
wd = open(fpath, O_RDONLY);
|
|
2092
|
+
if (wd == -1) {
|
|
2093
|
+
char errbuf[300];
|
|
2094
|
+
sprintf(errbuf, "failed to open file %s for registering with kqueue: %s", fpath, strerror(errno));
|
|
2095
|
+
throw std::runtime_error(errbuf);
|
|
2096
|
+
}
|
|
2097
|
+
_RegisterKqueueFileEvent(wd);
|
|
2098
|
+
#endif
|
|
2099
|
+
|
|
2100
|
+
if (wd != -1) {
|
|
2101
|
+
Bindable_t* b = new Bindable_t();
|
|
2102
|
+
Files.insert(make_pair (wd, b));
|
|
2103
|
+
|
|
2104
|
+
return b->GetBinding().c_str();
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
throw std::runtime_error("no file watching support on this system"); // is this the right thing to do?
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
|
|
2111
|
+
/***************************
|
|
2112
|
+
EventMachine_t::UnwatchFile
|
|
2113
|
+
***************************/
|
|
2114
|
+
|
|
2115
|
+
void EventMachine_t::UnwatchFile (int wd)
|
|
2116
|
+
{
|
|
2117
|
+
Bindable_t *b = Files[wd];
|
|
2118
|
+
assert(b);
|
|
2119
|
+
Files.erase(wd);
|
|
2120
|
+
|
|
2121
|
+
#ifdef HAVE_INOTIFY
|
|
2122
|
+
inotify_rm_watch(inotify->GetSocket(), wd);
|
|
2123
|
+
#elif HAVE_KQUEUE
|
|
2124
|
+
// With kqueue, closing the monitored fd automatically clears all registered events for it
|
|
2125
|
+
close(wd);
|
|
2126
|
+
#endif
|
|
2127
|
+
|
|
2128
|
+
if (EventCallback)
|
|
2129
|
+
(*EventCallback)(b->GetBinding().c_str(), EM_CONNECTION_UNBOUND, NULL, 0);
|
|
2130
|
+
|
|
2131
|
+
delete b;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
void EventMachine_t::UnwatchFile (const char *sig)
|
|
2135
|
+
{
|
|
2136
|
+
for(map<int, Bindable_t*>::iterator i=Files.begin(); i != Files.end(); i++)
|
|
2137
|
+
{
|
|
2138
|
+
if (strncmp(i->second->GetBinding().c_str(), sig, strlen(sig)) == 0) {
|
|
2139
|
+
UnwatchFile (i->first);
|
|
2140
|
+
return;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
throw std::runtime_error("attempted to remove invalid watch signature");
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
|
|
2147
|
+
/***********************************
|
|
2148
|
+
EventMachine_t::_ReadInotify_Events
|
|
2149
|
+
************************************/
|
|
2150
|
+
|
|
2151
|
+
void EventMachine_t::_ReadInotifyEvents()
|
|
2152
|
+
{
|
|
2153
|
+
#ifdef HAVE_INOTIFY
|
|
2154
|
+
struct inotify_event event;
|
|
2155
|
+
|
|
2156
|
+
assert(EventCallback);
|
|
2157
|
+
|
|
2158
|
+
while (read(inotify->GetSocket(), &event, INOTIFY_EVENT_SIZE) > 0) {
|
|
2159
|
+
assert(event.len == 0);
|
|
2160
|
+
if (event.mask & IN_MODIFY)
|
|
2161
|
+
(*EventCallback)(Files [event.wd]->GetBinding().c_str(), EM_CONNECTION_READ, "modified", 8);
|
|
2162
|
+
if (event.mask & IN_MOVE_SELF)
|
|
2163
|
+
(*EventCallback)(Files [event.wd]->GetBinding().c_str(), EM_CONNECTION_READ, "moved", 5);
|
|
2164
|
+
if (event.mask & IN_DELETE_SELF) {
|
|
2165
|
+
(*EventCallback)(Files [event.wd]->GetBinding().c_str(), EM_CONNECTION_READ, "deleted", 7);
|
|
2166
|
+
UnwatchFile (event.wd);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
#endif
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
|
|
2173
|
+
/*************************************
|
|
2174
|
+
EventMachine_t::_HandleKqueuePidEvent
|
|
2175
|
+
*************************************/
|
|
2176
|
+
|
|
2177
|
+
#ifdef HAVE_KQUEUE
|
|
2178
|
+
void EventMachine_t::_HandleKqueuePidEvent(struct kevent *event)
|
|
2179
|
+
{
|
|
2180
|
+
assert(EventCallback);
|
|
2181
|
+
|
|
2182
|
+
if (event->fflags & NOTE_FORK)
|
|
2183
|
+
(*EventCallback)(Pids [(int) event->ident]->GetBinding().c_str(), EM_CONNECTION_READ, "fork", 4);
|
|
2184
|
+
if (event->fflags & NOTE_EXIT) {
|
|
2185
|
+
(*EventCallback)(Pids [(int) event->ident]->GetBinding().c_str(), EM_CONNECTION_READ, "exit", 4);
|
|
2186
|
+
// stop watching the pid if it died
|
|
2187
|
+
UnwatchPid (event->ident);
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
#endif
|
|
2191
|
+
|
|
2192
|
+
|
|
2193
|
+
/**************************************
|
|
2194
|
+
EventMachine_t::_HandleKqueueFileEvent
|
|
2195
|
+
***************************************/
|
|
2196
|
+
|
|
2197
|
+
#ifdef HAVE_KQUEUE
|
|
2198
|
+
void EventMachine_t::_HandleKqueueFileEvent(struct kevent *event)
|
|
2199
|
+
{
|
|
2200
|
+
assert(EventCallback);
|
|
2201
|
+
|
|
2202
|
+
if (event->fflags & NOTE_WRITE)
|
|
2203
|
+
(*EventCallback)(Files [(int) event->ident]->GetBinding().c_str(), EM_CONNECTION_READ, "modified", 8);
|
|
2204
|
+
if (event->fflags & NOTE_RENAME)
|
|
2205
|
+
(*EventCallback)(Files [(int) event->ident]->GetBinding().c_str(), EM_CONNECTION_READ, "moved", 5);
|
|
2206
|
+
if (event->fflags & NOTE_DELETE) {
|
|
2207
|
+
(*EventCallback)(Files [(int) event->ident]->GetBinding().c_str(), EM_CONNECTION_READ, "deleted", 7);
|
|
2208
|
+
UnwatchFile (event->ident);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
#endif
|
|
2212
|
+
|
|
2213
|
+
|
|
2214
|
+
/****************************************
|
|
2215
|
+
EventMachine_t::_RegisterKqueueFileEvent
|
|
2216
|
+
*****************************************/
|
|
2217
|
+
|
|
2218
|
+
#ifdef HAVE_KQUEUE
|
|
2219
|
+
void EventMachine_t::_RegisterKqueueFileEvent(int fd)
|
|
2220
|
+
{
|
|
2221
|
+
struct kevent newevent;
|
|
2222
|
+
int kqres;
|
|
2223
|
+
|
|
2224
|
+
// Setup the event with our fd and proper flags
|
|
2225
|
+
EV_SET(&newevent, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_WRITE, 0, 0);
|
|
2226
|
+
|
|
2227
|
+
// Attempt to register the event
|
|
2228
|
+
kqres = kevent(kqfd, &newevent, 1, NULL, 0, NULL);
|
|
2229
|
+
if (kqres == -1) {
|
|
2230
|
+
char errbuf[200];
|
|
2231
|
+
sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
|
|
2232
|
+
close(fd);
|
|
2233
|
+
throw std::runtime_error(errbuf);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
#endif
|
|
2237
|
+
|
|
2238
|
+
|
|
2239
|
+
/************************************
|
|
2240
|
+
EventMachine_t::GetHeartbeatInterval
|
|
2241
|
+
*************************************/
|
|
2242
|
+
|
|
2243
|
+
float EventMachine_t::GetHeartbeatInterval()
|
|
2244
|
+
{
|
|
2245
|
+
return ((float)HeartbeatInterval / 1000000);
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
/************************************
|
|
2250
|
+
EventMachine_t::SetHeartbeatInterval
|
|
2251
|
+
*************************************/
|
|
2252
|
+
|
|
2253
|
+
int EventMachine_t::SetHeartbeatInterval(float interval)
|
|
2254
|
+
{
|
|
2255
|
+
int iv = (int)(interval * 1000000);
|
|
2256
|
+
if (iv > 0) {
|
|
2257
|
+
HeartbeatInterval = iv;
|
|
2258
|
+
return 1;
|
|
2259
|
+
}
|
|
2260
|
+
return 0;
|
|
2261
|
+
}
|
|
1936
2262
|
//#endif // OS_UNIX
|
|
1937
2263
|
|