sonixlabs-eventmachine-java 1.0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +33 -0
  6. data/GNU +281 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +60 -0
  9. data/README.md +109 -0
  10. data/README_JP.md +18 -0
  11. data/Rakefile +20 -0
  12. data/docs/DocumentationGuidesIndex.md +27 -0
  13. data/docs/GettingStarted.md +521 -0
  14. data/docs/old/ChangeLog +211 -0
  15. data/docs/old/DEFERRABLES +246 -0
  16. data/docs/old/EPOLL +141 -0
  17. data/docs/old/INSTALL +13 -0
  18. data/docs/old/KEYBOARD +42 -0
  19. data/docs/old/LEGAL +25 -0
  20. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  21. data/docs/old/PURE_RUBY +75 -0
  22. data/docs/old/RELEASE_NOTES +94 -0
  23. data/docs/old/SMTP +4 -0
  24. data/docs/old/SPAWNED_PROCESSES +148 -0
  25. data/docs/old/TODO +8 -0
  26. data/eventmachine.gemspec +38 -0
  27. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  28. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  29. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  30. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  31. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  32. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  33. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  34. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  35. data/examples/old/ex_channel.rb +43 -0
  36. data/examples/old/ex_queue.rb +2 -0
  37. data/examples/old/ex_tick_loop_array.rb +15 -0
  38. data/examples/old/ex_tick_loop_counter.rb +32 -0
  39. data/examples/old/helper.rb +2 -0
  40. data/ext/binder.cpp +124 -0
  41. data/ext/binder.h +46 -0
  42. data/ext/cmain.cpp +887 -0
  43. data/ext/ed.cpp +1988 -0
  44. data/ext/ed.h +422 -0
  45. data/ext/em.cpp +2351 -0
  46. data/ext/em.h +244 -0
  47. data/ext/eventmachine.h +128 -0
  48. data/ext/extconf.rb +177 -0
  49. data/ext/fastfilereader/extconf.rb +103 -0
  50. data/ext/fastfilereader/mapper.cpp +214 -0
  51. data/ext/fastfilereader/mapper.h +59 -0
  52. data/ext/fastfilereader/rubymain.cpp +127 -0
  53. data/ext/kb.cpp +79 -0
  54. data/ext/page.cpp +107 -0
  55. data/ext/page.h +51 -0
  56. data/ext/pipe.cpp +347 -0
  57. data/ext/project.h +156 -0
  58. data/ext/rubymain.cpp +1318 -0
  59. data/ext/ssl.cpp +468 -0
  60. data/ext/ssl.h +94 -0
  61. data/java/.classpath +6 -0
  62. data/java/.gitignore +1 -0
  63. data/java/.project +17 -0
  64. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  65. data/java/src/com/rubyeventmachine/EmReactor.java +529 -0
  66. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  67. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  68. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  69. data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
  70. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +180 -0
  71. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
  72. data/java/src/com/rubyeventmachine/SslBox.java +310 -0
  73. data/lib/em/buftok.rb +110 -0
  74. data/lib/em/callback.rb +58 -0
  75. data/lib/em/channel.rb +64 -0
  76. data/lib/em/completion.rb +304 -0
  77. data/lib/em/connection.rb +712 -0
  78. data/lib/em/deferrable.rb +210 -0
  79. data/lib/em/deferrable/pool.rb +2 -0
  80. data/lib/em/file_watch.rb +73 -0
  81. data/lib/em/future.rb +61 -0
  82. data/lib/em/iterator.rb +231 -0
  83. data/lib/em/messages.rb +66 -0
  84. data/lib/em/pool.rb +151 -0
  85. data/lib/em/process_watch.rb +45 -0
  86. data/lib/em/processes.rb +123 -0
  87. data/lib/em/protocols.rb +37 -0
  88. data/lib/em/protocols/header_and_content.rb +138 -0
  89. data/lib/em/protocols/httpclient.rb +279 -0
  90. data/lib/em/protocols/httpclient2.rb +600 -0
  91. data/lib/em/protocols/line_and_text.rb +125 -0
  92. data/lib/em/protocols/line_protocol.rb +29 -0
  93. data/lib/em/protocols/linetext2.rb +161 -0
  94. data/lib/em/protocols/memcache.rb +331 -0
  95. data/lib/em/protocols/object_protocol.rb +46 -0
  96. data/lib/em/protocols/postgres3.rb +246 -0
  97. data/lib/em/protocols/saslauth.rb +175 -0
  98. data/lib/em/protocols/smtpclient.rb +365 -0
  99. data/lib/em/protocols/smtpserver.rb +643 -0
  100. data/lib/em/protocols/socks4.rb +66 -0
  101. data/lib/em/protocols/stomp.rb +205 -0
  102. data/lib/em/protocols/tcptest.rb +54 -0
  103. data/lib/em/pure_ruby.rb +1017 -0
  104. data/lib/em/queue.rb +71 -0
  105. data/lib/em/resolver.rb +192 -0
  106. data/lib/em/spawnable.rb +84 -0
  107. data/lib/em/streamer.rb +118 -0
  108. data/lib/em/threaded_resource.rb +90 -0
  109. data/lib/em/tick_loop.rb +85 -0
  110. data/lib/em/timers.rb +61 -0
  111. data/lib/em/version.rb +3 -0
  112. data/lib/eventmachine.rb +1553 -0
  113. data/lib/jeventmachine.rb +331 -0
  114. data/lib/sonixlabs-eventmachine-java.rb +1 -0
  115. data/rakelib/cpp.rake_example +77 -0
  116. data/rakelib/package.rake +96 -0
  117. data/rakelib/test.rake +8 -0
  118. data/tests/client.crt +31 -0
  119. data/tests/client.key +51 -0
  120. data/tests/em_test_helper.rb +64 -0
  121. data/tests/server.crt +36 -0
  122. data/tests/server.key +51 -0
  123. data/tests/test_attach.rb +150 -0
  124. data/tests/test_basic.rb +294 -0
  125. data/tests/test_channel.rb +62 -0
  126. data/tests/test_completion.rb +177 -0
  127. data/tests/test_connection_count.rb +53 -0
  128. data/tests/test_defer.rb +18 -0
  129. data/tests/test_deferrable.rb +35 -0
  130. data/tests/test_epoll.rb +145 -0
  131. data/tests/test_error_handler.rb +38 -0
  132. data/tests/test_exc.rb +28 -0
  133. data/tests/test_file_watch.rb +65 -0
  134. data/tests/test_futures.rb +170 -0
  135. data/tests/test_get_sock_opt.rb +37 -0
  136. data/tests/test_handler_check.rb +35 -0
  137. data/tests/test_hc.rb +155 -0
  138. data/tests/test_httpclient.rb +190 -0
  139. data/tests/test_httpclient2.rb +133 -0
  140. data/tests/test_idle_connection.rb +25 -0
  141. data/tests/test_inactivity_timeout.rb +54 -0
  142. data/tests/test_iterator.rb +97 -0
  143. data/tests/test_kb.rb +34 -0
  144. data/tests/test_line_protocol.rb +33 -0
  145. data/tests/test_ltp.rb +138 -0
  146. data/tests/test_ltp2.rb +288 -0
  147. data/tests/test_next_tick.rb +104 -0
  148. data/tests/test_object_protocol.rb +36 -0
  149. data/tests/test_pause.rb +102 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +194 -0
  152. data/tests/test_process_watch.rb +48 -0
  153. data/tests/test_processes.rb +128 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +88 -0
  156. data/tests/test_queue.rb +50 -0
  157. data/tests/test_resolver.rb +55 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +47 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +33 -0
  162. data/tests/test_set_sock_opt.rb +37 -0
  163. data/tests/test_shutdown_hooks.rb +23 -0
  164. data/tests/test_smtpclient.rb +55 -0
  165. data/tests/test_smtpserver.rb +57 -0
  166. data/tests/test_spawn.rb +293 -0
  167. data/tests/test_ssl_args.rb +78 -0
  168. data/tests/test_ssl_echo_data.rb +60 -0
  169. data/tests/test_ssl_methods.rb +56 -0
  170. data/tests/test_ssl_verify.rb +82 -0
  171. data/tests/test_stomp.rb +37 -0
  172. data/tests/test_system.rb +42 -0
  173. data/tests/test_threaded_resource.rb +53 -0
  174. data/tests/test_tick_loop.rb +59 -0
  175. data/tests/test_timers.rb +123 -0
  176. data/tests/test_ud.rb +8 -0
  177. data/tests/test_unbind_reason.rb +48 -0
  178. metadata +298 -0
