eventmachine 1.0.3-x86-mingw32 → 1.2.0.dev.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +84 -1
  3. data/README.md +6 -7
  4. data/ext/binder.cpp +10 -10
  5. data/ext/binder.h +5 -5
  6. data/ext/cmain.cpp +173 -61
  7. data/ext/ed.cpp +262 -127
  8. data/ext/ed.h +50 -30
  9. data/ext/em.cpp +491 -445
  10. data/ext/em.h +101 -36
  11. data/ext/eventmachine.h +67 -51
  12. data/ext/extconf.rb +124 -31
  13. data/ext/fastfilereader/extconf.rb +9 -2
  14. data/ext/fastfilereader/mapper.cpp +3 -1
  15. data/ext/fastfilereader/rubymain.cpp +7 -7
  16. data/ext/kb.cpp +1 -1
  17. data/ext/pipe.cpp +11 -4
  18. data/ext/project.h +26 -6
  19. data/ext/rubymain.cpp +408 -201
  20. data/ext/ssl.cpp +167 -20
  21. data/ext/ssl.h +11 -2
  22. data/java/src/com/rubyeventmachine/EmReactor.java +16 -0
  23. data/java/src/com/rubyeventmachine/EventableChannel.java +2 -0
  24. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
  25. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +55 -10
  26. data/lib/1.9/fastfilereaderext.so +0 -0
  27. data/lib/1.9/rubyeventmachine.so +0 -0
  28. data/lib/2.0/fastfilereaderext.so +0 -0
  29. data/lib/2.0/rubyeventmachine.so +0 -0
  30. data/lib/2.1/fastfilereaderext.so +0 -0
  31. data/lib/2.1/rubyeventmachine.so +0 -0
  32. data/lib/2.2/fastfilereaderext.so +0 -0
  33. data/lib/2.2/rubyeventmachine.so +0 -0
  34. data/lib/2.3/fastfilereaderext.so +0 -0
  35. data/lib/2.3/rubyeventmachine.so +0 -0
  36. data/lib/em/buftok.rb +34 -85
  37. data/lib/em/channel.rb +5 -0
  38. data/lib/em/completion.rb +2 -2
  39. data/lib/em/connection.rb +62 -4
  40. data/lib/em/iterator.rb +30 -48
  41. data/lib/em/pool.rb +1 -1
  42. data/lib/em/protocols/httpclient.rb +31 -11
  43. data/lib/em/protocols/line_and_text.rb +4 -4
  44. data/lib/em/protocols/linetext2.rb +44 -39
  45. data/lib/em/protocols/smtpclient.rb +60 -31
  46. data/lib/em/protocols/smtpserver.rb +32 -9
  47. data/lib/em/pure_ruby.rb +8 -3
  48. data/lib/em/queue.rb +16 -7
  49. data/lib/em/resolver.rb +64 -24
  50. data/lib/em/threaded_resource.rb +2 -2
  51. data/lib/em/tick_loop.rb +19 -19
  52. data/lib/em/version.rb +1 -1
  53. data/lib/eventmachine.rb +96 -49
  54. data/lib/jeventmachine.rb +17 -0
  55. data/rakelib/package.rake +31 -4
  56. data/tests/dhparam.pem +13 -0
  57. data/tests/em_test_helper.rb +87 -0
  58. data/tests/test_attach.rb +25 -0
  59. data/tests/test_basic.rb +27 -38
  60. data/tests/test_channel.rb +14 -1
  61. data/tests/test_completion.rb +1 -0
  62. data/tests/test_connection_count.rb +22 -1
  63. data/tests/test_connection_write.rb +35 -0
  64. data/tests/test_defer.rb +17 -0
  65. data/tests/test_epoll.rb +26 -14
  66. data/tests/test_file_watch.rb +1 -0
  67. data/tests/test_fork.rb +75 -0
  68. data/tests/test_httpclient.rb +43 -0
  69. data/tests/test_idle_connection.rb +6 -4
  70. data/tests/test_ipv4.rb +125 -0
  71. data/tests/test_ipv6.rb +131 -0
  72. data/tests/test_iterator.rb +115 -0
  73. data/tests/test_kb.rb +19 -25
  74. data/tests/test_ltp2.rb +20 -0
  75. data/tests/test_many_fds.rb +22 -0
  76. data/tests/test_pause.rb +29 -0
  77. data/tests/test_pool.rb +2 -0
  78. data/tests/test_process_watch.rb +2 -0
  79. data/tests/test_processes.rb +7 -7
  80. data/tests/test_queue.rb +14 -0
  81. data/tests/test_resolver.rb +56 -7
  82. data/tests/test_set_sock_opt.rb +2 -0
  83. data/tests/test_smtpclient.rb +20 -0
  84. data/tests/test_ssl_args.rb +2 -2
  85. data/tests/test_ssl_dhparam.rb +83 -0
  86. data/tests/test_ssl_ecdh_curve.rb +79 -0
  87. data/tests/test_ssl_extensions.rb +49 -0
  88. data/tests/test_ssl_methods.rb +22 -5
  89. data/tests/test_ssl_protocols.rb +246 -0
  90. data/tests/test_ssl_verify.rb +103 -59
  91. data/tests/test_system.rb +4 -0
  92. data/tests/test_threaded_resource.rb +8 -0
  93. data/tests/test_unbind_reason.rb +5 -1
  94. metadata +173 -107
  95. data/.gitignore +0 -21
  96. data/.travis.yml +0 -12
  97. data/.yardopts +0 -7
  98. data/Gemfile +0 -2
  99. data/Rakefile +0 -20
  100. data/eventmachine.gemspec +0 -36
  101. data/rakelib/cpp.rake_example +0 -77
data/ext/ed.h CHANGED
@@ -27,7 +27,7 @@ class SslBox_t; // forward reference
27
27
  #endif
28
28
 
29
29
  bool SetSocketNonblocking (SOCKET);
30
-
30
+ bool SetFdCloexec (int);
31
31
 
