eventmachine 0.12.6-java → 0.12.8-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|