eventmachine 0.12.4 → 0.12.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +13 -0
  2. data/Rakefile +66 -3
  3. data/docs/ChangeLog +38 -10
  4. data/eventmachine.gemspec +32 -0
  5. data/ext/cmain.cpp +45 -3
  6. data/ext/cplusplus.cpp +21 -0
  7. data/ext/ed.cpp +34 -1
  8. data/ext/ed.h +12 -0
  9. data/ext/em.cpp +23 -3
  10. data/ext/em.h +6 -2
  11. data/ext/eventmachine.h +9 -1
  12. data/ext/eventmachine_cpp.h +1 -0
  13. data/ext/extconf.rb +8 -29
  14. data/ext/fastfilereader/extconf.rb +50 -134
  15. data/ext/fastfilereader/mapper.cpp +12 -0
  16. data/ext/fastfilereader/mapper.h +1 -1
  17. data/ext/kb.cpp +0 -286
  18. data/ext/pipe.cpp +30 -13
  19. data/ext/rubymain.cpp +127 -12
  20. data/ext/ssl.cpp +15 -0
  21. data/ext/ssl.h +4 -0
  22. data/java/.classpath +8 -0
  23. data/java/.project +17 -0
  24. data/lib/em/processes.rb +45 -0
  25. data/lib/eventmachine.rb +260 -102
  26. data/lib/eventmachine_version.rb +1 -1
  27. data/lib/pr_eventmachine.rb +1 -1
  28. data/lib/protocols/httpcli2.rb +10 -1
  29. data/lib/protocols/httpclient.rb +2 -2
  30. data/lib/protocols/memcache.rb +293 -0
  31. data/lib/protocols/smtpserver.rb +1 -1
  32. data/setup.rb +1585 -0
  33. data/tasks/tests.rake +1 -0
  34. data/tests/test_attach.rb +19 -2
  35. data/tests/test_basic.rb +2 -2
  36. data/tests/test_connection_count.rb +45 -0
  37. data/tests/test_error_handler.rb +35 -0
  38. data/tests/test_errors.rb +3 -3
  39. data/tests/test_exc.rb +2 -2
  40. data/tests/test_handler_check.rb +37 -0
  41. data/tests/test_httpclient2.rb +1 -1
  42. data/tests/test_kb.rb +2 -2
  43. data/tests/test_next_tick.rb +7 -0
  44. data/tests/test_processes.rb +39 -0
  45. data/tests/test_pure.rb +2 -2
  46. data/tests/test_send_file.rb +1 -1
  47. data/tests/test_ssl_args.rb +3 -3
  48. data/tests/test_ssl_methods.rb +50 -0
  49. data/tests/test_timers.rb +3 -1
  50. data/web/whatis +7 -0
  51. metadata +88 -84
data/ext/kb.cpp CHANGED
@@ -80,289 +80,3 @@ void KeyboardDescriptor::Read()
80
80
  if (EventCallback)
81
81
  (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, &c, 1);
82
82
  }