32
32
  /*************************
33
33
  class EventableDescriptor
@@ -36,10 +36,10 @@ class EventableDescriptor
36
36
  class EventableDescriptor: public Bindable_t
37
37
  {
38
38
  public:
39
- EventableDescriptor (int, EventMachine_t*);
39
+ EventableDescriptor (SOCKET, EventMachine_t*);
40
40
  virtual ~EventableDescriptor();
41
41
 
42
- int GetSocket() {return MySocket;}
42
+ SOCKET GetSocket() {return MySocket;}
43
43
  void SetSocketInvalid() { MySocket = INVALID_SOCKET; }
44
44
  void Close();
45
45
 
@@ -69,14 +69,18 @@ class EventableDescriptor: public Bindable_t
69
69
  virtual bool GetSubprocessPid (pid_t*) {return false;}
70
70
 
71
71
  virtual void StartTls() {}
72
- virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer) {}
72
+ virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int) {}
73
73
 
74
74
  #ifdef WITH_SSL
75
75
  virtual X509 *GetPeerCert() {return NULL;}
76
+ virtual int GetCipherBits() {return -1;}
77
+ virtual const char *GetCipherName() {return NULL;}
78
+ virtual const char *GetCipherProtocol() {return NULL;}
79
+ virtual const char *GetSNIHostname() {return NULL;}
76
80
  #endif
77
81
 
78
82
  virtual uint64_t GetCommInactivityTimeout() {return 0;}
79
- virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
83
+ virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
80
84
  uint64_t GetPendingConnectTimeout();
81
85
  int SetPendingConnectTimeout (uint64_t value);
82
86
  uint64_t GetLastActivity() { return LastActivity; }
@@ -85,11 +89,15 @@ class EventableDescriptor: public Bindable_t
85
89
  struct epoll_event *GetEpollEvent() { return &EpollEvent; }
86
90
  #endif
87
91
 
88
- virtual void StartProxy(const unsigned long, const unsigned long, const unsigned long);
92
+ #ifdef HAVE_KQUEUE
93
+ bool GetKqueueArmWrite() { return bKqueueArmWrite; }
94
+ #endif
95
+
96
+ virtual void StartProxy(const uintptr_t, const unsigned long, const unsigned long);
89
97
  virtual void StopProxy();
90
98
  virtual unsigned long GetProxiedBytes(){ return ProxiedBytes; };
91
99
  virtual void SetProxiedFrom(EventableDescriptor*, const unsigned long);
92
- virtual int SendOutboundData(const char*,int){ return -1; }
100
+ virtual int SendOutboundData(const char*,unsigned long){ return -1; }
93
101
  virtual bool IsPaused(){ return bPaused; }
94
102
  virtual bool Pause(){ bPaused = true; return bPaused; }
95
103
  virtual bool Resume(){ bPaused = false; return bPaused; }
@@ -104,12 +112,12 @@ class EventableDescriptor: public Bindable_t
104
112
  bool bCloseAfterWriting;
105
113
 
106
114
  protected:
107
- int MySocket;
115
+ SOCKET MySocket;
108
116
  bool bAttached;
109
117
  bool bWatchOnly;
110
118
 
111
119
  EMCallback EventCallback;
112
- void _GenericInboundDispatch(const char*, int);
120
+ void _GenericInboundDispatch(const char *buffer, unsigned long size);
113
121
 
114
122
  uint64_t CreatedAt;
115
123
  bool bCallbackUnbind;
@@ -126,6 +134,10 @@ class EventableDescriptor: public Bindable_t
126
134
  struct epoll_event EpollEvent;
127
135
  #endif
128
136
 
137
+ #ifdef HAVE_KQUEUE
138
+ bool bKqueueArmWrite;
139
+ #endif
140
+
129
141
  EventMachine_t *MyEventMachine;
130
142
  uint64_t PendingConnectTimeout;
131
143
  uint64_t InactivityTimeout;
@@ -143,7 +155,7 @@ class LoopbreakDescriptor
143
155
  class LoopbreakDescriptor: public EventableDescriptor
144
156
  {
145
157
  public:
146
- LoopbreakDescriptor (int, EventMachine_t*);
158
+ LoopbreakDescriptor (SOCKET, EventMachine_t*);
147
159
  virtual ~LoopbreakDescriptor() {}
148
160
 
149
161
  virtual void Read();
@@ -162,10 +174,10 @@ class ConnectionDescriptor
162
174
  class ConnectionDescriptor: public EventableDescriptor
163
175
  {
164
176
  public:
165
- ConnectionDescriptor (int, EventMachine_t*);
177
+ ConnectionDescriptor (SOCKET, EventMachine_t*);
166
178
  virtual ~ConnectionDescriptor();
167
179
 
168
- int SendOutboundData (const char*, int);
180
+ int SendOutboundData (const char*, unsigned long);
169
181
 
170
182
  void SetConnectPending (bool f);
171
183
  virtual void ScheduleClose (bool after_writing);
@@ -193,10 +205,14 @@ class ConnectionDescriptor: public EventableDescriptor
193
205
  virtual int GetOutboundDataSize() {return OutboundDataSize;}
194
206
 
195
207
  virtual void StartTls();
196
- virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer);
208
+ virtual void SetTlsParms (const char *, const char *, bool, bool, const char *, const char *, const char *, const char *, int);
197
209
 
198
210
  #ifdef WITH_SSL
199
211
  virtual X509 *GetPeerCert();
212
+ virtual int GetCipherBits();
213
+ virtual const char *GetCipherName();
214
+ virtual const char *GetCipherProtocol();
215
+ virtual const char *GetSNIHostname();
200
216
  virtual bool VerifySslPeer(const char*);
201
217
  virtual void AcceptSslPeer();
202
218
  #endif
@@ -215,7 +231,7 @@ class ConnectionDescriptor: public EventableDescriptor
215
231
  protected:
216
232
  struct OutboundPage {
217
233
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
218
- void Free() {if (Buffer) free ((char*)Buffer); }
234
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
219
235
  const char *Buffer;
220
236
  int Length;
221
237
  int Offset;
@@ -237,8 +253,14 @@ class ConnectionDescriptor: public EventableDescriptor
237
253
  SslBox_t *SslBox;
238
254
  std::string CertChainFilename;
239
255
  std::string PrivateKeyFilename;
256
+ std::string CipherList;
257
+ std::string EcdhCurve;
258
+ std::string DhParam;
259
+ int Protocols;
240
260
  bool bHandshakeSignaled;
241
261
  bool bSslVerifyPeer;
262
+ bool bSslFailIfNoPeerCert;
263
+ std::string SniHostName;
242
264
  bool bSslPeerAccepted;
243
265
  #endif
244
266
 
@@ -252,9 +274,9 @@ class ConnectionDescriptor: public EventableDescriptor
252
274
  void _UpdateEvents();
253
275
  void _UpdateEvents(bool, bool);
254
276
  void _WriteOutboundData();
255
- void _DispatchInboundData (const char *buffer, int size);
277
+ void _DispatchInboundData (const char *buffer, unsigned long size);
256
278
  void _DispatchCiphertext();
257
- int _SendRawOutboundData (const char*, int);
279
+ int _SendRawOutboundData (const char *buffer, unsigned long size);
258
280
  void _CheckHandshakeStatus();
259
281
 
260
282
  };
@@ -267,7 +289,7 @@ class DatagramDescriptor
267
289
  class DatagramDescriptor: public EventableDescriptor
268
290
  {
269
291
  public:
270
- DatagramDescriptor (int, EventMachine_t*);
292
+ DatagramDescriptor (SOCKET, EventMachine_t*);
271
293
  virtual ~DatagramDescriptor();
272
294
 
273
295
  virtual void Read();
@@ -277,8 +299,8 @@ class DatagramDescriptor: public EventableDescriptor
277
299
  virtual bool SelectForRead() {return true;}
278
300
  virtual bool SelectForWrite();
279
301
 
280
- int SendOutboundData (const char*, int);
281
- int SendOutboundDatagram (const char*, int, const char*, int);
302
+ int SendOutboundData (const char*, unsigned long);
303
+ int SendOutboundDatagram (const char*, unsigned long, const char*, int);
282
304
 
283
305
  // Do we have any data to write? This is used by ShouldDelete.
284
306
  virtual int GetOutboundDataSize() {return OutboundDataSize;}
@@ -291,18 +313,18 @@ class DatagramDescriptor: public EventableDescriptor
291
313
 
292
314
  protected:
293
315
  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 ((char*)Buffer); }
316
+ OutboundPage (const char *b, int l, struct sockaddr_in6 f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
317
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
296
318
  const char *Buffer;
297
319
  int Length;
298
320
  int Offset;
299
- struct sockaddr_in From;
321
+ struct sockaddr_in6 From;
300
322
  };
301
323
 
302
324
  deque<OutboundPage> OutboundPages;
303
325
  int OutboundDataSize;
304
326
 
305
- struct sockaddr_in ReturnAddress;
327
+ struct sockaddr_in6 ReturnAddress;
306
328
  };
307
329
 
308
330
 
@@ -313,7 +335,7 @@ class AcceptorDescriptor
313
335
  class AcceptorDescriptor: public EventableDescriptor
314
336
  {
315
337
  public:
316
- AcceptorDescriptor (int, EventMachine_t*);
338
+ AcceptorDescriptor (SOCKET, EventMachine_t*);
317
339
  virtual ~AcceptorDescriptor();
318
340
 
319
341
  virtual void Read();
@@ -325,7 +347,7 @@ class AcceptorDescriptor: public EventableDescriptor
325
347
 
326
348
  virtual bool GetSockname (struct sockaddr*, socklen_t*);
327
349
 
328
- static void StopAcceptor (const unsigned long binding);
350
+ static void StopAcceptor (const uintptr_t binding);
329
351
  };
330
352
 
331
353
  /********************
@@ -336,7 +358,7 @@ class PipeDescriptor
336
358
  class PipeDescriptor: public EventableDescriptor
337
359
  {
338
360
  public:
339
- PipeDescriptor (int, pid_t, EventMachine_t*);
361
+ PipeDescriptor (SOCKET, pid_t, EventMachine_t*);
340
362
  virtual ~PipeDescriptor();
341
363
 
342
364
  virtual void Read();
@@ -346,7 +368,7 @@ class PipeDescriptor: public EventableDescriptor
346
368
  virtual bool SelectForRead();
347
369
  virtual bool SelectForWrite();
348
370
 
349
- int SendOutboundData (const char*, int);
371
+ int SendOutboundData (const char*, unsigned long);
350
372
  virtual int GetOutboundDataSize() {return OutboundDataSize;}
351
373
 
352
374
  virtual bool GetSubprocessPid (pid_t*);
@@ -354,7 +376,7 @@ class PipeDescriptor: public EventableDescriptor
354
376
  protected:
355
377
  struct OutboundPage {
356
378
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
357
- void Free() {if (Buffer) free ((char*)Buffer); }
379
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
358
380
  const char *Buffer;
359
381
  int Length;
360
382
  int Offset;
@@ -418,5 +440,3 @@ class InotifyDescriptor: public EventableDescriptor
418
440
  };
419
441
 
420
442
  #endif // __EventableDescriptor__H_
421
-
422
-
data/ext/em.cpp CHANGED
@@ -27,11 +27,36 @@ See the file COPYING for complete licensing information.
27
27
  */
28
28
  static unsigned int MaxOutstandingTimers = 100000;
29
29
 
30
+ /* The number of accept() done at once in a single tick when the acceptor
31
+ * socket becomes readable.
32
+ */
33
+ static unsigned int SimultaneousAcceptCount = 10;
30
34
 
31
- /* Internal helper to convert strings to internet addresses. IPv6-aware.
32
- * Not reentrant or threadsafe, optimized for speed.
35
+ /* Internal helper to create a socket with SOCK_CLOEXEC set, and fall
36
+ * back to fcntl'ing it if the headers/runtime don't support it.
33
37
  */
34
- static struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size);
38
+ SOCKET EmSocket (int domain, int type, int protocol)
39
+ {
40
+ SOCKET sd;
41
+ #ifdef HAVE_SOCKET_CLOEXEC
42
+ sd = socket (domain, type | SOCK_CLOEXEC, protocol);
43
+ if (sd == INVALID_SOCKET) {
44
+ sd = socket (domain, type, protocol);
45
+ if (sd < 0) {
46
+ return sd;
47
+ }
48
+ SetFdCloexec(sd);
49
+ }
50
+ #else
51
+ sd = socket (domain, type, protocol);
52
+ if (sd == INVALID_SOCKET) {
53
+ return sd;
54
+ }
55
+ SetFdCloexec(sd);
56
+ #endif
57
+ return sd;
58
+ }
59
+
35
60
 
36
61
  /***************************************
37
62
  STATIC EventMachine_t::GetMaxTimerCount
@@ -61,30 +86,56 @@ void EventMachine_t::SetMaxTimerCount (int count)
61
86
  MaxOutstandingTimers = count;
62
87
  }
63
88
 
89
+ int EventMachine_t::GetSimultaneousAcceptCount()
90
+ {
91
+ return SimultaneousAcceptCount;
92
+ }
93
+
94
+ void EventMachine_t::SetSimultaneousAcceptCount (int count)
95
+ {
96
+ if (count < 1)
97
+ count = 1;
98
+ SimultaneousAcceptCount = count;
99
+ }
64
100
 
65
101
 
66
102
  /******************************
67
103
  EventMachine_t::EventMachine_t
68
104
  ******************************/
69
105
 
70
- EventMachine_t::EventMachine_t (EMCallback event_callback):
106
+ EventMachine_t::EventMachine_t (EMCallback event_callback, Poller_t poller):
107
+ NumCloseScheduled (0),
71
108
  HeartbeatInterval(2000000),
72
109
  EventCallback (event_callback),
73
- NextHeartbeatTime (0),
74
- LoopBreakerReader (-1),
75
- LoopBreakerWriter (-1),
76
- NumCloseScheduled (0),
110
+ LoopBreakerReader (INVALID_SOCKET),
111
+ LoopBreakerWriter (INVALID_SOCKET),
77
112
  bTerminateSignalReceived (false),
78
- bEpoll (false),
113
+ Poller (poller),
79
114
  epfd (-1),
