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.
Files changed (116) hide show
  1. data/{docs/README → README} +21 -13
  2. data/Rakefile +5 -3
  3. data/docs/DEFERRABLES +0 -5
  4. data/docs/INSTALL +2 -4
  5. data/docs/LEGAL +1 -1
  6. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -2
  7. data/docs/PURE_RUBY +0 -2
  8. data/docs/RELEASE_NOTES +0 -2
  9. data/docs/SMTP +0 -7
  10. data/docs/SPAWNED_PROCESSES +0 -4
  11. data/docs/TODO +0 -2
  12. data/eventmachine.gemspec +17 -8
  13. data/examples/ex_channel.rb +43 -0
  14. data/examples/ex_queue.rb +2 -0
  15. data/examples/helper.rb +2 -0
  16. data/ext/cmain.cpp +119 -20
  17. data/ext/cplusplus.cpp +15 -6
  18. data/ext/ed.cpp +303 -93
  19. data/ext/ed.h +49 -22
  20. data/ext/em.cpp +368 -42
  21. data/ext/em.h +43 -6
  22. data/ext/eventmachine.h +21 -8
  23. data/ext/eventmachine_cpp.h +1 -0
  24. data/ext/extconf.rb +4 -0
  25. data/ext/kb.cpp +1 -2
  26. data/ext/pipe.cpp +1 -3
  27. data/ext/project.h +21 -0
  28. data/ext/rubymain.cpp +232 -32
  29. data/ext/ssl.cpp +38 -1
  30. data/ext/ssl.h +5 -1
  31. data/java/src/com/rubyeventmachine/Application.java +7 -3
  32. data/java/src/com/rubyeventmachine/EmReactor.java +16 -1
  33. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +25 -3
  34. data/lib/{protocols → em}/buftok.rb +16 -5
  35. data/lib/em/callback.rb +26 -0
  36. data/lib/em/channel.rb +57 -0
  37. data/lib/em/connection.rb +505 -0
  38. data/lib/em/deferrable.rb +144 -165
  39. data/lib/em/file_watch.rb +54 -0
  40. data/lib/em/future.rb +24 -25
  41. data/lib/em/messages.rb +1 -1
  42. data/lib/em/process_watch.rb +44 -0
  43. data/lib/em/processes.rb +58 -52
  44. data/lib/em/protocols.rb +35 -0
  45. data/lib/em/protocols/header_and_content.rb +138 -0
  46. data/lib/em/protocols/httpclient.rb +263 -0
  47. data/lib/em/protocols/httpclient2.rb +582 -0
  48. data/lib/{protocols → em/protocols}/line_and_text.rb +2 -2
  49. data/lib/em/protocols/linetext2.rb +160 -0
  50. data/lib/{protocols → em/protocols}/memcache.rb +37 -7
  51. data/lib/em/protocols/object_protocol.rb +39 -0
  52. data/lib/em/protocols/postgres3.rb +247 -0
  53. data/lib/em/protocols/saslauth.rb +175 -0
  54. data/lib/em/protocols/smtpclient.rb +331 -0
  55. data/lib/em/protocols/smtpserver.rb +547 -0
  56. data/lib/em/protocols/stomp.rb +200 -0
  57. data/lib/{protocols → em/protocols}/tcptest.rb +21 -25
  58. data/lib/em/queue.rb +61 -0
  59. data/lib/em/spawnable.rb +53 -56
  60. data/lib/em/streamer.rb +92 -74
  61. data/lib/em/timers.rb +55 -0
  62. data/lib/em/version.rb +3 -0
  63. data/lib/eventmachine.rb +1008 -1298
  64. data/lib/evma.rb +1 -1
  65. data/lib/jeventmachine.rb +106 -101
  66. data/lib/pr_eventmachine.rb +47 -36
  67. data/tasks/project.rake +2 -1
  68. data/tests/client.crt +31 -0
  69. data/tests/client.key +51 -0
  70. data/tests/test_attach.rb +18 -0
  71. data/tests/test_basic.rb +108 -54
  72. data/tests/test_channel.rb +63 -0
  73. data/tests/test_connection_count.rb +2 -2
  74. data/tests/test_epoll.rb +109 -110
  75. data/tests/test_errors.rb +36 -36
  76. data/tests/test_exc.rb +22 -25
  77. data/tests/test_file_watch.rb +49 -0
  78. data/tests/test_futures.rb +77 -93
  79. data/tests/test_hc.rb +2 -2
  80. data/tests/test_httpclient.rb +55 -52
  81. data/tests/test_httpclient2.rb +110 -112
  82. data/tests/test_inactivity_timeout.rb +30 -0
  83. data/tests/test_kb.rb +8 -9
  84. data/tests/test_ltp2.rb +274 -277
  85. data/tests/test_next_tick.rb +91 -65
  86. data/tests/test_object_protocol.rb +37 -0
  87. data/tests/test_process_watch.rb +48 -0
  88. data/tests/test_processes.rb +56 -23
  89. data/tests/test_proxy_connection.rb +92 -0
  90. data/tests/test_pure.rb +1 -5
  91. data/tests/test_queue.rb +44 -0
  92. data/tests/test_running.rb +9 -14
  93. data/tests/test_sasl.rb +32 -34
  94. data/tests/test_send_file.rb +175 -176
  95. data/tests/test_servers.rb +37 -41
  96. data/tests/test_smtpserver.rb +47 -55
  97. data/tests/test_spawn.rb +284 -291
  98. data/tests/test_ssl_args.rb +1 -1
  99. data/tests/test_ssl_methods.rb +1 -1
  100. data/tests/test_ssl_verify.rb +82 -0
  101. data/tests/test_timers.rb +81 -88
  102. data/tests/test_ud.rb +0 -7
  103. data/tests/testem.rb +1 -1
  104. metadata +52 -36
  105. data/lib/em/eventable.rb +0 -39
  106. data/lib/eventmachine_version.rb +0 -31
  107. data/lib/protocols/header_and_content.rb +0 -129
  108. data/lib/protocols/httpcli2.rb +0 -803
  109. data/lib/protocols/httpclient.rb +0 -270
  110. data/lib/protocols/linetext2.rb +0 -161
  111. data/lib/protocols/postgres.rb +0 -261
  112. data/lib/protocols/saslauth.rb +0 -179
  113. data/lib/protocols/smtpclient.rb +0 -308
  114. data/lib/protocols/smtpserver.rb +0 -556
  115. data/lib/protocols/stomp.rb +0 -153
  116. 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