83
-
84
-
85
-
86
-
87
- #if 0
88
- /******************************
89
- PipeDescriptor::PipeDescriptor
90
- ******************************/
91
-
92
- PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
93
- EventableDescriptor (fd, parent_em),
94
- bReadAttemptedAfterClose (false),
95
- LastIo (gCurrentLoopTime),
96
- InactivityTimeout (0),
97
- OutboundDataSize (0),
98
- SubprocessPid (subpid)
99
- {
100
- #ifdef HAVE_EPOLL
101
- EpollEvent.events = EPOLLIN;
102
- #endif
103
- }
104
-
105
-
106
- /*******************************
107
- PipeDescriptor::~PipeDescriptor
108
- *******************************/
109
-
110
- PipeDescriptor::~PipeDescriptor()
111
- {
112
- // Run down any stranded outbound data.
113
- for (size_t i=0; i < OutboundPages.size(); i++)
114
- OutboundPages[i].Free();
115
-
116
- /* As a virtual destructor, we come here before the base-class
117
- * destructor that closes our file-descriptor.
118
- * We have to make sure the subprocess goes down (if it's not
119
- * already down) and we have to reap the zombie.
120
- *
121
- * This implementation is PROVISIONAL and will surely be improved.
122
- * The intention here is that we never block, hence the highly
123
- * undesirable sleeps. But if we can't reap the subprocess even
124
- * after sending it SIGKILL, then something is wrong and we
125
- * throw a fatal exception, which is also not something we should
126
- * be doing.
127
- *
128
- * Eventually the right thing to do will be to have the reactor
129
- * core respond to SIGCHLD by chaining a handler on top of the
130
- * one Ruby may have installed, and dealing with a list of dead
131
- * children that are pending cleanup.
132
- *
133
- * Since we want to have a signal processor integrated into the
134
- * client-visible API, let's wait until that is done before cleaning
135
- * this up.
136
- */
137
-
138
- struct timespec req = {0, 10000000};
139
- kill (SubprocessPid, SIGTERM);
140
- nanosleep (&req, NULL);
141
- if (waitpid (SubprocessPid, NULL, WNOHANG) == 0) {
142
- kill (SubprocessPid, SIGKILL);
143
- nanosleep (&req, NULL);
144
- if (waitpid (SubprocessPid, NULL, WNOHANG) == 0)
145
- throw std::runtime_error ("unable to reap subprocess");
146
- }
147
- }
148
-
149
-
150
-
151
- /********************
152
- PipeDescriptor::Read
153
- ********************/
154
-
155
- void PipeDescriptor::Read()
156
- {
157
- int sd = GetSocket();
158
- if (sd == INVALID_SOCKET) {
159
- assert (!bReadAttemptedAfterClose);
160
- bReadAttemptedAfterClose = true;
161
- return;
162
- }
163
-
164
- LastIo = gCurrentLoopTime;
165
-
166
- int total_bytes_read = 0;
167
- char readbuffer [16 * 1024];
168
-
169
- for (int i=0; i < 10; i++) {
170
- // Don't read just one buffer and then move on. This is faster
171
- // if there is a lot of incoming.
172
- // But don't read indefinitely. Give other sockets a chance to run.
173
- // NOTICE, we're reading one less than the buffer size.
174
- // That's so we can put a guard byte at the end of what we send
175
- // to user code.
176
- // Use read instead of recv, which on Linux gives a "socket operation
177
- // on nonsocket" error.
178
-
179
-
180
- int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
181
- //cerr << "<R:" << r << ">";
182
-
183
- if (r > 0) {
184
- total_bytes_read += r;
185
- LastRead = gCurrentLoopTime;
186
-
187
- // Add a null-terminator at the the end of the buffer
188
- // that we will send to the callback.
189
- // DO NOT EVER CHANGE THIS. We want to explicitly allow users
190
- // to be able to depend on this behavior, so they will have
191
- // the option to do some things faster. Additionally it's
192
- // a security guard against buffer overflows.
193
- readbuffer [r] = 0;
194
- if (EventCallback)
195
- (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);
196
- }
197
- else if (r == 0) {
198
- break;
199
- }
200
- else {
201
- // Basically a would-block, meaning we've read everything there is to read.
202
- break;
203
- }
204
-
205
- }
206
-
207
-
208
- if (total_bytes_read == 0) {
209
- // If we read no data on a socket that selected readable,
210
- // it generally means the other end closed the connection gracefully.
211
- ScheduleClose (false);
212
- //bCloseNow = true;
213
- }
214
-
215
- }
216
-
217
- /*********************
218
- PipeDescriptor::Write
219
- *********************/
220
-
221
- void PipeDescriptor::Write()
222
- {
223
- int sd = GetSocket();
224
- assert (sd != INVALID_SOCKET);
225
-
226
- LastIo = gCurrentLoopTime;
227
- char output_buffer [16 * 1024];
228
- size_t nbytes = 0;
229
-
230
- while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
231
- OutboundPage *op = &(OutboundPages[0]);
232
- if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
233
- memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
234
- nbytes += (op->Length - op->Offset);
235
- op->Free();
236
- OutboundPages.pop_front();
237
- }
238
- else {
239
- int len = sizeof(output_buffer) - nbytes;
240
- memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
241
- op->Offset += len;
242
- nbytes += len;
243
- }
244
- }
245
-
246
- // We should never have gotten here if there were no data to write,
247
- // so assert that as a sanity check.
248
- // Don't bother to make sure nbytes is less than output_buffer because
249
- // if it were we probably would have crashed already.
250
- assert (nbytes > 0);
251
-
252
- assert (GetSocket() != INVALID_SOCKET);
253
- int bytes_written = write (GetSocket(), output_buffer, nbytes);
254
-
255
- if (bytes_written > 0) {
256
- OutboundDataSize -= bytes_written;
257
- if ((size_t)bytes_written < nbytes) {
258
- int len = nbytes - bytes_written;
259
- char *buffer = (char*) malloc (len + 1);
260
- if (!buffer)
261
- throw std::runtime_error ("bad alloc throwing back data");
262
- memcpy (buffer, output_buffer + bytes_written, len);
263
- buffer [len] = 0;
264
- OutboundPages.push_front (OutboundPage (buffer, len));
265
- }
266
- #ifdef HAVE_EPOLL
267
- EpollEvent.events = (EPOLLIN | (SelectForWrite() ? EPOLLOUT : 0));
268
- assert (MyEventMachine);
269
- MyEventMachine->Modify (this);
270
- #endif
271
- }
272
- else {
273
- #ifdef OS_UNIX
274
- if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
275
- #endif
276
- #ifdef OS_WIN32
277
- if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
278
- #endif
279
- Close();
280
- }
281
- }
282
-
283
-
284
- /*************************
285
- PipeDescriptor::Heartbeat
286
- *************************/
287
-
288
- void PipeDescriptor::Heartbeat()
289
- {
290
- // If an inactivity timeout is defined, then check for it.
291
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
292
- ScheduleClose (false);
293
- //bCloseNow = true;
294
- }
295
-
296
-
297
- /*****************************
298
- PipeDescriptor::SelectForRead
299
- *****************************/
300
-
301
- bool PipeDescriptor::SelectForRead()
302
- {
303
- /* Pipe descriptors, being local by definition, don't have
304
- * a pending state, so this is simpler than for the
305
- * ConnectionDescriptor object.
306
- */
307
- return true;
308
- }
309
-
310
- /******************************
311
- PipeDescriptor::SelectForWrite
312
- ******************************/
313
-
314
- bool PipeDescriptor::SelectForWrite()
315
- {
316
- /* Pipe descriptors, being local by definition, don't have
317
- * a pending state, so this is simpler than for the
318
- * ConnectionDescriptor object.
319
- */
320
- return (GetOutboundDataSize() > 0);
321
- }
322
-
323
-
324
-
325
-
326
- /********************************
327
- PipeDescriptor::SendOutboundData
328
- ********************************/
329
-
330
- int PipeDescriptor::SendOutboundData (const char *data, int length)
331
- {
332
- //if (bCloseNow || bCloseAfterWriting)
333
- if (IsCloseScheduled())
334
- return 0;
335
-
336
- if (!data && (length > 0))
337
- throw std::runtime_error ("bad outbound data");
338
- char *buffer = (char *) malloc (length + 1);
339
- if (!buffer)
340
- throw std::runtime_error ("no allocation for outbound data");
341
- memcpy (buffer, data, length);
342
- buffer [length] = 0;
343
- OutboundPages.push_back (OutboundPage (buffer, length));
344
- OutboundDataSize += length;
345
- #ifdef HAVE_EPOLL
346
- EpollEvent.events = (EPOLLIN | EPOLLOUT);
347
- assert (MyEventMachine);
348
- MyEventMachine->Modify (this);
349
- #endif
350
- return length;
351
- }
352
-
353
- /********************************
354
- PipeDescriptor::GetSubprocessPid
355
- ********************************/
356
-
357
- bool PipeDescriptor::GetSubprocessPid (pid_t *pid)
358
- {
359
- bool ok = false;
360
- if (pid && (SubprocessPid > 0)) {
361
- *pid = SubprocessPid;
362
- ok = true;
363
- }
364
- return ok;
365
- }
366
-
367
- #endif
368
-
@@ -94,21 +94,38 @@ PipeDescriptor::~PipeDescriptor()
94
94
 