80
- bKqueue (false),
81
- kqfd (-1),
82
- inotify (NULL)
115
+ kqfd (-1)
116
+ #ifdef HAVE_INOTIFY
117
+ , inotify (NULL)
118
+ #endif
83
119
  {
84
120
  // Default time-slice is just smaller than one hundred mills.
85
121
  Quantum.tv_sec = 0;
86
122
  Quantum.tv_usec = 90000;
87
123
 
124
+ // Override the requested poller back to default if needed.
125
+ #if !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
126
+ Poller = Poller_Default;
127
+ #endif
128
+
129
+ /* Initialize monotonic timekeeping on OS X before the first call to GetRealTime */
130
+ #ifdef OS_DARWIN
131
+ (void) mach_timebase_info(&mach_timebase);
132
+ #endif
133
+
134
+ #ifdef OS_WIN32
135
+ TickCountTickover = 0;
136
+ LastTickCount = 0;
137
+ #endif
138
+
88
139
  // Make sure the current loop time is sane, in case we do any initializations of
89
140
  // objects before we start running.
90
141
  _UpdateTime();
@@ -101,6 +152,7 @@ EventMachine_t::EventMachine_t (EMCallback event_callback):
101
152
  #endif
102
153
 
103
154
  _InitializeLoopBreaker();
155
+ SelectData = new SelectData_t();
104
156
  }
105
157
 
106
158
 
@@ -130,40 +182,8 @@ EventMachine_t::~EventMachine_t()
130
182
  close (epfd);
131
183
  if (kqfd != -1)
132
184
  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
185
 
164
- #ifdef HAVE_KQUEUE
165
- bKqueue = true;
166
- #endif
186
+ delete SelectData;
167
187
  }
168
188
 
169
189
 
@@ -173,23 +193,32 @@ EventMachine_t::ScheduleHalt
173
193
 
174
194
  void EventMachine_t::ScheduleHalt()
175
195
  {
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
- */
196
+ /* This is how we stop the machine.
197
+ * This can be called by clients. Signal handlers will probably
198
+ * set the global flag.
199
+ * For now this means there can only be one EventMachine ever running at a time.
200
+ *
201
+ * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
202
+ * because it may be called from signal handlers invoked from code that we don't
203
+ * control. At this writing (20Sep06), EM does NOT install any signal handlers of
204
+ * its own.
205
+ *
206
+ * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
207
+ * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
208
+ */
189
209
  bTerminateSignalReceived = true;
190
- }
191
210
 
211
+ /* Signal the loopbreaker so we break out of long-running select/epoll/kqueue and
212
+ * notice the halt boolean is set. Signalling the loopbreaker also uses a single
213
+ * signal-safe syscall.
214
+ */
215
+ SignalLoopBreaker();
216
+ }
192
217
 
218
+ bool EventMachine_t::Stopping()
219
+ {
220
+ return bTerminateSignalReceived;
221
+ }
193
222
 
194
223
  /*******************************
195
224
  EventMachine_t::SetTimerQuantum
@@ -212,45 +241,54 @@ void EventMachine_t::SetTimerQuantum (int interval)
212
241
  (STATIC) EventMachine_t::SetuidString
213
242
  *************************************/
214
243
 
244
+ #ifdef OS_UNIX
215
245
  void EventMachine_t::SetuidString (const char *username)
216
246
  {
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
- */
247
+ /* This method takes a caller-supplied username and tries to setuid
248
+ * to that user. There is no meaningful implementation (and no error)
249
+ * on Windows. On Unix, a failure to setuid the caller-supplied string
250
+ * causes a fatal abort, because presumably the program is calling here
251
+ * in order to fulfill a security requirement. If we fail silently,
252
+ * the user may continue to run with too much privilege.
253
+ *
254
+ * TODO, we need to decide on and document a way of generating C++ level errors
255
+ * that can be wrapped in documented Ruby exceptions, so users can catch
256
+ * and handle them. And distinguish it from errors that we WON'T let the Ruby
257
+ * user catch (like security-violations and resource-overallocation).
258
+ * A setuid failure here would be in the latter category.
259
+ */
230
260
 
231
- #ifdef OS_UNIX
232
- if (!username || !*username)
233
- throw std::runtime_error ("setuid_string failed: no username specified");
261
+ if (!username || !*username)
262
+ throw std::runtime_error ("setuid_string failed: no username specified");
234
263
 
235
- struct passwd *p = getpwnam (username);
236
- if (!p)
237
- throw std::runtime_error ("setuid_string failed: unknown username");
264
+ errno = 0;
265
+ struct passwd *p = getpwnam (username);
266
+ if (!p) {
267
+ if (errno) {
268
+ char buf[200];
269
+ snprintf (buf, sizeof(buf)-1, "setuid_string failed: %s", strerror(errno));
270
+ throw std::runtime_error (buf);
271
+ } else {
272
+ throw std::runtime_error ("setuid_string failed: unknown username");
273
+ }
274
+ }
238
275
 
239
- if (setuid (p->pw_uid) != 0)
240
- throw std::runtime_error ("setuid_string failed: no setuid");
276
+ if (setuid (p->pw_uid) != 0)
277
+ throw std::runtime_error ("setuid_string failed: no setuid");
241
278
 
242
- // Success.
243
- #endif
279
+ // Success.
244
280
  }
245
-
281
+ #else
282
+ void EventMachine_t::SetuidString (const char *username UNUSED) { }
283
+ #endif
246
284
 
247
285
  /****************************************
248
286
  (STATIC) EventMachine_t::SetRlimitNofile
249
287
  ****************************************/
250
288
 
289
+ #ifdef OS_UNIX
251
290
  int EventMachine_t::SetRlimitNofile (int nofiles)
252
291
  {
253
- #ifdef OS_UNIX
254
292
  struct rlimit rlim;
255
293
  getrlimit (RLIMIT_NOFILE, &rlim);
256
294
  if (nofiles >= 0) {
@@ -263,14 +301,10 @@ int EventMachine_t::SetRlimitNofile (int nofiles)
263
301
  }
264
302
  getrlimit (RLIMIT_NOFILE, &rlim);
265
303
  return rlim.rlim_cur;
266
- #endif
267
-
268
- #ifdef OS_WIN32
269
- // No meaningful implementation on Windows.
270
- return 0;
271
- #endif
272
304
  }
273
-
305
+ #else
306
+ int EventMachine_t::SetRlimitNofile (int nofiles UNUSED) { return 0; }
307
+ #endif
274
308
 
275
309
  /*********************************
276
310
  EventMachine_t::SignalLoopBreaker
@@ -279,7 +313,7 @@ EventMachine_t::SignalLoopBreaker
279
313
  void EventMachine_t::SignalLoopBreaker()
280
314
  {
281
315
  #ifdef OS_UNIX
282
- write (LoopBreakerWriter, "", 1);
316
+ (void)write (LoopBreakerWriter, "", 1);
283
317
  #endif
284
318
  #ifdef OS_WIN32
285
319
  sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
@@ -303,8 +337,18 @@ void EventMachine_t::_InitializeLoopBreaker()
303
337
 
304
338
  #ifdef OS_UNIX
305
339
  int fd[2];
340
+ #if defined (HAVE_CLOEXEC) && defined (HAVE_PIPE2)
341
+ int pipestatus = pipe2(fd, O_CLOEXEC);
342
+ if (pipestatus < 0) {
343
+ if (pipe(fd))
344
+ throw std::runtime_error (strerror(errno));
345
+ }
346
+ #else
306
347
  if (pipe (fd))
307
348
  throw std::runtime_error (strerror(errno));
349
+ #endif
350
+ if (!SetFdCloexec(fd[0]) || !SetFdCloexec(fd[1]))
351
+ throw std::runtime_error (strerror(errno));
308
352
 
309
353
  LoopBreakerWriter = fd[1];
310
354
  LoopBreakerReader = fd[0];
@@ -315,7 +359,7 @@ void EventMachine_t::_InitializeLoopBreaker()
315
359
  #endif
316
360
 
317
361
  #ifdef OS_WIN32
318
- int sd = socket (AF_INET, SOCK_DGRAM, 0);
362
+ SOCKET sd = EmSocket (AF_INET, SOCK_DGRAM, 0);
319
363
  if (sd == INVALID_SOCKET)
320
364
  throw std::runtime_error ("no loop breaker socket");
321
365
  SetSocketNonblocking (sd);
@@ -337,6 +381,43 @@ void EventMachine_t::_InitializeLoopBreaker()
337
381
  throw std::runtime_error ("no loop breaker");
338
382
  LoopBreakerReader = sd;
339
383
  #endif
384
+
385
+ #ifdef HAVE_EPOLL
386
+ if (Poller == Poller_Epoll) {
387
+ epfd = epoll_create (MaxEpollDescriptors);
388
+ if (epfd == -1) {
389
+ char buf[200];
390
+ snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
391
+ throw std::runtime_error (buf);
392
+ }
393
+ int cloexec = fcntl (epfd, F_GETFD, 0);
394
+ assert (cloexec >= 0);
395
+ cloexec |= FD_CLOEXEC;
396
+ fcntl (epfd, F_SETFD, cloexec);
397
+
398
+ assert (LoopBreakerReader >= 0);
399
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
400
+ assert (ld);
401
+ Add (ld);
402
+ }
403
+ #endif
404
+
405
+ #ifdef HAVE_KQUEUE
406
+ if (Poller == Poller_Kqueue) {
407
+ kqfd = kqueue();
408
+ if (kqfd == -1) {
409
+ char buf[200];
410
+ snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
411
+ throw std::runtime_error (buf);
412
+ }
413
+ // cloexec not needed. By definition, kqueues are not carried across forks.
414
+
415
+ assert (LoopBreakerReader >= 0);
416
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
417
+ assert (ld);
418
+ Add (ld);
419
+ }
420
+ #endif
340
421
  }
341
422
 
342
423
  /***************************
@@ -352,16 +433,49 @@ void EventMachine_t::_UpdateTime()
352
433
  EventMachine_t::GetRealTime
353
434
  ***************************/
354
435
 
436
+ // Two great writeups of cross-platform monotonic time are at:
437
+ // http://www.python.org/dev/peps/pep-0418
438
+ // http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking
439
+ // Uncomment the #pragma messages to confirm which compile-time option was used
355
440
  uint64_t EventMachine_t::GetRealTime()
