eventmachine 0.12.0-i386-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/COPYING +60 -0
  2. data/DEFERRABLES +138 -0
  3. data/EPOLL +141 -0
  4. data/GNU +281 -0
  5. data/KEYBOARD +38 -0
  6. data/LEGAL +25 -0
  7. data/LIGHTWEIGHT_CONCURRENCY +72 -0
  8. data/PURE_RUBY +77 -0
  9. data/README +74 -0
  10. data/RELEASE_NOTES +96 -0
  11. data/SMTP +9 -0
  12. data/SPAWNED_PROCESSES +93 -0
  13. data/TODO +10 -0
  14. data/ext/Makefile +180 -0
  15. data/ext/binder.cpp +126 -0
  16. data/ext/binder.h +48 -0
  17. data/ext/cmain.cpp +527 -0
  18. data/ext/cplusplus.cpp +172 -0
  19. data/ext/ed.cpp +1442 -0
  20. data/ext/ed.h +351 -0
  21. data/ext/em.cpp +1781 -0
  22. data/ext/em.h +167 -0
  23. data/ext/emwin.cpp +300 -0
  24. data/ext/emwin.h +94 -0
  25. data/ext/epoll.cpp +26 -0
  26. data/ext/epoll.h +25 -0
  27. data/ext/eventmachine.h +83 -0
  28. data/ext/eventmachine_cpp.h +94 -0
  29. data/ext/extconf.rb +203 -0
  30. data/ext/files.cpp +94 -0
  31. data/ext/files.h +65 -0
  32. data/ext/kb.cpp +368 -0
  33. data/ext/mkmf.log +129 -0
  34. data/ext/page.cpp +107 -0
  35. data/ext/page.h +51 -0
  36. data/ext/pipe.cpp +327 -0
  37. data/ext/project.h +119 -0
  38. data/ext/rubyeventmachine-i386-mswin32.def +2 -0
  39. data/ext/rubyeventmachine-i386-mswin32.exp +0 -0
  40. data/ext/rubyeventmachine-i386-mswin32.lib +0 -0
  41. data/ext/rubyeventmachine-i386-mswin32.pdb +0 -0
  42. data/ext/rubyeventmachine.so +0 -0
  43. data/ext/rubymain.cpp +630 -0
  44. data/ext/sigs.cpp +89 -0
  45. data/ext/sigs.h +32 -0
  46. data/ext/ssl.cpp +408 -0
  47. data/ext/ssl.h +86 -0
  48. data/ext/vc60.pdb +0 -0
  49. data/lib/em/deferrable.rb +208 -0
  50. data/lib/em/eventable.rb +39 -0
  51. data/lib/em/future.rb +62 -0
  52. data/lib/em/messages.rb +66 -0
  53. data/lib/em/processes.rb +68 -0
  54. data/lib/em/spawnable.rb +88 -0
  55. data/lib/em/streamer.rb +112 -0
  56. data/lib/eventmachine.rb +1621 -0
  57. data/lib/eventmachine_version.rb +31 -0
  58. data/lib/evma.rb +32 -0
  59. data/lib/evma/callback.rb +32 -0
  60. data/lib/evma/container.rb +75 -0
  61. data/lib/evma/factory.rb +77 -0
  62. data/lib/evma/protocol.rb +87 -0
  63. data/lib/evma/reactor.rb +48 -0
  64. data/lib/jeventmachine.rb +106 -0
  65. data/lib/pr_eventmachine.rb +1011 -0
  66. data/lib/protocols/buftok.rb +127 -0
  67. data/lib/protocols/header_and_content.rb +123 -0
  68. data/lib/protocols/httpcli2.rb +784 -0
  69. data/lib/protocols/httpclient.rb +253 -0
  70. data/lib/protocols/line_and_text.rb +122 -0
  71. data/lib/protocols/linetext2.rb +145 -0
  72. data/lib/protocols/saslauth.rb +179 -0
  73. data/lib/protocols/smtpclient.rb +308 -0
  74. data/lib/protocols/smtpserver.rb +543 -0
  75. data/lib/protocols/stomp.rb +127 -0
  76. data/lib/protocols/tcptest.rb +57 -0
  77. data/lib/rubyeventmachine.so +0 -0
  78. data/tests/test_basic.rb +142 -0
  79. data/tests/test_defer.rb +63 -0
  80. data/tests/test_epoll.rb +168 -0
  81. data/tests/test_errors.rb +82 -0
  82. data/tests/test_eventables.rb +78 -0
  83. data/tests/test_exc.rb +58 -0
  84. data/tests/test_futures.rb +214 -0
  85. data/tests/test_hc.rb +221 -0
  86. data/tests/test_httpclient.rb +194 -0
  87. data/tests/test_httpclient2.rb +133 -0
  88. data/tests/test_kb.rb +61 -0
  89. data/tests/test_ltp.rb +190 -0
  90. data/tests/test_ltp2.rb +261 -0
  91. data/tests/test_next_tick.rb +58 -0
  92. data/tests/test_processes.rb +56 -0
  93. data/tests/test_pure.rb +128 -0
  94. data/tests/test_running.rb +47 -0
  95. data/tests/test_sasl.rb +73 -0
  96. data/tests/test_send_file.rb +238 -0
  97. data/tests/test_servers.rb +90 -0
  98. data/tests/test_smtpclient.rb +81 -0
  99. data/tests/test_smtpserver.rb +93 -0
  100. data/tests/test_spawn.rb +329 -0
  101. data/tests/test_timers.rb +138 -0
  102. data/tests/test_ud.rb +43 -0
  103. data/tests/testem.rb +5 -0
  104. metadata +170 -0