95
95
  assert (MyEventMachine);
96
96
 
97
- // check if the process is already dead
98
- if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) {
99
- kill (SubprocessPid, SIGTERM);
100
- // wait 0.25s for process to die
101
- struct timespec req = {0, 250000000};
97
+ /* Another hack to make the SubprocessPid available to get_subprocess_status */
98
+ MyEventMachine->SubprocessPid = SubprocessPid;
99
+
100
+ /* 01Mar09: Updated to use a small nanosleep in a loop. When nanosleep is interrupted by SIGCHLD,
101
+ * it resumes the system call after processing the signal (resulting in unnecessary latency).
102
+ * Calling nanosleep in a loop avoids this problem.
103
+ */
104
+ struct timespec req = {0, 50000000}; // 0.05s
105
+ int n;
106
+
107
+ // wait 0.25s for the process to die
108
+ for (n=0; n<5; n++) {
109
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
102
110
  nanosleep (&req, NULL);
103
- if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0) {
104
- kill (SubprocessPid, SIGKILL);
105
- // wait 0.5s for process to die
106
- struct timespec req = {0, 500000000};
107
- nanosleep (&req, NULL);
108
- if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) == 0)
109
- throw std::runtime_error ("unable to reap subprocess");
110
- }
111
111
  }
112
+
113
+ // send SIGTERM and wait another 0.5s
114
+ kill (SubprocessPid, SIGTERM);
115
+ for (n=0; n<10; n++) {
116
+ nanosleep (&req, NULL);
117
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
118
+ }
119
+
120
+ // send SIGKILL and wait another 1s
121
+ kill (SubprocessPid, SIGKILL);
122
+ for (n=0; n<20; n++) {
123
+ nanosleep (&req, NULL);
124
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
125
+ }
126
+
127
+ // still not dead, give up!
128
+ throw std::runtime_error ("unable to reap subprocess");
112
129
  }