356
441
  {
357
442
  uint64_t current_time;
358
443
 
359
- #if defined(OS_UNIX)
444
+ #if defined(HAVE_CONST_CLOCK_MONOTONIC_RAW)
445
+ // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC_RAW"
446
+ // Linux 2.6.28 and above
447
+ struct timespec tv;
448
+ clock_gettime (CLOCK_MONOTONIC_RAW, &tv);
449
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
450
+
451
+ #elif defined(HAVE_CONST_CLOCK_MONOTONIC)
452
+ // #pragma message "GetRealTime: clock_gettime CLOCK_MONOTONIC"
453
+ // Linux, FreeBSD 5.0 and above, Solaris 8 and above, OpenBSD, NetBSD, DragonflyBSD
454
+ struct timespec tv;
455
+ clock_gettime (CLOCK_MONOTONIC, &tv);
456
+ current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)((tv.tv_nsec)/1000));
457
+
458
+ #elif defined(HAVE_GETHRTIME)
459
+ // #pragma message "GetRealTime: gethrtime"
460
+ // Solaris and HP-UX
461
+ current_time = (uint64_t)gethrtime() / 1000;
462
+
463
+ #elif defined(OS_DARWIN)
464
+ // #pragma message "GetRealTime: mach_absolute_time"
465
+ // Mac OS X
466
+ // https://developer.apple.com/library/mac/qa/qa1398/_index.html
467
+ current_time = mach_absolute_time() * mach_timebase.numer / mach_timebase.denom / 1000;
468
+
469
+ #elif defined(OS_UNIX)
470
+ // #pragma message "GetRealTime: gettimeofday"
471
+ // Unix fallback
360
472
  struct timeval tv;
361
473
  gettimeofday (&tv, NULL);
362
474
  current_time = (((uint64_t)(tv.tv_sec)) * 1000000LL) + ((uint64_t)(tv.tv_usec));
363
475
 
364
476
  #elif defined(OS_WIN32)
477
+ // #pragma message "GetRealTime: GetTickCount"
478
+ // Future improvement: use GetTickCount64 in Windows Vista / Server 2008
365
479
  unsigned tick = GetTickCount();
366
480
  if (tick < LastTickCount)
367
481
  TickCountTickover += 1;
@@ -370,6 +484,8 @@ uint64_t EventMachine_t::GetRealTime()
370
484
  current_time *= 1000; // convert to microseconds
371
485
 
372
486
  #else
487
+ // #pragma message "GetRealTime: time"
488
+ // Universal fallback
373
489
  current_time = (uint64_t)time(NULL) * 1000000LL;
374
490
  #endif
375
491
 
@@ -382,15 +498,27 @@ EventMachine_t::_DispatchHeartbeats
382
498
 
383
499
  void EventMachine_t::_DispatchHeartbeats()
384
500
  {
501
+ // Store the first processed heartbeat descriptor and bail out if
502
+ // we see it again. This fixes an infinite loop in case the system time
503
+ // is changed out from underneath MyCurrentLoopTime.
504
+ const EventableDescriptor *head = NULL;
505
+
385
506
  while (true) {
386
507
  multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
387
508
  if (i == Heartbeats.end())
388
509
  break;
389
510
  if (i->first > MyCurrentLoopTime)
390
511
  break;
512
+
391
513
  EventableDescriptor *ed = i->second;
514
+ if (ed == head)
515
+ break;
516
+
392
517
  ed->Heartbeat();
393
518
  QueueHeartbeat(ed);
519
+
520
+ if (head == NULL)
521
+ head = ed;
394
522
  }
395
523
  }
396
524
 
@@ -434,75 +562,44 @@ EventMachine_t::Run
434
562
 
435
563
  void EventMachine_t::Run()
436
564
  {
437
- #ifdef HAVE_EPOLL
438
- if (bEpoll) {
439
- epfd = epoll_create (MaxEpollDescriptors);
440
- if (epfd == -1) {
441
- char buf[200];
442
- snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
443
- throw std::runtime_error (buf);
444
- }
445
- int cloexec = fcntl (epfd, F_GETFD, 0);
446
- assert (cloexec >= 0);
447
- cloexec |= FD_CLOEXEC;
448
- fcntl (epfd, F_SETFD, cloexec);
449
-
450
- assert (LoopBreakerReader >= 0);
451
- LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
452
- assert (ld);
453
- Add (ld);
454
- }
455
- #endif
456
-
457
- #ifdef HAVE_KQUEUE
458
- if (bKqueue) {
459
- kqfd = kqueue();
460
- if (kqfd == -1) {
461
- char buf[200];
462
- snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
463
- throw std::runtime_error (buf);
464
- }
465
- // cloexec not needed. By definition, kqueues are not carried across forks.
466
-
467
- assert (LoopBreakerReader >= 0);
468
- LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
469
- assert (ld);
470
- Add (ld);
471
- }
472
- #endif
473
-
474
- while (true) {
475
- _UpdateTime();
476
- _RunTimers();
477
-
478
- /* _Add must precede _Modify because the same descriptor might
479
- * be on both lists during the same pass through the machine,
480
- * and to modify a descriptor before adding it would fail.
481
- */
482
- _AddNewDescriptors();
483
- _ModifyDescriptors();
484
-
485
- _RunOnce();
486
- if (bTerminateSignalReceived)
487
- break;
488
- }
565
+ while (RunOnce()) ;
489
566
  }
490
567
 
568
+ /***********************
569
+ EventMachine_t::RunOnce
570
+ ***********************/
491
571
 
492
- /************************
493
- EventMachine_t::_RunOnce
494
- ************************/
495
-
496
- void EventMachine_t::_RunOnce()
572
+ bool EventMachine_t::RunOnce()
497
573
  {
498
- if (bEpoll)
574
+ _UpdateTime();
575
+ _RunTimers();
576
+
577
+ /* _Add must precede _Modify because the same descriptor might
578
+ * be on both lists during the same pass through the machine,
579
+ * and to modify a descriptor before adding it would fail.
580
+ */
581
+ _AddNewDescriptors();
582
+ _ModifyDescriptors();
583
+
584
+ switch (Poller) {
585
+ case Poller_Epoll:
499
586
  _RunEpollOnce();
500
- else if (bKqueue)
587
+ break;
588
+ case Poller_Kqueue:
501
589
  _RunKqueueOnce();
502
- else
590
+ break;
591
+ case Poller_Default:
503
592
  _RunSelectOnce();
593
+ break;
594
+ }
595
+
504
596
  _DispatchHeartbeats();
505
597
  _CleanupSockets();
598
+
599
+ if (bTerminateSignalReceived)
600
+ return false;
601
+
602
+ return true;
506
603
  }
507
604
 
508
605
 
@@ -583,9 +680,9 @@ void EventMachine_t::_RunEpollOnce()
583
680
  EventMachine_t::_RunKqueueOnce
584
681
  ******************************/
585
682
 
683
+ #ifdef HAVE_KQUEUE
586
684
  void EventMachine_t::_RunKqueueOnce()
587
685
  {
588
- #ifdef HAVE_KQUEUE
589
686
  assert (kqfd != -1);
590
687
  int k;
591
688
 
@@ -663,10 +760,13 @@ void EventMachine_t::_RunKqueueOnce()
663
760
  rb_thread_schedule();
664
761
  }
665
762
  #endif
666
- #else
763
+ }
764
+ #else
765
+ void EventMachine_t::_RunKqueueOnce()
766
+ {
667
767
  throw std::runtime_error ("kqueue is not implemented on this platform");
668
- #endif
669
768
  }
769
+ #endif
670
770
 
671
771
 
672
772
  /*********************************
@@ -675,7 +775,7 @@ EventMachine_t::_TimeTilNextEvent
675
775
 
676
776
  timeval EventMachine_t::_TimeTilNextEvent()
677
777
  {
678
- // 29jul11: Changed calculation base from MyCurrentLoopTime to the
778
+ // 29jul11: Changed calculation base from MyCurrentLoopTime to the
679
779
  // real time. As MyCurrentLoopTime is set at the beginning of an
680
780
  // iteration and this calculation is done at the end, evenmachine
681
781
  // will potentially oversleep by the amount of time the iteration
@@ -697,10 +797,12 @@ timeval EventMachine_t::_TimeTilNextEvent()
697
797
  if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
698
798
  next_event = current_time;
699
799
  }
700
-
800
+
701
801
  timeval tv;
702
802
 
703
- if (next_event == 0 || NumCloseScheduled > 0) {
803
+ if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
804
+ tv.tv_sec = tv.tv_usec = 0;
805
+ } else if (next_event == 0) {
704
806
  tv = Quantum;
705
807
  } else {
706
808
  if (next_event > current_time) {
@@ -739,7 +841,7 @@ void EventMachine_t::_CleanupSockets()
739
841
  assert (ed);
740
842
  if (ed->ShouldDelete()) {
741
843
  #ifdef HAVE_EPOLL
742
- if (bEpoll) {
844
+ if (Poller == Poller_Epoll) {
743
845
  assert (epfd != -1);
744
846
  if (ed->GetSocket() != INVALID_SOCKET) {
745
847
  int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
@@ -766,10 +868,10 @@ void EventMachine_t::_CleanupSockets()
766
868
  EventMachine_t::_ModifyEpollEvent
767
869
  *********************************/
768
870
 
871
+ #ifdef HAVE_EPOLL
769
872
  void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
770
873
  {
771
- #ifdef HAVE_EPOLL
772
- if (bEpoll) {
874
+ if (Poller == Poller_Epoll) {
773
875
  assert (epfd != -1);
774
876
  assert (ed);
775
877
  assert (ed->GetSocket() != INVALID_SOCKET);
@@ -780,9 +882,10 @@ void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
780
882
  throw std::runtime_error (buf);
781
883
  }
782
884
  }
783
- #endif
784
885
  }
785
-
886
+ #else
887
+ void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed UNUSED) { }
888
+ #endif
786
889
 
787
890
 
788
891
  /**************************
@@ -792,22 +895,28 @@ SelectData_t::SelectData_t
792
895
  SelectData_t::SelectData_t()
793
896
  {
794
897
  maxsocket = 0;
795
- FD_ZERO (&fdreads);
796
- FD_ZERO (&fdwrites);
797
- FD_ZERO (&fderrors);
898
+ rb_fd_init (&fdreads);
899
+ rb_fd_init (&fdwrites);
900
+ rb_fd_init (&fderrors);
798
901
  }
799
902
 
903
+ SelectData_t::~SelectData_t()
904
+ {
905
+ rb_fd_term (&fdreads);
906
+ rb_fd_term (&fdwrites);
907
+ rb_fd_term (&fderrors);
908
+ }
800
909
 
801
910
  #ifdef BUILD_FOR_RUBY
802
911
  /*****************
803
912
  _SelectDataSelect
804
913
  *****************/