- // Properties: return 0/1 to signify T/F, and handle the values
77
- // through arguments.
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
- PendingConnectTimeout = 50 // can easily be made an instance variable
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
- time_t CreatedAt;
105
- time_t LastRead;
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 readable) { bNotifyReadable = readable; }
157
- void SetNotifyWritable (bool writable) { bNotifyWritable = writable; }
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 int GetCommInactivityTimeout (int *value);
182
- virtual int SetCommInactivityTimeout (int *value);
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
- time_t LastIo;
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 int GetCommInactivityTimeout (int *value);
255
- virtual int SetCommInactivityTimeout (int *value);
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
- time_t LastIo;
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
- time_t LastIo;
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
- time_t LastIo;
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
- time_t gCurrentLoopTime;
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
- gCurrentLoopTime = time(NULL);
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
- gCurrentLoopTime = time(NULL);
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, ev, MaxEpollDescriptors, 50);
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*) ev[i].data.ptr;
478
+ EventableDescriptor *ed = (EventableDescriptor*) epoll_events[i].data.ptr;
452
479
 
453
- if (ev[i].events & (EPOLLERR | EPOLLHUP))
480
+ if (epoll_events[i].events & (EPOLLERR | EPOLLHUP))
454
481
  ed->ScheduleClose (false);
455
- if (ev[i].events & EPOLLIN)
482
+ if (epoll_events[i].events & EPOLLIN)
456
483
  ed->Read();
457
- if (ev[i].events & EPOLLOUT) {
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, maxKevents, &ts);
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
- EventableDescriptor *ed = (EventableDescriptor*) (ke->udata);
569
- assert (ed);
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
- if (ke->filter == EVFILT_READ)
572
- ed->Read();
573
- else if (ke->filter == EVFILT_WRITE)
574
- ed->Write();
575
- else
576
- cerr << "Discarding unknown kqueue event " << ke->filter << endl;
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 > now)
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 *bind_as = name2address (server, port, &family, &bind_size);
979
- if (!bind_as)
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