113
130
 
114
131
 
@@ -30,43 +30,61 @@ Statics
30
30
  static VALUE EmModule;
31
31
  static VALUE EmConnection;
32
32
 
33
+ static VALUE EM_eUnknownTimerFired;
34
+ static VALUE EM_eConnectionNotBound;
35
+
33
36
  static VALUE Intern_at_signature;
34
37
  static VALUE Intern_at_timers;
35
38
  static VALUE Intern_at_conns;
39
+ static VALUE Intern_at_error_handler;
36
40
  static VALUE Intern_event_callback;
37
41
  static VALUE Intern_run_deferred_callbacks;
38
42
  static VALUE Intern_delete;
39
43
  static VALUE Intern_call;
40
44
  static VALUE Intern_receive_data;
41
-
45
+ static VALUE Intern_ssl_handshake_completed;
42
46
  static VALUE Intern_notify_readable;
43
47
  static VALUE Intern_notify_writable;
44
48
 
49
+ static VALUE rb_cProcStatus;
50
+
51
+ struct em_event {
52
+ const char *a1;
53
+ int a2;
54
+ const char *a3;
55
+ int a4;
56
+ };
57
+
45
58
  /****************
46
59
  t_event_callback
47
60
  ****************/
48
61
 
49
- static void event_callback (const char *a1, int a2, const char *a3, int a4)
62
+ static void event_callback (struct em_event* e)
50
63
  {
64
+ const char *a1 = e->a1;
65
+ int a2 = e->a2;
66
+ const char *a3 = e->a3;
67
+ int a4 = e->a4;
68
+
51
69
  if (a2 == EM_CONNECTION_READ) {
52
70
  VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
53
71
  VALUE q = rb_hash_aref (t, rb_str_new2(a1));
54
72
  if (q == Qnil)
55
- rb_raise (rb_eRuntimeError, "no connection");
73
+ rb_raise (EM_eConnectionNotBound, "received %d bytes of data for unknown signature: %s", a4, a1);
56
74
  rb_funcall (q, Intern_receive_data, 1, rb_str_new (a3, a4));
57
75
  }
58
76
  else if (a2 == EM_CONNECTION_NOTIFY_READABLE) {
59
77
  VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
60
78
  VALUE q = rb_hash_aref (t, rb_str_new2(a1));
61
79
  if (q == Qnil)
62
- rb_raise (rb_eRuntimeError, "no connection");
80
+ rb_raise (EM_eConnectionNotBound, "unknown connection: %s", a1);
63
81
  rb_funcall (q, Intern_notify_readable, 0);
64
82
  }
65
83
  else if (a2 == EM_CONNECTION_NOTIFY_WRITABLE) {
66
84
  VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
67
85
  VALUE q = rb_hash_aref (t, rb_str_new2(a1));
68
86
  if (q == Qnil)
69
- rb_raise (rb_eRuntimeError, "no connection");
87
+ rb_raise (EM_eConnectionNotBound, "unknown connection: %s", a1);
70
88
  rb_funcall (q, Intern_notify_writable, 0);
71
89
  }
72
90
  else if (a2 == EM_LOOPBREAK_SIGNAL) {
@@ -76,14 +94,47 @@ static void event_callback (const char *a1, int a2, const char *a3, int a4)
76
94
  VALUE t = rb_ivar_get (EmModule, Intern_at_timers);
77
95
  VALUE q = rb_funcall (t, Intern_delete, 1, rb_str_new(a3, a4));
78
96
  if (q == Qnil)
79
- rb_raise (rb_eRuntimeError, "no timer");
97
+ rb_raise (EM_eUnknownTimerFired, "no such timer: %s", a1);
80
98
  rb_funcall (q, Intern_call, 0);
81
99
  }
100
+ else if (a2 == EM_SSL_HANDSHAKE_COMPLETED) {
101
+ VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
102
+ VALUE q = rb_hash_aref (t, rb_str_new2(a1));
103
+ if (q == Qnil)
104
+ rb_raise (EM_eConnectionNotBound, "unknown connection: %s", a1);
105
+ rb_funcall (q, Intern_ssl_handshake_completed, 0);
106
+ }
82
107
  else
83
108
  rb_funcall (EmModule, Intern_event_callback, 3, rb_str_new2(a1), (a2 << 1) | 1, rb_str_new(a3,a4));
84
109
  }