805
914
 
806
- #ifdef HAVE_TBR
915
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
807
916
  static VALUE _SelectDataSelect (void *v)
808
917
  {
809
918
  SelectData_t *sd = (SelectData_t*)v;
810
- sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv));
919
+ sd->nSockets = select (sd->maxsocket+1, rb_fd_ptr(&(sd->fdreads)), rb_fd_ptr(&(sd->fdwrites)), rb_fd_ptr(&(sd->fderrors)), &(sd->tv));
811
920
  return Qnil;
812
921
  }
813
922
  #endif
@@ -818,18 +927,27 @@ SelectData_t::_Select
818
927
 
819
928
  int SelectData_t::_Select()
820
929
  {
821
- #ifdef HAVE_TBR
930
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
931
+ // added in ruby 1.9.3
932
+ rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
933
+ return nSockets;
934
+ #elif defined(HAVE_TBR)
935
+ // added in ruby 1.9.1, deprecated in ruby 2.0.0
822
936
  rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
823
937
  return nSockets;
824
- #endif
825
-
826
- #ifndef HAVE_TBR
938
+ #else
827
939
  return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
828
940
  #endif
829
941
  }
830
942
  #endif
831
943
 
832
-
944
+ void SelectData_t::_Clear()
945
+ {
946
+ maxsocket = 0;
947
+ rb_fd_zero (&fdreads);
948
+ rb_fd_zero (&fdwrites);
949
+ rb_fd_zero (&fderrors);
950
+ }
833
951
 
834
952
  /******************************
835
953
  EventMachine_t::_RunSelectOnce
@@ -846,56 +964,51 @@ void EventMachine_t::_RunSelectOnce()
846
964
  // however it has the same problem interoperating with Ruby
847
965
  // threads that select does.
848
966
 
849
- SelectData_t SelectData;
850
- /*
851
- fd_set fdreads, fdwrites;
852
- FD_ZERO (&fdreads);
853
- FD_ZERO (&fdwrites);
854
-
855
- int maxsocket = 0;
856
- */
967
+ // Get ready for select()
968
+ SelectData->_Clear();
857
969
 
858
970
  // Always read the loop-breaker reader.
859
971
  // Changed 23Aug06, provisionally implemented for Windows with a UDP socket
860
972
  // running on localhost with a randomly-chosen port. (*Puke*)
861
973
  // Windows has a version of the Unix pipe() library function, but it doesn't
862
974
  // give you back descriptors that are selectable.
863
- FD_SET (LoopBreakerReader, &(SelectData.fdreads));
864
- if (SelectData.maxsocket < LoopBreakerReader)
865
- SelectData.maxsocket = LoopBreakerReader;
975
+ rb_fd_set (LoopBreakerReader, &(SelectData->fdreads));
976
+ if (SelectData->maxsocket < LoopBreakerReader)
977
+ SelectData->maxsocket = LoopBreakerReader;
866
978
 
867
979
  // prepare the sockets for reading and writing
868
980
  size_t i;
869
981
  for (i = 0; i < Descriptors.size(); i++) {
870
982
  EventableDescriptor *ed = Descriptors[i];
871
983
  assert (ed);
872
- int sd = ed->GetSocket();
984
+ SOCKET sd = ed->GetSocket();
873
985
  if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
874
986
  continue;
875
987
  assert (sd != INVALID_SOCKET);
876
988
 
877
989
  if (ed->SelectForRead())
878
- FD_SET (sd, &(SelectData.fdreads));
990
+ rb_fd_set (sd, &(SelectData->fdreads));
879
991
  if (ed->SelectForWrite())
880
- FD_SET (sd, &(SelectData.fdwrites));
992
+ rb_fd_set (sd, &(SelectData->fdwrites));
881
993
 
882
994
  #ifdef OS_WIN32
883
995
  /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable.
884
996
  Instead, it is added to the error set. See http://www.mail-archive.com/openssl-users@openssl.org/msg58500.html
885
997
  */
886
- FD_SET (sd, &(SelectData.fderrors));
998
+ if (ed->IsConnectPending())
999
+ rb_fd_set (sd, &(SelectData->fderrors));
887
1000
  #endif
888
1001
 
889
- if (SelectData.maxsocket < sd)
890
- SelectData.maxsocket = sd;
1002
+ if (SelectData->maxsocket < sd)
1003
+ SelectData->maxsocket = sd;
891
1004
  }
892
1005
 
893
1006
 
894
1007
  { // read and write the sockets
895
1008
  //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
896
1009
  //timeval tv = Quantum;
897
- SelectData.tv = _TimeTilNextEvent();
898
- int s = SelectData._Select();
1010
+ SelectData->tv = _TimeTilNextEvent();
1011
+ int s = SelectData->_Select();
899
1012
  //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0);
900
1013
  //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
901
1014
  //int s = SelectData.nSockets;
@@ -913,20 +1026,24 @@ void EventMachine_t::_RunSelectOnce()
913
1026
  for (i=0; i < Descriptors.size(); i++) {
914
1027
  EventableDescriptor *ed = Descriptors[i];
915
1028
  assert (ed);
916
- int sd = ed->GetSocket();
1029
+ SOCKET sd = ed->GetSocket();
917
1030
  if (ed->IsWatchOnly() && sd == INVALID_SOCKET)
918
1031
  continue;
919
1032
  assert (sd != INVALID_SOCKET);
920
1033
 
921
- if (FD_ISSET (sd, &(SelectData.fdwrites)))
922
- ed->Write();
923
- if (FD_ISSET (sd, &(SelectData.fdreads)))
1034
+ if (rb_fd_isset (sd, &(SelectData->fdwrites))) {
1035
+ // Double-check SelectForWrite() still returns true. If not, one of the callbacks must have
1036
+ // modified some value since we checked SelectForWrite() earlier in this method.
1037
+ if (ed->SelectForWrite())
1038
+ ed->Write();
1039
+ }
1040
+ if (rb_fd_isset (sd, &(SelectData->fdreads)))
924
1041
  ed->Read();
925
- if (FD_ISSET (sd, &(SelectData.fderrors)))
1042
+ if (rb_fd_isset (sd, &(SelectData->fderrors)))
926
1043
  ed->HandleError();
927
1044
  }
928
1045
 
929
- if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads)))
1046
+ if (rb_fd_isset (LoopBreakerReader, &(SelectData->fdreads)))
930
1047
  _ReadLoopBreaker();
931
1048
  }