@@ -0,0 +1,351 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: ed.h 679 2008-01-19 01:40:06Z blackhedd $
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 Close();
44
+
45
+ virtual void Read() = 0;
46
+ virtual void Write() = 0;
47
+ virtual void Heartbeat() = 0;
48
+
49
+ // These methods tell us whether the descriptor
50
+ // should be selected or polled for read/write.
51
+ virtual bool SelectForRead() = 0;
52
+ virtual bool SelectForWrite() = 0;
53
+
54
+ // are we scheduled for a close, or in an error state, or already closed?
55
+ bool ShouldDelete();
56
+ // Do we have any data to write? This is used by ShouldDelete.
57
+ virtual int GetOutboundDataSize() {return 0;}
58
+
59
+ void ScheduleClose (bool after_writing);
60
+ bool IsCloseScheduled();
61
+
62
+ void SetEventCallback (void (*cb)(const char*, int, const char*, int));
63
+
64
+ virtual bool GetPeername (struct sockaddr*) {return false;}
65
+ virtual bool GetSockname (struct sockaddr*) {return false;}
66
+ virtual bool GetSubprocessPid (pid_t*) {return false;}
67
+
68
+ virtual void StartTls() {}
69
+ virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename) {}
70
+
71
+ // Properties: return 0/1 to signify T/F, and handle the values
72
+ // through arguments.
73
+ virtual int GetCommInactivityTimeout (int *value) {return 0;}
74
+ virtual int SetCommInactivityTimeout (int *value) {return 0;}
75
+
76
+ #ifdef HAVE_EPOLL
77
+ struct epoll_event *GetEpollEvent() { return &EpollEvent; }
78
+ #endif
79
+
80
+ private:
81
+ bool bCloseNow;
82
+ bool bCloseAfterWriting;
83
+ int MySocket;
84
+
85
+ protected:
86
+ enum {
87
+ PendingConnectTimeout = 4 // can easily be made an instance variable
88
+ };
89
+
90
+ void (*EventCallback)(const char*, int, const char*, int);
91
+
92
+ time_t CreatedAt;
93
+ time_t LastRead;
94
+ time_t LastWritten;
95
+ bool bCallbackUnbind;
96
+
97
+ #ifdef HAVE_EPOLL
98
+ struct epoll_event EpollEvent;
99
+ #endif
100
+
101
+ EventMachine_t *MyEventMachine;
102
+ };
103
+
104
+
105
+
106
+ /*************************
107
+ class LoopbreakDescriptor
108
+ *************************/
109
+
110
+ class LoopbreakDescriptor: public EventableDescriptor
111
+ {
112
+ public:
113
+ LoopbreakDescriptor (int, EventMachine_t*);
114
+ virtual ~LoopbreakDescriptor() {}
115
+
116
+ virtual void Read();
117
+ virtual void Write();
118
+ virtual void Heartbeat() {}
119
+
120
+ virtual bool SelectForRead() {return true;}
121
+ virtual bool SelectForWrite() {return false;}
122
+ };
123
+
124
+
125
+ /**************************
126
+ class ConnectionDescriptor
127
+ **************************/
128
+
129
+ class ConnectionDescriptor: public EventableDescriptor
130
+ {
131
+ public:
132
+ ConnectionDescriptor (int, EventMachine_t*);
133
+ virtual ~ConnectionDescriptor();
134
+
135
+ static int SendDataToConnection (const char*, const char*, int);
136
+ static void CloseConnection (const char*, bool);
137
+ static int ReportErrorStatus (const char*);
138
+
139
+ int SendOutboundData (const char*, int);
140
+
141
+ void SetConnectPending (bool f) { bConnectPending = f; }
142
+
143
+ virtual void Read();
144
+ virtual void Write();
145
+ virtual void Heartbeat();
146
+
147
+ virtual bool SelectForRead();
148
+ virtual bool SelectForWrite();
149
+
150
+ // Do we have any data to write? This is used by ShouldDelete.
151
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
152
+
153
+ virtual void StartTls();
154
+ virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename);
155
+ void SetServerMode() {bIsServer = true;}
156
+
157
+ virtual bool GetPeername (struct sockaddr*);
158
+ virtual bool GetSockname (struct sockaddr*);
159
+
160
+ virtual int GetCommInactivityTimeout (int *value);
161
+ virtual int SetCommInactivityTimeout (int *value);
162
+
163
+
164
+ protected:
165
+ struct OutboundPage {
166
+ OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
167
+ void Free() {if (Buffer) free ((char*)Buffer); }
168
+ const char *Buffer;
169
+ int Length;
170
+ int Offset;
171
+ };
172
+
173
+ protected:
174
+ bool bConnectPending;
175
+ bool bReadAttemptedAfterClose;
176
+ bool bWriteAttemptedAfterClose;
177
+
178
+ deque<OutboundPage> OutboundPages;
179
+ int OutboundDataSize;
180
+
181
+ #ifdef WITH_SSL
182
+ SslBox_t *SslBox;
183
+ std::string CertChainFilename;
184
+ std::string PrivateKeyFilename;
185
+ #endif
186
+ bool bIsServer;
187
+
188
+ time_t LastIo;
189
+ int InactivityTimeout;
190
+
191
+ private:
192
+ void _WriteOutboundData();
193
+ void _DispatchInboundData (const char *buffer, int size);
194
+ void _DispatchCiphertext();
195
+ int _SendRawOutboundData (const char*, int);
196
+ int _ReportErrorStatus();
197
+
198
+ };
199
+
200
+
201
+ /************************
202
+ class DatagramDescriptor
203
+ ************************/
204
+
205
+ class DatagramDescriptor: public EventableDescriptor
206
+ {
207
+ public:
208
+ DatagramDescriptor (int, EventMachine_t*);
209
+ virtual ~DatagramDescriptor();
210
+
211
+ virtual void Read();
212
+ virtual void Write();
213
+ virtual void Heartbeat();
214
+
215
+ virtual bool SelectForRead() {return true;}
216
+ virtual bool SelectForWrite();
217
+
218
+ int SendOutboundData (const char*, int);
219
+ int SendOutboundDatagram (const char*, int, const char*, int);
220
+
221
+ // Do we have any data to write? This is used by ShouldDelete.
222
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
223
+
224
+ virtual bool GetPeername (struct sockaddr*);
225
+ virtual bool GetSockname (struct sockaddr*);
226
+
227
+ virtual int GetCommInactivityTimeout (int *value);
228
+ virtual int SetCommInactivityTimeout (int *value);
229
+
230
+ static int SendDatagram (const char*, const char*, int, const char*, int);
231
+
232
+
233
+ protected:
234
+ struct OutboundPage {
235
+ OutboundPage (const char *b, int l, struct sockaddr_in f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
236
+ void Free() {if (Buffer) free ((char*)Buffer); }
237
+ const char *Buffer;
238
+ int Length;
239
+ int Offset;
240
+ struct sockaddr_in From;
241
+ };
242
+
243
+ deque<OutboundPage> OutboundPages;
244
+ int OutboundDataSize;
245
+
246
+ struct sockaddr_in ReturnAddress;
247
+
248
+ time_t LastIo;
249
+ int InactivityTimeout;
250
+ };
251
+
252
+
253
+ /************************
254
+ class AcceptorDescriptor
255
+ ************************/
256
+
257
+ class AcceptorDescriptor: public EventableDescriptor
258
+ {
259
+ public:
260
+ AcceptorDescriptor (int, EventMachine_t*);
261
+ virtual ~AcceptorDescriptor();
262
+
263
+ virtual void Read();
264
+ virtual void Write();
265
+ virtual void Heartbeat();
266
+
267
+ virtual bool SelectForRead() {return true;}
268
+ virtual bool SelectForWrite() {return false;}
269
+
270
+ static void StopAcceptor (const char *binding);
271
+ };
272
+
273
+ /********************
274
+ class PipeDescriptor
275
+ ********************/
276
+
277
+ #ifdef OS_UNIX
278
+ class PipeDescriptor: public EventableDescriptor
279
+ {
280
+ public:
281
+ PipeDescriptor (int, pid_t, EventMachine_t*);
282
+ virtual ~PipeDescriptor();
283
+
284
+ virtual void Read();
285
+ virtual void Write();
286
+ virtual void Heartbeat();
287
+
288
+ virtual bool SelectForRead();
289
+ virtual bool SelectForWrite();
290
+
291
+ int SendOutboundData (const char*, int);
292
+ virtual int GetOutboundDataSize() {return OutboundDataSize;}
293
+
294
+ virtual bool GetSubprocessPid (pid_t*);
295
+
296
+ protected:
297
+ struct OutboundPage {
298
+ OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
299
+ void Free() {if (Buffer) free ((char*)Buffer); }
300
+ const char *Buffer;
301
+ int Length;
302
+ int Offset;
303
+ };
304
+
305
+ protected:
306
+ bool bReadAttemptedAfterClose;
307
+ time_t LastIo;
308
+ int InactivityTimeout;
309
+
310
+ deque<OutboundPage> OutboundPages;
311
+ int OutboundDataSize;
312
+
313
+ pid_t SubprocessPid;
314
+
315
+ private:
316
+ void _DispatchInboundData (const char *buffer, int size);
317
+ };
318
+ #endif // OS_UNIX
319
+
320
+
321
+ /************************
322
+ class KeyboardDescriptor
323
+ ************************/
324
+
325
+ class KeyboardDescriptor: public EventableDescriptor
326
+ {
327
+ public:
328
+ KeyboardDescriptor (EventMachine_t*);
329
+ virtual ~KeyboardDescriptor();
330
+
331
+ virtual void Read();
332
+ virtual void Write();
333
+ virtual void Heartbeat();
334
+
335
+ virtual bool SelectForRead() {return true;}
336
+ virtual bool SelectForWrite() {return false;}
337
+
338
+ protected:
339
+ bool bReadAttemptedAfterClose;
340
+ time_t LastIo;
341
+ int InactivityTimeout;
342
+
343
+ private:
344
+ void _DispatchInboundData (const char *buffer, int size);
345
+ };
346
+
347
+
348
+
349
+ #endif // __EventableDescriptor__H_
350
+
351
+
@@ -0,0 +1,1781 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: em.cpp 684 2008-04-30 11:31:46Z francis $
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
+
24
+ #include "project.h"
25
+
26
+ // Keep a global variable floating around
27
+ // with the current loop time as set by the Event Machine.
28
+ // This avoids the need for frequent expensive calls to time(NULL);
29
+ time_t gCurrentLoopTime;
30
+
31
+ #ifdef OS_WIN32
32
+ unsigned gTickCountTickover;
33
+ unsigned gLastTickCount;
34
+ #endif
35
+
36
+
37
+ /* The numer of max outstanding timers was once a const enum defined in em.h.
38
+ * Now we define it here so that users can change its value if necessary.
39
+ */
40
+ static int MaxOutstandingTimers = 1000;
41
+
42
+
43
+ /* Internal helper to convert strings to internet addresses. IPv6-aware.
44
+ * Not reentrant or threadsafe, optimized for speed.
45
+ */
46
+ static struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size);
47
+
48
+
49
+ /***************************************
50
+ STATIC EventMachine_t::SetMaxTimerCount
51
+ ***************************************/
52
+
53
+ void EventMachine_t::SetMaxTimerCount (int count)
54
+ {
55
+ /* Allow a user to increase the maximum number of outstanding timers.
56
+ * If this gets "too high" (a metric that is of course platform dependent),
57
+ * bad things will happen like performance problems and possible overuse
58
+ * of memory.
59
+ * The actual timer mechanism is very efficient so it's hard to know what
60
+ * the practical max, but 100,000 shouldn't be too problematical.
61
+ */
62
+ if (count < 100)
63
+ count = 100;
64
+ MaxOutstandingTimers = count;
65
+ }
66
+
67
+
68
+
69
+ /******************************
70
+ EventMachine_t::EventMachine_t
71
+ ******************************/
72
+
73
+ EventMachine_t::EventMachine_t (void (*event_callback)(const char*, int, const char*, int)):
74
+ EventCallback (event_callback),
75
+ NextHeartbeatTime (0),
76
+ LoopBreakerReader (-1),
77
+ LoopBreakerWriter (-1),
78
+ bEpoll (false),
79
+ bKqueue (false),
80
+ epfd (-1)
81
+ {
82
+ // Default time-slice is just smaller than one hundred mills.
83
+ Quantum.tv_sec = 0;
84
+ Quantum.tv_usec = 90000;
85
+
86
+ gTerminateSignalReceived = false;
87
+ // Make sure the current loop time is sane, in case we do any initializations of
88
+ // objects before we start running.
89
+ gCurrentLoopTime = time(NULL);
90
+
91
+ /* We initialize the network library here (only on Windows of course)
92
+ * and initialize "loop breakers." Our destructor also does some network-level
93
+ * cleanup. There's thus an implicit assumption that any given instance of EventMachine_t
94
+ * will only call ::Run once. Is that a good assumption? Should we move some of these
95
+ * inits and de-inits into ::Run?
96
+ */
97
+ #ifdef OS_WIN32
98
+ WSADATA w;
99
+ WSAStartup (MAKEWORD (1, 1), &w);
100
+ #endif
101
+
102
+ _InitializeLoopBreaker();
103
+ }
104
+
105
+
106
+ /*******************************
107
+ EventMachine_t::~EventMachine_t
108
+ *******************************/
109
+
110
+ EventMachine_t::~EventMachine_t()
111
+ {
112
+ // Run down descriptors
113
+ size_t i;
114
+ for (i = 0; i < NewDescriptors.size(); i++)
115
+ delete NewDescriptors[i];
116
+ for (i = 0; i < Descriptors.size(); i++)
117
+ delete Descriptors[i];
118
+
119
+ close (LoopBreakerReader);
120
+ close (LoopBreakerWriter);
121
+
122
+ if (epfd != -1)
123
+ close (epfd);
124
+ if (kqfd != -1)
125
+ close (kqfd);
126
+ }
127
+
128
+
129
+ /*************************
130
+ EventMachine_t::_UseEpoll
131
+ *************************/
132
+
133
+ void EventMachine_t::_UseEpoll()
134
+ {
135
+ /* Temporary.
136
+ * Use an internal flag to switch in epoll-based functionality until we determine
137
+ * how it should be integrated properly and the extent of the required changes.
138
+ * A permanent solution needs to allow the integration of additional technologies,
139
+ * like kqueue and Solaris's events.
140
+ */
141
+
142
+ #ifdef HAVE_EPOLL
143
+ bEpoll = true;
144
+ #endif
145
+ }
146
+
147
+ /**************************
148
+ EventMachine_t::_UseKqueue
149
+ **************************/
150
+
151
+ void EventMachine_t::_UseKqueue()
152
+ {
153
+ /* Temporary.
154
+ * See comments under _UseEpoll.
155
+ */
156
+
157
+ #ifdef HAVE_KQUEUE
158
+ bKqueue = true;
159
+ #endif
160
+ }
161
+
162
+
163
+ /****************************
164
+ EventMachine_t::ScheduleHalt
165
+ ****************************/
166
+
167
+ void EventMachine_t::ScheduleHalt()
168
+ {
169
+ /* This is how we stop the machine.
170
+ * This can be called by clients. Signal handlers will probably
171
+ * set the global flag.
172
+ * For now this means there can only be one EventMachine ever running at a time.
173
+ *
174
+ * IMPORTANT: keep this light, fast, and async-safe. Don't do anything frisky in here,
175
+ * because it may be called from signal handlers invoked from code that we don't
176
+ * control. At this writing (20Sep06), EM does NOT install any signal handlers of
177
+ * its own.
178
+ *
179
+ * We need a FAQ. And one of the questions is: how do I stop EM when Ctrl-C happens?
180
+ * The answer is to call evma_stop_machine, which calls here, from a SIGINT handler.
181
+ */
182
+ gTerminateSignalReceived = true;
183
+ }
184
+
185
+
186
+
187
+ /*******************************
188
+ EventMachine_t::SetTimerQuantum
189
+ *******************************/
190
+
191
+ void EventMachine_t::SetTimerQuantum (int interval)
192
+ {
193
+ /* We get a timer-quantum expressed in milliseconds.
194
+ * Don't set a quantum smaller than 5 or larger than 2500.
195
+ */
196
+
197
+ if ((interval < 5) || (interval > 2500))
198
+ throw std::runtime_error ("invalid timer-quantum");
199
+
200
+ Quantum.tv_sec = interval / 1000;
201
+ Quantum.tv_usec = (interval % 1000) * 1000;
202
+ }
203
+
204
+
205
+ /*************************************
206
+ (STATIC) EventMachine_t::SetuidString
207
+ *************************************/
208
+
209
+ void EventMachine_t::SetuidString (const char *username)
210
+ {
211
+ /* This method takes a caller-supplied username and tries to setuid
212
+ * to that user. There is no meaningful implementation (and no error)
213
+ * on Windows. On Unix, a failure to setuid the caller-supplied string
214
+ * causes a fatal abort, because presumably the program is calling here
215
+ * in order to fulfill a security requirement. If we fail silently,
216
+ * the user may continue to run with too much privilege.
217
+ *
218
+ * TODO, we need to decide on and document a way of generating C++ level errors
219
+ * that can be wrapped in documented Ruby exceptions, so users can catch
220
+ * and handle them. And distinguish it from errors that we WON'T let the Ruby
221
+ * user catch (like security-violations and resource-overallocation).
222
+ * A setuid failure here would be in the latter category.
223
+ */
224
+
225
+ #ifdef OS_UNIX
226
+ if (!username || !*username)
227
+ throw std::runtime_error ("setuid_string failed: no username specified");
228
+
229
+ struct passwd *p = getpwnam (username);
230
+ if (!p)
231
+ throw std::runtime_error ("setuid_string failed: unknown username");
232
+
233
+ if (setuid (p->pw_uid) != 0)
234
+ throw std::runtime_error ("setuid_string failed: no setuid");
235
+
236
+ // Success.
237
+ #endif
238
+ }
239
+
240
+
241
+ /****************************************
242
+ (STATIC) EventMachine_t::SetRlimitNofile
243
+ ****************************************/
244
+
245
+ int EventMachine_t::SetRlimitNofile (int nofiles)
246
+ {
247
+ #ifdef OS_UNIX
248
+ struct rlimit rlim;
249
+ getrlimit (RLIMIT_NOFILE, &rlim);
250
+ if (nofiles >= 0) {
251
+ rlim.rlim_cur = nofiles;
252
+ if (nofiles > rlim.rlim_max)
253
+ rlim.rlim_max = nofiles;
254
+ setrlimit (RLIMIT_NOFILE, &rlim);
255
+ // ignore the error return, for now at least.
256
+ // TODO, emit an error message someday when we have proper debug levels.
257
+ }
258
+ getrlimit (RLIMIT_NOFILE, &rlim);
259
+ return rlim.rlim_cur;
260
+ #endif
261
+
262
+ #ifdef OS_WIN32
263
+ // No meaningful implementation on Windows.
264
+ return 0;
265
+ #endif
266
+ }
267
+
268
+
269
+ /*********************************
270
+ EventMachine_t::SignalLoopBreaker
271
+ *********************************/
272
+
273
+ void EventMachine_t::SignalLoopBreaker()
274
+ {
275
+ #ifdef OS_UNIX
276
+ write (LoopBreakerWriter, "", 1);
277
+ #endif
278
+ #ifdef OS_WIN32
279
+ sendto (LoopBreakerReader, "", 0, 0, (struct sockaddr*)&(LoopBreakerTarget), sizeof(LoopBreakerTarget));
280
+ #endif
281
+ }
282
+
283
+
284
+ /**************************************
285
+ EventMachine_t::_InitializeLoopBreaker
286
+ **************************************/
287
+
288
+ void EventMachine_t::_InitializeLoopBreaker()
289
+ {
290
+ /* A "loop-breaker" is a socket-descriptor that we can write to in order
291
+ * to break the main select loop. Primarily useful for things running on
292
+ * threads other than the main EM thread, so they can trigger processing
293
+ * of events that arise exogenously to the EM.
294
+ * Keep the loop-breaker pipe out of the main descriptor set, otherwise
295
+ * its events will get passed on to user code.
296
+ */
297
+
298
+ #ifdef OS_UNIX
299
+ int fd[2];
300
+ if (pipe (fd))
301
+ throw std::runtime_error ("no loop breaker");
302
+
303
+ LoopBreakerWriter = fd[1];
304
+ LoopBreakerReader = fd[0];
305
+ #endif
306
+
307
+ #ifdef OS_WIN32
308
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
309
+ if (sd == INVALID_SOCKET)
310
+ throw std::runtime_error ("no loop breaker socket");
311
+ SetSocketNonblocking (sd);
312
+
313
+ memset (&LoopBreakerTarget, 0, sizeof(LoopBreakerTarget));
314
+ LoopBreakerTarget.sin_family = AF_INET;
315
+ LoopBreakerTarget.sin_addr.s_addr = inet_addr ("127.0.0.1");
316
+
317
+ srand ((int)time(NULL));
318
+ int i;
319
+ for (i=0; i < 100; i++) {
320
+ int r = (rand() % 10000) + 20000;
321
+ LoopBreakerTarget.sin_port = htons (r);
322
+ if (bind (sd, (struct sockaddr*)&LoopBreakerTarget, sizeof(LoopBreakerTarget)) == 0)
323
+ break;
324
+ }
325
+
326
+ if (i == 100)
327
+ throw std::runtime_error ("no loop breaker");
328
+ LoopBreakerReader = sd;
329
+ #endif
330
+ }
331
+
332
+
333
+ /*******************
334
+ EventMachine_t::Run
335
+ *******************/
336
+
337
+ void EventMachine_t::Run()
338
+ {
339
+ #ifdef OS_WIN32
340
+ HookControlC (true);
341
+ #endif
342
+
343
+ #ifdef HAVE_EPOLL
344
+ if (bEpoll) {
345
+ epfd = epoll_create (MaxEpollDescriptors);
346
+ if (epfd == -1) {
347
+ char buf[200];
348
+ snprintf (buf, sizeof(buf)-1, "unable to create epoll descriptor: %s", strerror(errno));
349
+ throw std::runtime_error (buf);
350
+ }
351
+ int cloexec = fcntl (epfd, F_GETFD, 0);
352
+ assert (cloexec >= 0);
353
+ cloexec |= FD_CLOEXEC;
354
+ fcntl (epfd, F_SETFD, cloexec);
355
+
356
+ assert (LoopBreakerReader >= 0);
357
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
358
+ assert (ld);
359
+ Add (ld);
360
+ }
361
+ #endif
362
+
363
+ #ifdef HAVE_KQUEUE
364
+ if (bKqueue) {
365
+ kqfd = kqueue();
366
+ if (kqfd == -1) {
367
+ char buf[200];
368
+ snprintf (buf, sizeof(buf)-1, "unable to create kqueue descriptor: %s", strerror(errno));
369
+ throw std::runtime_error (buf);
370
+ }
371
+ // cloexec not needed. By definition, kqueues are not carried across forks.
372
+
373
+ assert (LoopBreakerReader >= 0);
374
+ LoopbreakDescriptor *ld = new LoopbreakDescriptor (LoopBreakerReader, this);
375
+ assert (ld);
376
+ Add (ld);
377
+ }
378
+ #endif
379
+
380
+ while (true) {
381
+ gCurrentLoopTime = time(NULL);
382
+ if (!_RunTimers())
383
+ break;
384
+
385
+ /* _Add must precede _Modify because the same descriptor might
386
+ * be on both lists during the same pass through the machine,
387
+ * and to modify a descriptor before adding it would fail.
388
+ */
389
+ _AddNewDescriptors();
390
+ _ModifyDescriptors();
391
+
392
+ if (!_RunOnce())
393
+ break;
394
+ if (gTerminateSignalReceived)
395
+ break;
396
+ }
397
+
398
+ #ifdef OS_WIN32
399
+ HookControlC (false);
400
+ #endif
401
+ }
402
+
403
+
404
+ /************************
405
+ EventMachine_t::_RunOnce
406
+ ************************/
407
+
408
+ bool EventMachine_t::_RunOnce()
409
+ {
410
+ if (bEpoll)
411
+ return _RunEpollOnce();
412
+ else if (bKqueue)
413
+ return _RunKqueueOnce();
414
+ else
415
+ return _RunSelectOnce();
416
+ }
417
+
418
+
419
+
420
+ /*****************************
421
+ EventMachine_t::_RunEpollOnce
422
+ *****************************/
423
+
424
+ bool EventMachine_t::_RunEpollOnce()
425
+ {
426
+ #ifdef HAVE_EPOLL
427
+ assert (epfd != -1);
428
+ struct epoll_event ev [MaxEpollDescriptors];
429
+ int s = epoll_wait (epfd, ev, MaxEpollDescriptors, 50);
430
+ if (s > 0) {
431
+ for (int i=0; i < s; i++) {
432
+ EventableDescriptor *ed = (EventableDescriptor*) ev[i].data.ptr;
433
+
434
+ if (ev[i].events & (EPOLLERR | EPOLLHUP))
435
+ ed->ScheduleClose (false);
436
+ if (ev[i].events & EPOLLIN)
437
+ ed->Read();
438
+ if (ev[i].events & EPOLLOUT) {
439
+ ed->Write();
440
+ epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent());
441
+ // Ignoring return value
442
+ }
443
+ }
444
+ }
445
+ else if (s < 0) {
446
+ // epoll_wait can fail on error in a handful of ways.
447
+ // If this happens, then wait for a little while to avoid busy-looping.
448
+ // If the error was EINTR, we probably caught SIGCHLD or something,
449
+ // so keep the wait short.
450
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
451
+ EmSelect (0, NULL, NULL, NULL, &tv);
452
+ }
453
+
454
+ { // cleanup dying sockets
455
+ // vector::pop_back works in constant time.
456
+ // TODO, rip this out and only delete the descriptors we know have died,
457
+ // rather than traversing the whole list.
458
+ // Modified 05Jan08 per suggestions by Chris Heath. It's possible that
459
+ // an EventableDescriptor will have a descriptor value of -1. That will
460
+ // happen if EventableDescriptor::Close was called on it. In that case,
461
+ // don't call epoll_ctl to remove the socket's filters from the epoll set.
462
+ // According to the epoll docs, this happens automatically when the
463
+ // descriptor is closed anyway. This is different from the case where
464
+ // the socket has already been closed but the descriptor in the ED object
465
+ // hasn't yet been set to INVALID_SOCKET.
466
+ int i, j;
467
+ int nSockets = Descriptors.size();
468
+ for (i=0, j=0; i < nSockets; i++) {
469
+ EventableDescriptor *ed = Descriptors[i];
470
+ assert (ed);
471
+ if (ed->ShouldDelete()) {
472
+ if (ed->GetSocket() != INVALID_SOCKET) {
473
+ assert (bEpoll); // wouldn't be in this method otherwise.
474
+ assert (epfd != -1);
475
+ int e = epoll_ctl (epfd, EPOLL_CTL_DEL, ed->GetSocket(), ed->GetEpollEvent());
476
+ // ENOENT or EBADF are not errors because the socket may be already closed when we get here.
477
+ if (e && (errno != ENOENT) && (errno != EBADF)) {
478
+ char buf [200];
479
+ snprintf (buf, sizeof(buf)-1, "unable to delete epoll event: %s", strerror(errno));
480
+ throw std::runtime_error (buf);
481
+ }
482
+ }
483
+
484
+ ModifiedDescriptors.erase (ed);
485
+ delete ed;
486
+ }
487
+ else
488
+ Descriptors [j++] = ed;
489
+ }
490
+ while ((size_t)j < Descriptors.size())
491
+ Descriptors.pop_back();
492
+
493
+ }
494
+
495
+ // TODO, heartbeats.
496
+ // Added 14Sep07, its absence was noted by Brian Candler. But the comment was here, indicated
497
+ // that this got thought about and not done when EPOLL was originally written. Was there a reason
498
+ // not to do it, or was it an oversight? Certainly, running a heartbeat on 50,000 connections every
499
+ // two seconds can get to be a real bear, especially if all we're doing is timing out dead ones.
500
+ // Maybe there's a better way to do this. (Or maybe it's not that expensive after all.)
501
+ //
502
+ { // dispatch heartbeats
503
+ if (gCurrentLoopTime >= NextHeartbeatTime) {
504
+ NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
505
+
506
+ for (int i=0; i < Descriptors.size(); i++) {
507
+ EventableDescriptor *ed = Descriptors[i];
508
+ assert (ed);
509
+ ed->Heartbeat();
510
+ }
511
+ }
512
+ }
513
+
514
+ timeval tv = {0,0};
515
+ EmSelect (0, NULL, NULL, NULL, &tv);
516
+
517
+ return true;
518
+ #else
519
+ throw std::runtime_error ("epoll is not implemented on this platform");
520
+ #endif
521
+ }
522
+
523
+
524
+ /******************************
525
+ EventMachine_t::_RunKqueueOnce
526
+ ******************************/
527
+
528
+ bool EventMachine_t::_RunKqueueOnce()
529
+ {
530
+ #ifdef HAVE_KQUEUE
531
+ assert (kqfd != -1);
532
+ const int maxKevents = 2000;
533
+ struct kevent Karray [maxKevents];
534
+ struct timespec ts = {0, 10000000}; // Too frequent. Use blocking_region
535
+
536
+ int k = kevent (kqfd, NULL, 0, Karray, maxKevents, &ts);
537
+ struct kevent *ke = Karray;
538
+ while (k > 0) {
539
+ EventableDescriptor *ed = (EventableDescriptor*) (ke->udata);
540
+ assert (ed);
541
+
542
+ if (ke->filter == EVFILT_READ)
543
+ ed->Read();
544
+ else if (ke->filter == EVFILT_WRITE)
545
+ ed->Write();
546
+ else
547
+ cerr << "Discarding unknown kqueue event " << ke->filter << endl;
548
+
549
+ --k;
550
+ ++ke;
551
+ }
552
+
553
+ { // cleanup dying sockets
554
+ // vector::pop_back works in constant time.
555
+ // TODO, rip this out and only delete the descriptors we know have died,
556
+ // rather than traversing the whole list.
557
+ // In kqueue, closing a descriptor automatically removes its event filters.
558
+
559
+ int i, j;
560
+ int nSockets = Descriptors.size();
561
+ for (i=0, j=0; i < nSockets; i++) {
562
+ EventableDescriptor *ed = Descriptors[i];
563
+ assert (ed);
564
+ if (ed->ShouldDelete()) {
565
+ ModifiedDescriptors.erase (ed);
566
+ delete ed;
567
+ }
568
+ else
569
+ Descriptors [j++] = ed;
570
+ }
571
+ while ((size_t)j < Descriptors.size())
572
+ Descriptors.pop_back();
573
+
574
+ }
575
+
576
+ { // dispatch heartbeats
577
+ if (gCurrentLoopTime >= NextHeartbeatTime) {
578
+ NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
579
+
580
+ for (int i=0; i < Descriptors.size(); i++) {
581
+ EventableDescriptor *ed = Descriptors[i];
582
+ assert (ed);
583
+ ed->Heartbeat();
584
+ }
585
+ }
586
+ }
587
+
588
+
589
+ // TODO, replace this with rb_thread_blocking_region for 1.9 builds.
590
+ timeval tv = {0,0};
591
+ EmSelect (0, NULL, NULL, NULL, &tv);
592
+
593
+ return true;
594
+ #else
595
+ throw std::runtime_error ("kqueue is not implemented on this platform");
596
+ #endif
597
+ }
598
+
599
+
600
+ /*********************************
601
+ EventMachine_t::_ModifyEpollEvent
602
+ *********************************/
603
+
604
+ void EventMachine_t::_ModifyEpollEvent (EventableDescriptor *ed)
605
+ {
606
+ #ifdef HAVE_EPOLL
607
+ if (bEpoll) {
608
+ assert (epfd != -1);
609
+ assert (ed);
610
+ int e = epoll_ctl (epfd, EPOLL_CTL_MOD, ed->GetSocket(), ed->GetEpollEvent());
611
+ if (e) {
612
+ char buf [200];
613
+ snprintf (buf, sizeof(buf)-1, "unable to modify epoll event: %s", strerror(errno));
614
+ throw std::runtime_error (buf);
615
+ }
616
+ }
617
+ #endif
618
+ }
619
+
620
+
621
+
622
+ /**************************
623
+ SelectData_t::SelectData_t
624
+ **************************/
625
+
626
+ SelectData_t::SelectData_t()
627
+ {
628
+ maxsocket = 0;
629
+ FD_ZERO (&fdreads);
630
+ FD_ZERO (&fdwrites);
631
+ }
632
+
633
+
634
+ /*****************
635
+ _SelectDataSelect
636
+ *****************/
637
+
638
+ static VALUE _SelectDataSelect (void *v)
639
+ {
640
+ SelectData_t *sd = (SelectData_t*)v;
641
+ sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), NULL, &(sd->tv));
642
+ return Qnil;
643
+ }
644
+
645
+ /*********************
646
+ SelectData_t::_Select
647
+ *********************/
648
+
649
+ int SelectData_t::_Select()
650
+ {
651
+ #ifdef HAVE_TBR
652
+ rb_thread_blocking_region (_SelectDataSelect, (void*)this, RB_UBF_DFL, 0);
653
+ return nSockets;
654
+ #endif
655
+
656
+ #ifndef HAVE_TBR
657
+ return rb_thread_select (maxsocket+1, &fdreads, &fdwrites, NULL, &tv);
658
+ #endif
659
+ }
660
+
661
+
662
+
663
+ /******************************
664
+ EventMachine_t::_RunSelectOnce
665
+ ******************************/
666
+
667
+ bool EventMachine_t::_RunSelectOnce()
668
+ {
669
+ // Crank the event machine once.
670
+ // If there are no descriptors to process, then sleep
671
+ // for a few hundred mills to avoid busy-looping.
672
+ // Return T/F to indicate whether we should continue.
673
+ // This is based on a select loop. Alternately provide epoll
674
+ // if we know we're running on a 2.6 kernel.
675
+ // epoll will be effective if we provide it as an alternative,
676
+ // however it has the same problem interoperating with Ruby
677
+ // threads that select does.
678
+
679
+ //cerr << "X";
680
+
681
+ /* This protection is now obsolete, because we will ALWAYS
682
+ * have at least one descriptor (the loop-breaker) to read.
683
+ */
684
+ /*
685
+ if (Descriptors.size() == 0) {
686
+ #ifdef OS_UNIX
687
+ timeval tv = {0, 200 * 1000};
688
+ EmSelect (0, NULL, NULL, NULL, &tv);
689
+ return true;
690
+ #endif
691
+ #ifdef OS_WIN32
692
+ Sleep (200);
693
+ return true;
694
+ #endif
695
+ }
696
+ */
697
+
698
+ SelectData_t SelectData;
699
+ /*
700
+ fd_set fdreads, fdwrites;
701
+ FD_ZERO (&fdreads);
702
+ FD_ZERO (&fdwrites);
703
+
704
+ int maxsocket = 0;
705
+ */
706
+
707
+ // Always read the loop-breaker reader.
708
+ // Changed 23Aug06, provisionally implemented for Windows with a UDP socket
709
+ // running on localhost with a randomly-chosen port. (*Puke*)
710
+ // Windows has a version of the Unix pipe() library function, but it doesn't
711
+ // give you back descriptors that are selectable.
712
+ FD_SET (LoopBreakerReader, &(SelectData.fdreads));
713
+ if (SelectData.maxsocket < LoopBreakerReader)
714
+ SelectData.maxsocket = LoopBreakerReader;
715
+
716
+ // prepare the sockets for reading and writing
717
+ size_t i;
718
+ for (i = 0; i < Descriptors.size(); i++) {
719
+ EventableDescriptor *ed = Descriptors[i];
720
+ assert (ed);
721
+ int sd = ed->GetSocket();
722
+ assert (sd != INVALID_SOCKET);
723
+
724
+ if (ed->SelectForRead())
725
+ FD_SET (sd, &(SelectData.fdreads));
726
+ if (ed->SelectForWrite())
727
+ FD_SET (sd, &(SelectData.fdwrites));
728
+
729
+ if (SelectData.maxsocket < sd)
730
+ SelectData.maxsocket = sd;
731
+ }
732
+
733
+
734
+ { // read and write the sockets
735
+ //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000.
736
+ //timeval tv = Quantum;
737
+ SelectData.tv = Quantum;
738
+ int s = SelectData._Select();
739
+ //rb_thread_blocking_region(xxx,(void*)&SelectData,RB_UBF_DFL,0);
740
+ //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv));
741
+ //int s = SelectData.nSockets;
742
+ if (s > 0) {
743
+ /* Changed 01Jun07. We used to handle the Loop-breaker right here.
744
+ * Now we do it AFTER all the regular descriptors. There's an
745
+ * incredibly important and subtle reason for this. Code on
746
+ * loop breakers is sometimes used to cause the reactor core to
747
+ * cycle (for example, to allow outbound network buffers to drain).
748
+ * If a loop-breaker handler reschedules itself (say, after determining
749
+ * that the write buffers are still too full), then it will execute
750
+ * IMMEDIATELY if _ReadLoopBreaker is done here instead of after
751
+ * the other descriptors are processed. That defeats the whole purpose.
752
+ */
753
+ for (i=0; i < Descriptors.size(); i++) {
754
+ EventableDescriptor *ed = Descriptors[i];
755
+ assert (ed);
756
+ int sd = ed->GetSocket();
757
+ assert (sd != INVALID_SOCKET);
758
+
759
+ if (FD_ISSET (sd, &(SelectData.fdwrites)))
760
+ ed->Write();
761
+ if (FD_ISSET (sd, &(SelectData.fdreads)))
762
+ ed->Read();
763
+ }
764
+
765
+ if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads)))
766
+ _ReadLoopBreaker();
767
+ }
768
+ else if (s < 0) {
769
+ // select can fail on error in a handful of ways.
770
+ // If this happens, then wait for a little while to avoid busy-looping.
771
+ // If the error was EINTR, we probably caught SIGCHLD or something,
772
+ // so keep the wait short.
773
+ timeval tv = {0, ((errno == EINTR) ? 5 : 50) * 1000};
774
+ EmSelect (0, NULL, NULL, NULL, &tv);
775
+ }
776
+ }
777
+
778
+
779
+ { // dispatch heartbeats
780
+ if (gCurrentLoopTime >= NextHeartbeatTime) {
781
+ NextHeartbeatTime = gCurrentLoopTime + HeartbeatInterval;
782
+
783
+ for (i=0; i < Descriptors.size(); i++) {
784
+ EventableDescriptor *ed = Descriptors[i];
785
+ assert (ed);
786
+ ed->Heartbeat();
787
+ }
788
+ }
789
+ }
790
+
791
+ { // cleanup dying sockets
792
+ // vector::pop_back works in constant time.
793
+ int i, j;
794
+ int nSockets = Descriptors.size();
795
+ for (i=0, j=0; i < nSockets; i++) {
796
+ EventableDescriptor *ed = Descriptors[i];
797
+ assert (ed);
798
+ if (ed->ShouldDelete())
799
+ delete ed;
800
+ else
801
+ Descriptors [j++] = ed;
802
+ }
803
+ while ((size_t)j < Descriptors.size())
804
+ Descriptors.pop_back();
805
+
806
+ }
807
+
808
+ return true;
809
+ }
810
+
811
+
812
+ /********************************
813
+ EventMachine_t::_ReadLoopBreaker
814
+ ********************************/
815
+
816
+ void EventMachine_t::_ReadLoopBreaker()
817
+ {
818
+ /* The loop breaker has selected readable.
819
+ * Read it ONCE (it may block if we try to read it twice)
820
+ * and send a loop-break event back to user code.
821
+ */
822
+ char buffer [1024];
823
+ read (LoopBreakerReader, buffer, sizeof(buffer));
824
+ if (EventCallback)
825
+ (*EventCallback)("", EM_LOOPBREAK_SIGNAL, "", 0);
826
+ }
827
+
828
+
829
+ /**************************
830
+ EventMachine_t::_RunTimers
831
+ **************************/
832
+
833
+ bool EventMachine_t::_RunTimers()
834
+ {
835
+ // These are caller-defined timer handlers.
836
+ // Return T/F to indicate whether we should continue the main loop.
837
+ // We rely on the fact that multimaps sort by their keys to avoid
838
+ // inspecting the whole list every time we come here.
839
+ // Just keep inspecting and processing the list head until we hit
840
+ // one that hasn't expired yet.
841
+
842
+ #ifdef OS_UNIX
843
+ struct timeval tv;
844
+ gettimeofday (&tv, NULL);
845
+ Int64 now = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
846
+ #endif
847
+
848
+ #ifdef OS_WIN32
849
+ unsigned tick = GetTickCount();
850
+ if (tick < gLastTickCount)
851
+ gTickCountTickover += 1;
852
+ gLastTickCount = tick;
853
+ Int64 now = ((Int64)gTickCountTickover << 32) + (Int64)tick;
854
+ #endif
855
+
856
+ while (true) {
857
+ multimap<Int64,Timer_t>::iterator i = Timers.begin();
858
+ if (i == Timers.end())
859
+ break;
860
+ if (i->first > now)
861
+ break;
862
+ if (EventCallback)
863
+ (*EventCallback) ("", EM_TIMER_FIRED, i->second.GetBinding().c_str(), i->second.GetBinding().length());
864
+ Timers.erase (i);
865
+ }
866
+ return true;
867
+ }
868
+
869
+
870
+
871
+ /***********************************
872
+ EventMachine_t::InstallOneshotTimer
873
+ ***********************************/
874
+
875
+ const char *EventMachine_t::InstallOneshotTimer (int milliseconds)
876
+ {
877
+ if (Timers.size() > MaxOutstandingTimers)
878
+ return false;
879
+ // Don't use the global loop-time variable here, because we might
880
+ // get called before the main event machine is running.
881
+
882
+ #ifdef OS_UNIX
883
+ struct timeval tv;
884
+ gettimeofday (&tv, NULL);
885
+ Int64 fire_at = (((Int64)(tv.tv_sec)) * 1000000LL) + ((Int64)(tv.tv_usec));
886
+ fire_at += ((Int64)milliseconds) * 1000LL;
887
+ #endif
888
+
889
+ #ifdef OS_WIN32
890
+ unsigned tick = GetTickCount();
891
+ if (tick < gLastTickCount)
892
+ gTickCountTickover += 1;
893
+ gLastTickCount = tick;
894
+
895
+ Int64 fire_at = ((Int64)gTickCountTickover << 32) + (Int64)tick;
896
+ fire_at += (Int64)milliseconds;
897
+ #endif
898
+
899
+ Timer_t t;
900
+ multimap<Int64,Timer_t>::iterator i =
901
+ Timers.insert (make_pair (fire_at, t));
902
+ return i->second.GetBindingChars();
903
+ }
904
+
905
+
906
+ /*******************************
907
+ EventMachine_t::ConnectToServer
908
+ *******************************/
909
+
910
+ const char *EventMachine_t::ConnectToServer (const char *server, int port)
911
+ {
912
+ /* We want to spend no more than a few seconds waiting for a connection
913
+ * to a remote host. So we use a nonblocking connect.
914
+ * Linux disobeys the usual rules for nonblocking connects.
915
+ * Per Stevens (UNP p.410), you expect a nonblocking connect to select
916
+ * both readable and writable on error, and not to return EINPROGRESS
917
+ * if the connect can be fulfilled immediately. Linux violates both
918
+ * of these expectations.
919
+ * Any kind of nonblocking connect on Linux returns EINPROGRESS.
920
+ * The socket will then return writable when the disposition of the
921
+ * connect is known, but it will not also be readable in case of
922
+ * error! Weirdly, it will be readable in case there is data to read!!!
923
+ * (Which can happen with protocols like SSH and SMTP.)
924
+ * I suppose if you were so inclined you could consider this logical,
925
+ * but it's not the way Unix has historically done it.
926
+ * So we ignore the readable flag and read getsockopt to see if there
927
+ * was an error connecting. A select timeout works as expected.
928
+ * In regard to getsockopt: Linux does the Berkeley-style thing,
929
+ * not the Solaris-style, and returns zero with the error code in
930
+ * the error parameter.
931
+ * Return the binding-text of the newly-created pending connection,
932
+ * or NULL if there was a problem.
933
+ */
934
+
935
+ if (!server || !*server || !port)
936
+ return NULL;
937
+
938
+ int family, bind_size;
939
+ struct sockaddr *bind_as = name2address (server, port, &family, &bind_size);
940
+ if (!bind_as)
941
+ return NULL;
942
+
943
+ int sd = socket (family, SOCK_STREAM, 0);
944
+ if (sd == INVALID_SOCKET)
945
+ return NULL;
946
+
947
+ /*
948
+ sockaddr_in pin;
949
+ unsigned long HostAddr;
950
+
951
+ HostAddr = inet_addr (server);
952
+ if (HostAddr == INADDR_NONE) {
953
+ hostent *hp = gethostbyname ((char*)server); // Windows requires (char*)
954
+ if (!hp) {
955
+ // TODO: This gives the caller a fatal error. Not good.
956
+ // They can respond by catching RuntimeError (blecch).
957
+ // Possibly we need to fire an unbind event and provide
958
+ // a status code so user code can detect the cause of the
959
+ // failure.
960
+ return NULL;
961
+ }
962
+ HostAddr = ((in_addr*)(hp->h_addr))->s_addr;
963
+ }
964
+
965
+ memset (&pin, 0, sizeof(pin));
966
+ pin.sin_family = AF_INET;
967
+ pin.sin_addr.s_addr = HostAddr;
968
+ pin.sin_port = htons (port);
969
+
970
+ int sd = socket (AF_INET, SOCK_STREAM, 0);
971
+ if (sd == INVALID_SOCKET)
972
+ return NULL;
973
+ */
974
+
975
+ // From here on, ALL error returns must close the socket.
976
+ // Set the new socket nonblocking.
977
+ if (!SetSocketNonblocking (sd)) {
978
+ closesocket (sd);
979
+ return NULL;
980
+ }
981
+ // Disable slow-start (Nagle algorithm).
982
+ int one = 1;
983
+ setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));
984
+
985
+ const char *out = NULL;
986
+
987
+ #ifdef OS_UNIX
988
+ //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
989
+ if (connect (sd, bind_as, bind_size) == 0) {
990
+ // This is a connect success, which Linux appears
991
+ // never to give when the socket is nonblocking,
992
+ // even if the connection is intramachine or to
993
+ // localhost.
994
+
995
+ /* Changed this branch 08Aug06. Evidently some kernels
996
+ * (FreeBSD for example) will actually return success from
997
+ * a nonblocking connect. This is a pretty simple case,
998
+ * just set up the new connection and clear the pending flag.
999
+ * Thanks to Chris Ochs for helping track this down.
1000
+ * This branch never gets taken on Linux or (oddly) OSX.
1001
+ * The original behavior was to throw an unimplemented,
1002
+ * which the user saw as a fatal exception. Very unfriendly.
1003
+ *
1004
+ * Tweaked 10Aug06. Even though the connect disposition is
1005
+ * known, we still set the connect-pending flag. That way
1006
+ * some needed initialization will happen in the ConnectionDescriptor.
1007
+ * (To wit, the ConnectionCompleted event gets sent to the client.)
1008
+ */
1009
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1010
+ if (!cd)
1011
+ throw std::runtime_error ("no connection allocated");
1012
+ cd->SetConnectPending (true);
1013
+ Add (cd);
1014
+ out = cd->GetBinding().c_str();
1015
+ }
1016
+ else if (errno == EINPROGRESS) {
1017
+ // Errno will generally always be EINPROGRESS, but on Linux
1018
+ // we have to look at getsockopt to be sure what really happened.
1019
+ int error;
1020
+ socklen_t len;
1021
+ len = sizeof(error);
1022
+ int o = getsockopt (sd, SOL_SOCKET, SO_ERROR, &error, &len);
1023
+ if ((o == 0) && (error == 0)) {
1024
+ // Here, there's no disposition.
1025
+ // Put the connection on the stack and wait for it to complete
1026
+ // or time out.
1027
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1028
+ if (!cd)
1029
+ throw std::runtime_error ("no connection allocated");
1030
+ cd->SetConnectPending (true);
1031
+ Add (cd);
1032
+ out = cd->GetBinding().c_str();
1033
+ }
1034
+ else {
1035
+ /* This could be connection refused or some such thing.
1036
+ * We will come here on Linux if a localhost connection fails.
1037
+ * Changed 16Jul06: Originally this branch was a no-op, and
1038
+ * we'd drop down to the end of the method, close the socket,
1039
+ * and return NULL, which would cause the caller to GET A
1040
+ * FATAL EXCEPTION. Now we keep the socket around but schedule an
1041
+ * immediate close on it, so the caller will get a close-event
1042
+ * scheduled on it. This was only an issue for localhost connections
1043
+ * to non-listening ports. We may eventually need to revise this
1044
+ * revised behavior, in case it causes problems like making it hard
1045
+ * for people to know that a failure occurred.
1046
+ */
1047
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1048
+ if (!cd)
1049
+ throw std::runtime_error ("no connection allocated");
1050
+ cd->ScheduleClose (false);
1051
+ Add (cd);
1052
+ out = cd->GetBinding().c_str();
1053
+ }
1054
+ }
1055
+ else {
1056
+ // The error from connect was something other then EINPROGRESS.
1057
+ }
1058
+ #endif
1059
+
1060
+ #ifdef OS_WIN32
1061
+ //if (connect (sd, (sockaddr*)&pin, sizeof pin) == 0) {
1062
+ if (connect (sd, bind_as, bind_size) == 0) {
1063
+ // This is a connect success, which Windows appears
1064
+ // never to give when the socket is nonblocking,
1065
+ // even if the connection is intramachine or to
1066
+ // localhost.
1067
+ throw std::runtime_error ("unimplemented");
1068
+ }
1069
+ else if (WSAGetLastError() == WSAEWOULDBLOCK) {
1070
+ // Here, there's no disposition.
1071
+ // Windows appears not to surface refused connections or
1072
+ // such stuff at this point.
1073
+ // Put the connection on the stack and wait for it to complete
1074
+ // or time out.
1075
+ ConnectionDescriptor *cd = new ConnectionDescriptor (sd, this);
1076
+ if (!cd)
1077
+ throw std::runtime_error ("no connection allocated");
1078
+ cd->SetConnectPending (true);
1079
+ Add (cd);
1080
+ out = cd->GetBinding().c_str();
1081
+ }
1082
+ else {
1083
+ // The error from connect was something other then WSAEWOULDBLOCK.
1084
+ }
1085
+
1086
+ #endif
1087
+
1088
+ if (out == NULL)
1089
+ closesocket (sd);
1090
+ return out;
1091
+ }
1092
+
1093
+ /***********************************
1094
+ EventMachine_t::ConnectToUnixServer
1095
+ ***********************************/
1096
+
1097
+ const char *EventMachine_t::ConnectToUnixServer (const char *server)
1098
+ {
1099
+ /* Connect to a Unix-domain server, which by definition is running
1100
+ * on the same host.
1101
+ * There is no meaningful implementation on Windows.
1102
+ * There's no need to do a nonblocking connect, since the connection
1103
+ * is always local and can always be fulfilled immediately.
1104
+ */
1105
+
1106
+ #ifdef OS_WIN32
1107
+ throw std::runtime_error ("unix-domain connection unavailable on this platform");
1108
+ return NULL;
1109
+ #endif
1110
+
1111
+ // The whole rest of this function is only compiled on Unix systems.
1112
+ #ifdef OS_UNIX
1113
+
1114
+ const char *out = NULL;
1115
+
1116
+ if (!server || !*server)
1117
+ return NULL;
1118
+
1119
+ sockaddr_un pun;
1120
+ memset (&pun, 0, sizeof(pun));
1121
+ pun.sun_family = AF_LOCAL;
1122
+
1123
+ // You ordinarily expect the server name field to be at least 1024 bytes long,
1124
+ // but on Linux it can be MUCH shorter.
1125
+ if (strlen(server) >= sizeof(pun.sun_path))
1126
+ throw std::runtime_error ("unix-domain server name is too long");
1127
+
1128
+
1129
+ strcpy (pun.sun_path, server);
1130
+
1131
+ int fd = socket (AF_LOCAL, SOCK_STREAM, 0);
1132
+ if (fd == INVALID_SOCKET)
1133
+ return NULL;
1134
+
1135
+ // From here on, ALL error returns must close the socket.
1136
+ // NOTE: At this point, the socket is still a blocking socket.
1137
+ if (connect (fd, (struct sockaddr*)&pun, sizeof(pun)) != 0) {
1138
+ closesocket (fd);
1139
+ return NULL;
1140
+ }
1141
+
1142
+ // Set the newly-connected socket nonblocking.
1143
+ if (!SetSocketNonblocking (fd)) {
1144
+ closesocket (fd);
1145
+ return NULL;
1146
+ }
1147
+
1148
+ // Set up a connection descriptor and add it to the event-machine.
1149
+ // Observe, even though we know the connection status is connect-success,
1150
+ // we still set the "pending" flag, so some needed initializations take
1151
+ // place.
1152
+ ConnectionDescriptor *cd = new ConnectionDescriptor (fd, this);
1153
+ if (!cd)
1154
+ throw std::runtime_error ("no connection allocated");
1155
+ cd->SetConnectPending (true);
1156
+ Add (cd);
1157
+ out = cd->GetBinding().c_str();
1158
+
1159
+ if (out == NULL)
1160
+ closesocket (fd);
1161
+
1162
+ return out;
1163
+ #endif
1164
+ }
1165
+
1166
+
1167
+ /************
1168
+ name2address
1169
+ ************/
1170
+
1171
+ struct sockaddr *name2address (const char *server, int port, int *family, int *bind_size)
1172
+ {
1173
+ // THIS IS NOT RE-ENTRANT OR THREADSAFE. Optimize for speed.
1174
+ // Check the more-common cases first.
1175
+ // Return NULL if no resolution.
1176
+
1177
+ static struct sockaddr_in in4;
1178
+ static struct sockaddr_in6 in6;
1179
+ struct hostent *hp;
1180
+
1181
+ if (!server || !*server)
1182
+ server = "0.0.0.0";
1183
+
1184
+ memset (&in4, 0, sizeof(in4));
1185
+ if ( (in4.sin_addr.s_addr = inet_addr (server)) != INADDR_NONE) {
1186
+ if (family)
1187
+ *family = AF_INET;
1188
+ if (bind_size)
1189
+ *bind_size = sizeof(in4);
1190
+ in4.sin_family = AF_INET;
1191
+ in4.sin_port = htons (port);
1192
+ return (struct sockaddr*)&in4;
1193
+ }
1194
+
1195
+ #ifdef OS_UNIX
1196
+ memset (&in6, 0, sizeof(in6));
1197
+ if (inet_pton (AF_INET6, server, in6.sin6_addr.s6_addr) > 0) {
1198
+ if (family)
1199
+ *family = AF_INET6;
1200
+ if (bind_size)
1201
+ *bind_size = sizeof(in6);
1202
+ in6.sin6_family = AF_INET6;
1203
+ in6.sin6_port = htons (port);
1204
+ return (struct sockaddr*)&in6;
1205
+ }
1206
+ #endif
1207
+
1208
+ #ifdef OS_WIN32
1209
+ // TODO, must complete this branch. Windows doesn't have inet_pton.
1210
+ // A possible approach is to make a getaddrinfo call with the supplied
1211
+ // server address, constraining the hints to ipv6 and seeing if we
1212
+ // get any addresses.
1213
+ // For the time being, Ipv6 addresses aren't supported on Windows.
1214
+ #endif
1215
+
1216
+ hp = gethostbyname ((char*)server); // Windows requires the cast.
1217
+ if (hp) {
1218
+ in4.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1219
+ if (family)
1220
+ *family = AF_INET;
1221
+ if (bind_size)
1222
+ *bind_size = sizeof(in4);
1223
+ in4.sin_family = AF_INET;
1224
+ in4.sin_port = htons (port);
1225
+ return (struct sockaddr*)&in4;
1226
+ }
1227
+
1228
+ return NULL;
1229
+ }
1230
+
1231
+
1232
+ /*******************************
1233
+ EventMachine_t::CreateTcpServer
1234
+ *******************************/
1235
+
1236
+ const char *EventMachine_t::CreateTcpServer (const char *server, int port)
1237
+ {
1238
+ /* Create a TCP-acceptor (server) socket and add it to the event machine.
1239
+ * Return the binding of the new acceptor to the caller.
1240
+ * This binding will be referenced when the new acceptor sends events
1241
+ * to indicate accepted connections.
1242
+ */
1243
+
1244
+
1245
+ int family, bind_size;
1246
+ struct sockaddr *bind_here = name2address (server, port, &family, &bind_size);
1247
+ if (!bind_here)
1248
+ return NULL;
1249
+
1250
+ const char *output_binding = NULL;
1251
+
1252
+ //struct sockaddr_in sin;
1253
+
1254
+ int sd_accept = socket (family, SOCK_STREAM, 0);
1255
+ if (sd_accept == INVALID_SOCKET) {
1256
+ goto fail;
1257
+ }
1258
+
1259
+ /*
1260
+ memset (&sin, 0, sizeof(sin));
1261
+ sin.sin_family = AF_INET;
1262
+ sin.sin_addr.s_addr = INADDR_ANY;
1263
+ sin.sin_port = htons (port);
1264
+
1265
+ if (server && *server) {
1266
+ sin.sin_addr.s_addr = inet_addr (server);
1267
+ if (sin.sin_addr.s_addr == INADDR_NONE) {
1268
+ hostent *hp = gethostbyname ((char*)server); // Windows requires the cast.
1269
+ if (hp == NULL) {
1270
+ //__warning ("hostname not resolved: ", server);
1271
+ goto fail;
1272
+ }
1273
+ sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1274
+ }
1275
+ }
1276
+ */
1277
+
1278
+ { // set reuseaddr to improve performance on restarts.
1279
+ int oval = 1;
1280
+ if (setsockopt (sd_accept, SOL_SOCKET, SO_REUSEADDR, (char*)&oval, sizeof(oval)) < 0) {
1281
+ //__warning ("setsockopt failed while creating listener","");
1282
+ goto fail;
1283
+ }
1284
+ }
1285
+
1286
+ { // set CLOEXEC. Only makes sense on Unix
1287
+ #ifdef OS_UNIX
1288
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
1289
+ assert (cloexec >= 0);
1290
+ cloexec |= FD_CLOEXEC;
1291
+ fcntl (sd_accept, F_SETFD, cloexec);
1292
+ #endif
1293
+ }
1294
+
1295
+
1296
+ //if (bind (sd_accept, (struct sockaddr*)&sin, sizeof(sin))) {
1297
+ if (bind (sd_accept, bind_here, bind_size)) {
1298
+ //__warning ("binding failed");
1299
+ goto fail;
1300
+ }
1301
+
1302
+ if (listen (sd_accept, 100)) {
1303
+ //__warning ("listen failed");
1304
+ goto fail;
1305
+ }
1306
+
1307
+ {
1308
+ // Set the acceptor non-blocking.
1309
+ // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1310
+ if (!SetSocketNonblocking (sd_accept)) {
1311
+ //int val = fcntl (sd_accept, F_GETFL, 0);
1312
+ //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1313
+ goto fail;
1314
+ }
1315
+ }
1316
+
1317
+ { // Looking good.
1318
+ AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1319
+ if (!ad)
1320
+ throw std::runtime_error ("unable to allocate acceptor");
1321
+ Add (ad);
1322
+ output_binding = ad->GetBinding().c_str();
1323
+ }
1324
+
1325
+ return output_binding;
1326
+
1327
+ fail:
1328
+ if (sd_accept != INVALID_SOCKET)
1329
+ closesocket (sd_accept);
1330
+ return NULL;
1331
+ }
1332
+
1333
+
1334
+ /**********************************
1335
+ EventMachine_t::OpenDatagramSocket
1336
+ **********************************/
1337
+
1338
+ const char *EventMachine_t::OpenDatagramSocket (const char *address, int port)
1339
+ {
1340
+ const char *output_binding = NULL;
1341
+
1342
+ int sd = socket (AF_INET, SOCK_DGRAM, 0);
1343
+ if (sd == INVALID_SOCKET)
1344
+ goto fail;
1345
+ // from here on, early returns must close the socket!
1346
+
1347
+
1348
+ struct sockaddr_in sin;
1349
+ memset (&sin, 0, sizeof(sin));
1350
+ sin.sin_family = AF_INET;
1351
+ sin.sin_port = htons (port);
1352
+
1353
+
1354
+ if (address && *address) {
1355
+ sin.sin_addr.s_addr = inet_addr (address);
1356
+ if (sin.sin_addr.s_addr == INADDR_NONE) {
1357
+ hostent *hp = gethostbyname ((char*)address); // Windows requires the cast.
1358
+ if (hp == NULL)
1359
+ goto fail;
1360
+ sin.sin_addr.s_addr = ((in_addr*)(hp->h_addr))->s_addr;
1361
+ }
1362
+ }
1363
+ else
1364
+ sin.sin_addr.s_addr = htonl (INADDR_ANY);
1365
+
1366
+
1367
+ // Set the new socket nonblocking.
1368
+ {
1369
+ if (!SetSocketNonblocking (sd))
1370
+ //int val = fcntl (sd, F_GETFL, 0);
1371
+ //if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1)
1372
+ goto fail;
1373
+ }
1374
+
1375
+ if (bind (sd, (struct sockaddr*)&sin, sizeof(sin)) != 0)
1376
+ goto fail;
1377
+
1378
+ { // Looking good.
1379
+ DatagramDescriptor *ds = new DatagramDescriptor (sd, this);
1380
+ if (!ds)
1381
+ throw std::runtime_error ("unable to allocate datagram-socket");
1382
+ Add (ds);
1383
+ output_binding = ds->GetBinding().c_str();
1384
+ }
1385
+
1386
+ return output_binding;
1387
+
1388
+ fail:
1389
+ if (sd != INVALID_SOCKET)
1390
+ closesocket (sd);
1391
+ return NULL;
1392
+ }
1393
+
1394
+
1395
+
1396
+ /*******************
1397
+ EventMachine_t::Add
1398
+ *******************/
1399
+
1400
+ void EventMachine_t::Add (EventableDescriptor *ed)
1401
+ {
1402
+ if (!ed)
1403
+ throw std::runtime_error ("added bad descriptor");
1404
+ ed->SetEventCallback (EventCallback);
1405
+ NewDescriptors.push_back (ed);
1406
+ }
1407
+
1408
+
1409
+ /*******************************
1410
+ EventMachine_t::ArmKqueueWriter
1411
+ *******************************/
1412
+
1413
+ void EventMachine_t::ArmKqueueWriter (EventableDescriptor *ed)
1414
+ {
1415
+ #ifdef HAVE_KQUEUE
1416
+ if (bKqueue) {
1417
+ if (!ed)
1418
+ throw std::runtime_error ("added bad descriptor");
1419
+ struct kevent k;
1420
+ EV_SET (&k, ed->GetSocket(), EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, ed);
1421
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1422
+ assert (t == 0);
1423
+ }
1424
+ #endif
1425
+ }
1426
+
1427
+ /*******************************
1428
+ EventMachine_t::ArmKqueueReader
1429
+ *******************************/
1430
+
1431
+ void EventMachine_t::ArmKqueueReader (EventableDescriptor *ed)
1432
+ {
1433
+ #ifdef HAVE_KQUEUE
1434
+ if (bKqueue) {
1435
+ if (!ed)
1436
+ throw std::runtime_error ("added bad descriptor");
1437
+ struct kevent k;
1438
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1439
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1440
+ assert (t == 0);
1441
+ }
1442
+ #endif
1443
+ }
1444
+
1445
+ /**********************************
1446
+ EventMachine_t::_AddNewDescriptors
1447
+ **********************************/
1448
+
1449
+ void EventMachine_t::_AddNewDescriptors()
1450
+ {
1451
+ /* Avoid adding descriptors to the main descriptor list
1452
+ * while we're actually traversing the list.
1453
+ * Any descriptors that are added as a result of processing timers
1454
+ * or acceptors should go on a temporary queue and then added
1455
+ * while we're not traversing the main list.
1456
+ * Also, it (rarely) happens that a newly-created descriptor
1457
+ * is immediately scheduled to close. It might be a good
1458
+ * idea not to bother scheduling these for I/O but if
1459
+ * we do that, we might bypass some important processing.
1460
+ */
1461
+
1462
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1463
+ EventableDescriptor *ed = NewDescriptors[i];
1464
+ if (ed == NULL)
1465
+ throw std::runtime_error ("adding bad descriptor");
1466
+
1467
+ #if HAVE_EPOLL
1468
+ if (bEpoll) {
1469
+ assert (epfd != -1);
1470
+ int e = epoll_ctl (epfd, EPOLL_CTL_ADD, ed->GetSocket(), ed->GetEpollEvent());
1471
+ if (e) {
1472
+ char buf [200];
1473
+ snprintf (buf, sizeof(buf)-1, "unable to add new descriptor: %s", strerror(errno));
1474
+ throw std::runtime_error (buf);
1475
+ }
1476
+ }
1477
+ #endif
1478
+
1479
+ #if HAVE_KQUEUE
1480
+ /*
1481
+ if (bKqueue) {
1482
+ // INCOMPLETE. Some descriptors don't want to be readable.
1483
+ assert (kqfd != -1);
1484
+ struct kevent k;
1485
+ EV_SET (&k, ed->GetSocket(), EVFILT_READ, EV_ADD, 0, 0, ed);
1486
+ int t = kevent (kqfd, &k, 1, NULL, 0, NULL);
1487
+ assert (t == 0);
1488
+ }
1489
+ */
1490
+ #endif
1491
+
1492
+ Descriptors.push_back (ed);
1493
+ }
1494
+ NewDescriptors.clear();
1495
+ }
1496
+
1497
+
1498
+ /**********************************
1499
+ EventMachine_t::_ModifyDescriptors
1500
+ **********************************/
1501
+
1502
+ void EventMachine_t::_ModifyDescriptors()
1503
+ {
1504
+ /* For implementations which don't level check every descriptor on
1505
+ * every pass through the machine, as select does.
1506
+ * If we're not selecting, then descriptors need a way to signal to the
1507
+ * machine that their readable or writable status has changed.
1508
+ * That's what the ::Modify call is for. We do it this way to avoid
1509
+ * modifying descriptors during the loop traversal, where it can easily
1510
+ * happen that an object (like a UDP socket) gets data written on it by
1511
+ * the application during #post_init. That would take place BEFORE the
1512
+ * descriptor even gets added to the epoll descriptor, so the modify
1513
+ * operation will crash messily.
1514
+ * Another really messy possibility is for a descriptor to put itself
1515
+ * on the Modified list, and then get deleted before we get here.
1516
+ * Remember, deletes happen after the I/O traversal and before the
1517
+ * next pass through here. So we have to make sure when we delete a
1518
+ * descriptor to remove it from the Modified list.
1519
+ */
1520
+
1521
+ #ifdef HAVE_EPOLL
1522
+ if (bEpoll) {
1523
+ set<EventableDescriptor*>::iterator i = ModifiedDescriptors.begin();
1524
+ while (i != ModifiedDescriptors.end()) {
1525
+ assert (*i);
1526
+ _ModifyEpollEvent (*i);
1527
+ ++i;
1528
+ }
1529
+ }
1530
+ #endif
1531
+
1532
+ ModifiedDescriptors.clear();
1533
+ }
1534
+
1535
+
1536
+ /**********************
1537
+ EventMachine_t::Modify
1538
+ **********************/
1539
+
1540
+ void EventMachine_t::Modify (EventableDescriptor *ed)
1541
+ {
1542
+ if (!ed)
1543
+ throw std::runtime_error ("modified bad descriptor");
1544
+ ModifiedDescriptors.insert (ed);
1545
+ }
1546
+
1547
+
1548
+ /***********************************
1549
+ EventMachine_t::_OpenFileForWriting
1550
+ ***********************************/
1551
+
1552
+ const char *EventMachine_t::_OpenFileForWriting (const char *filename)
1553
+ {
1554
+ /*
1555
+ * Return the binding-text of the newly-opened file,
1556
+ * or NULL if there was a problem.
1557
+ */
1558
+
1559
+ if (!filename || !*filename)
1560
+ return NULL;
1561
+
1562
+ int fd = open (filename, O_CREAT|O_TRUNC|O_WRONLY|O_NONBLOCK, 0644);
1563
+
1564
+ FileStreamDescriptor *fsd = new FileStreamDescriptor (fd, this);
1565
+ if (!fsd)
1566
+ throw std::runtime_error ("no file-stream allocated");
1567
+ Add (fsd);
1568
+ return fsd->GetBinding().c_str();
1569
+
1570
+ }
1571
+
1572
+
1573
+ /**************************************
1574
+ EventMachine_t::CreateUnixDomainServer
1575
+ **************************************/
1576
+
1577
+ const char *EventMachine_t::CreateUnixDomainServer (const char *filename)
1578
+ {
1579
+ /* Create a UNIX-domain acceptor (server) socket and add it to the event machine.
1580
+ * Return the binding of the new acceptor to the caller.
1581
+ * This binding will be referenced when the new acceptor sends events
1582
+ * to indicate accepted connections.
1583
+ * THERE IS NO MEANINGFUL IMPLEMENTATION ON WINDOWS.
1584
+ */
1585
+
1586
+ #ifdef OS_WIN32
1587
+ throw std::runtime_error ("unix-domain server unavailable on this platform");
1588
+ #endif
1589
+
1590
+ // The whole rest of this function is only compiled on Unix systems.
1591
+ #ifdef OS_UNIX
1592
+ const char *output_binding = NULL;
1593
+
1594
+ struct sockaddr_un s_sun;
1595
+
1596
+ int sd_accept = socket (AF_LOCAL, SOCK_STREAM, 0);
1597
+ if (sd_accept == INVALID_SOCKET) {
1598
+ goto fail;
1599
+ }
1600
+
1601
+ if (!filename || !*filename)
1602
+ goto fail;
1603
+ unlink (filename);
1604
+
1605
+ bzero (&s_sun, sizeof(s_sun));
1606
+ s_sun.sun_family = AF_LOCAL;
1607
+ strncpy (s_sun.sun_path, filename, sizeof(s_sun.sun_path)-1);
1608
+
1609
+ // don't bother with reuseaddr for a local socket.
1610
+
1611
+ { // set CLOEXEC. Only makes sense on Unix
1612
+ #ifdef OS_UNIX
1613
+ int cloexec = fcntl (sd_accept, F_GETFD, 0);
1614
+ assert (cloexec >= 0);
1615
+ cloexec |= FD_CLOEXEC;
1616
+ fcntl (sd_accept, F_SETFD, cloexec);
1617
+ #endif
1618
+ }
1619
+
1620
+ if (bind (sd_accept, (struct sockaddr*)&s_sun, sizeof(s_sun))) {
1621
+ //__warning ("binding failed");
1622
+ goto fail;
1623
+ }
1624
+
1625
+ if (listen (sd_accept, 100)) {
1626
+ //__warning ("listen failed");
1627
+ goto fail;
1628
+ }
1629
+
1630
+ {
1631
+ // Set the acceptor non-blocking.
1632
+ // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1633
+ if (!SetSocketNonblocking (sd_accept)) {
1634
+ //int val = fcntl (sd_accept, F_GETFL, 0);
1635
+ //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1636
+ goto fail;
1637
+ }
1638
+ }
1639
+
1640
+ { // Looking good.
1641
+ AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1642
+ if (!ad)
1643
+ throw std::runtime_error ("unable to allocate acceptor");
1644
+ Add (ad);
1645
+ output_binding = ad->GetBinding().c_str();
1646
+ }
1647
+
1648
+ return output_binding;
1649
+
1650
+ fail:
1651
+ if (sd_accept != INVALID_SOCKET)
1652
+ closesocket (sd_accept);
1653
+ return NULL;
1654
+ #endif // OS_UNIX
1655
+ }
1656
+
1657
+
1658
+ /*********************
1659
+ EventMachine_t::Popen
1660
+ *********************/
1661
+ #if OBSOLETE
1662
+ const char *EventMachine_t::Popen (const char *cmd, const char *mode)
1663
+ {
1664
+ #ifdef OS_WIN32
1665
+ throw std::runtime_error ("popen is currently unavailable on this platform");
1666
+ #endif
1667
+
1668
+ // The whole rest of this function is only compiled on Unix systems.
1669
+ // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1670
+ #ifdef OS_UNIX
1671
+ const char *output_binding = NULL;
1672
+
1673
+ FILE *fp = popen (cmd, mode);
1674
+ if (!fp)
1675
+ return NULL;
1676
+
1677
+ // From here, all early returns must pclose the stream.
1678
+
1679
+ // According to the pipe(2) manpage, descriptors returned from pipe have both
1680
+ // CLOEXEC and NONBLOCK clear. Do NOT set CLOEXEC. DO set nonblocking.
1681
+ if (!SetSocketNonblocking (fileno (fp))) {
1682
+ pclose (fp);
1683
+ return NULL;
1684
+ }
1685
+
1686
+ { // Looking good.
1687
+ PipeDescriptor *pd = new PipeDescriptor (fp, this);
1688
+ if (!pd)
1689
+ throw std::runtime_error ("unable to allocate pipe");
1690
+ Add (pd);
1691
+ output_binding = pd->GetBinding().c_str();
1692
+ }
1693
+
1694
+ return output_binding;
1695
+ #endif
1696
+ }
1697
+ #endif // OBSOLETE
1698
+
1699
+ /**************************
1700
+ EventMachine_t::Socketpair
1701
+ **************************/
1702
+
1703
+ const char *EventMachine_t::Socketpair (char * const*cmd_strings)
1704
+ {
1705
+ #ifdef OS_WIN32
1706
+ throw std::runtime_error ("socketpair is currently unavailable on this platform");
1707
+ #endif
1708
+
1709
+ // The whole rest of this function is only compiled on Unix systems.
1710
+ // Eventually we need this functionality (or a full-duplex equivalent) on Windows.
1711
+ #ifdef OS_UNIX
1712
+ // Make sure the incoming array of command strings is sane.
1713
+ if (!cmd_strings)
1714
+ return NULL;
1715
+ int j;
1716
+ for (j=0; j < 100 && cmd_strings[j]; j++)
1717
+ ;
1718
+ if ((j==0) || (j==100))
1719
+ return NULL;
1720
+
1721
+ const char *output_binding = NULL;
1722
+
1723
+ int sv[2];
1724
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, sv) < 0)
1725
+ return NULL;
1726
+ // from here, all early returns must close the pair of sockets.
1727
+
1728
+ // Set the parent side of the socketpair nonblocking.
1729
+ // We don't care about the child side, and most child processes will expect their
1730
+ // stdout to be blocking. Thanks to Duane Johnson and Bill Kelly for pointing this out.
1731
+ // Obviously DON'T set CLOEXEC.
1732
+ if (!SetSocketNonblocking (sv[0])) {
1733
+ close (sv[0]);
1734
+ close (sv[1]);
1735
+ return NULL;
1736
+ }
1737
+
1738
+ pid_t f = fork();
1739
+ if (f > 0) {
1740
+ close (sv[1]);
1741
+ PipeDescriptor *pd = new PipeDescriptor (sv[0], f, this);
1742
+ if (!pd)
1743
+ throw std::runtime_error ("unable to allocate pipe");
1744
+ Add (pd);
1745
+ output_binding = pd->GetBinding().c_str();
1746
+ }
1747
+ else if (f == 0) {
1748
+ close (sv[0]);
1749
+ dup2 (sv[1], STDIN_FILENO);
1750
+ close (sv[1]);
1751
+ dup2 (STDIN_FILENO, STDOUT_FILENO);
1752
+ execvp (cmd_strings[0], cmd_strings+1);
1753
+ exit (-1); // end the child process if the exec doesn't work.
1754
+ }
1755
+ else
1756
+ throw std::runtime_error ("no fork");
1757
+
1758
+ return output_binding;
1759
+ #endif
1760
+ }
1761
+
1762
+
1763
+ /****************************
1764
+ EventMachine_t::OpenKeyboard
1765
+ ****************************/
1766
+
1767
+ const char *EventMachine_t::OpenKeyboard()
1768
+ {
1769
+ KeyboardDescriptor *kd = new KeyboardDescriptor (this);
1770
+ if (!kd)
1771
+ throw std::runtime_error ("no keyboard-object allocated");
1772
+ Add (kd);
1773
+ return kd->GetBinding().c_str();
1774
+ }
1775
+
1776
+
1777
+
1778
+
1779
+
1780
+ //#endif // OS_UNIX
1781
+