85
110
 
111
+ /*******************
112
+ event_error_handler
113
+ *******************/
114
+
115
+ static void event_error_handler(VALUE unused, VALUE err)
116
+ {
117
+ VALUE error_handler = rb_ivar_get(EmModule, Intern_at_error_handler);
118
+ rb_funcall (error_handler, Intern_call, 1, err);
119
+ }
120
+
121
+ /**********************
122
+ event_callback_wrapper
123
+ **********************/
86
124
 
125
+ static void event_callback_wrapper (const char *a1, int a2, const char *a3, int a4)
126
+ {
127
+ struct em_event e;
128
+ e.a1 = a1;
129
+ e.a2 = a2;
130
+ e.a3 = a3;
131
+ e.a4 = a4;
132
+
133
+ if (!rb_ivar_defined(EmModule, Intern_at_error_handler))
134
+ event_callback(&e);
135
+ else
136
+ rb_rescue((VALUE (*)(ANYARGS))event_callback, (VALUE)&e, (VALUE (*)(ANYARGS))event_error_handler, Qnil);
137
+ }
87
138
 
88
139
  /**************************
89
140
  t_initialize_event_machine
@@ -91,7 +142,7 @@ t_initialize_event_machine
91
142
 
92
143
  static VALUE t_initialize_event_machine (VALUE self)
93
144
  {
94
- evma_initialize_library (event_callback);
145
+ evma_initialize_library (event_callback_wrapper);
95
146
  return Qnil;
96
147
  }
97
148
 
@@ -194,6 +245,34 @@ static VALUE t_set_tls_parms (VALUE self, VALUE signature, VALUE privkeyfile, VA
194
245
  return Qnil;
195
246
  }
196
247
 
248
+ /***********
249
+ t_get_peer_cert
250
+ ***********/
251
+
252
+ static VALUE t_get_peer_cert (VALUE self, VALUE signature)
253
+ {
254
+ VALUE ret = Qnil;
255
+
256
+ #ifdef WITH_SSL
257
+ X509 *cert = NULL;
258
+ BUF_MEM *buf;
259
+ BIO *out;
260
+
261
+ cert = evma_get_peer_cert (StringValuePtr (signature));
262
+
263
+ if (cert != NULL) {
264
+ out = BIO_new(BIO_s_mem());
265
+ PEM_write_bio_X509(out, cert);
266
+ BIO_get_mem_ptr(out, &buf);
267
+ ret = rb_str_new(buf->data, buf->length);
268
+ X509_free(cert);
269
+ BUF_MEM_free(buf);
270
+ }
271
+ #endif
272
+
273
+ return ret;
274
+ }
275
+
197
276
  /**************
198
277
  t_get_peername
199
278
  **************/