932
1049
  else if (s < 0) {
@@ -958,17 +1075,18 @@ void EventMachine_t::_CleanBadDescriptors()
958
1075
  if (ed->ShouldDelete())
959
1076
  continue;
960
1077
 
961
- int sd = ed->GetSocket();
1078
+ SOCKET sd = ed->GetSocket();
962
1079
 
963
1080
  struct timeval tv;
964
1081
  tv.tv_sec = 0;
965
1082
  tv.tv_usec = 0;
966
1083
 
967
- fd_set fds;
968
- FD_ZERO(&fds);
969
- FD_SET(sd, &fds);
1084
+ rb_fdset_t fds;
1085
+ rb_fd_init(&fds);
1086
+ rb_fd_set(sd, &fds);
970
1087
 
971
- int ret = select(sd + 1, &fds, NULL, NULL, &tv);
1088
+ int ret = rb_fd_select(sd + 1, &fds, NULL, NULL, &tv);
1089
+ rb_fd_term(&fds);
972
1090
 
973
1091
  if (ret == -1) {
974
1092
  if (errno == EBADF)
@@ -988,7 +1106,7 @@ void EventMachine_t::_ReadLoopBreaker()
988
1106
  * and send a loop-break event back to user code.
989
1107
  */
990
1108
  char buffer [1024];
991
- read (LoopBreakerReader, buffer, sizeof(buffer));
1109
+ (void)read (LoopBreakerReader, buffer, sizeof(buffer));
992
1110
  if (EventCallback)
993
1111
  (*EventCallback)(0, EM_LOOPBREAK_SIGNAL, "", 0);
994
1112
  }
@@ -1024,7 +1142,7 @@ void EventMachine_t::_RunTimers()
1024
1142
  EventMachine_t::InstallOneshotTimer
1025
1143
  ***********************************/
1026
1144
 
1027
- const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
1145
+ const uintptr_t EventMachine_t::InstallOneshotTimer (int milliseconds)
1028
1146
  {
1029
1147
  if (Timers.size() > MaxOutstandingTimers)
1030
1148
  return false;
@@ -1046,7 +1164,7 @@ const unsigned long EventMachine_t::InstallOneshotTimer (int milliseconds)
1046
1164
  EventMachine_t::ConnectToServer
1047
1165
  *******************************/
1048
1166
 
1049
- const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port)
1167
+ const uintptr_t EventMachine_t::ConnectToServer (const char *bind_addr, int bind_port, const char *server, int port)
1050
1168
  {
1051
1169
  /* We want to spend no more than a few seconds waiting for a connection
1052
1170
  * to a remote host. So we use a nonblocking connect.
@@ -1074,13 +1192,15 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1074
1192
  if (!server || !*server || !port)
1075
1193
  throw std::runtime_error ("invalid server or port");
1076
1194
 
1077
- int family, bind_size;
1078
- struct sockaddr bind_as, *bind_as_ptr = name2address (server, port, &family, &bind_size);
1079
- if (!bind_as_ptr)
1080
- throw std::runtime_error ("unable to resolve server address");
1081
- bind_as = *bind_as_ptr; // copy because name2address points to a static
1195
+ struct sockaddr_storage bind_as;
1196
+ size_t bind_as_len = sizeof bind_as;
1197
+ if (!name2address (server, port, (struct sockaddr *)&bind_as, &bind_as_len)) {
1198
+ char buf [200];
1199
+ snprintf (buf, sizeof(buf)-1, "unable to resolve server address: %s", strerror(errno));
1200
+ throw std::runtime_error (buf);
1201
+ }
1082
1202
 
1083
- int sd = socket (family, SOCK_STREAM, 0);
1203
+ SOCKET sd = EmSocket (bind_as.ss_family, SOCK_STREAM, 0);
1084
1204
  if (sd == INVALID_SOCKET) {
1085
1205
  char buf [200];
1086
1206
  snprintf (buf, sizeof(buf)-1, "unable to create new socket: %s", strerror(errno));
@@ -1100,24 +1220,23 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1100
1220
  setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
1101
1221
 
1102
1222
  if (bind_addr) {
1103
- int bind_to_size, bind_to_family;
1104
- struct sockaddr *bind_to = name2address (bind_addr, bind_port, &bind_to_family, &bind_to_size);
1105
- if (!bind_to) {
1223
+ struct sockaddr_storage bind_to;
1224
+ size_t bind_to_len = sizeof bind_to;
1225
+ if (!name2address (bind_addr, bind_port, (struct sockaddr *)&bind_to, &bind_to_len)) {
1106
1226
  close (sd);
1107
1227
  throw std::runtime_error ("invalid bind address");
1108
1228
  }
1109
- if (bind (sd, bind_to, bind_to_size) < 0) {
1229
+ if (bind (sd, (struct sockaddr *)&bind_to, bind_to_len) < 0) {
1110
1230
  close (sd);
1111
1231
  throw std::runtime_error ("couldn't bind to address");
1112
1232
  }
1113
1233
  }
1114
1234
 
1115
- unsigned long out = 0;
1116
- int e = 0;
1235
+ uintptr_t out = 0;
1117
1236
 
1118
1237
  #ifdef OS_UNIX
1119
- //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
1120
- if (connect (sd, &bind_as, bind_size) == 0) {
1238
+ int e_reason = 0;
1239
+ if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
1121
1240
  // This is a connect success, which Linux appears
1122
1241
  // never to give when the socket is nonblocking,
1123
1242
  // even if the connection is intramachine or to
@@ -1163,13 +1282,13 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1163
1282
  out = cd->GetBinding();
1164
1283
  } else {
1165
1284
  // Fall through to the !out case below.
1166
- e = error;
1285
+ e_reason = error;
1167
1286
  }
1168
1287
  }
1169
1288
  else {
1170
1289
  // The error from connect was something other then EINPROGRESS (EHOSTDOWN, etc).
1171
1290
  // Fall through to the !out case below
1172
- e = errno;
1291
+ e_reason = errno;
1173
1292
  }
1174
1293
 
1175
1294
  if (!out) {
@@ -1188,7 +1307,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1188
1307
  ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1189
1308
  if (!cd)
1190
1309
  throw std::runtime_error ("no connection allocated");
1191
- cd->SetUnbindReasonCode(e);
1310
+ cd->SetUnbindReasonCode (e_reason);
1192
1311
  cd->ScheduleClose (false);
1193
1312
  Add (cd);
1194
1313
  out = cd->GetBinding();
@@ -1196,8 +1315,7 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1196
1315
  #endif
1197
1316
 
1198
1317
  #ifdef OS_WIN32
1199
- //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
1200
- if (connect (sd, &bind_as, bind_size) == 0) {
1318
+ if (connect (sd, (struct sockaddr *)&bind_as, bind_as_len) == 0) {
1201
1319
  // This is a connect success, which Windows appears
1202
1320
  // never to give when the socket is nonblocking,
1203
1321
  // even if the connection is intramachine or to
@@ -1232,7 +1350,8 @@ const unsigned long EventMachine_t::ConnectToServer (const char *bind_addr, int
1232
1350
  EventMachine_t::ConnectToUnixServer
1233
1351
  ***********************************/
1234
1352
 
1235
- const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1353
+ #ifdef OS_UNIX
1354
+ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server)
1236
1355
  {
1237
1356
  /* Connect to a Unix-domain server, which by definition is running
1238
1357
  * on the same host.
@@ -1241,15 +1360,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1241
1360
  * is always local and can always be fulfilled immediately.
1242
1361
  */
1243
1362
 
1244
- #ifdef OS_WIN32
1245
- throw std::runtime_error ("unix-domain connection unavailable on this platform");
1246
- return 0;
1247
- #endif
1248
-
1249
- // The whole rest of this function is only compiled on Unix systems.
1250
- #ifdef OS_UNIX
1251
-
1252
- unsigned long out = 0;
1363
+ uintptr_t out = 0;
1253
1364
 
1254
1365
  if (!server || !*server)
1255
1366
  return 0;
@@ -1266,7 +1377,7 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1266
1377
 
1267
1378
  strcpy (pun.sun_path, server);
1268
1379
 
1269
- int fd = socket (AF_LOCAL, SOCK_STREAM, 0);
1380
+ SOCKET fd = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1270
1381
  if (fd == INVALID_SOCKET)
1271
1382
  return 0;
1272
1383
 
@@ -1298,18 +1409,28 @@ const unsigned long EventMachine_t::ConnectToUnixServer (const char *server)
1298
1409
  close (fd);
1299
1410
 
1300
1411
  return out;
1301
- #endif
1302
1412
  }
1413
+ #else
1414
+ const uintptr_t EventMachine_t::ConnectToUnixServer (const char *server UNUSED)
1415
+ {
1416
+ throw std::runtime_error ("unix-domain connection unavailable on this platform");
1417
+ }
1418
+ #endif
1303
1419
 
1304
1420
  /************************
1305
1421
  EventMachine_t::AttachFD
1306
1422
  ************************/
1307
1423
 
1308
- const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
1424
+ const uintptr_t EventMachine_t::AttachFD (SOCKET fd, bool watch_mode)
1309
1425
  {
1310
1426
  #ifdef OS_UNIX
1311
- if (fcntl(fd, F_GETFL, 0) < 0)
1312
- throw std::runtime_error ("invalid file descriptor");
1427
+ if (fcntl(fd, F_GETFL, 0) < 0) {
1428
+ if (errno) {
1429
+ throw std::runtime_error (strerror(errno));
1430
+ } else {
1431
+ throw std::runtime_error ("invalid file descriptor");
1432
+ }
1433
+ }
1313
1434
  #endif
1314
1435
 
1315
1436
  #ifdef OS_WIN32
@@ -1348,7 +1469,7 @@ const unsigned long EventMachine_t::AttachFD (int fd, bool watch_mode)
1348
1469
 
1349
1470
  Add (cd);
1350
1471
 
1351
- const unsigned long out = cd->GetBinding();
1472
+ const uintptr_t out = cd->GetBinding();
1352
1473
  return out;
1353
1474
  }
1354
1475
 
@@ -1361,10 +1482,10 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1361
1482
  if (!ed)
1362
1483
  throw std::runtime_error ("detaching bad descriptor");
1363
1484
 
1364
- int fd = ed->GetSocket();
1485
+ SOCKET fd = ed->GetSocket();
1365
1486
 
1366
1487
  #ifdef HAVE_EPOLL
1367
- if (bEpoll) {
1488
+ if (Poller == Poller_Epoll) {
1368
1489
  if (ed->GetSocket() != INVALID_SOCKET) {
1369
1490
  assert (epfd != -1);
1370
1491
  int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
@@ -1379,7 +1500,7 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1379
1500
  #endif
1380
1501
 
1381
1502
  #ifdef HAVE_KQUEUE
1382
- if (bKqueue) {
1503
+ if (Poller == Poller_Kqueue) {
1383
1504
  // remove any read/write events for this fd
1384
1505
  struct kevent k;
1385
1506
  #ifdef __NetBSD__
@@ -1399,6 +1520,14 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1399
1520
  // Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
1400
1521
  ModifiedDescriptors.erase (ed);
1401
1522
 
1523
+ // Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
1524
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1525
+ if (ed == NewDescriptors[i]) {
1526
+ NewDescriptors.erase(NewDescriptors.begin() + i);
1527
+ break;
1528
+ }
1529
+ }
1530
+
1402
1531
  // Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
1403
1532
  // and also to prevent anyone from calling close() on the detached fd
1404
1533
  ed->SetSocketInvalid();
@@ -1410,66 +1539,30 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1410
1539
  name2address
1411
1540
  ************/
1412
1541
 
1413
- struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size)
1542
+ bool EventMachine_t::name2address (const char *server, int port, struct sockaddr *addr, size_t *addr_len)
1414
1543
  {
1415
- // THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.
1416
- // Check the more-common cases first.
1417
- // Return NULL if no resolution.
1418
-
1419
- static struct sockaddr_in in4;
1420
- #ifndef __CYGWIN__
1421
- static struct sockaddr_in6 in6;
1422
- #endif
1423
- struct hostent *hp;
1424
-
1425
1544
  if (!server || !*server)
1426
1545
  server = "0.0.0.0";
1427
1546
 
1428
- memset (&in4, 0, sizeof(in4));
1429
- if ( (in4.sin_addr.s_addr = inet_addr (server)) != INADDR_NONE) {
1430
- if (family)
1431
- *family = AF_INET;
1432
- if (bind_size)
1433
- *bind_size = sizeof(in4);
1434
- in4.sin_family = AF_INET;
1435
- in4.sin_port = htons (port);
1436
- return (struct sockaddr*)&in4;
1437
- }
1438
-
1439
- #if defined(OS_UNIX) && !defined(__CYGWIN__)
1440
- memset (&in6, 0, sizeof(in6));
1441
- if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) {
1442
- if (family)
1443
- *family = AF_INET6;
1444
- if (bind_size)
1445
- *bind_size = sizeof(in6);
1446
- in6.sin6_family = AF_INET6;
1447
- in6.sin6_port = htons (port);
1448
- return (struct sockaddr*)&in6;
1449
- }
1450
- #endif
1547
+ struct addrinfo *ai;
1548
+ struct addrinfo hints;
1549
+ memset (&hints, 0, sizeof(hints));
1550
+ hints.ai_family = AF_UNSPEC;
1551
+ hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
1451
1552
 
1452
- #ifdef OS_WIN32
1453
- // TODO, must complete this branch. Windows doesn't have inet_pton.
1454
- // A possible approach is to make a getaddrinfo call with the supplied
1455
- // server address, constraining the hints to ipv6 and seeing if we
1456
- // get any addresses.
1457
- // For the time being, Ipv6 addresses aren't supported on Windows.
1458
- #endif
1553
+ char portstr[12];
1554
+ snprintf(portstr, sizeof(portstr), "%u", port);
1459
1555
 
1460
- hp = gethostbyname ((char*)server); // Windows requires the cast.
1461
- if (hp) {
1462
- in4.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1463
- if (family)
1464
- *family = AF_INET;
1465
- if (bind_size)
1466
- *bind_size = sizeof(in4);
1467
- in4.sin_family = AF_INET;
1468
- in4.sin_port = htons (port);
1469
- return (struct sockaddr*)&in4;
1556
+ if (getaddrinfo (server, portstr, &hints, &ai) == 0) {
1557
+ assert (ai->ai_addrlen <= *addr_len);
1558
+ memcpy (addr, ai->ai_addr, ai->ai_addrlen);
1559
+ *addr_len = ai->ai_addrlen;
1560
+
1561
+ freeaddrinfo(ai);
1562
+ return true;
1470
1563
  }
1471
1564
 
1472
- return NULL;
1565
+ return false;
1473
1566
  }
1474
1567
 
1475
1568
 
@@ -1477,7 +1570,7 @@ struct sockaddr *name2address (const char *server, int port, int *family, int *b
1477
1570
  EventMachine_t::CreateTcpServer
1478
1571
  *******************************/
1479
1572
 
1480
- const unsigned long EventMachine_t::CreateTcpServer (const char *server, int port)
1573
+ const uintptr_t EventMachine_t::CreateTcpServer (const char *server, int port)
1481
1574
  {
1482
1575
  /* Create a TCP-acceptor (server) socket and add it to the event machine.
1483
1576
  * Return the binding of the new acceptor to the caller.
@@ -1486,16 +1579,12 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1486
1579
  */
1487
1580
 
1488
1581
 
1489
- int family, bind_size;
1490
- struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1491
- if (!bind_here)
1582
+ struct sockaddr_storage bind_here;
1583
+ size_t bind_here_len = sizeof bind_here;
1584
+ if (!name2address (server, port, (struct sockaddr *)&bind_here, &bind_here_len))
1492
1585
  return 0;
1493
1586
 
1494
- unsigned long output_binding = 0;
1495
-
1496
- //struct sockaddr_in sin;
1497
-
1498
- int sd_accept = socket (family, SOCK_STREAM, 0);
1587
+ SOCKET sd_accept = EmSocket (bind_here.ss_family, SOCK_STREAM, 0);
1499
1588
  if (sd_accept == INVALID_SOCKET) {
1500
1589
  goto fail;
1501
1590
  }
@@ -1518,8 +1607,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1518
1607
  }
1519
1608
 
1520
1609
 
1521
- //if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
1522
- if (bind (sd_accept, bind_here, bind_size)) {
1610
+ if (bind (sd_accept, (struct sockaddr *)&bind_here, bind_here_len)) {
1523
1611
  //__warning ("binding failed");
1524
1612
  goto fail;
1525
1613
  }
@@ -1529,25 +1617,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1529
1617
  goto fail;
1530
1618
  }
1531
1619
 
1532
- {
1533
- // Set the acceptor non-blocking.
1534
- // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1535
- if (!SetSocketNonblocking (sd_accept)) {
1536
- //int val = fcntl (sd_accept, F_GETFL, 0);
1537
- //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1538
- goto fail;
1539
- }
1540
- }
1541
-
1542
- { // Looking good.
1543
- AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1544
- if (!ad)
1545
- throw std::runtime_error ("unable to allocate acceptor");
1546
- Add (ad);
1547
- output_binding = ad->GetBinding();
1548
- }
1549
-
1550
- return output_binding;
1620
+ return AttachSD(sd_accept);
1551
1621
 
1552
1622
  fail:
1553
1623
  if (sd_accept != INVALID_SOCKET)
@@ -1560,44 +1630,31 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1560
1630
  EventMachine_t::OpenDatagramSocket
1561
1631
  **********************************/
1562
1632
 
1563
- const unsigned long EventMachine_t::OpenDatagramSocket (const char *address, int port)
1633
+ const uintptr_t EventMachine_t::OpenDatagramSocket (const char *address, int port)
1564
1634
  {
1565
- unsigned long output_binding = 0;
1635
+ uintptr_t output_binding = 0;
1566
1636
 
1567
- int sd = socket (AF_INET, SOCK_DGRAM, 0);
1637
+ struct sockaddr_storage bind_here;
1638
+ size_t bind_here_len = sizeof bind_here;
1639
+ if (!name2address (address, port, (struct sockaddr *)&bind_here, &bind_here_len))
1640
+ return 0;
1641
+
1642
+ // from here on, early returns must close the socket!
1643
+ SOCKET sd = EmSocket (bind_here.ss_family, SOCK_DGRAM, 0);
1568
1644
  if (sd == INVALID_SOCKET)
1569
1645
  goto fail;
1570
- // from here on, early returns must close the socket!
1571
-
1572
-
1573
- struct sockaddr_in sin;
1574
- memset (&sin, 0, sizeof(sin));
1575
- sin.sin_family = AF_INET;
1576
- sin.sin_port = htons (port);
1577
1646
 
1578
-
1579
- if (address && *address) {
1580
- sin.sin_addr.s_addr = inet_addr (address);
1581
- if (sin.sin_addr.s_addr == INADDR_NONE) {
1582
- hostent *hp = gethostbyname ((char*)address); // Windows requires the cast.
1583
- if (hp == NULL)
1584
- goto fail;
1585
- sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1586
- }
1647
+ { // set the SO_REUSEADDR on the socket before we bind, otherwise it won't work for a second one
1648
+ int oval = 1;
1649
+ if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0)
1650
+ goto fail;
1587
1651
  }
1588
- else
1589
- sin.sin_addr.s_addr = htonl (INADDR_ANY);
1590
-
1591
1652
 
1592
1653
  // Set the new socket nonblocking.
1593
- {
1594
- if (!SetSocketNonblocking (sd))
1595
- //int val = fcntl (sd, F_GETFL, 0);
1596
- //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1)
1597
- goto fail;
1598
- }
1654
+ if (!SetSocketNonblocking (sd))
1655
+ goto fail;
1599
1656
 
1600
- if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0)
1657
+ if (bind (sd, (struct sockaddr *)&bind_here, bind_here_len) != 0)
1601
1658
  goto fail;
1602
1659
 
1603
1660
  { // Looking good.
@@ -1635,10 +1692,10 @@ void EventMachine_t::Add (EventableDescriptor *ed)
1635
1692
  EventMachine_t::ArmKqueueWriter
1636
1693
  *******************************/
1637
1694
 
1695
+ #ifdef HAVE_KQUEUE
1638
1696
  void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
1639
1697
  {
1640
- #ifdef HAVE_KQUEUE
1641
- if (bKqueue) {
1698
+ if (Poller == Poller_Kqueue) {
1642
1699
  if (!ed)
1643
1700
  throw std::runtime_error ("added bad descriptor");
1644
1701
  struct kevent k;
@@ -1654,17 +1711,19 @@ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
1654
1711
  throw std::runtime_error (buf);
1655
1712
  }
1656
1713
  }
1657
- #endif
1658
1714
  }
1715
+ #else
1716
+ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed UNUSED) { }
1717
+ #endif
1659
1718
 
1660
1719
  /*******************************
1661
1720
  EventMachine_t::ArmKqueueReader
1662
1721
  *******************************/
1663
1722
 
1723
+ #ifdef HAVE_KQUEUE
1664
1724
  void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
1665
1725
  {
1666
- #ifdef HAVE_KQUEUE
1667
- if (bKqueue) {
1726
+ if (Poller == Poller_Kqueue) {
1668
1727
  if (!ed)
1669
1728
  throw std::runtime_error ("added bad descriptor");
1670
1729
  struct kevent k;
@@ -1680,8 +1739,10 @@ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
1680
1739
  throw std::runtime_error (buf);
1681
1740
  }
1682
1741
  }
1683
- #endif
1684
1742
  }
1743
+ #else
1744
+ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed UNUSED) { }
1745
+ #endif
1685
1746
 
1686
1747
  /**********************************
1687
1748
  EventMachine_t::_AddNewDescriptors
@@ -1706,7 +1767,7 @@ void EventMachine_t::_AddNewDescriptors()
1706
1767
  throw std::runtime_error ("adding bad descriptor");
1707
1768
 
1708
1769
  #if HAVE_EPOLL
1709
- if (bEpoll) {
1770
+ if (Poller == Poller_Epoll) {
1710
1771
  assert (epfd != -1);
1711
1772
  int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent());
1712
1773
  if (e) {
@@ -1719,7 +1780,7 @@ void EventMachine_t::_AddNewDescriptors()
1719
1780
 
1720
1781
  #if HAVE_KQUEUE
1721
1782
  /*
1722
- if (bKqueue) {
1783
+ if (Poller == Poller_Kqueue) {
1723
1784
  // INCOMPLETE. Some descriptors don't want to be readable.
1724
1785
  assert (kqfd != -1);
1725
1786
  struct kevent k;
@@ -1765,7 +1826,7 @@ void EventMachine_t::_ModifyDescriptors()
1765
1826
  */
1766
1827
 
1767
1828
  #ifdef HAVE_EPOLL
1768
- if (bEpoll) {
1829
+ if (Poller == Poller_Epoll) {
1769
1830
  set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
1770
1831
  while (i != ModifiedDescriptors.end()) {
1771
1832
  assert (*i);
@@ -1775,6 +1836,18 @@ void EventMachine_t::_ModifyDescriptors()
1775
1836
  }
1776
1837
  #endif
1777
1838
 
1839
+ #ifdef HAVE_KQUEUE
1840
+ if (Poller == Poller_Kqueue) {
1841
+ set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
1842
+ while (i != ModifiedDescriptors.end()) {
1843
+ assert (*i);
1844
+ if ((*i)->GetKqueueArmWrite())
1845
+ ArmKqueueWriter (*i);
1846
+ ++i;
1847
+ }
1848
+ }
1849
+ #endif
1850
+
1778
1851
  ModifiedDescriptors.clear();
1779
1852
  }
1780
1853
 
@@ -1803,7 +1876,7 @@ void EventMachine_t::Deregister (EventableDescriptor *ed)
1803
1876
  // cut/paste from _CleanupSockets(). The error handling could be
1804
1877
  // refactored out of there, but it is cut/paste all over the
1805
1878
  // file already.
1806
- if (bEpoll) {
1879
+ if (Poller == Poller_Epoll) {
1807
1880
  assert (epfd != -1);
1808
1881
  assert (ed->GetSocket() != INVALID_SOCKET);
1809
1882
  int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
@@ -1823,7 +1896,8 @@ void EventMachine_t::Deregister (EventableDescriptor *ed)
1823
1896
  EventMachine_t::CreateUnixDomainServer
1824
1897
  **************************************/
1825
1898
 
1826
- const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename)
1899
+ #ifdef OS_UNIX
1900
+ const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename)
1827
1901
  {
1828
1902
  /* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
1829
1903
  * Return the binding of the new acceptor to the caller.
@@ -1832,17 +1906,9 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1832
1906
  * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
1833
1907
  */
1834
1908
 
1835
- #ifdef OS_WIN32
1836
- throw std::runtime_error ("unix-domain server unavailable on this platform");
1837
- #endif
1838
-
1839
- // The whole rest of this function is only compiled on Unix systems.
1840
- #ifdef OS_UNIX
1841
- unsigned long output_binding = 0;
1842
-
1843
1909
  struct sockaddr_un s_sun;
1844
1910
 
1845
- int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0);
1911
+ SOCKET sd_accept = EmSocket (AF_LOCAL, SOCK_STREAM, 0);
1846
1912
  if (sd_accept == INVALID_SOCKET) {
1847
1913
  goto fail;
1848
1914
  }
@@ -1876,6 +1942,29 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1876
1942
  goto fail;
1877
1943
  }
1878
1944
 
1945
+ return AttachSD(sd_accept);
1946
+
1947
+ fail:
1948
+ if (sd_accept != INVALID_SOCKET)
1949
+ close (sd_accept);
1950
+ return 0;
1951
+ }
1952
+ #else
1953
+ const uintptr_t EventMachine_t::CreateUnixDomainServer (const char *filename UNUSED)
1954
+ {
1955
+ throw std::runtime_error ("unix-domain server unavailable on this platform");
1956
+ }
1957
+ #endif
1958
+
1959
+
1960
+ /**************************************
1961
+ EventMachine_t::AttachSD
1962
+ **************************************/
1963
+
1964
+ const uintptr_t EventMachine_t::AttachSD (SOCKET sd_accept)
1965
+ {
1966
+ uintptr_t output_binding = 0;
1967
+
1879
1968
  {
1880
1969
  // Set the acceptor non-blocking.
1881
1970
  // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
@@ -1900,64 +1989,16 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1900
1989
  if (sd_accept != INVALID_SOCKET)
1901
1990
  close (sd_accept);
1902
1991
  return 0;
1903
- #endif // OS_UNIX
1904
1992
  }
1905
1993
 
1906
1994
 
1907
- /*********************
1908
- EventMachine_t::Popen
1909
- *********************/
1910
- #if OBSOLETE
1911
- const char *EventMachine_t::Popen (const char *cmd, const char *mode)
1912
- {
1913
- #ifdef OS_WIN32
1914
- throw std::runtime_error ("popen is currently unavailable on this platform");
1915
- #endif
1916
-
1917
- // The whole rest of this function is only compiled on Unix systems.
1918
- // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1919
- #ifdef OS_UNIX
1920
- const char *output_binding = NULL;
1921
-
1922
- FILE *fp = popen (cmd, mode);
1923
- if (!fp)
1924
- return NULL;
1925
-
1926
- // From here, all early returns must pclose the stream.
1927
-
1928
- // According to the pipe(2) manpage, descriptors returned from pipe have both
1929
- // CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.
1930
- if (!SetSocketNonblocking (fileno (fp))) {
1931
- pclose (fp);
1932
- return NULL;
1933
- }
1934
-
1935
- { // Looking good.
1936
- PipeDescriptor *pd = new PipeDescriptor (fp, this);
1937
- if (!pd)
1938
- throw std::runtime_error ("unable to allocate pipe");
1939
- Add (pd);
1940
- output_binding = pd->GetBinding();
1941
- }
1942
-
1943
- return output_binding;
1944
- #endif
1945
- }
1946
- #endif // OBSOLETE
1947
-
1948
1995
  /**************************
1949
1996
  EventMachine_t::Socketpair
1950
1997
  **************************/
1951
1998
 
1952
- const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1999
+ #ifdef OS_UNIX
2000
+ const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings)
1953
2001
  {
1954
- #ifdef OS_WIN32
1955
- throw std::runtime_error ("socketpair is currently unavailable on this platform");
1956
- #endif
1957
-
1958
- // The whole rest of this function is only compiled on Unix systems.
1959
- // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1960
- #ifdef OS_UNIX
1961
2002
  // Make sure the incoming array of command strings is sane.
1962
2003
  if (!cmd_strings)
1963
2004
  return 0;
@@ -1967,7 +2008,7 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
1967
2008
  if ((j==0) || (j==2048))
1968
2009
  return 0;
1969
2010
 
1970
- unsigned long output_binding = 0;
2011
+ uintptr_t output_binding = 0;
1971
2012
 
1972
2013
  int sv[2];
1973
2014
  if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
@@ -2005,15 +2046,21 @@ const unsigned long EventMachine_t::Socketpair (char * const*cmd_strings)
2005
2046
  throw std::runtime_error ("no fork");
2006
2047
 
2007
2048
  return output_binding;
2008
- #endif
2009
2049
  }
2050
+ #else
2051
+ const uintptr_t EventMachine_t::Socketpair (char * const * cmd_strings UNUSED)
2052
+ {
2053
+ throw std::runtime_error ("socketpair is currently unavailable on this platform");
2054
+ }
2055
+ #endif
2056
+
2010
2057
 
2011
2058
 
2012
2059
  /****************************
2013
2060
  EventMachine_t::OpenKeyboard
2014
2061
  ****************************/
2015
2062
 
2016
- const unsigned long EventMachine_t::OpenKeyboard()
2063
+ const uintptr_t EventMachine_t::OpenKeyboard()
2017
2064
  {
2018
2065
  KeyboardDescriptor *kd = new KeyboardDescriptor (this);
2019
2066
  if (!kd)
@@ -2037,10 +2084,10 @@ int EventMachine_t::GetConnectionCount ()
2037
2084
  EventMachine_t::WatchPid
2038
2085
  ************************/
2039
2086
 
2040
- const unsigned long EventMachine_t::WatchPid (int pid)
2087
+ #ifdef HAVE_KQUEUE
2088
+ const uintptr_t EventMachine_t::WatchPid (int pid)
2041
2089
  {
2042
- #ifdef HAVE_KQUEUE
2043
- if (!bKqueue)
2090
+ if (Poller != Poller_Kqueue)
2044
2091
  throw std::runtime_error("must enable kqueue (EM.kqueue=true) for pid watching support");
2045
2092
 
2046
2093
  struct kevent event;
@@ -2055,17 +2102,17 @@ const unsigned long EventMachine_t::WatchPid (int pid)
2055
2102
  sprintf(errbuf, "failed to register file watch descriptor with kqueue: %s", strerror(errno));
2056
2103
  throw std::runtime_error(errbuf);
2057
2104
  }
2058
- #endif
2059
-
2060
- #ifdef HAVE_KQUEUE
2061
2105
  Bindable_t* b = new Bindable_t();
2062
2106
  Pids.insert(make_pair (pid, b));
2063
2107
 
2064
2108
  return b->GetBinding();
2065
- #endif
2066
-
2109
+ }
2110
+ #else
2111
+ const uintptr_t EventMachine_t::WatchPid (int pid UNUSED)
2112
+ {
2067
2113
  throw std::runtime_error("no pid watching support on this system");
2068
2114
  }
2115
+ #endif
2069
2116
 
2070
2117
  /**************************
2071
2118
  EventMachine_t::UnwatchPid
@@ -2091,7 +2138,7 @@ void EventMachine_t::UnwatchPid (int pid)
2091
2138
  delete b;
2092
2139
  }
2093
2140
 
2094
- void EventMachine_t::UnwatchPid (const unsigned long sig)
2141
+ void EventMachine_t::UnwatchPid (const uintptr_t sig)
2095
2142
  {
2096
2143
  for(map<int, Bindable_t*>::iterator i=Pids.begin(); i != Pids.end(); i++)
2097
2144
  {
@@ -2109,7 +2156,7 @@ void EventMachine_t::UnwatchPid (const unsigned long sig)
2109
2156
  EventMachine_t::WatchFile
2110
2157
  *************************/
2111
2158
 
2112
- const unsigned long EventMachine_t::WatchFile (const char *fpath)
2159
+ const uintptr_t EventMachine_t::WatchFile (const char *fpath)
2113
2160
  {
2114
2161
  struct stat sb;
2115
2162
  int sres;
@@ -2140,7 +2187,7 @@ const unsigned long EventMachine_t::WatchFile (const char *fpath)
2140
2187
  #endif
2141
2188
 
2142
2189
  #ifdef HAVE_KQUEUE
2143
- if (!bKqueue)
2190
+ if (Poller != Poller_Kqueue)
2144
2191
  throw std::runtime_error("must enable kqueue (EM.kqueue=true) for file watching support");
2145
2192
 
2146
2193
  // With kqueue we have to open the file first and use the resulting fd to register for events
@@ -2187,7 +2234,7 @@ void EventMachine_t::UnwatchFile (int wd)
2187
2234
  delete b;
2188
2235
  }
2189
2236
 
2190
- void EventMachine_t::UnwatchFile (const unsigned long sig)
2237
+ void EventMachine_t::UnwatchFile (const uintptr_t sig)
2191
2238
  {
2192
2239
  for(map<int, Bindable_t*>::iterator i=Files.begin(); i != Files.end(); i++)
2193
2240
  {
@@ -2213,9 +2260,9 @@ void EventMachine_t::_ReadInotifyEvents()
2213
2260
 
2214
2261
  for (;;) {
2215
2262
  int returned = read(inotify->GetSocket(), buffer, sizeof(buffer));
2216
- assert(!(returned == 0 || returned == -1 && errno == EINVAL));
2263
+ assert(!(returned == 0 || (returned == -1 && errno == EINVAL)));
2217
2264
  if (returned <= 0) {
2218
- break;
2265
+ break;
2219
2266
  }
2220
2267
  int current = 0;
2221
2268
  while (current < returned) {
@@ -2330,4 +2377,3 @@ int EventMachine_t::SetHeartbeatInterval(float interval)
2330
2377
  return 0;
2331
2378
  }
2332
2379
  //#endif // OS_UNIX
2333
-