@@ -0,0 +1,422 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: ed.h
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #ifndef __EventableDescriptor__H_
21
+ #define __EventableDescriptor__H_
22
+
23
+
24
+ class EventMachine_t; // forward reference
25
+ #ifdef WITH_SSL
26
+ class SslBox_t; // forward reference
27
+ #endif
28
+
29
+ bool SetSocketNonblocking (SOCKET);
30
+
31
+
32
+ /*************************
33
+ class EventableDescriptor
34
+ *************************/
35
+
36
+ class EventableDescriptor: public Bindable_t
37
+ {
38
+ public:
39
+ EventableDescriptor (int, EventMachine_t*);
40
+ virtual ~EventableDescriptor();
41
+
42
+ int GetSocket() {return MySocket;}
43
+ void SetSocketInvalid() { MySocket = INVALID_SOCKET; }
44
+ void Close();
45
+
46
+ virtual void Read() = 0;
47
+ virtual void Write() = 0;
48
+ virtual void Heartbeat() = 0;
49
+
50
+ // These methods tell us whether the descriptor
51
+ // should be selected or polled for read/write.
52
+ virtual bool SelectForRead() = 0;
53
+ virtual bool SelectForWrite() = 0;
54
+
55
+ // are we scheduled for a close, or in an error state, or already closed?
56
+ bool ShouldDelete();
57
+ // Do we have any data to write? This is used by ShouldDelete.
58
+ virtual int GetOutboundDataSize() {return 0;}
59
+ virtual bool IsWatchOnly(){ return bWatchOnly; }
60
+
61
+ virtual void ScheduleClose (bool after_writing);
62
+ bool IsCloseScheduled();
63
+ virtual void HandleError(){ ScheduleClose (false); }
64
+
65
+ void SetEventCallback (EMCallback);
66
+
67
+ virtual bool GetPeername (struct sockaddr*, socklen_t*) {return false;}
68
+ virtual bool GetSockname (struct sockaddr*, socklen_t*) {return false;}
69
+ virtual bool GetSubprocessPid (pid_t*) {return false;}
70
+
71
+ virtual void StartTls() {}
72
+ virtual void SetTlsParms (const char *, const char *, bool) {}
73
+
74
+ #ifdef WITH_SSL
75
+ virtual X509 *GetPeerCert() {return NULL;}
76
+ #endif
77
+
78
+ virtual uint64_t GetCommInactivityTimeout() {return 0;}
79
+ virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
80
+ uint64_t GetPendingConnectTimeout();
81
+ int SetPendingConnectTimeout (uint64_t value);
82
+ uint64_t GetLastActivity() { return LastActivity; }
83
+
84
+ #ifdef HAVE_EPOLL
85
+ struct epoll_event *GetEpollEvent() { return &EpollEvent; }
86
+ #endif
87
+
88
+ virtual void StartProxy(const unsigned long, const unsigned long, const unsigned long);
89
+ virtual void StopProxy();
90
+ virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; };
91
+ virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
92
+ virtual int SendOutboundData(const char*,int){ return -1; }
93
+ virtual bool IsPaused(){ return bPaused; }
94
+ virtual bool Pause(){ bPaused = true; return bPaused; }
95
+ virtual bool Resume(){ bPaused = false; return bPaused; }
96
+
97
+ void SetUnbindReasonCode(int code){ UnbindReasonCode = code; }
98
+ virtual int ReportErrorStatus(){ return 0; }
99
+ virtual bool IsConnectPending(){ return false; }
100
+ virtual uint64_t GetNextHeartbeat();
101
+
102
+ private:
103
+ bool bCloseNow;
104
+ bool bCloseAfterWriting;
105
+
106
+ protected:
107
+ int MySocket;
108
+ bool bAttached;
109
+ bool bWatchOnly;
110
+
111
+ EMCallback EventCallback;
112
+ void _GenericInboundDispatch(const char*, int);
113
+
114
+ uint64_t CreatedAt;
115
+ bool bCallbackUnbind;
116
+ int UnbindReasonCode;
117
+
118
+ unsigned long BytesToProxy;
119
+ EventableDescriptor *ProxyTarget;
120
+ EventableDescriptor *ProxiedFrom;
121
+ unsigned long ProxiedBytes;
122
+
123
+ unsigned long MaxOutboundBufSize;
124
+
125
+ #ifdef HAVE_EPOLL
126
+ struct epoll_event EpollEvent;
127
+ #endif
128
+
129
+ EventMachine_t *MyEventMachine;
130
+ uint64_t PendingConnectTimeout;
131
+ uint64_t InactivityTimeout;
132
+ uint64_t LastActivity;
133
+ uint64_t NextHeartbeat;
134
+ bool bPaused;
135
+ };
136
+
137
+
138
+
139
+ /*************************
140
+ class LoopbreakDescriptor
141
+ *************************/
142
+
143
+ class LoopbreakDescriptor: public EventableDescriptor
144
+ {
145
+ public:
146
+ LoopbreakDescriptor (int, EventMachine_t*);
147
+ virtual ~LoopbreakDescriptor() {}
148
+
149
+ virtual void Read();
150
+ virtual void Write();
151
+ virtual void Heartbeat() {}
152
+
153
+ virtual bool SelectForRead() {return true;}
154
+ virtual bool SelectForWrite() {return false;}
155
+ };
156
+
157
+
158
+ /**************************
159
+ class ConnectionDescriptor
160
+ **************************/
161
+
162
+ class ConnectionDescriptor: public EventableDescriptor
163
+ {
164
+ public:
165
+ ConnectionDescriptor (int, EventMachine_t*);
166
+ virtual ~ConnectionDescriptor();
167
+
168
+ int SendOutboundData (const char*, int);
169
+
170
+ void SetConnectPending (bool f);
171
+ virtual void ScheduleClose (bool after_writing);
172
+ virtual void HandleError();
173
+
174
+ void SetNotifyReadable (bool);
175
+ void SetNotifyWritable (bool);
176
+ void SetAttached (bool);
177
+ void SetWatchOnly (bool);
178
+
179
+ bool Pause();
180
+ bool Resume();
181
+
182
+ bool IsNotifyReadable(){ return bNotifyReadable; }
183
+ bool IsNotifyWritable(){ return bNotifyWritable; }
184
+
185
+ virtual void Read();
186
+ virtual void Write();
187
+ virtual void Heartbeat();
188
+
189
+ virtual bool SelectForRead();
190
+ virtual bool SelectForWrite();
191
+
192
+ // Do we have any data to write? This is used by ShouldDelete.
193
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
194
+
195
+ virtual void StartTls();
196
+ virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer);
197
+
198
+ #ifdef WITH_SSL
199
+ virtual X509 *GetPeerCert();
200
+ virtual bool VerifySslPeer(const char*);
201
+ virtual void AcceptSslPeer();
202
+ #endif
203
+
204
+ void SetServerMode() {bIsServer = true;}
205
+
206
+ virtual bool GetPeername (struct sockaddr*, socklen_t*);
207
+ virtual bool GetSockname (struct sockaddr*, socklen_t*);
208
+
209
+ virtual uint64_t GetCommInactivityTimeout();
210
+ virtual int SetCommInactivityTimeout (uint64_t value);
211
+
212
+ virtual int ReportErrorStatus();
213
+ virtual bool IsConnectPending(){ return bConnectPending; }
214
+
215
+ protected:
216
+ struct OutboundPage {
217
+ OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
218
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
219
+ const char *Buffer;
220
+ int Length;
221
+ int Offset;
222
+ };
223
+
224
+ protected:
225
+ bool bConnectPending;
226
+
227
+ bool bNotifyReadable;
228
+ bool bNotifyWritable;
229
+
230
+ bool bReadAttemptedAfterClose;
231
+ bool bWriteAttemptedAfterClose;
232
+
233
+ deque<OutboundPage> OutboundPages;
234
+ int OutboundDataSize;
235
+
236
+ #ifdef WITH_SSL
237
+ SslBox_t *SslBox;
238
+ std::string CertChainFilename;
239
+ std::string PrivateKeyFilename;
240
+ bool bHandshakeSignaled;
241
+ bool bSslVerifyPeer;
242
+ bool bSslPeerAccepted;
243
+ #endif
244
+
245
+ #ifdef HAVE_KQUEUE
246
+ bool bGotExtraKqueueEvent;
247
+ #endif
248
+
249
+ bool bIsServer;
250
+
251
+ private:
252
+ void _UpdateEvents();
253
+ void _UpdateEvents(bool, bool);
254
+ void _WriteOutboundData();
255
+ void _DispatchInboundData (const char *buffer, int size);
256
+ void _DispatchCiphertext();
257
+ int _SendRawOutboundData (const char*, int);
258
+ void _CheckHandshakeStatus();
259
+
260
+ };
261
+
262
+
263
+ /************************
264
+ class DatagramDescriptor
265
+ ************************/
266
+
267
+ class DatagramDescriptor: public EventableDescriptor
268
+ {
269
+ public:
270
+ DatagramDescriptor (int, EventMachine_t*);
271
+ virtual ~DatagramDescriptor();
272
+
273
+ virtual void Read();
274
+ virtual void Write();
275
+ virtual void Heartbeat();
276
+
277
+ virtual bool SelectForRead() {return true;}
278
+ virtual bool SelectForWrite();
279
+
280
+ int SendOutboundData (const char*, int);
281
+ int SendOutboundDatagram (const char*, int, const char*, int);
282
+
283
+ // Do we have any data to write? This is used by ShouldDelete.
284
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
285
+
286
+ virtual bool GetPeername (struct sockaddr*, socklen_t*);
287
+ virtual bool GetSockname (struct sockaddr*, socklen_t*);
288
+
289
+ virtual uint64_t GetCommInactivityTimeout();
290
+ virtual int SetCommInactivityTimeout (uint64_t value);
291
+
292
+ protected:
293
+ struct OutboundPage {
294
+ OutboundPage (const char *b, int l, struct sockaddr_in f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
295
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
296
+ const char *Buffer;
297
+ int Length;
298
+ int Offset;
299
+ struct sockaddr_in From;
300
+ };
301
+
302
+ deque<OutboundPage> OutboundPages;
303
+ int OutboundDataSize;
304
+
305
+ struct sockaddr_in ReturnAddress;
306
+ };
307
+
308
+
309
+ /************************
310
+ class AcceptorDescriptor
311
+ ************************/
312
+
313
+ class AcceptorDescriptor: public EventableDescriptor
314
+ {
315
+ public:
316
+ AcceptorDescriptor (int, EventMachine_t*);
317
+ virtual ~AcceptorDescriptor();
318
+
319
+ virtual void Read();
320
+ virtual void Write();
321
+ virtual void Heartbeat();
322
+
323
+ virtual bool SelectForRead() {return true;}
324
+ virtual bool SelectForWrite() {return false;}
325
+
326
+ virtual bool GetSockname (struct sockaddr*, socklen_t*);
327
+
328
+ static void StopAcceptor (const unsigned long binding);
329
+ };
330
+
331
+ /********************
332
+ class PipeDescriptor
333
+ ********************/
334
+
335
+ #ifdef OS_UNIX
336
+ class PipeDescriptor: public EventableDescriptor
337
+ {
338
+ public:
339
+ PipeDescriptor (int, pid_t, EventMachine_t*);
340
+ virtual ~PipeDescriptor();
341
+
342
+ virtual void Read();
343
+ virtual void Write();
344
+ virtual void Heartbeat();
345
+
346
+ virtual bool SelectForRead();
347
+ virtual bool SelectForWrite();
348
+
349
+ int SendOutboundData (const char*, int);
350
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
351
+
352
+ virtual bool GetSubprocessPid (pid_t*);
353
+
354
+ protected:
355
+ struct OutboundPage {
356
+ OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
357
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
358
+ const char *Buffer;
359
+ int Length;
360
+ int Offset;
361
+ };
362
+
363
+ protected:
364
+ bool bReadAttemptedAfterClose;
365
+
366
+ deque<OutboundPage> OutboundPages;
367
+ int OutboundDataSize;
368
+
369
+ pid_t SubprocessPid;
370
+
371
+ private:
372
+ void _DispatchInboundData (const char *buffer, int size);
373
+ };
374
+ #endif // OS_UNIX
375
+
376
+
377
+ /************************
378
+ class KeyboardDescriptor
379
+ ************************/
380
+
381
+ class KeyboardDescriptor: public EventableDescriptor
382
+ {
383
+ public:
384
+ KeyboardDescriptor (EventMachine_t*);
385
+ virtual ~KeyboardDescriptor();
386
+
387
+ virtual void Read();
388
+ virtual void Write();
389
+ virtual void Heartbeat();
390
+
391
+ virtual bool SelectForRead() {return true;}
392
+ virtual bool SelectForWrite() {return false;}
393
+
394
+ protected:
395
+ bool bReadAttemptedAfterClose;
396
+
397
+ private:
398
+ void _DispatchInboundData (const char *buffer, int size);
399
+ };
400
+
401
+
402
+ /***********************
403
+ class InotifyDescriptor
404
+ ************************/
405
+
406
+ class InotifyDescriptor: public EventableDescriptor
407
+ {
408
+ public:
409
+ InotifyDescriptor (EventMachine_t*);
410
+ virtual ~InotifyDescriptor();
411
+
412
+ void Read();
413
+ void Write();
414
+
415
+ virtual void Heartbeat() {}
416
+ virtual bool SelectForRead() {return true;}
417
+ virtual bool SelectForWrite() {return false;}
418
+ };
419
+
420
+ #endif // __EventableDescriptor__H_
421
+
422
+
@@ -0,0 +1,2351 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: em.cpp
6
+ Date: 06Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ // THIS ENTIRE FILE WILL EVENTUALLY BE FOR UNIX BUILDS ONLY.
21
+ //#ifdef OS_UNIX
22
+
23
+ #include "project.h"
24
+
25
+ /* The numer of max outstanding timers was once a const enum defined in em.h.
26
+ * Now we define it here so that users can change its value if necessary.
27
+ */
28
+ static unsigned int MaxOutstandingTimers = 100000;
29
+
30
+
31
+ /* Internal helper to convert strings to internet addresses. IPv6-aware.
32
+ * Not reentrant or threadsafe, optimized for speed.
33
+ */
34
+ static struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size);
35
+
36
+ /***************************************
37
+ STATIC EventMachine_t::GetMaxTimerCount
38
+ ***************************************/
39
+
40
+ int EventMachine_t::GetMaxTimerCount()
41
+ {
42
+ return MaxOutstandingTimers;
43
+ }
44
+
45
+
46
+ /***************************************
47
+ STATIC EventMachine_t::SetMaxTimerCount
48
+ ***************************************/
49
+
50
+ void EventMachine_t::SetMaxTimerCount (int count)
51
+ {
52
+ /* Allow a user to increase the maximum number of outstanding timers.
53
+ * If this gets "too high" (a metric that is of course platform dependent),
54
+ * bad things will happen like performance problems and possible overuse
55
+ * of memory.
56
+ * The actual timer mechanism is very efficient so it's hard to know what
57
+ * the practical max, but 100,000 shouldn't be too problematical.
58
+ */
59
+ if (count < 100)
60
+ count = 100;
61
+ MaxOutstandingTimers = count;
62
+ }
63
+
64
+
65
+
66
+ /******************************
67
+ EventMachine_t::EventMachine_t
68
+ ******************************/
69
+
70
+ EventMachine_t::EventMachine_t (EMCallback event_callback):
71
+ HeartbeatInterval(2000000),
72
+ EventCallback (event_callback),
73
+ NextHeartbeatTime (0),
74
+ LoopBreakerReader (-1),
75
+ LoopBreakerWriter (-1),
76
+ NumCloseScheduled (0),
77
+ bTerminateSignalReceived (false),
78
+ bEpoll (false),
79
+ epfd (-1),
80
+ bKqueue (false),
81
+ kqfd (-1),
82
+ inotify (NULL)
83
+ {
84
+ // Default time-slice is just smaller than one hundred mills.
85
+ Quantum.tv_sec = 0;
86
+ Quantum.tv_usec = 90000;
87
+
88
+ // Make sure the current loop time is sane, in case we do any initializations of
89
+ // objects before we start running.
90
+ _UpdateTime();
91
+
92
+ /* We initialize the network library here (only on Windows of course)
93
+ * and initialize "loop breakers." Our destructor also does some network-level
94
+ * cleanup. There's thus an implicit assumption that any given instance of EventMachine_t
95
+ * will only call ::Run once. Is that a good assumption? Should we move some of these
96
+ * inits and de-inits into ::Run?
97
+ */
98
+ #ifdef OS_WIN32
99
+ WSADATA w;
100
+ WSAStartup (MAKEWORD (1, 1), &w);
101
+ #endif
102
+
103
+ _InitializeLoopBreaker();
104
+ }
105
+
106
+
107
+ /*******************************
108
+ EventMachine_t::~EventMachine_t
109
+ *******************************/
110
+
111
+ EventMachine_t::~EventMachine_t()
112
+ {
113
+ // Run down descriptors
114
+ size_t i;
115
+ for (i = 0; i < NewDescriptors.size(); i++)
116
+ delete NewDescriptors[i];
117
+ for (i = 0; i < Descriptors.size(); i++)
118
+ delete Descriptors[i];
119
+
120
+ close (LoopBreakerReader);
121
+ close (LoopBreakerWriter);
122
+
123
+ // Remove any file watch descriptors
124
+ while(!Files.empty()) {
125
+ map<int, Bindable_t*>::iterator f = Files.begin();
126
+ UnwatchFile (f->first);
127
+ }
128
+
129
+ if (epfd != -1)
130
+ close (epfd);
131
+ if (kqfd != -1)
132
+ close (kqfd);
133
+ }
134
+
135
+
136
+ /*************************
137
+ EventMachine_t::_UseEpoll
138
+ *************************/
139
+
140
+ void EventMachine_t::_UseEpoll()
141
+ {
142
+ /* Temporary.
143
+ * Use an internal flag to switch in epoll-based functionality until we determine
144
+ * how it should be integrated properly and the extent of the required changes.
145
+ * A permanent solution needs to allow the integration of additional technologies,
146
+ * like kqueue and Solaris's events.
147
+ */
148
+
149
+ #ifdef HAVE_EPOLL
150
+ bEpoll = true;
151
+ #endif
152
+ }
153
+
154
+ /**************************
155
+ EventMachine_t::_UseKqueue
156
+ **************************/
157
+
158
+ void EventMachine_t::_UseKqueue()
159
+ {
160
+ /* Temporary.
161
+ * See comments under _UseEpoll.
162
+ */
163
+
164
+ #ifdef HAVE_KQUEUE
165
+ bKqueue = true;
166
+ #endif
167
+ }
168
+
169
+
170
+ /****************************
171
+ EventMachine_t::ScheduleHalt
172
+ ****************************/
173
+
174
+ void EventMachine_t::ScheduleHalt()
175
+ {
176
+ /* This is how we stop the machine.
177
+ * This can be called by clients. Signal handlers will probably
178
+ * set the global flag.
179
+ * For now this means there can only be one EventMachine ever running at a time.
180
+ *
181
+ * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
182
+ * because it may be called from signal handlers invoked from code that we don't
183
+ * control. At this writing (20Sep06), EM does NOT install any signal handlers of
184
+ * its own.
185
+ *
186
+ * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
187
+ * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
188
+ */
189
+ bTerminateSignalReceived = true;
190
+ }
191
+
192
+
193
+
194
+ /*******************************
195
+ EventMachine_t::SetTimerQuantum
196
+ *******************************/
197
+
198
+ void EventMachine_t::SetTimerQuantum (int interval)
199
+ {
200
+ /* We get a timer-quantum expressed in milliseconds.
201
+ */
202
+
203
+ if ((interval < 5) || (interval > 5*60*1000))
204
+ throw std::runtime_error ("invalid timer-quantum");
205
+
206
+ Quantum.tv_sec = interval / 1000;
207
+ Quantum.tv_usec = (interval % 1000) * 1000;
208
+ }
209
+
210
+
211
+ /*************************************
212
+ (STATIC) EventMachine_t::SetuidString
213
+ *************************************/
214
+
215
+ void EventMachine_t::SetuidString (const char *username)
216
+ {
217
+ /* This method takes a caller-supplied username and tries to setuid
218
+ * to that user. There is no meaningful implementation (and no error)
219
+ * on Windows. On Unix, a failure to setuid the caller-supplied string
220
+ * causes a fatal abort, because presumably the program is calling here
221
+ * in order to fulfill a security requirement. If we fail silently,
222
+ * the user may continue to run with too much privilege.
223
+ *
224
+ * TODO, we need to decide on and document a way of generating C++ level errors
225
+ * that can be wrapped in documented Ruby exceptions, so users can catch
226
+ * and handle them. And distinguish it from errors that we WON'T let the Ruby
227
+ * user catch (like security-violations and resource-overallocation).
228
+ * A setuid failure here would be in the latter category.
229
+ */
230
+
231
+ #ifdef OS_UNIX
232
+ if (!username || !*username)
233
+ throw std::runtime_error ("setuid_string failed: no username specified");
234
+
235
+ struct passwd *p = getpwnam (username);
236
+ if (!p)
237
+ throw std::runtime_error ("setuid_string failed: unknown username");
238
+
239
+ if (setuid (p->pw_uid) != 0)
240
+ throw std::runtime_error ("setuid_string failed: no setuid");
241
+
242
+ // Success.
243
+ #endif
244
+ }
245
+
246
+
247
+ /****************************************
248
+ (STATIC) EventMachine_t::SetRlimitNofile
249
+ ****************************************/
250
+
251
+ int EventMachine_t::SetRlimitNofile (int nofiles)
252
+ {
253
+ #ifdef OS_UNIX
254
+ struct rlimit rlim;
255
+ getrlimit (RLIMIT_NOFILE, &rlim);
256
+ if (nofiles >= 0) {
257
+ rlim.rlim_cur = nofiles;
258
+ if ((unsigned int)nofiles > rlim.rlim_max)
259
+ rlim.rlim_max = nofiles;
260
+ setrlimit (RLIMIT_NOFILE, &rlim);
261
+ // ignore the error return, for now at least.
262
+ // TODO, emit an error message someday when we have proper debug levels.
263
+ }
264
+ getrlimit (RLIMIT_NOFILE, &rlim);
265
+ return rlim.rlim_cur;
266
+ #endif
267
+
268
+ #ifdef OS_WIN32
269
+ // No meaningful implementation on Windows.
270
+ return 0;
271
+ #endif
272
+ }
273
+
274
+
275
+ /*********************************
276
+ EventMachine_t::SignalLoopBreaker
277
+ *********************************/
278
+
279
+ void EventMachine_t::SignalLoopBreaker()
280
+ {
281
+ #ifdef OS_UNIX
282
+ write (LoopBreakerWriter, "", 1);
283
+ #endif
284
+ #ifdef OS_WIN32
285
+ sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
286
+ #endif
287
+ }
288
+
289
+
290
+ /**************************************
291
+ EventMachine_t::_InitializeLoopBreaker
292
+ **************************************/
293
+
294
+ void EventMachine_t::_InitializeLoopBreaker()
295
+ {
296
+ /* A "loop-breaker" is a socket-descriptor that we can write to in order
297
+ * to break the main select loop. Primarily useful for things running on
298
+ * threads other than the main EM thread, so they can trigger processing
299
+ * of events that arise exogenously to the EM.
300
+ * Keep the loop-breaker pipe out of the main descriptor set, otherwise
301
+ * its events will get passed on to user code.
302
+ */
303
+
304
+ #ifdef OS_UNIX
305
+ int fd[2];
306
+ if (pipe (fd))
307
+ throw std::runtime_error (strerror(errno));
308
+
309
+ LoopBreakerWriter = fd[1];
310
+ LoopBreakerReader = fd[0];
311
+
312
+ /* 16Jan11: Make sure the pipe is non-blocking, so more than 65k loopbreaks
313
+ * in one tick do not fill up the pipe and block the process on write() */
314
+ SetSocketNonblocking (LoopBreakerWriter);
315
+ #endif
316
+
317
+ #ifdef OS_WIN32
318
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
319
+ if (sd == INVALID_SOCKET)
320
+ throw std::runtime_error ("no loop breaker socket");
321
+ SetSocketNonblocking (sd);
322
+
323
+ memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget));
324
+ LoopBreakerTarget.sin_family = AF_INET;
325
+ LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1");
326
+
327
+ srand ((int)time(NULL));
328
+ int i;
329
+ for (i=0; i < 100; i++) {
330
+ int r = (rand() % 10000) + 20000;
331
+ LoopBreakerTarget.sin_port = htons (r);
332
+ if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0)
333
+ break;
334
+ }
335
+
336
+ if (i == 100)
337
+ throw std::runtime_error ("no loop breaker");
338
+ LoopBreakerReader = sd;
339
+ #endif
340
+ }
341
+
342
+ /***************************
343
+ EventMachine_t::_UpdateTime
344
+ ***************************/
345
+
346
+ void EventMachine_t::_UpdateTime()
347
+ {
348
+ MyCurrentLoopTime = GetRealTime();
349
+ }
350
+
351
+ /***************************
352
+ EventMachine_t::GetRealTime
353
+ ***************************/
354
+
355
+ uint64_t EventMachine_t::GetRealTime()
356
+ {
357
+ uint64_t current_time;
358
+
359
+ #if defined(OS_UNIX)
360
+ struct timeval tv;
361
+ gettimeofday (&tv, NULL);
362
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
363
+
364
+ #elif defined(OS_WIN32)
365
+ unsigned tick = GetTickCount();
366
+ if (tick < LastTickCount)
367
+ TickCountTickover += 1;
368
+ LastTickCount = tick;
369
+ current_time = ((uint64_t)TickCountTickover << 32) + (uint64_t)tick;
370
+ current_time *= 1000; // convert to microseconds
371
+
372
+ #else
373
+ current_time = (uint64_t)time(NULL) * 1000000LL;
374
+ #endif
375
+
376
+ return current_time;
377
+ }
378
+
379
+ /***********************************
380
+ EventMachine_t::_DispatchHeartbeats
381
+ ***********************************/
382
+
383
+ void EventMachine_t::_DispatchHeartbeats()
384
+ {
385
+ // Store the first processed heartbeat descriptor and bail out if
386
+ // we see it again. This fixes an infinite loop in case the system time
387
+ // is changed out from underneath MyCurrentLoopTime.
388
+ const EventableDescriptor *head = NULL;
389
+
390
+ while (true) {
391
+ multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
392
+ if (i == Heartbeats.end())
393
+ break;
394
+ if (i->first > MyCurrentLoopTime)
395
+ break;
396
+
397
+ EventableDescriptor *ed = i->second;
398
+ if (ed == head)
399
+ break;
400
+
401
+ ed->Heartbeat();
402
+ QueueHeartbeat(ed);
403
+
404
+ if (head == NULL)
405
+ head = ed;
406
+ }
407
+ }
408
+
409
+ /******************************
410
+ EventMachine_t::QueueHeartbeat
411
+ ******************************/
412
+
413
+ void EventMachine_t::QueueHeartbeat(EventableDescriptor *ed)
414
+ {
415
+ uint64_t heartbeat = ed->GetNextHeartbeat();
416
+
417
+ if (heartbeat) {
418
+ #ifndef HAVE_MAKE_PAIR
419
+ Heartbeats.insert (multimap<uint64_t,EventableDescriptor*>::value_type (heartbeat, ed));
420
+ #else
421
+ Heartbeats.insert (make_pair (heartbeat, ed));
422
+ #endif
423
+ }
424
+ }
425
+
426
+ /******************************
427
+ EventMachine_t::ClearHeartbeat
428
+ ******************************/
429
+
430
+ void EventMachine_t::ClearHeartbeat(uint64_t key, EventableDescriptor* ed)
431
+ {
432
+ multimap<uint64_t,EventableDescriptor*>::iterator it;
433
+ pair<multimap<uint64_t,EventableDescriptor*>::iterator,multimap<uint64_t,EventableDescriptor*>::iterator> ret;
434
+ ret = Heartbeats.equal_range (key);
435
+ for (it = ret.first; it != ret.second; ++it) {
436
+ if (it->second == ed) {
437
+ Heartbeats.erase (it);
438
+ break;
439
+ }
440
+ }
441
+ }
442
+
443
+ /*******************
444
+ EventMachine_t::Run
445
+ *******************/
446
+
447
+ void EventMachine_t::Run()
448
+ {
449
+ #ifdef HAVE_EPOLL
450
+ if (bEpoll) {
451
+ epfd = epoll_create (MaxEpollDescriptors);
452
+ if (epfd == -1) {
453
+ char buf[200];
454
+ snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
455
+ throw std::runtime_error (buf);
456
+ }
457
+ int cloexec = fcntl (epfd, F_GETFD, 0);
458
+ assert (cloexec >= 0);
459
+ cloexec |= FD_CLOEXEC;
460
+ fcntl (epfd, F_SETFD, cloexec);
461
+
462
+ assert (LoopBreakerReader >= 0);
463
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
464
+ assert (ld);
465
+ Add (ld);
466
+ }
467
+ #endif
468
+
469
+ #ifdef HAVE_KQUEUE
470
+ if (bKqueue) {
471
+ kqfd = kqueue();
472
+ if (kqfd == -1) {
473
+ char buf[200];
474
+ snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
475
+ throw std::runtime_error (buf);
476
+ }
477
+ // cloexec not needed. By definition, kqueues are not carried across forks.
478
+
479
+ assert (LoopBreakerReader >= 0);
480
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
481
+ assert (ld);
482
+ Add (ld);
483
+ }
484
+ #endif
485
+
486
+ while (true) {
487
+ _UpdateTime();
488
+ _RunTimers();
489
+
490
+ /* _Add must precede _Modify because the same descriptor might
491
+ * be on both lists during the same pass through the machine,
492
+ * and to modify a descriptor before adding it would fail.
493
+ */
494
+ _AddNewDescriptors();
495
+ _ModifyDescriptors();
496
+
497
+ _RunOnce();
498
+ if (bTerminateSignalReceived)
499
+ break;
500
+ }
501
+ }
502
+
503
+
504
+ /************************
505
+ EventMachine_t::_RunOnce
506
+ ************************/
507
+
508
+ void EventMachine_t::_RunOnce()
509
+ {
510
+ if (bEpoll)
511
+ _RunEpollOnce();
512
+ else if (bKqueue)
513
+ _RunKqueueOnce();
514
+ else
515
+ _RunSelectOnce();
516
+ _DispatchHeartbeats();
517
+ _CleanupSockets();
518
+ }
519
+
520
+
521
+ /*****************************
522
+ EventMachine_t::_RunEpollOnce
523
+ *****************************/
524
+
525
+ void EventMachine_t::_RunEpollOnce()
526
+ {
527
+ #ifdef HAVE_EPOLL
528
+ assert (epfd != -1);
529
+ int s;
530
+
531
+ timeval tv = _TimeTilNextEvent();
532
+
533
+ #ifdef BUILD_FOR_RUBY
534
+ int ret = 0;
535
+
536
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
537
+ if ((ret = rb_wait_for_single_fd(epfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) {
538
+ #else
539
+ fd_set fdreads;
540
+
541
+ FD_ZERO(&fdreads);
542
+ FD_SET(epfd, &fdreads);
543
+
544
+ if ((ret = rb_thread_select(epfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
545
+ #endif
546
+ if (ret == -1) {
547
+ assert(errno != EINVAL);
548
+ assert(errno != EBADF);
549
+ }
550
+ return;
551
+ }
552
+
553
+ TRAP_BEG;
554
+ s = epoll_wait (epfd, epoll_events, MaxEvents, 0);
555
+ TRAP_END;
556
+ #else
557
+ int duration = 0;
558
+ duration = duration + (tv.tv_sec * 1000);
559
+ duration = duration + (tv.tv_usec / 1000);
560
+ s = epoll_wait (epfd, epoll_events, MaxEvents, duration);
561
+ #endif
562
+
563
+ if (s > 0) {
564
+ for (int i=0; i < s; i++) {
565
+ EventableDescriptor *ed = (EventableDescriptor*) epoll_events[i].data.ptr;
566
+
567
+ if (ed->IsWatchOnly() && ed->GetSocket() == INVALID_SOCKET)
568
+ continue;
569
+
570
+ assert(ed->GetSocket() != INVALID_SOCKET);
571
+
572
+ if (epoll_events[i].events & EPOLLIN)
573
+ ed->Read();
574
+ if (epoll_events[i].events & EPOLLOUT)
575
+ ed->Write();
576
+ if (epoll_events[i].events & (EPOLLERR | EPOLLHUP))
577
+ ed->HandleError();
578
+ }
579
+ }
580
+ else if (s < 0) {
581
+ // epoll_wait can fail on error in a handful of ways.
582
+ // If this happens, then wait for a little while to avoid busy-looping.
583
+ // If the error was EINTR, we probably caught SIGCHLD or something,
584
+ // so keep the wait short.
585
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
586
+ EmSelect (0, NULL, NULL, NULL, &tv);
587
+ }
588
+ #else
589
+ throw std::runtime_error ("epoll is not implemented on this platform");
590
+ #endif
591
+ }
592
+
593
+
594
+ /******************************
595
+ EventMachine_t::_RunKqueueOnce
596
+ ******************************/
597
+
598
+ void EventMachine_t::_RunKqueueOnce()
599
+ {
600
+ #ifdef HAVE_KQUEUE
601
+ assert (kqfd != -1);
602
+ int k;
603
+
604
+ timeval tv = _TimeTilNextEvent();
605
+
606
+ struct timespec ts;
607
+ ts.tv_sec = tv.tv_sec;
608
+ ts.tv_nsec = tv.tv_usec * 1000;
609
+
610
+ #ifdef BUILD_FOR_RUBY
611
+ int ret = 0;
612
+
613
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
614
+ if ((ret = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN|RB_WAITFD_PRI, &tv)) < 1) {
615
+ #else
616
+ fd_set fdreads;
617
+
618
+ FD_ZERO(&fdreads);
619
+ FD_SET(kqfd, &fdreads);
620
+
621
+ if ((ret = rb_thread_select(kqfd + 1, &fdreads, NULL, NULL, &tv)) < 1) {
622
+ #endif
623
+ if (ret == -1) {
624
+ assert(errno != EINVAL);
625
+ assert(errno != EBADF);
626
+ }
627
+ return;
628
+ }
629
+
630
+ TRAP_BEG;
631
+ ts.tv_sec = ts.tv_nsec = 0;
632
+ k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
633
+ TRAP_END;
634
+ #else
635
+ k = kevent (kqfd, NULL, 0, Karray, MaxEvents, &ts);
636
+ #endif
637
+
638
+ struct kevent *ke = Karray;
639
+ while (k > 0) {
640
+ switch (ke->filter)
641
+ {
642
+ case EVFILT_VNODE:
643
+ _HandleKqueueFileEvent (ke);
644
+ break;
645
+
646
+ case EVFILT_PROC:
647
+ _HandleKqueuePidEvent (ke);
648
+ break;
649
+
650
+ case EVFILT_READ:
651
+ case EVFILT_WRITE:
652
+ EventableDescriptor *ed = (EventableDescriptor*) (ke->udata);
653
+ assert (ed);
654
+
655
+ if (ed->IsWatchOnly() && ed->GetSocket() == INVALID_SOCKET)
656
+ break;
657
+
658
+ if (ke->filter == EVFILT_READ)
659
+ ed->Read();
660
+ else if (ke->filter == EVFILT_WRITE)
661
+ ed->Write();
662
+ else
663
+ cerr << "Discarding unknown kqueue event " << ke->filter << endl;
664
+
665
+ break;
666
+ }
667
+
668
+ --k;
669
+ ++ke;
670
+ }
671
+
672
+ // TODO, replace this with rb_thread_blocking_region for 1.9 builds.
673
+ #ifdef BUILD_FOR_RUBY
674
+ if (!rb_thread_alone()) {
675
+ rb_thread_schedule();
676
+ }
677
+ #endif
678
+ #else
679
+ throw std::runtime_error ("kqueue is not implemented on this platform");
680
+ #endif
681
+ }
682
+
683
+
684
+ /*********************************
685
+ EventMachine_t::_TimeTilNextEvent
686
+ *********************************/
687
+
688
+ timeval EventMachine_t::_TimeTilNextEvent()
689
+ {
690
+ // 29jul11: Changed calculation base from MyCurrentLoopTime to the
691
+ // real time. As MyCurrentLoopTime is set at the beginning of an
692
+ // iteration and this calculation is done at the end, evenmachine
693
+ // will potentially oversleep by the amount of time the iteration
694
+ // took to execute.
695
+ uint64_t next_event = 0;
696
+ uint64_t current_time = GetRealTime();
697
+
698
+ if (!Heartbeats.empty()) {
699
+ multimap<uint64_t,EventableDescriptor*>::iterator heartbeats = Heartbeats.begin();
700
+ next_event = heartbeats->first;
701
+ }
702
+
703
+ if (!Timers.empty()) {
704
+ multimap<uint64_t,Timer_t>::iterator timers = Timers.begin();
705
+ if (next_event == 0 || timers->first < next_event)
706
+ next_event = timers->first;
707
+ }
708
+
709
+ if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
710
+ next_event = current_time;
711
+ }
712
+
713
+ timeval tv;
714
+
715
+ if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
716
+ tv.tv_sec = tv.tv_usec = 0;
717
+ } else if (next_event == 0) {
718
+ tv = Quantum;
719
+ } else {
720
+ if (next_event > current_time) {
721
+ uint64_t duration = next_event - current_time;
722
+ tv.tv_sec = duration / 1000000;
723
+ tv.tv_usec = duration % 1000000;
724
+ } else {
725
+ tv.tv_sec = tv.tv_usec = 0;
726
+ }
727
+ }
728
+
729
+ return tv;
730
+ }
731
+
732
+ /*******************************
733
+ EventMachine_t::_CleanupSockets
734
+ *******************************/
735
+
736
+ void EventMachine_t::_CleanupSockets()
737
+ {
738
+ // TODO, rip this out and only delete the descriptors we know have died,
739
+ // rather than traversing the whole list.
740
+ // Modified 05Jan08 per suggestions by Chris Heath. It's possible that
741
+ // an EventableDescriptor will have a descriptor value of -1. That will
742
+ // happen if EventableDescriptor::Close was called on it. In that case,
743
+ // don't call epoll_ctl to remove the socket's filters from the epoll set.
744
+ // According to the epoll docs, this happens automatically when the
745
+ // descriptor is closed anyway. This is different from the case where
746
+ // the socket has already been closed but the descriptor in the ED object
747
+ // hasn't yet been set to INVALID_SOCKET.
748
+ // In kqueue, closing a descriptor automatically removes its event filters.
749
+ int i, j;
750
+ int nSockets = Descriptors.size();
751
+ for (i=0, j=0; i < nSockets; i++) {
752
+ EventableDescriptor *ed = Descriptors[i];
753
+ assert (ed);
754
+ if (ed->ShouldDelete()) {
755
+ #ifdef HAVE_EPOLL
756
+ if (bEpoll) {
757
+ assert (epfd != -1);
758
+ if (ed->GetSocket() != INVALID_SOCKET) {
759
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
760
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
761
+ if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
762
+ char buf [200];
763
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
764
+ throw std::runtime_error (buf);
765
+ }
766
+ }
767
+ ModifiedDescriptors.erase(ed);
768
+ }
769
+ #endif
770
+ delete ed;
771
+ }
772
+ else
773
+ Descriptors [j++] = ed;
774
+ }
775
+ while ((size_t)j < Descriptors.size())
776
+ Descriptors.pop_back();
777
+ }
778
+
779
+ /*********************************
780
+ EventMachine_t::_ModifyEpollEvent
781
+ *********************************/
782
+
783
+ void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
784
+ {
785
+ #ifdef HAVE_EPOLL
786
+ if (bEpoll) {
787
+ assert (epfd != -1);
788
+ assert (ed);
789
+ assert (ed->GetSocket() != INVALID_SOCKET);
790
+ int e = epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent());
791
+ if (e) {
792
+ char buf [200];
793
+ snprintf (buf, sizeof(buf)-1, "unable to modify epoll event: %s", strerror(errno));
794
+ throw std::runtime_error (buf);
795
+ }
796
+ }
797
+ #endif
798
+ }
799
+
800
+
801
+
802
+ /**************************
803
+ SelectData_t::SelectData_t
804
+ **************************/
805
+
806
+ SelectData_t::SelectData_t()
807
+ {
808
+ maxsocket = 0;
809
+ FD_ZERO (&fdreads);
810
+ FD_ZERO (&fdwrites);
811
+ FD_ZERO (&fderrors);
812
+ }
813
+
814
+
815
+ #ifdef BUILD_FOR_RUBY
816
+ /*****************
817
+ _SelectDataSelect
818
+ *****************/
819
+
820
+ #ifdef HAVE_TBR
821
+ static VALUE _SelectDataSelect (void *v)
822
+ {
823
+ SelectData_t *sd = (SelectData_t*)v;
824
+ sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
825
+ return Qnil;
826
+ }
827
+ #endif
828
+
829
+ /*********************
830
+ SelectData_t::_Select
831
+ *********************/
832
+
833
+ int SelectData_t::_Select()
834
+ {
835
+ #ifdef HAVE_TBR
836
+ rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
837
+ return nSockets;
838
+ #endif
839
+
840
+ #ifndef HAVE_TBR
841
+ return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
842
+ #endif
843
+ }
844
+ #endif
845
+
846
+
847
+
848
+ /******************************
849
+ EventMachine_t::_RunSelectOnce
850
+ ******************************/
851
+
852
+ void EventMachine_t::_RunSelectOnce()
853
+ {
854
+ // Crank the event machine once.
855
+ // If there are no descriptors to process, then sleep
856
+ // for a few hundred mills to avoid busy-looping.
857
+ // This is based on a select loop. Alternately provide epoll
858
+ // if we know we're running on a 2.6 kernel.
859
+ // epoll will be effective if we provide it as an alternative,
860
+ // however it has the same problem interoperating with Ruby
861
+ // threads that select does.
862
+
863
+ SelectData_t SelectData;
864
+ /*
865
+ fd_set fdreads, fdwrites;
866
+ FD_ZERO (&fdreads);
867
+ FD_ZERO (&fdwrites);
868
+
869
+ int maxsocket = 0;
870
+ */
871
+
872
+ // Always read the loop-breaker reader.
873
+ // Changed 23Aug06, provisionally implemented for Windows with a UDP socket
874
+ // running on localhost with a randomly-chosen port. (*Puke*)
875
+ // Windows has a version of the Unix pipe() library function, but it doesn't
876
+ // give you back descriptors that are selectable.
877
+ FD_SET (LoopBreakerReader, &(SelectData.fdreads));
878
+ if (SelectData.maxsocket < LoopBreakerReader)
879
+ SelectData.maxsocket = LoopBreakerReader;
880
+
881
+ // prepare the sockets for reading and writing
882
+ size_t i;
883
+ for (i = 0; i < Descriptors.size(); i++) {
884
+ EventableDescriptor *ed = Descriptors[i];
885
+ assert (ed);
886
+ int sd = ed->GetSocket();
887
+ if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
888
+ continue;
889
+ assert (sd != INVALID_SOCKET);
890
+
891
+ if (ed->SelectForRead())
892
+ FD_SET (sd, &(SelectData.fdreads));
893
+ if (ed->SelectForWrite())
894
+ FD_SET (sd, &(SelectData.fdwrites));
895
+
896
+ #ifdef OS_WIN32
897
+ /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable.
898
+ Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html
899
+ */
900
+ FD_SET (sd, &(SelectData.fderrors));
901
+ #endif
902
+
903
+ if (SelectData.maxsocket < sd)
904
+ SelectData.maxsocket = sd;
905
+ }
906
+
907
+
908
+ { // read and write the sockets
909
+ //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
910
+ //timeval tv = Quantum;
911
+ SelectData.tv = _TimeTilNextEvent();
912
+ int s = SelectData._Select();
913
+ //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
914
+ //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
915
+ //int s = SelectData.nSockets;
916
+ if (s > 0) {
917
+ /* Changed 01Jun07. We used to handle the Loop-breaker right here.
918
+ * Now we do it AFTER all the regular descriptors. There's an
919
+ * incredibly important and subtle reason for this. Code on
920
+ * loop breakers is sometimes used to cause the reactor core to
921
+ * cycle (for example, to allow outbound network buffers to drain).
922
+ * If a loop-breaker handler reschedules itself (say, after determining
923
+ * that the write buffers are still too full), then it will execute
924
+ * IMMEDIATELY if _ReadLoopBreaker is done here instead of after
925
+ * the other descriptors are processed. That defeats the whole purpose.
926
+ */
927
+ for (i=0; i < Descriptors.size(); i++) {
928
+ EventableDescriptor *ed = Descriptors[i];
929
+ assert (ed);
930
+ int sd = ed->GetSocket();
931
+ if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
932
+ continue;
933
+ assert (sd != INVALID_SOCKET);
934
+
935
+ if (FD_ISSET (sd, &(SelectData.fdwrites)))
936
+ ed->Write();
937
+ if (FD_ISSET (sd, &(SelectData.fdreads)))
938
+ ed->Read();
939
+ if (FD_ISSET (sd, &(SelectData.fderrors)))
940
+ ed->HandleError();
941
+ }
942
+
943
+ if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads)))
944
+ _ReadLoopBreaker();
945
+ }
946
+ else if (s < 0) {
947
+ switch (errno) {
948
+ case EBADF:
949
+ _CleanBadDescriptors();
950
+ break;
951
+ case EINVAL:
952
+ throw std::runtime_error ("Somehow EM passed an invalid nfds or invalid timeout to select(2), please report this!");
953
+ break;
954
+ default:
955
+ // select can fail on error in a handful of ways.
956
+ // If this happens, then wait for a little while to avoid busy-looping.
957
+ // If the error was EINTR, we probably caught SIGCHLD or something,
958
+ // so keep the wait short.
959
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
960
+ EmSelect (0, NULL, NULL, NULL, &tv);
961
+ }
962
+ }
963
+ }
964
+ }
965
+
966
+ void EventMachine_t::_CleanBadDescriptors()
967
+ {
968
+ size_t i;
969
+
970
+ for (i = 0; i < Descriptors.size(); i++) {
971
+ EventableDescriptor *ed = Descriptors[i];
972
+ if (ed->ShouldDelete())
973
+ continue;
974
+
975
+ int sd = ed->GetSocket();
976
+
977
+ struct timeval tv;
978
+ tv.tv_sec = 0;
979
+ tv.tv_usec = 0;
980
+
981
+ fd_set fds;
982
+ FD_ZERO(&fds);
983
+ FD_SET(sd, &fds);
984
+
985
+ int ret = select(sd + 1, &fds, NULL, NULL, &tv);
986
+
987
+ if (ret == -1) {
988
+ if (errno == EBADF)
989
+ ed->ScheduleClose(false);
990
+ }
991
+ }
992
+ }
993
+
994
+ /********************************
995
+ EventMachine_t::_ReadLoopBreaker
996
+ ********************************/
997
+
998
+ void EventMachine_t::_ReadLoopBreaker()
999
+ {
1000
+ /* The loop breaker has selected readable.
1001
+ * Read it ONCE (it may block if we try to read it twice)
1002
+ * and send a loop-break event back to user code.
1003
+ */
1004
+ char buffer [1024];
1005
+ read (LoopBreakerReader, buffer, sizeof(buffer));
1006
+ if (EventCallback)
1007
+ (*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0);
1008
+ }
1009
+
1010
+
1011
+ /**************************
1012
+ EventMachine_t::_RunTimers
1013
+ **************************/
1014
+
1015
+ void EventMachine_t::_RunTimers()
1016
+ {
1017
+ // These are caller-defined timer handlers.
1018
+ // We rely on the fact that multimaps sort by their keys to avoid
1019
+ // inspecting the whole list every time we come here.
1020
+ // Just keep inspecting and processing the list head until we hit
1021
+ // one that hasn't expired yet.
1022
+
1023
+ while (true) {
1024
+ multimap<uint64_t,Timer_t>::iterator i = Timers.begin();
1025
+ if (i == Timers.end())
1026
+ break;
1027
+ if (i->first > MyCurrentLoopTime)
1028
+ break;
1029
+ if (EventCallback)
1030
+ (*EventCallback) (0, EM_TIMER_FIRED, NULL, i->second.GetBinding());
1031
+ Timers.erase (i);
1032
+ }
1033
+ }
1034
+
1035
+
1036
+
1037
+ /***********************************
1038
+ EventMachine_t::InstallOneshotTimer
1039
+ ***********************************/
1040
+
1041
+ const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
1042
+ {
1043
+ if (Timers.size() > MaxOutstandingTimers)
1044
+ return false;
1045
+
1046
+ uint64_t fire_at = GetRealTime();
1047
+ fire_at += ((uint64_t)milliseconds) * 1000LL;
1048
+
1049
+ Timer_t t;
1050
+ #ifndef HAVE_MAKE_PAIR
1051
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (multimap<uint64_t,Timer_t>::value_type (fire_at, t));
1052
+ #else
1053
+ multimap<uint64_t,Timer_t>::iterator i = Timers.insert (make_pair (fire_at, t));
1054
+ #endif
1055
+ return i->second.GetBinding();
1056
+ }
1057
+
1058
+
1059
+ /*******************************
1060
+ EventMachine_t::ConnectToServer
1061
+ *******************************/
1062
+
1063
+ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port)
1064
+ {
1065
+ /* We want to spend no more than a few seconds waiting for a connection
1066
+ * to a remote host. So we use a nonblocking connect.
1067
+ * Linux disobeys the usual rules for nonblocking connects.
1068
+ * Per Stevens (UNP p.410), you expect a nonblocking connect to select
1069
+ * both readable and writable on error, and not to return EINPROGRESS
1070
+ * if the connect can be fulfilled immediately. Linux violates both
1071
+ * of these expectations.
1072
+ * Any kind of nonblocking connect on Linux returns EINPROGRESS.
1073
+ * The socket will then return writable when the disposition of the
1074
+ * connect is known, but it will not also be readable in case of
1075
+ * error! Weirdly, it will be readable in case there is data to read!!!
1076
+ * (Which can happen with protocols like SSH and SMTP.)
1077
+ * I suppose if you were so inclined you could consider this logical,
1078
+ * but it's not the way Unix has historically done it.
1079
+ * So we ignore the readable flag and read getsockopt to see if there
1080
+ * was an error connecting. A select timeout works as expected.
1081
+ * In regard to getsockopt: Linux does the Berkeley-style thing,
1082
+ * not the Solaris-style, and returns zero with the error code in
1083
+ * the error parameter.
1084
+ * Return the binding-text of the newly-created pending connection,
1085
+ * or NULL if there was a problem.
1086
+ */
1087
+
1088
+ if (!server || !*server || !port)
1089
+ throw std::runtime_error ("invalid server or port");
1090
+
1091
+ int family, bind_size;
1092
+ struct sockaddr bind_as, *bind_as_ptr = name2address (server, port, &family, &bind_size);
1093
+ if (!bind_as_ptr)
1094
+ throw std::runtime_error ("unable to resolve server address");
1095
+ bind_as = *bind_as_ptr; // copy because name2address points to a static
1096
+
1097
+ int sd = socket (family, SOCK_STREAM, 0);
1098
+ if (sd == INVALID_SOCKET) {
1099
+ char buf [200];
1100
+ snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
1101
+ throw std::runtime_error (buf);
1102
+ }
1103
+
1104
+ // From here on, ALL error returns must close the socket.
1105
+ // Set the new socket nonblocking.
1106
+ if (!SetSocketNonblocking (sd)) {
1107
+ close (sd);
1108
+ throw std::runtime_error ("unable to set socket as non-blocking");
1109
+ }
1110
+ // Disable slow-start (Nagle algorithm).
1111
+ int one = 1;
1112
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
1113
+ // Set reuseaddr to improve performance on restarts
1114
+ setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
1115
+
1116
+ if (bind_addr) {
1117
+ int bind_to_size, bind_to_family;
1118
+ struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
1119
+ if (!bind_to) {
1120
+ close (sd);
1121
+ throw std::runtime_error ("invalid bind address");
1122
+ }
1123
+ if (bind (sd, bind_to, bind_to_size) < 0) {
1124
+ close (sd);
1125
+ throw std::runtime_error ("couldn't bind to address");
1126
+ }
1127
+ }
1128
+
1129
+ unsigned long out = 0;
1130
+ int e = 0;
1131
+
1132
+ #ifdef OS_UNIX
1133
+ //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
1134
+ if (connect (sd, &bind_as, bind_size) == 0) {
1135
+ // This is a connect success, which Linux appears
1136
+ // never to give when the socket is nonblocking,
1137
+ // even if the connection is intramachine or to
1138
+ // localhost.
1139
+
1140
+ /* Changed this branch 08Aug06. Evidently some kernels
1141
+ * (FreeBSD for example) will actually return success from
1142
+ * a nonblocking connect. This is a pretty simple case,
1143
+ * just set up the new connection and clear the pending flag.
1144
+ * Thanks to Chris Ochs for helping track this down.
1145
+ * This branch never gets taken on Linux or (oddly) OSX.
1146
+ * The original behavior was to throw an unimplemented,
1147
+ * which the user saw as a fatal exception. Very unfriendly.
1148
+ *
1149
+ * Tweaked 10Aug06. Even though the connect disposition is
1150
+ * known, we still set the connect-pending flag. That way
1151
+ * some needed initialization will happen in the ConnectionDescriptor.
1152
+ * (To wit, the ConnectionCompleted event gets sent to the client.)
1153
+ */
1154
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1155
+ if (!cd)
1156
+ throw std::runtime_error ("no connection allocated");
1157
+ cd->SetConnectPending (true);
1158
+ Add (cd);
1159
+ out = cd->GetBinding();
1160
+ }
1161
+ else if (errno == EINPROGRESS) {
1162
+ // Errno will generally always be EINPROGRESS, but on Linux
1163
+ // we have to look at getsockopt to be sure what really happened.
1164
+ int error = 0;
1165
+ socklen_t len;
1166
+ len = sizeof(error);
1167
+ int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
1168
+ if ((o == 0) && (error == 0)) {
1169
+ // Here, there's no disposition.
1170
+ // Put the connection on the stack and wait for it to complete
1171
+ // or time out.
1172
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1173
+ if (!cd)
1174
+ throw std::runtime_error ("no connection allocated");
1175
+ cd->SetConnectPending (true);
1176
+ Add (cd);
1177
+ out = cd->GetBinding();
1178
+ } else {
1179
+ // Fall through to the !out case below.
1180
+ e = error;
1181
+ }
1182
+ }
1183
+ else {
1184
+ // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
1185
+ // Fall through to the !out case below
1186
+ e = errno;
1187
+ }
1188
+
1189
+ if (!out) {
1190
+ /* This could be connection refused or some such thing.
1191
+ * We will come here on Linux if a localhost connection fails.
1192
+ * Changed 16Jul06: Originally this branch was a no-op, and
1193
+ * we'd drop down to the end of the method, close the socket,
1194
+ * and return NULL, which would cause the caller to GET A
1195
+ * FATAL EXCEPTION. Now we keep the socket around but schedule an
1196
+ * immediate close on it, so the caller will get a close-event
1197
+ * scheduled on it. This was only an issue for localhost connections
1198
+ * to non-listening ports. We may eventually need to revise this
1199
+ * revised behavior, in case it causes problems like making it hard
1200
+ * for people to know that a failure occurred.
1201
+ */
1202
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1203
+ if (!cd)
1204
+ throw std::runtime_error ("no connection allocated");
1205
+ cd->SetUnbindReasonCode(e);
1206
+ cd->ScheduleClose (false);
1207
+ Add (cd);
1208
+ out = cd->GetBinding();
1209
+ }
1210
+ #endif
1211
+
1212
+ #ifdef OS_WIN32
1213
+ //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
1214
+ if (connect (sd, &bind_as, bind_size) == 0) {
1215
+ // This is a connect success, which Windows appears
1216
+ // never to give when the socket is nonblocking,
1217
+ // even if the connection is intramachine or to
1218
+ // localhost.
1219
+ throw std::runtime_error ("unimplemented");
1220
+ }
1221
+ else if (WSAGetLastError() == WSAEWOULDBLOCK) {
1222
+ // Here, there's no disposition.
1223
+ // Windows appears not to surface refused connections or
1224
+ // such stuff at this point.
1225
+ // Put the connection on the stack and wait for it to complete
1226
+ // or time out.
1227
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1228
+ if (!cd)
1229
+ throw std::runtime_error ("no connection allocated");
1230
+ cd->SetConnectPending (true);
1231
+ Add (cd);
1232
+ out = cd->GetBinding();
1233
+ }
1234
+ else {
1235
+ // The error from connect was something other then WSAEWOULDBLOCK.
1236
+ }
1237
+
1238
+ #endif
1239
+
1240
+ if (!out)
1241
+ close (sd);
1242
+ return out;
1243
+ }
1244
+
1245
+ /***********************************
1246
+ EventMachine_t::ConnectToUnixServer
1247
+ ***********************************/
1248
+
1249
+ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1250
+ {
1251
+ /* Connect to a Unix-domain server, which by definition is running
1252
+ * on the same host.
1253
+ * There is no meaningful implementation on Windows.
1254
+ * There's no need to do a nonblocking connect, since the connection
1255
+ * is always local and can always be fulfilled immediately.
1256
+ */
1257
+
1258
+ #ifdef OS_WIN32
1259
+ throw std::runtime_error ("unix-domain connection unavailable on this platform");
1260
+ return 0;
1261
+ #endif
1262
+
1263
+ // The whole rest of this function is only compiled on Unix systems.
1264
+ #ifdef OS_UNIX
1265
+
1266
+ unsigned long out = 0;
1267
+
1268
+ if (!server || !*server)
1269
+ return 0;
1270
+
1271
+ sockaddr_un pun;
1272
+ memset (&pun, 0, sizeof(pun));
1273
+ pun.sun_family = AF_LOCAL;
1274
+
1275
+ // You ordinarily expect the server name field to be at least 1024 bytes long,
1276
+ // but on Linux it can be MUCH shorter.
1277
+ if (strlen(server) >= sizeof(pun.sun_path))
1278
+ throw std::runtime_error ("unix-domain server name is too long");
1279
+
1280
+
1281
+ strcpy (pun.sun_path, server);
1282
+
1283
+ int fd = socket (AF_LOCAL, SOCK_STREAM, 0);
1284
+ if (fd == INVALID_SOCKET)
1285
+ return 0;
1286
+
1287
+ // From here on, ALL error returns must close the socket.
1288
+ // NOTE: At this point, the socket is still a blocking socket.
1289
+ if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) {
1290
+ close (fd);
1291
+ return 0;
1292
+ }
1293
+
1294
+ // Set the newly-connected socket nonblocking.
1295
+ if (!SetSocketNonblocking (fd)) {
1296
+ close (fd);
1297
+ return 0;
1298
+ }
1299
+
1300
+ // Set up a connection descriptor and add it to the event-machine.
1301
+ // Observe, even though we know the connection status is connect-success,
1302
+ // we still set the "pending" flag, so some needed initializations take
1303
+ // place.
1304
+ ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this);
1305
+ if (!cd)
1306
+ throw std::runtime_error ("no connection allocated");
1307
+ cd->SetConnectPending (true);
1308
+ Add (cd);
1309
+ out = cd->GetBinding();
1310
+
1311
+ if (!out)
1312
+ close (fd);
1313
+
1314
+ return out;
1315
+ #endif
1316
+ }
1317
+
1318
+ /************************
1319
+ EventMachine_t::AttachFD
1320
+ ************************/
1321
+
1322
+ const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
1323
+ {
1324
+ #ifdef OS_UNIX
1325
+ if (fcntl(fd, F_GETFL, 0) < 0)
1326
+ throw std::runtime_error ("invalid file descriptor");
1327
+ #endif
1328
+
1329
+ #ifdef OS_WIN32
1330
+ // TODO: add better check for invalid file descriptors (see ioctlsocket or getsockopt)
1331
+ if (fd == INVALID_SOCKET)
1332
+ throw std::runtime_error ("invalid file descriptor");
1333
+ #endif
1334
+
1335
+ {// Check for duplicate descriptors
1336
+ size_t i;
1337
+ for (i = 0; i < Descriptors.size(); i++) {
1338
+ EventableDescriptor *ed = Descriptors[i];
1339
+ assert (ed);
1340
+ if (ed->GetSocket() == fd)
1341
+ throw std::runtime_error ("adding existing descriptor");
1342
+ }
1343
+
1344
+ for (i = 0; i < NewDescriptors.size(); i++) {
1345
+ EventableDescriptor *ed = NewDescriptors[i];
1346
+ assert (ed);
1347
+ if (ed->GetSocket() == fd)
1348
+ throw std::runtime_error ("adding existing new descriptor");
1349
+ }
1350
+ }
1351
+
1352
+ if (!watch_mode)
1353
+ SetSocketNonblocking(fd);
1354
+
1355
+ ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this);
1356
+ if (!cd)
1357
+ throw std::runtime_error ("no connection allocated");
1358
+
1359
+ cd->SetAttached(true);
1360
+ cd->SetWatchOnly(watch_mode);
1361
+ cd->SetConnectPending (false);
1362
+
1363
+ Add (cd);
1364
+
1365
+ const unsigned long out = cd->GetBinding();
1366
+ return out;
1367
+ }
1368
+
1369
+ /************************
1370
+ EventMachine_t::DetachFD
1371
+ ************************/
1372
+
1373
+ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1374
+ {
1375
+ if (!ed)
1376
+ throw std::runtime_error ("detaching bad descriptor");
1377
+
1378
+ int fd = ed->GetSocket();
1379
+
1380
+ #ifdef HAVE_EPOLL
1381
+ if (bEpoll) {
1382
+ if (ed->GetSocket() != INVALID_SOCKET) {
1383
+ assert (epfd != -1);
1384
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
1385
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
1386
+ if (e && (errno != ENOENT) && (errno != EBADF)) {
1387
+ char buf [200];
1388
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
1389
+ throw std::runtime_error (buf);
1390
+ }
1391
+ }
1392
+ }
1393
+ #endif
1394
+
1395
+ #ifdef HAVE_KQUEUE
1396
+ if (bKqueue) {
1397
+ // remove any read/write events for this fd
1398
+ struct kevent k;
1399
+ #ifdef __NetBSD__
1400
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, (intptr_t)ed);
1401
+ #else
1402
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ | EVFILT_WRITE, EV_DELETE, 0, 0, ed);
1403
+ #endif
1404
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1405
+ if (t < 0 && (errno != ENOENT) && (errno != EBADF)) {
1406
+ char buf [200];
1407
+ snprintf (buf, sizeof(buf)-1, "unable to delete kqueue event: %s", strerror(errno));
1408
+ throw std::runtime_error (buf);
1409
+ }
1410
+ }
1411
+ #endif
1412
+
1413
+ // Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
1414
+ ModifiedDescriptors.erase (ed);
1415
+
1416
+ // Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
1417
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1418
+ if (ed == NewDescriptors[i]) {
1419
+ NewDescriptors.erase(NewDescriptors.begin() + i);
1420
+ break;
1421
+ }
1422
+ }
1423
+
1424
+ // Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
1425
+ // and also to prevent anyone from calling close() on the detached fd
1426
+ ed->SetSocketInvalid();
1427
+
1428
+ return fd;
1429
+ }
1430
+
1431
+ /************
1432
+ name2address
1433
+ ************/
1434
+
1435
+ struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size)
1436
+ {
1437
+ // THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.
1438
+ // Check the more-common cases first.
1439
+ // Return NULL if no resolution.
1440
+
1441
+ static struct sockaddr_in in4;
1442
+ #ifndef __CYGWIN__
1443
+ static struct sockaddr_in6 in6;
1444
+ #endif
1445
+ struct hostent *hp;
1446
+
1447
+ if (!server || !*server)
1448
+ server = "0.0.0.0";
1449
+
1450
+ memset (&in4, 0, sizeof(in4));
1451
+ if ( (in4.sin_addr.s_addr = inet_addr (server)) != INADDR_NONE) {
1452
+ if (family)
1453
+ *family = AF_INET;
1454
+ if (bind_size)
1455
+ *bind_size = sizeof(in4);
1456
+ in4.sin_family = AF_INET;
1457
+ in4.sin_port = htons (port);
1458
+ return (struct sockaddr*)&in4;
1459
+ }
1460
+
1461
+ #if defined(OS_UNIX) && !defined(__CYGWIN__)
1462
+ memset (&in6, 0, sizeof(in6));
1463
+ if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) {
1464
+ if (family)
1465
+ *family = AF_INET6;
1466
+ if (bind_size)
1467
+ *bind_size = sizeof(in6);
1468
+ in6.sin6_family = AF_INET6;
1469
+ in6.sin6_port = htons (port);
1470
+ return (struct sockaddr*)&in6;
1471
+ }
1472
+ #endif
1473
+
1474
+ #ifdef OS_WIN32
1475
+ // TODO, must complete this branch. Windows doesn't have inet_pton.
1476
+ // A possible approach is to make a getaddrinfo call with the supplied
1477
+ // server address, constraining the hints to ipv6 and seeing if we
1478
+ // get any addresses.
1479
+ // For the time being, Ipv6 addresses aren't supported on Windows.
1480
+ #endif
1481
+
1482
+ hp = gethostbyname ((char*)server); // Windows requires the cast.
1483
+ if (hp) {
1484
+ in4.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1485
+ if (family)
1486
+ *family = AF_INET;
1487
+ if (bind_size)
1488
+ *bind_size = sizeof(in4);
1489
+ in4.sin_family = AF_INET;
1490
+ in4.sin_port = htons (port);
1491
+ return (struct sockaddr*)&in4;
1492
+ }
1493
+
1494
+ return NULL;
1495
+ }
1496
+
1497
+
1498
+ /*******************************
1499
+ EventMachine_t::CreateTcpServer
1500
+ *******************************/
1501
+
1502
+ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int port)
1503
+ {
1504
+ /* Create a TCP-acceptor (server) socket and add it to the event machine.
1505
+ * Return the binding of the new acceptor to the caller.
1506
+ * This binding will be referenced when the new acceptor sends events
1507
+ * to indicate accepted connections.
1508
+ */
1509
+
1510
+
1511
+ int family, bind_size;
1512
+ struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1513
+ if (!bind_here)
1514
+ return 0;
1515
+
1516
+ //struct sockaddr_in sin;
1517
+
1518
+ int sd_accept = socket (family, SOCK_STREAM, 0);
1519
+ if (sd_accept == INVALID_SOCKET) {
1520
+ goto fail;
1521
+ }
1522
+
1523
+ { // set reuseaddr to improve performance on restarts.
1524
+ int oval = 1;
1525
+ if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) {
1526
+ //__warning ("setsockopt failed while creating listener","");
1527
+ goto fail;
1528
+ }
1529
+ }
1530
+
1531
+ { // set CLOEXEC. Only makes sense on Unix
1532
+ #ifdef OS_UNIX
1533
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
1534
+ assert (cloexec >= 0);
1535
+ cloexec |= FD_CLOEXEC;
1536
+ fcntl (sd_accept, F_SETFD, cloexec);
1537
+ #endif
1538
+ }
1539
+
1540
+
1541
+ //if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
1542
+ if (bind (sd_accept, bind_here, bind_size)) {
1543
+ //__warning ("binding failed");
1544
+ goto fail;
1545
+ }
1546
+
1547
+ if (listen (sd_accept, 100)) {
1548
+ //__warning ("listen failed");
1549
+ goto fail;
1550
+ }
1551
+
1552
+ return AttachSD(sd_accept);
1553
+
1554
+ fail:
1555
+ if (sd_accept != INVALID_SOCKET)
1556
+ close (sd_accept);
1557
+ return 0;
1558
+ }
1559
+
1560
+
1561
+ /**********************************
1562
+ EventMachine_t::OpenDatagramSocket
1563
+ **********************************/
1564
+
1565
+ const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int port)
1566
+ {
1567
+ unsigned long output_binding = 0;
1568
+
1569
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
1570
+ if (sd == INVALID_SOCKET)
1571
+ goto fail;
1572
+ // from here on, early returns must close the socket!
1573
+
1574
+
1575
+ struct sockaddr_in sin;
1576
+ memset (&sin, 0, sizeof(sin));
1577
+ sin.sin_family = AF_INET;
1578
+ sin.sin_port = htons (port);
1579
+
1580
+
1581
+ if (address && *address) {
1582
+ sin.sin_addr.s_addr = inet_addr (address);
1583
+ if (sin.sin_addr.s_addr == INADDR_NONE) {
1584
+ hostent *hp = gethostbyname ((char*)address); // Windows requires the cast.
1585
+ if (hp == NULL)
1586
+ goto fail;
1587
+ sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1588
+ }
1589
+ }
1590
+ else
1591
+ sin.sin_addr.s_addr = htonl (INADDR_ANY);
1592
+
1593
+
1594
+ // Set the new socket nonblocking.
1595
+ {
1596
+ if (!SetSocketNonblocking (sd))
1597
+ //int val = fcntl (sd, F_GETFL, 0);
1598
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1)
1599
+ goto fail;
1600
+ }
1601
+
1602
+ if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0)
1603
+ goto fail;
1604
+
1605
+ { // Looking good.
1606
+ DatagramDescriptor *ds = new DatagramDescriptor (sd, this);
1607
+ if (!ds)
1608
+ throw std::runtime_error ("unable to allocate datagram-socket");
1609
+ Add (ds);
1610
+ output_binding = ds->GetBinding();
1611
+ }
1612
+
1613
+ return output_binding;
1614
+
1615
+ fail:
1616
+ if (sd != INVALID_SOCKET)
1617
+ close (sd);
1618
+ return 0;
1619
+ }
1620
+
1621
+
1622
+
1623
+ /*******************
1624
+ EventMachine_t::Add
1625
+ *******************/
1626
+
1627
+ void EventMachine_t::Add (EventableDescriptor *ed)
1628
+ {
1629
+ if (!ed)
1630
+ throw std::runtime_error ("added bad descriptor");
1631
+ ed->SetEventCallback (EventCallback);
1632
+ NewDescriptors.push_back (ed);
1633
+ }
1634
+
1635
+
1636
+ /*******************************
1637
+ EventMachine_t::ArmKqueueWriter
1638
+ *******************************/
1639
+
1640
+ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
1641
+ {
1642
+ #ifdef HAVE_KQUEUE
1643
+ if (bKqueue) {
1644
+ if (!ed)
1645
+ throw std::runtime_error ("added bad descriptor");
1646
+ struct kevent k;
1647
+ #ifdef __NetBSD__
1648
+ EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, (intptr_t)ed);
1649
+ #else
1650
+ EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed);
1651
+ #endif
1652
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1653
+ if (t < 0) {
1654
+ char buf [200];
1655
+ snprintf (buf, sizeof(buf)-1, "arm kqueue writer failed on %d: %s", ed->GetSocket(), strerror(errno));
1656
+ throw std::runtime_error (buf);
1657
+ }
1658
+ }
1659
+ #endif
1660
+ }
1661
+
1662
+ /*******************************
1663
+ EventMachine_t::ArmKqueueReader
1664
+ *******************************/
1665
+
1666
+ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
1667
+ {
1668
+ #ifdef HAVE_KQUEUE
1669
+ if (bKqueue) {
1670
+ if (!ed)
1671
+ throw std::runtime_error ("added bad descriptor");
1672
+ struct kevent k;
1673
+ #ifdef __NetBSD__
1674
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
1675
+ #else
1676
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1677
+ #endif
1678
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1679
+ if (t < 0) {
1680
+ char buf [200];
1681
+ snprintf (buf, sizeof(buf)-1, "arm kqueue reader failed on %d: %s", ed->GetSocket(), strerror(errno));
1682
+ throw std::runtime_error (buf);
1683
+ }
1684
+ }
1685
+ #endif
1686
+ }
1687
+
1688
+ /**********************************
1689
+ EventMachine_t::_AddNewDescriptors
1690
+ **********************************/
1691
+
1692
+ void EventMachine_t::_AddNewDescriptors()
1693
+ {
1694
+ /* Avoid adding descriptors to the main descriptor list
1695
+ * while we're actually traversing the list.
1696
+ * Any descriptors that are added as a result of processing timers
1697
+ * or acceptors should go on a temporary queue and then added
1698
+ * while we're not traversing the main list.
1699
+ * Also, it (rarely) happens that a newly-created descriptor
1700
+ * is immediately scheduled to close. It might be a good
1701
+ * idea not to bother scheduling these for I/O but if
1702
+ * we do that, we might bypass some important processing.
1703
+ */
1704
+
1705
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1706
+ EventableDescriptor *ed = NewDescriptors[i];
1707
+ if (ed == NULL)
1708
+ throw std::runtime_error ("adding bad descriptor");
1709
+
1710
+ #if HAVE_EPOLL
1711
+ if (bEpoll) {
1712
+ assert (epfd != -1);
1713
+ int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent());
1714
+ if (e) {
1715
+ char buf [200];
1716
+ snprintf (buf, sizeof(buf)-1, "unable to add new descriptor: %s", strerror(errno));
1717
+ throw std::runtime_error (buf);
1718
+ }
1719
+ }
1720
+ #endif
1721
+
1722
+ #if HAVE_KQUEUE
1723
+ /*
1724
+ if (bKqueue) {
1725
+ // INCOMPLETE. Some descriptors don't want to be readable.
1726
+ assert (kqfd != -1);
1727
+ struct kevent k;
1728
+ #ifdef __NetBSD__
1729
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, (intptr_t)ed);
1730
+ #else
1731
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1732
+ #endif
1733
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1734
+ assert (t == 0);
1735
+ }
1736
+ */
1737
+ #endif
1738
+
1739
+ QueueHeartbeat(ed);
1740
+ Descriptors.push_back (ed);
1741
+ }
1742
+ NewDescriptors.clear();
1743
+ }
1744
+
1745
+
1746
+ /**********************************
1747
+ EventMachine_t::_ModifyDescriptors
1748
+ **********************************/
1749
+
1750
+ void EventMachine_t::_ModifyDescriptors()
1751
+ {
1752
+ /* For implementations which don't level check every descriptor on
1753
+ * every pass through the machine, as select does.
1754
+ * If we're not selecting, then descriptors need a way to signal to the
1755
+ * machine that their readable or writable status has changed.
1756
+ * That's what the ::Modify call is for. We do it this way to avoid
1757
+ * modifying descriptors during the loop traversal, where it can easily
1758
+ * happen that an object (like a UDP socket) gets data written on it by
1759
+ * the application during #post_init. That would take place BEFORE the
1760
+ * descriptor even gets added to the epoll descriptor, so the modify
1761
+ * operation will crash messily.
1762
+ * Another really messy possibility is for a descriptor to put itself
1763
+ * on the Modified list, and then get deleted before we get here.
1764
+ * Remember, deletes happen after the I/O traversal and before the
1765
+ * next pass through here. So we have to make sure when we delete a
1766
+ * descriptor to remove it from the Modified list.
1767
+ */
1768
+
1769
+ #ifdef HAVE_EPOLL
1770
+ if (bEpoll) {
1771
+ set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
1772
+ while (i != ModifiedDescriptors.end()) {
1773
+ assert (*i);
1774
+ _ModifyEpollEvent (*i);
1775
+ ++i;
1776
+ }
1777
+ }
1778
+ #endif
1779
+
1780
+ ModifiedDescriptors.clear();
1781
+ }
1782
+
1783
+
1784
+ /**********************
1785
+ EventMachine_t::Modify
1786
+ **********************/
1787
+
1788
+ void EventMachine_t::Modify (EventableDescriptor *ed)
1789
+ {
1790
+ if (!ed)
1791
+ throw std::runtime_error ("modified bad descriptor");
1792
+ ModifiedDescriptors.insert (ed);
1793
+ }
1794
+
1795
+
1796
+ /***********************
1797
+ EventMachine_t::Deregister
1798
+ ***********************/
1799
+
1800
+ void EventMachine_t::Deregister (EventableDescriptor *ed)
1801
+ {
1802
+ if (!ed)
1803
+ throw std::runtime_error ("modified bad descriptor");
1804
+ #ifdef HAVE_EPOLL
1805
+ // cut/paste from _CleanupSockets(). The error handling could be
1806
+ // refactored out of there, but it is cut/paste all over the
1807
+ // file already.
1808
+ if (bEpoll) {
1809
+ assert (epfd != -1);
1810
+ assert (ed->GetSocket() != INVALID_SOCKET);
1811
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
1812
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
1813
+ if (e && (errno != ENOENT) && (errno != EBADF) && (errno != EPERM)) {
1814
+ char buf [200];
1815
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
1816
+ throw std::runtime_error (buf);
1817
+ }
1818
+ ModifiedDescriptors.erase(ed);
1819
+ }
1820
+ #endif
1821
+ }
1822
+
1823
+
1824
+ /**************************************
1825
+ EventMachine_t::CreateUnixDomainServer
1826
+ **************************************/
1827
+
1828
+ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename)
1829
+ {
1830
+ /* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
1831
+ * Return the binding of the new acceptor to the caller.
1832
+ * This binding will be referenced when the new acceptor sends events
1833
+ * to indicate accepted connections.
1834
+ * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
1835
+ */
1836
+
1837
+ #ifdef OS_WIN32
1838
+ throw std::runtime_error ("unix-domain server unavailable on this platform");
1839
+ #endif
1840
+
1841
+ // The whole rest of this function is only compiled on Unix systems.
1842
+ #ifdef OS_UNIX
1843
+
1844
+ struct sockaddr_un s_sun;
1845
+
1846
+ int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0);
1847
+ if (sd_accept == INVALID_SOCKET) {
1848
+ goto fail;
1849
+ }
1850
+
1851
+ if (!filename || !*filename)
1852
+ goto fail;
1853
+ unlink (filename);
1854
+
1855
+ bzero (&s_sun, sizeof(s_sun));
1856
+ s_sun.sun_family = AF_LOCAL;
1857
+ strncpy (s_sun.sun_path, filename, sizeof(s_sun.sun_path)-1);
1858
+
1859
+ // don't bother with reuseaddr for a local socket.
1860
+
1861
+ { // set CLOEXEC. Only makes sense on Unix
1862
+ #ifdef OS_UNIX
1863
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
1864
+ assert (cloexec >= 0);
1865
+ cloexec |= FD_CLOEXEC;
1866
+ fcntl (sd_accept, F_SETFD, cloexec);
1867
+ #endif
1868
+ }
1869
+
1870
+ if (bind (sd_accept, (struct sockaddr*)&s_sun, sizeof(s_sun))) {
1871
+ //__warning ("binding failed");
1872
+ goto fail;
1873
+ }
1874
+
1875
+ if (listen (sd_accept, 100)) {
1876
+ //__warning ("listen failed");
1877
+ goto fail;
1878
+ }
1879
+
1880
+ return AttachSD(sd_accept);
1881
+
1882
+ fail:
1883
+ if (sd_accept != INVALID_SOCKET)
1884
+ close (sd_accept);
1885
+ return 0;
1886
+ #endif // OS_UNIX
1887
+ }
1888
+
1889
+
1890
+ /**************************************
1891
+ EventMachine_t::AttachSD
1892
+ **************************************/
1893
+
1894
+ const unsigned long EventMachine_t::AttachSD (int sd_accept)
1895
+ {
1896
+ unsigned long output_binding = 0;
1897
+
1898
+ {
1899
+ // Set the acceptor non-blocking.
1900
+ // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1901
+ if (!SetSocketNonblocking (sd_accept)) {
1902
+ //int val = fcntl (sd_accept, F_GETFL, 0);
1903
+ //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1904
+ goto fail;
1905
+ }
1906
+ }
1907
+
1908
+ { // Looking good.
1909
+ AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1910
+ if (!ad)
1911
+ throw std::runtime_error ("unable to allocate acceptor");
1912
+ Add (ad);
1913
+ output_binding = ad->GetBinding();
1914
+ }
1915
+
1916
+ return output_binding;
1917
+
1918
+ fail:
1919
+ if (sd_accept != INVALID_SOCKET)
1920
+ close (sd_accept);
1921
+ return 0;
1922
+ }
1923
+
1924
+
1925
+ /*********************
1926
+ EventMachine_t::Popen
1927
+ *********************/
1928
+ #if OBSOLETE
1929
+ const char *EventMachine_t::Popen (const char *cmd, const char *mode)
1930
+ {
1931
+ #ifdef OS_WIN32
1932
+ throw std::runtime_error ("popen is currently unavailable on this platform");
1933
+ #endif
1934
+
1935
+ // The whole rest of this function is only compiled on Unix systems.
1936
+ // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1937
+ #ifdef OS_UNIX
1938
+ const char *output_binding = NULL;
1939
+
1940
+ FILE *fp = popen (cmd, mode);
1941
+ if (!fp)
1942
+ return NULL;
1943
+
1944
+ // From here, all early returns must pclose the stream.
1945
+
1946
+ // According to the pipe(2) manpage, descriptors returned from pipe have both
1947
+ // CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.
1948
+ if (!SetSocketNonblocking (fileno (fp))) {
1949
+ pclose (fp);
1950
+ return NULL;
1951
+ }
1952
+
1953
+ { // Looking good.
1954
+ PipeDescriptor *pd = new PipeDescriptor (fp, this);
1955
+ if (!pd)
1956
+ throw std::runtime_error ("unable to allocate pipe");
1957
+ Add (pd);
1958
+ output_binding = pd->GetBinding();
1959
+ }
1960
+
1961
+ return output_binding;
1962
+ #endif
1963
+ }
1964
+ #endif // OBSOLETE
1965
+
1966
+ /**************************
1967
+ EventMachine_t::Socketpair
1968
+ **************************/
1969
+
1970
+ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1971
+ {
1972
+ #ifdef OS_WIN32
1973
+ throw std::runtime_error ("socketpair is currently unavailable on this platform");
1974
+ #endif
1975
+
1976
+ // The whole rest of this function is only compiled on Unix systems.
1977
+ // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1978
+ #ifdef OS_UNIX
1979
+ // Make sure the incoming array of command strings is sane.
1980
+ if (!cmd_strings)
1981
+ return 0;
1982
+ int j;
1983
+ for (j=0; j < 2048 && cmd_strings[j]; j++)
1984
+ ;
1985
+ if ((j==0) || (j==2048))
1986
+ return 0;
1987
+
1988
+ unsigned long output_binding = 0;
1989
+
1990
+ int sv[2];
1991
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
1992
+ return 0;
1993
+ // from here, all early returns must close the pair of sockets.
1994
+
1995
+ // Set the parent side of the socketpair nonblocking.
1996
+ // We don't care about the child side, and most child processes will expect their
1997
+ // stdout to be blocking. Thanks to Duane Johnson and Bill Kelly for pointing this out.
1998
+ // Obviously DON'T set CLOEXEC.
1999
+ if (!SetSocketNonblocking (sv[0])) {
2000
+ close (sv[0]);
2001
+ close (sv[1]);
2002
+ return 0;
2003
+ }
2004
+
2005
+ pid_t f = fork();
2006
+ if (f > 0) {
2007
+ close (sv[1]);
2008
+ PipeDescriptor *pd = new PipeDescriptor (sv[0], f, this);
2009
+ if (!pd)
2010
+ throw std::runtime_error ("unable to allocate pipe");
2011
+ Add (pd);
2012
+ output_binding = pd->GetBinding();
2013
+ }
2014
+ else if (f == 0) {
2015
+ close (sv[0]);
2016
+ dup2 (sv[1], STDIN_FILENO);
2017
+ close (sv[1]);
2018
+ dup2 (STDIN_FILENO, STDOUT_FILENO);
2019
+ execvp (cmd_strings[0], cmd_strings+1);
2020
+ exit (-1); // end the child process if the exec doesn't work.
2021
+ }
2022
+ else
2023
+ throw std::runtime_error ("no fork");
2024
+
2025
+ return output_binding;
2026
+ #endif
2027
+ }
2028
+
2029
+
2030
+ /****************************
2031
+ EventMachine_t::OpenKeyboard
2032
+ ****************************/
2033
+
2034
+ const unsigned long EventMachine_t::OpenKeyboard()
2035
+ {
2036
+ KeyboardDescriptor *kd = new KeyboardDescriptor (this);
2037
+ if (!kd)
2038
+ throw std::runtime_error ("no keyboard-object allocated");
2039
+ Add (kd);
2040
+ return kd->GetBinding();
2041
+ }
2042
+
2043
+
2044
+ /**********************************
2045
+ EventMachine_t::GetConnectionCount
2046
+ **********************************/
2047
+
2048
+ int EventMachine_t::GetConnectionCount ()
2049
+ {
2050
+ return Descriptors.size() + NewDescriptors.size();
2051
+ }
2052
+
2053
+
2054
+ /************************
2055
+ EventMachine_t::WatchPid
2056
+ ************************/
2057
+
2058
+ const unsigned long EventMachine_t::WatchPid (int pid)
2059
+ {
2060
+ #ifdef HAVE_KQUEUE
2061
+ if (!bKqueue)
2062
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support");
2063
+
2064
+ struct kevent event;
2065
+ int kqres;
2066
+
2067
+ EV_SET(&event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT | NOTE_FORK, 0, 0);
2068
+
2069
+ // Attempt to register the event
2070
+ kqres = kevent(kqfd, &event, 1, NULL, 0, NULL);
2071
+ if (kqres == -1) {
2072
+ char errbuf[200];
2073
+ sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
2074
+ throw std::runtime_error(errbuf);
2075
+ }
2076
+ #endif
2077
+
2078
+ #ifdef HAVE_KQUEUE
2079
+ Bindable_t* b = new Bindable_t();
2080
+ Pids.insert(make_pair (pid, b));
2081
+
2082
+ return b->GetBinding();
2083
+ #endif
2084
+
2085
+ throw std::runtime_error("no pid watching support on this system");
2086
+ }
2087
+
2088
+ /**************************
2089
+ EventMachine_t::UnwatchPid
2090
+ **************************/
2091
+
2092
+ void EventMachine_t::UnwatchPid (int pid)
2093
+ {
2094
+ Bindable_t *b = Pids[pid];
2095
+ assert(b);
2096
+ Pids.erase(pid);
2097
+
2098
+ #ifdef HAVE_KQUEUE
2099
+ struct kevent k;
2100
+
2101
+ EV_SET(&k, pid, EVFILT_PROC, EV_DELETE, 0, 0, 0);
2102
+ /*int t =*/ kevent (kqfd, &k, 1, NULL, 0, NULL);
2103
+ // t==-1 if the process already exited; ignore this for now
2104
+ #endif
2105
+
2106
+ if (EventCallback)
2107
+ (*EventCallback)(b->GetBinding(), EM_CONNECTION_UNBOUND, NULL, 0);
2108
+
2109
+ delete b;
2110
+ }
2111
+
2112
+ void EventMachine_t::UnwatchPid (const unsigned long sig)
2113
+ {
2114
+ for(map<int, Bindable_t*>::iterator i=Pids.begin(); i != Pids.end(); i++)
2115
+ {
2116
+ if (i->second->GetBinding() == sig) {
2117
+ UnwatchPid (i->first);
2118
+ return;
2119
+ }
2120
+ }
2121
+
2122
+ throw std::runtime_error("attempted to remove invalid pid signature");
2123
+ }
2124
+
2125
+
2126
+ /*************************
2127
+ EventMachine_t::WatchFile
2128
+ *************************/
2129
+
2130
+ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2131
+ {
2132
+ struct stat sb;
2133
+ int sres;
2134
+ int wd = -1;
2135
+
2136
+ sres = stat(fpath, &sb);
2137
+
2138
+ if (sres == -1) {
2139
+ char errbuf[300];
2140
+ sprintf(errbuf, "error registering file %s for watching: %s", fpath, strerror(errno));
2141
+ throw std::runtime_error(errbuf);
2142
+ }
2143
+
2144
+ #ifdef HAVE_INOTIFY
2145
+ if (!inotify) {
2146
+ inotify = new InotifyDescriptor(this);
2147
+ assert (inotify);
2148
+ Add(inotify);
2149
+ }
2150
+
2151
+ wd = inotify_add_watch(inotify->GetSocket(), fpath,
2152
+ IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_CREATE | IN_DELETE | IN_MOVE) ;
2153
+ if (wd == -1) {
2154
+ char errbuf[300];
2155
+ sprintf(errbuf, "failed to open file %s for registering with inotify: %s", fpath, strerror(errno));
2156
+ throw std::runtime_error(errbuf);
2157
+ }
2158
+ #endif
2159
+
2160
+ #ifdef HAVE_KQUEUE
2161
+ if (!bKqueue)
2162
+ throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support");
2163
+
2164
+ // With kqueue we have to open the file first and use the resulting fd to register for events
2165
+ wd = open(fpath, O_RDONLY);
2166
+ if (wd == -1) {
2167
+ char errbuf[300];
2168
+ sprintf(errbuf, "failed to open file %s for registering with kqueue: %s", fpath, strerror(errno));
2169
+ throw std::runtime_error(errbuf);
2170
+ }
2171
+ _RegisterKqueueFileEvent(wd);
2172
+ #endif
2173
+
2174
+ if (wd != -1) {
2175
+ Bindable_t* b = new Bindable_t();
2176
+ Files.insert(make_pair (wd, b));
2177
+
2178
+ return b->GetBinding();
2179
+ }
2180
+
2181
+ throw std::runtime_error("no file watching support on this system"); // is this the right thing to do?
2182
+ }
2183
+
2184
+
2185
+ /***************************
2186
+ EventMachine_t::UnwatchFile
2187
+ ***************************/
2188
+
2189
+ void EventMachine_t::UnwatchFile (int wd)
2190
+ {
2191
+ Bindable_t *b = Files[wd];
2192
+ assert(b);
2193
+ Files.erase(wd);
2194
+
2195
+ #ifdef HAVE_INOTIFY
2196
+ inotify_rm_watch(inotify->GetSocket(), wd);
2197
+ #elif HAVE_KQUEUE
2198
+ // With kqueue, closing the monitored fd automatically clears all registered events for it
2199
+ close(wd);
2200
+ #endif
2201
+
2202
+ if (EventCallback)
2203
+ (*EventCallback)(b->GetBinding(), EM_CONNECTION_UNBOUND, NULL, 0);
2204
+
2205
+ delete b;
2206
+ }
2207
+
2208
+ void EventMachine_t::UnwatchFile (const unsigned long sig)
2209
+ {
2210
+ for(map<int, Bindable_t*>::iterator i=Files.begin(); i != Files.end(); i++)
2211
+ {
2212
+ if (i->second->GetBinding() == sig) {
2213
+ UnwatchFile (i->first);
2214
+ return;
2215
+ }
2216
+ }
2217
+ throw std::runtime_error("attempted to remove invalid watch signature");
2218
+ }
2219
+
2220
+
2221
+ /***********************************
2222
+ EventMachine_t::_ReadInotify_Events
2223
+ ************************************/
2224
+
2225
+ void EventMachine_t::_ReadInotifyEvents()
2226
+ {
2227
+ #ifdef HAVE_INOTIFY
2228
+ char buffer[1024];
2229
+
2230
+ assert(EventCallback);
2231
+
2232
+ for (;;) {
2233
+ int returned = read(inotify->GetSocket(), buffer, sizeof(buffer));
2234
+ assert(!(returned == 0 || returned == -1 && errno == EINVAL));
2235
+ if (returned <= 0) {
2236
+ break;
2237
+ }
2238
+ int current = 0;
2239
+ while (current < returned) {
2240
+ struct inotify_event* event = (struct inotify_event*)(buffer+current);
2241
+ map<int, Bindable_t*>::const_iterator bindable = Files.find(event->wd);
2242
+ if (bindable != Files.end()) {
2243
+ if (event->mask & (IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVE)){
2244
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "modified", 8);
2245
+ }
2246
+ if (event->mask & IN_MOVE_SELF){
2247
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "moved", 5);
2248
+ }
2249
+ if (event->mask & IN_DELETE_SELF) {
2250
+ (*EventCallback)(bindable->second->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
2251
+ UnwatchFile ((int)event->wd);
2252
+ }
2253
+ }
2254
+ current += sizeof(struct inotify_event) + event->len;
2255
+ }
2256
+ }
2257
+ #endif
2258
+ }
2259
+
2260
+
2261
+ /*************************************
2262
+ EventMachine_t::_HandleKqueuePidEvent
2263
+ *************************************/
2264
+
2265
+ #ifdef HAVE_KQUEUE
2266
+ void EventMachine_t::_HandleKqueuePidEvent(struct kevent *event)
2267
+ {
2268
+ assert(EventCallback);
2269
+
2270
+ if (event->fflags & NOTE_FORK)
2271
+ (*EventCallback)(Pids [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "fork", 4);
2272
+ if (event->fflags & NOTE_EXIT) {
2273
+ (*EventCallback)(Pids [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "exit", 4);
2274
+ // stop watching the pid if it died
2275
+ UnwatchPid ((int)event->ident);
2276
+ }
2277
+ }
2278
+ #endif
2279
+
2280
+
2281
+ /**************************************
2282
+ EventMachine_t::_HandleKqueueFileEvent
2283
+ ***************************************/
2284
+
2285
+ #ifdef HAVE_KQUEUE
2286
+ void EventMachine_t::_HandleKqueueFileEvent(struct kevent *event)
2287
+ {
2288
+ assert(EventCallback);
2289
+
2290
+ if (event->fflags & NOTE_WRITE)
2291
+ (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "modified", 8);
2292
+ if (event->fflags & NOTE_RENAME)
2293
+ (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "moved", 5);
2294
+ if (event->fflags & NOTE_DELETE) {
2295
+ (*EventCallback)(Files [(int) event->ident]->GetBinding(), EM_CONNECTION_READ, "deleted", 7);
2296
+ UnwatchFile ((int)event->ident);
2297
+ }
2298
+ }
2299
+ #endif
2300
+
2301
+
2302
+ /****************************************
2303
+ EventMachine_t::_RegisterKqueueFileEvent
2304
+ *****************************************/
2305
+
2306
+ #ifdef HAVE_KQUEUE
2307
+ void EventMachine_t::_RegisterKqueueFileEvent(int fd)
2308
+ {
2309
+ struct kevent newevent;
2310
+ int kqres;
2311
+
2312
+ // Setup the event with our fd and proper flags
2313
+ EV_SET(&newevent, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_RENAME | NOTE_WRITE, 0, 0);
2314
+
2315
+ // Attempt to register the event
2316
+ kqres = kevent(kqfd, &newevent, 1, NULL, 0, NULL);
2317
+ if (kqres == -1) {
2318
+ char errbuf[200];
2319
+ sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
2320
+ close(fd);
2321
+ throw std::runtime_error(errbuf);
2322
+ }
2323
+ }
2324
+ #endif
2325
+
2326
+
2327
+ /************************************
2328
+ EventMachine_t::GetHeartbeatInterval
2329
+ *************************************/
2330
+
2331
+ float EventMachine_t::GetHeartbeatInterval()
2332
+ {
2333
+ return ((float)HeartbeatInterval / 1000000);
2334
+ }
2335
+
2336
+
2337
+ /************************************
2338
+ EventMachine_t::SetHeartbeatInterval
2339
+ *************************************/
2340
+
2341
+ int EventMachine_t::SetHeartbeatInterval(float interval)
2342
+ {
2343
+ int iv = (int)(interval * 1000000);
2344
+ if (iv > 0) {
2345
+ HeartbeatInterval = iv;
2346
+ return 1;
2347
+ }
2348
+ return 0;
2349
+ }
2350
+ //#endif // OS_UNIX
2351
+