@@ -242,12 +321,29 @@ t_get_subprocess_status
242
321
 
243
322
  static VALUE t_get_subprocess_status (VALUE self, VALUE signature)
244
323
  {
324
+ VALUE proc_status = Qnil;
325
+
245
326
  int status;
327
+ pid_t pid;
328
+
246
329
  if (evma_get_subprocess_status (StringValuePtr (signature), &status)) {
247
- return INT2NUM (status);
330
+ if (evma_get_subprocess_pid (StringValuePtr (signature), &pid)) {
331
+ proc_status = rb_obj_alloc(rb_cProcStatus);
332
+ rb_iv_set(proc_status, "status", INT2FIX(status));
333
+ rb_iv_set(proc_status, "pid", INT2FIX(pid));
334
+ }
248
335
  }
249
336
 
250
- return Qnil;
337
+ return proc_status;
338
+ }
339
+
340
+ /**********************
341
+ t_get_connection_count
342
+ **********************/
343
+
344
+ static VALUE t_get_connection_count (VALUE self)
345
+ {
346
+ return INT2NUM(evma_get_connection_count());
251
347
  }
252
348
 
253
349
  /*****************************
@@ -423,6 +519,15 @@ static VALUE t_set_timer_quantum (VALUE self, VALUE interval)
423
519
  return Qnil;
424
520
  }
425
521
 
522
+ /********************
523
+ t_get_max_timer_count
524
+ ********************/
525
+
526
+ static VALUE t_get_max_timer_count (VALUE self)
527
+ {
528
+ return INT2FIX (evma_get_max_timer_count());
529
+ }
530
+
426
531
  /********************
427
532
  t_set_max_timer_count
428
533
  ********************/
@@ -640,17 +745,22 @@ Init_rubyeventmachine
640
745
 
641
746
  extern "C" void Init_rubyeventmachine()
642
747
  {
748
+ // Lookup Process::Status for get_subprocess_status
749
+ VALUE rb_mProcess = rb_const_get(rb_cObject, rb_intern("Process"));
750
+ rb_cProcStatus = rb_const_get(rb_mProcess, rb_intern("Status"));
751
+
643
752
  // Tuck away some symbol values so we don't have to look 'em up every time we need 'em.
644
753
  Intern_at_signature = rb_intern ("@signature");
645
754
  Intern_at_timers = rb_intern ("@timers");
646
755
  Intern_at_conns = rb_intern ("@conns");
756
+ Intern_at_error_handler = rb_intern("@error_handler");
647
757
 
648
758
  Intern_event_callback = rb_intern ("event_callback");
649
759
  Intern_run_deferred_callbacks = rb_intern ("run_deferred_callbacks");
650
760
  Intern_delete = rb_intern ("delete");
651
761
  Intern_call = rb_intern ("call");
652
762
  Intern_receive_data = rb_intern ("receive_data");
653
-
763
+ Intern_ssl_handshake_completed = rb_intern ("ssl_handshake_completed");
654
764
  Intern_notify_readable = rb_intern ("notify_readable");
655
765
  Intern_notify_writable = rb_intern ("notify_writable");
656
766
 
@@ -660,9 +770,9 @@ extern "C" void Init_rubyeventmachine()
660
770
  EmModule = rb_define_module ("EventMachine");
661
771
  EmConnection = rb_define_class_under (EmModule, "Connection", rb_cObject);
662
772
 
663
- rb_define_class_under (EmModule, "ConnectionNotBound", rb_eException);
664
773
  rb_define_class_under (EmModule, "NoHandlerForAcceptedConnection", rb_eException);
665
- rb_define_class_under (EmModule, "UnknownTimerFired", rb_eException);
774
+ EM_eConnectionNotBound = rb_define_class_under (EmModule, "ConnectionNotBound", rb_eRuntimeError);
775
+ EM_eUnknownTimerFired = rb_define_class_under (EmModule, "UnknownTimerFired", rb_eRuntimeError);
666
776
 
667
777
  rb_define_module_function (EmModule, "initialize_event_machine", (VALUE(*)(...))t_initialize_event_machine, 0);
668
778
  rb_define_module_function (EmModule, "run_machine", (VALUE(*)(...))t_run_machine_without_threads, 0);
@@ -673,6 +783,7 @@ extern "C" void Init_rubyeventmachine()
673
783
  rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
674
784
  rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 3);
675
785
  rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
786
+ rb_define_module_function (EmModule, "get_peer_cert", (VALUE(*)(...))t_get_peer_cert, 1);
676
787
  rb_define_module_function (EmModule, "send_data", (VALUE(*)(...))t_send_data, 3);
677
788
  rb_define_module_function (EmModule, "send_datagram", (VALUE(*)(...))t_send_datagram, 5);
678
789
  rb_define_module_function (EmModule, "close_connection", (VALUE(*)(...))t_close_connection, 2);
@@ -692,6 +803,7 @@ extern "C" void Init_rubyeventmachine()
692
803
  rb_define_module_function (EmModule, "signal_loopbreak", (VALUE(*)(...))t_signal_loopbreak, 0);
693
804
  rb_define_module_function (EmModule, "library_type", (VALUE(*)(...))t_library_type, 0);
694
805
  rb_define_module_function (EmModule, "set_timer_quantum", (VALUE(*)(...))t_set_timer_quantum, 1);
806
+ rb_define_module_function (EmModule, "get_max_timer_count", (VALUE(*)(...))t_get_max_timer_count, 0);
695
807
  rb_define_module_function (EmModule, "set_max_timer_count", (VALUE(*)(...))t_set_max_timer_count, 1);
696
808
  rb_define_module_function (EmModule, "setuid_string", (VALUE(*)(...))t_setuid_string, 1);
697
809
  rb_define_module_function (EmModule, "invoke_popen", (VALUE(*)(...))t_invoke_popen, 1);
@@ -707,6 +819,7 @@ extern "C" void Init_rubyeventmachine()
707
819
  rb_define_module_function (EmModule, "get_comm_inactivity_timeout", (VALUE(*)(...))t_get_comm_inactivity_timeout, 1);
708
820
  rb_define_module_function (EmModule, "set_comm_inactivity_timeout", (VALUE(*)(...))t_set_comm_inactivity_timeout, 2);
709
821
  rb_define_module_function (EmModule, "set_rlimit_nofile", (VALUE(*)(...))t_set_rlimit_nofile, 1);
822
+ rb_define_module_function (EmModule, "get_connection_count", (VALUE(*)(...))t_get_connection_count, 0);
710
823
 
711
824
  // Temporary:
712
825
  rb_define_module_function (EmModule, "epoll", (VALUE(*)(...))t__epoll, 0);
@@ -728,5 +841,7 @@ extern "C" void Init_rubyeventmachine()
728
841
  rb_define_const (EmModule, "ConnectionNotifyReadable", INT2NUM(106));
729
842
  rb_define_const (EmModule, "ConnectionNotifyWritable", INT2NUM(107));
730
843
 
844
+ rb_define_const (EmModule, "SslHandshakeCompleted", INT2NUM(108));
845
+
731
846
  }
732
847